diff options
author | Simon MacMullen <simon@rabbitmq.com> | 2014-03-24 13:44:54 +0000 |
---|---|---|
committer | Simon MacMullen <simon@rabbitmq.com> | 2014-03-24 13:44:54 +0000 |
commit | 5495855d608b440f647205345ce2cb9bf6ef9dc0 (patch) | |
tree | 76c60dcdfa52c7c429c197883fe4745c90549d7a /src/truncate.erl | |
parent | 5b7a9d91885a40234ff681750c4c49b947648764 (diff) | |
download | rabbitmq-server-5495855d608b440f647205345ce2cb9bf6ef9dc0.tar.gz |
Something of a rewrite:
* Allow choice of how much size to "eat" each time we descend
* Fix at least one more recurse-indefinitely bug
* Try to reduce the amount of copying we do, and use more efficient techniques
* Add some tests
Diffstat (limited to 'src/truncate.erl')
-rw-r--r-- | src/truncate.erl | 116 |
1 files changed, 70 insertions, 46 deletions
diff --git a/src/truncate.erl b/src/truncate.erl index 433a18e7..3cbc8c0b 100644 --- a/src/truncate.erl +++ b/src/truncate.erl @@ -16,67 +16,91 @@ -module(truncate). --export([log_event/2]). +-define(ELLIPSIS_LENGTH, 3). + +-export([log_event/3]). %% exported for testing --export([term/2]). +-export([test/0, term/3]). -log_event({Type, GL, {Pid, Format, Args}}, Size) +log_event({Type, GL, {Pid, Format, Args}}, Size, Decr) when Type =:= error orelse Type =:= info_msg orelse Type =:= warning_msg -> - {Type, GL, {Pid, Format, [term(T, Size) || T <- Args]}}; -log_event({Type, GL, {Pid, ReportType, Report}}, Size) + {Type, GL, {Pid, Format, [term(T, Size, Decr) || T <- Args]}}; +log_event({Type, GL, {Pid, ReportType, Report}}, Size, Decr) when Type =:= error_report orelse Type =:= info_report orelse Type =:= warning_report -> Report2 = case ReportType of - crash_report -> [[{K, term(V, Size)} || {K, V} <- R] || + crash_report -> [[{K, term(V, Size, Decr)} || {K, V} <- R] || R <- Report]; - _ -> [{K, term(V, Size)} || {K, V} <- Report] + _ -> [{K, term(V, Size, Decr)} || {K, V} <- Report] end, {Type, GL, {Pid, ReportType, Report2}}; -log_event(Event, _Size) -> +log_event(Event, _Size, _Decr) -> Event. -%% TODO: avoid copying -term(_T, 0) -> '...'; -term(T, N) when is_binary(T) andalso size(T) > N -> - Suffix = N - 3, - Len = case is_bitstring(T) of - true -> byte_size(T); - false -> size(T) - end, - case Len - Suffix of - Sz when Sz >= 1 -> <<Head:Suffix/binary, _/binary>> = T, - <<Head/binary, <<"...">>/binary>>; - _ -> T - end; -term([A|B], N) when not is_list(B) -> - term([A,B], N); -term(T, N) when is_list(T) -> - IsPrintable = io_lib:printable_list(T), - Len = length(T), - case {Len > N, IsPrintable} of - {true, true} - when N > 3 -> lists:append(lists:sublist(T, resize(N-3)), "..."); - {true, false} -> lists:append([term(E, resize(N-1, Len)) || - E <- lists:sublist(T, resize(N-1))], - ['...']); - {false, false} -> [term(E, resize(N-1, Len)) || E <- T]; - _ -> T +term(_, N, _) when N =< 0 -> + '...'; +term(Bin, N, _D) when is_binary(Bin) andalso size(Bin) > N - ?ELLIPSIS_LENGTH -> + Suffix = without_ellipsis(N), + <<Head:Suffix/binary, _/binary>> = Bin, + <<Head/binary, <<"...">>/binary>>; +term(L, N, D) when is_list(L) -> + IsPrintable = io_lib:printable_list(L), + case IsPrintable of + true -> case length(L) > without_ellipsis(N) of + true -> string:left(L, without_ellipsis(N)) ++ "..."; + false -> L + end; + false -> shrink_list(L, N, D) end; -term(T, N) when is_tuple(T) -> - case tuple_size(T) > N of - true -> list_to_tuple( - lists:append([term(E, N-1) || - E <- lists:sublist(tuple_to_list(T), N-1)], - ['...'])); - false -> list_to_tuple([term(E, N-1) || - E <- tuple_to_list(T)]) - end; -term(T, _) -> T. +term(T, N, D) when is_tuple(T) -> + shrink_tuple(T, N, D); +term(T, _, _) -> + T. + +without_ellipsis(N) -> erlang:max(N - ?ELLIPSIS_LENGTH, 0). + +shrink_list(_, 0, _) -> + ['...']; +shrink_list([], _N, _D) -> + []; +shrink_list([H|T], N, D) -> + [term(H, N - D, D) | case is_list(T) of + true -> shrink_list(T, N - 1, D); + false -> term(T, N - 1, D) + end]. + +shrink_tuple(T, N, D) -> + shrink_tuple(T, N, D, erlang:min(tuple_size(T), N)). + +shrink_tuple(_T, _N, _D, 0) -> + {}; +shrink_tuple(T, N, D, Ix) -> + erlang:append_element(shrink_tuple(T, N, D, Ix - 1), + term(element(Ix, T), N - D, D)). + +%%---------------------------------------------------------------------------- -resize(N) -> resize(N, 1). +test() -> + test_short_examples_exactly(), + test_large_examples_for_size(), + ok. -resize(N, M) -> erlang:max(N, M). +test_short_examples_exactly() -> + F = fun (Term, Exp) -> Exp = term(Term, 10, 5) end, + F([], []), + F("h", "h"), + F("hello world", "hello w..."), + F([a|b], [a|b]), + F([<<"hello world">>], [<<"he...">>]), + F({{{{a}}},{b},c,d,e,f,g,h,i,j,k}, {{'...'},{'...'},c,d,e,f,g,h,i,j}), + P = spawn(fun() -> receive die -> ok end end), + F([0, 0.0, <<1:1>>, F, P], [0, 0.0, <<1:1>>, F, P]), + P ! die, + ok. +test_large_examples_for_size() -> + %% TODO + ok. |