diff --git a/README.md b/README.md index 645d3aa..eed11b5 100644 --- a/README.md +++ b/README.md @@ -392,6 +392,20 @@ Lager 2.0 changed the backend API, there are various 3rd party backends for lager available, but they may not have been updated to the new API. As they are updated, links to them can be re-added here. +Exception Pretty Printing +---------------------- + +```erlang +try + foo() +catch + Class:Reason -> + lager:error( + "~nStacktrace:~s", + [lager:pr_stacktrace(erlang:get_stacktrace(), {Class, Reason})]) +end. +``` + Record Pretty Printing ---------------------- Lager's parse transform will keep track of any record definitions it encounters diff --git a/src/error_logger_lager_h.erl b/src/error_logger_lager_h.erl index 2bdab73..789ffab 100644 --- a/src/error_logger_lager_h.erl +++ b/src/error_logger_lager_h.erl @@ -31,7 +31,7 @@ -export([init/1, handle_call/2, handle_event/2, handle_info/2, terminate/2, code_change/3]). --export([format_reason/1]). +-export([format_reason/1, format_mfa/1, format_args/3]). -record(state, { shaper :: lager_shaper(), diff --git a/src/lager.erl b/src/lager.erl index 90386c3..9e4b051 100644 --- a/src/lager.erl +++ b/src/lager.erl @@ -33,7 +33,7 @@ get_loglevel/1, get_loglevel/2, set_loglevel/2, set_loglevel/3, set_loglevel/4, get_loglevels/1, update_loglevel_config/1, posix_error/1, set_loghwm/2, set_loghwm/3, set_loghwm/4, safe_format/3, safe_format_chop/3, unsafe_format/2, dispatch_log/5, dispatch_log/7, dispatch_log/9, - do_log/9, do_log/10, do_log_unsafe/10, pr/2, pr/3]). + do_log/9, do_log/10, do_log_unsafe/10, pr/2, pr/3, pr_stacktrace/1, pr_stacktrace/2]). -type log_level() :: debug | info | notice | warning | error | critical | alert | emergency. -type log_level_number() :: 0..7. @@ -580,3 +580,17 @@ is_record_known(Record, Module) -> end end. + +%% @doc Print stacktrace in human readable form +pr_stacktrace(Stacktrace) -> + Indent = "\n ", + lists:foldl( + fun(Entry, Acc) -> + Acc ++ Indent ++ error_logger_lager_h:format_mfa(Entry) + end, + [], + lists:reverse(Stacktrace)). + +pr_stacktrace(Stacktrace, {Class, Reason}) -> + lists:flatten( + pr_stacktrace(Stacktrace) ++ "\n" ++ io_lib:format("~s:~p", [Class, Reason])). diff --git a/test/pr_stacktrace_test.erl b/test/pr_stacktrace_test.erl new file mode 100644 index 0000000..6e3d8cc --- /dev/null +++ b/test/pr_stacktrace_test.erl @@ -0,0 +1,55 @@ +-module(pr_stacktrace_test). + +-compile([{parse_transform, lager_transform}]). + +-include_lib("eunit/include/eunit.hrl"). + +make_throw() -> + throw({test, exception}). + +bad_arity() -> + lists:concat([], []). + +bad_arg() -> + integer_to_list(1.0). + +pr_stacktrace_throw_test() -> + Result = try + make_throw() + catch + Class:Reason -> + lager:pr_stacktrace(erlang:get_stacktrace(), {Class, Reason}) + end, +ExpectedPart = " + pr_stacktrace_test:pr_stacktrace_throw_test/0 line 18 + pr_stacktrace_test:make_throw/0 line 8 +throw:{test,exception}", + ?assertNotEqual(0, string:str(Result, ExpectedPart)). + + +pr_stacktrace_bad_arg_test() -> + Result = try + bad_arg() + catch + Class:Reason -> + lager:pr_stacktrace(erlang:get_stacktrace(), {Class, Reason}) + end, +ExpectedPart = " + pr_stacktrace_test:pr_stacktrace_bad_arg_test/0 line 32 + pr_stacktrace_test:bad_arg/0 line 14 +error:badarg", + ?assertNotEqual(0, string:str(Result, ExpectedPart)). + + +pr_stacktrace_bad_arity_test() -> + Result = try + bad_arity() + catch + Class:Reason -> + lager:pr_stacktrace(erlang:get_stacktrace(), {Class, Reason}) + end, +ExpectedPart = " + pr_stacktrace_test:pr_stacktrace_bad_arity_test/0 line 46 + lists:concat([], []) +error:undef", + ?assertNotEqual(0, string:str(Result, ExpectedPart)). \ No newline at end of file