├── .gitignore ├── LICENSE ├── README.md ├── src ├── pe.erl ├── pretty_errors.app.src └── pretty_errors.erl └── test └── pretty_errors_tests.erl /.gitignore: -------------------------------------------------------------------------------- 1 | .eunit 2 | deps 3 | *.o 4 | *.beam 5 | *.plt 6 | erl_crash.dump 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Adam Lindberg 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | pretty_errors 2 | ============= 3 | 4 | Error and stack trace pretty printers for Erlang 5 | 6 | ## Stacktraces 7 | 8 | Normal: 9 | 10 | ```erl 11 | 1> try error(expected) catch _:_ -> erlang:get_stacktrace() end. 12 | [{erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,573}]}, 13 | {erl_eval,try_clauses,8,[{file,"erl_eval.erl"},{line,764}]}, 14 | {shell,exprs,7,[{file,"shell.erl"},{line,674}]}, 15 | {shell,eval_exprs,7,[{file,"shell.erl"},{line,629}]}, 16 | {shell,eval_loop,3,[{file,"shell.erl"},{line,614}]}] 17 | ``` 18 | 19 | With pretty printing: 20 | ```erl 21 | 1> io:format(try error(expected) catch _:_ -> pe:st(erlang:get_stacktrace()) end). 22 | erl_eval:do_apply/6 (erl_eval.erl:573) 23 | erl_eval:try_clauses/8 (erl_eval.erl:764) 24 | erl_eval:expr_list/6 (erl_eval.erl:738) 25 | erl_eval:expr/5 (erl_eval.erl:330) 26 | shell:exprs/7 (shell.erl:674) 27 | shell:eval_exprs/7 (shell.erl:629) 28 | shell:eval_loop/3 (shell.erl:614) 29 | ok 30 | ``` 31 | 32 | -------------------------------------------------------------------------------- /src/pe.erl: -------------------------------------------------------------------------------- 1 | -module(pe). 2 | 3 | % API 4 | -export([st/1]). 5 | -export([st/2]). 6 | -export([stacktrace/1]). 7 | -export([stacktrace/2]). 8 | 9 | %--- API ---------------------------------------------------------------------- 10 | 11 | st(S) -> pretty_errors:stacktrace(S). 12 | st(S, O) -> pretty_errors:stacktrace(S, O). 13 | stacktrace(S) -> pretty_errors:stacktrace(S). 14 | stacktrace(S, O) -> pretty_errors:stacktrace(S, O). 15 | -------------------------------------------------------------------------------- /src/pretty_errors.app.src: -------------------------------------------------------------------------------- 1 | {application, pretty_errors, [ 2 | {description, "Error and stack trace pretty printers"}, 3 | {vsn, "0.1"}, 4 | {applications, [kernel, stdlib]} 5 | ]}. 6 | -------------------------------------------------------------------------------- /src/pretty_errors.erl: -------------------------------------------------------------------------------- 1 | -module(pretty_errors). 2 | 3 | % API 4 | -export([stacktrace/1]). 5 | -export([stacktrace/2]). 6 | 7 | %--- API ---------------------------------------------------------------------- 8 | 9 | stacktrace(Stacktrace) -> stacktrace(Stacktrace, [{indent, 4}]). 10 | 11 | stacktrace(Stacktrace, Options) -> 12 | Indent = lists:duplicate(proplists:get_value(indent, Options), <<" ">>), 13 | stacktrace_pretty(Indent, Stacktrace). 14 | 15 | stacktrace_pretty(_Indent, []) -> 16 | []; 17 | stacktrace_pretty(Indent, [Entry|Stacktrace]) -> 18 | {Mod, Func, Arity, [{file, File}, {line, Line}]} = Entry, 19 | Output = [ 20 | Indent, 21 | atom_to_list(Mod), 22 | <<":">>, 23 | atom_to_list(Func), 24 | <<"/">>, 25 | integer_to_binary(Arity), 26 | <<" (">>, 27 | File, 28 | <<":">>, 29 | integer_to_binary(Line), 30 | <<")">>, 31 | io_lib:format("~n", []) 32 | ], 33 | [Output|stacktrace_pretty(Indent, Stacktrace)]. 34 | -------------------------------------------------------------------------------- /test/pretty_errors_tests.erl: -------------------------------------------------------------------------------- 1 | -module(pretty_errors_tests). 2 | 3 | -include_lib("eunit/include/eunit.hrl"). 4 | 5 | %--- Tests -------------------------------------------------------------------- 6 | 7 | stacktrace_test() -> 8 | ?assert(is_iodata(pe:st(stacktrace()))). 9 | 10 | %--- Internal Functions ------------------------------------------------------- 11 | 12 | stacktrace() -> 13 | try error(expected) catch _:_ -> erlang:get_stacktrace() end. 14 | 15 | % http://erlang.org/pipermail/erlang-questions/2009-May/044073.html 16 | is_iodata(B) when is_binary(B) -> true; 17 | is_iodata(L) -> is_iolist(L). 18 | 19 | is_iolist([]) -> true; 20 | is_iolist([X|Xs]) when is_integer(X), X >= 0, X =< 255 -> 21 | is_iodata(Xs); 22 | is_iolist([X|Xs]) -> 23 | case is_iodata(X) of 24 | true -> is_iodata(Xs); 25 | false -> false 26 | end; 27 | is_iolist(_) -> false. --------------------------------------------------------------------------------