diff --git a/src/lager_crash_log.erl b/src/lager_crash_log.erl index 3c3a224..b8192df 100644 --- a/src/lager_crash_log.erl +++ b/src/lager_crash_log.erl @@ -69,12 +69,11 @@ handle_call(_Call, _From, State) -> %% @private handle_cast({log, Event}, #state{name=Name, fd=FD, inode=Inode, flap=Flap} = State) -> %% TODO these should probably be configurable and have saner defaults - FmtMaxBytes = 1024, - TermMaxSize = 500, + FmtMaxBytes = 6192, %% borrowed from riak_err {ReportStr, Pid, MsgStr, _ErrorP} = case Event of {error, _GL, {Pid1, Fmt, Args}} -> - {"ERROR REPORT", Pid1, limited_fmt(Fmt, Args, TermMaxSize, FmtMaxBytes), true}; + {"ERROR REPORT", Pid1, limited_fmt(Fmt, Args, FmtMaxBytes), true}; {error_report, _GL, {Pid1, std_error, Rep}} -> {"ERROR REPORT", Pid1, limited_str(Rep, FmtMaxBytes), true}; {error_report, _GL, Other} -> @@ -127,7 +126,7 @@ code_change(_OldVsn, State, _Extra) -> %% ===== Begin code lifted from riak_err ===== --spec limited_fmt(string(), list(), integer(), integer()) -> iolist(). +-spec limited_fmt(string(), list(), integer()) -> iolist(). %% @doc Format Fmt and Args similar to what io_lib:format/2 does but with %% limits on how large the formatted string may be. %% @@ -135,19 +134,8 @@ code_change(_OldVsn, State, _Extra) -> %% formatting is done by trunc_io:print/2, where FmtMaxBytes is used %% to limit the formatted string's size. -limited_fmt(Fmt, Args, TermMaxSize, FmtMaxBytes) -> - TermSize = erts_debug:flat_size(Args), - if TermSize > TermMaxSize -> - ["Oversize args for format \"", Fmt, "\": \n", - [ - begin - {Str, _} = trunc_io:print(lists:nth(N, Args), FmtMaxBytes), - [" arg", integer_to_list(N), ": ", Str, "\n"] - end || N <- lists:seq(1, length(Args)) - ]]; - true -> - io_lib:format(Fmt, Args) - end. +limited_fmt(Fmt, Args, FmtMaxBytes) -> + trunc_io:format(Fmt, Args, FmtMaxBytes). limited_str(Term, FmtMaxBytes) -> {Str, _} = trunc_io:print(Term, FmtMaxBytes), diff --git a/src/trunc_io.erl b/src/trunc_io.erl index a354385..2ddc433 100644 --- a/src/trunc_io.erl +++ b/src/trunc_io.erl @@ -29,10 +29,90 @@ -module(trunc_io). -author('matthias@corelatus.se'). %% And thanks to Chris Newcombe for a bug fix --export([print/2, fprint/2, safe/2]). % interface functions +-export([format/3, print/2, fprint/2, safe/2]). % interface functions -export([perf/0, perf/3, perf1/0, test/0, test/2]). % testing functions -version("$Id: trunc_io.erl,v 1.11 2009-02-23 12:01:06 matthias Exp $"). +format(String, Args, Max) -> + Parts = re:split(String, + "(~(?:-??\\d+\\.|\\*\\.|)(?:-??\d+\\.|\\*\\.|)(?:-??\\d+|\\*|)(?:t|)(?:[cfegswpWPBX#bx+ni]))", + [{return, list}, trim]), + Maxlen = Max - length(String), + format(Parts, Args, Maxlen, [], []). + +format([], _Args, _Max, Acc, ArgAcc) -> + io_lib:format(lists:flatten(lists:reverse(Acc)), lists:reverse(ArgAcc)); +format([[] | T], Args, Max, Acc, ArgAcc) -> + % discard the null list generated by split + format(T, Args, Max, Acc, ArgAcc); +format(["~n" | T], Args, Max, Acc, ArgAcc) -> + % ignore newlines for the purposes of argument indexing + format(T, Args, Max+1, ["~n" | Acc], ArgAcc); +format(["~i" | T], [AH | AT], Max, Acc, ArgAcc) -> + % ~i means ignore this argument, but we'll just pass it through + format(T, AT, Max+2, ["~i" | Acc], [AH | ArgAcc]); +format([[$~|H]| T], [AH1, AH2 | AT], Max, Acc, ArgAcc) when H == "W"; H == "P"; H == "X" -> + % these crazy ones consume TWO arguments, just pass them through + % because W and P implicitly limit size so we trust the user knows + % what they're doing. Unfortunately we can't change Max at all because + % depth based limits are not of known length. + format(T, AT, Max, [[$~ | H] | Acc], [AH2, AH1 | ArgAcc]); +format([[$~|H]| T], [AH | AT], Max, Acc, ArgAcc) when length(H) == 1 -> + % single character format specifier, relatively simple + case H of + _ when H == "p"; H == "w"; H == "s" -> + %okay, these are prime candidates for rewriting + {String, Length} = case print(AH, Max) of + {_Res, Max} when AT /= [] -> + % this isn't the last argument, but it consumed all available space, give it half instead + print(AH, Max div 2); + {Res, Len} -> + {Res, Len} + end, + {Value, RealLen} = case H of + "s" -> + % strip off the doublequotes + {string:substr(String, 2, length(String) -2), Length -2}; + _ -> + {String, Length} + end, + format(T, AT, Max + 2 - RealLen, ["~s" | Acc], [Value | ArgAcc]); + _ -> + % whatever, just pass them on through + format(T, AT, Max, [[$~ | H], Acc], [AH | ArgAcc]) + end; +format([[$~|H]| T], [AH | AT], Max, Acc, ArgAcc) -> + %% TODO + % complicated format specifier, gonna have to parse it.. + case re:run(H, "^(?:-??(\\d+|\\*)\\.|)(?:-??(\\d+|\\*)\\.|)(-??\\d+|\\*|)(t|)([cfegswpWPBX#bx+ni])$", [{capture, all_but_first, list}]) of + {match, [_F, _P, _Pad, _Mod, C]} when C == "p"; C=="w"; C=="s" -> + %okay, these are prime candidates for rewriting + {String, Length} = case print(AH, Max) of + {_Res, Max} when AT /= [] -> + % this isn't the last argument, but it consumed all available space, give it half instead + print(AH, Max div 2); + {Res, Len} -> + {Res, Len} + end, + {Value, RealLen} = case H of + "s" -> + % strip off the doublequotes + {string:substr(String, 2, length(String) -2), Length -2}; + _ -> + {String, Length} + end, + format(T, AT, Max + length(H) + 1 - RealLen, ["~s" | Acc], [Value | ArgAcc]); + {match, [_F, _P, _Pad, _Mod, C]} when C == "P"; C=="W" -> + [AH2 | AT2] = AT, + format(T, AT2, Max, [[$~|H]|Acc], [AH2, AH |ArgAcc]); + {match, _} -> + format(T, AT, Max, [H | Acc], [AH|ArgAcc]); + nomatch -> + io:format("unable to match format pattern ~~~p~n", [H]), + format(T, AT, Max, [H | Acc], [AH|ArgAcc]) + end; +format([H | T], Args, Max, Acc, ArgAcc) -> + format(T, Args, Max, [H | Acc], ArgAcc). %% @doc Returns an flattened list containing the ASCII representation of the given %% term. @@ -79,7 +159,7 @@ print(<<>>, _Max) -> print(Binary, Max) when is_binary(Binary) -> B = binary_to_list(Binary, 1, lists:min([Max, size(Binary)])), {L, Len} = alist_start(B, Max-4), - {["<<", L, ">>"], Len}; + {["<<", L, ">>"], Len+4}; print(Float, _Max) when is_float(Float) -> L = float_to_list(Float), @@ -146,7 +226,7 @@ alist_start([], _) -> {"[]", 2}; alist_start(_, Max) when Max < 4 -> {"...", 3}; alist_start([H|T], Max) when H >= 16#20, H =< 16#7e -> % definitely printable {L, Len} = alist([H|T], Max-1), - {[$\"|L], Len + 1}; + {[$"|L], Len + 1}; alist_start([H|T], Max) when H == 9; H == 10; H == 13 -> % show as space {L, Len} = alist(T, Max-1), {[$ |L], Len + 1}; @@ -164,7 +244,7 @@ alist([H|T], Max) when H == 9; H == 10; H == 13 -> % show as space {[$ |L], Len + 1}; alist(L, Max) -> {R, Len} = list_body(L, Max-3), - {[$\", $[, R, $]], Len + 3}. + {[$", $[, R, $]], Len + 3}. %%--------------------