Просмотр исходного кода

Add truc_io:format and use it in the crash logger

pull/4/head
Andrew Thompson 14 лет назад
Родитель
Сommit
01dc584838
2 измененных файлов: 89 добавлений и 21 удалений
  1. +5
    -17
      src/lager_crash_log.erl
  2. +84
    -4
      src/trunc_io.erl

+ 5
- 17
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),

+ 84
- 4
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}.
%%--------------------

Загрузка…
Отмена
Сохранить