瀏覽代碼

ft: 代码修改

master
SisMaker 3 年之前
父節點
當前提交
4aac990e70
共有 9 個檔案被更改,包括 156 行新增102 行删除
  1. +3
    -3
      README.md
  2. +30
    -24
      include/eTpf.hrl
  3. +24
    -25
      src/eTpf.erl
  4. +1
    -1
      src/tracer/tpTracerConsole.erl
  5. +47
    -15
      src/tracer/tpTracerFile.erl
  6. +0
    -3
      src/tracer/tpTracerPool.erl
  7. +2
    -1
      src/tracer/tpTracerSocket.erl
  8. +46
    -27
      src/utils/tpTermCut.erl
  9. +3
    -3
      test/lg_SUITE.erl

+ 3
- 3
README.md 查看文件

@ -235,13 +235,13 @@ end.
对于长时间运行的会话,eTpf可以旋转跟踪文件。这是一项有助于避免磁盘空间用完的功能,并且不用于保留较小的文件(eTpf可以处理非常大的文件就可以了)。
eTpf:trace/3,4可以提供一个映射,而不是将文件名前缀作为第三个参数传递 给。当前有三个选项,包括filename_prefix。其他选项是最大文件大小(以字节为单位)max_size,以及将在文件中每LZ4帧存储的事件数
events_per_frame。这两个选项使您可以控制文件写入或旋转的频率。
eTpf:trace/3,4可以提供一个映射,而不是将文件名前缀作为第三个参数传递 给。当前有三个选项,包括filename_prefix。其他选项是最大文件大小(以字节为单位)fMaxSize,以及将在文件中每LZ4帧存储的事件数
fEventFrame。这两个选项使您可以控制文件写入或旋转的频率。
以下示例将文件大小限制为100MB:
```
1> eTpf:trace('_', lg_file_tracer, #{filename_prefix => "traces.lz4", max_size => 100000000}, #{mode => utils, running =>true}).
1> eTpf:trace('_', lg_file_tracer, #{fBaseName => "traces.lz4", fMaxSize => 100000000}, #{mode => utils, running =>true}).
```
在测试此功能期间,目前实施的轮换似乎很昂贵,因此您应注意不要设置太低的值。

+ 30
- 24
include/eTpf.hrl 查看文件

@ -2,14 +2,18 @@
-define(eTpfHole, '$eTpfHole').
%%
-define(tcmIsCut, false).
-define(tcmDepth, 3).
-define(tcmListSize, 32).
-define(tcmMapSize, 32).
-define(tcmTupleSize, 32).
-define(tcmBinSize, 128).
-define(tcmBitSize, ?tcmBinSize * 8).
-define(tcmNestStruct, 6).
-define(defTcmMap, #{
tcmIsCut => false
, tcmDepth => 5
, tcmListSize => 32
, tcmMapSize => 32
, tcmTupleSize => 32
, tcmBinSize => 128
, tcmBitSize => 128 * 8
, tcmNestStruct => 6
}).
-define(defPoolId, defPoolId).
%%
-export_type([input/0, userInput/0, traceOpts/0, tracerOpts/0]).
@ -22,30 +26,32 @@
-type userInput() :: pattern() | input().
-type traceOpts() :: #{
mode => trace | profile
, poolId => any()
, poolSize => pos_integer()
, send => boolean()
, running => boolean()
mode => trace | profile
, poolId => any()
, poolSize => pos_integer()
, send => boolean()
, running => boolean()
, process_dump => boolean() %% trace选项 使`process_dump`, `true`
}.
-type tracerOpts() :: #{
%% tracer for socket
port => pos_integer()
port => pos_integer()
%% tracer for file
,filename_prefix => string()
, max_size => pos_integer()
, events_per_frame => pos_integer()
, fBaseName => string()
, fMaxSize => pos_integer()
, fEventFrame => pos_integer()
%% tracer for console
%% trace msg term cut cfg
,tcmIsCut => boolean() %% cut trace msg term
,tcmDepth => boolean() %% term cut时保留的最大深度
,tcmListSize => boolean() %% List term cut时保留的最大数量
,tcmMapSize => boolean() %% Map term cut时保留的最大数量
,tcmTupleSize => boolean() %% Tuple term cut时保留的最大数量
,tcmBitSize => boolean() %% Bits term cut时保留的最大字节数
,tcmNestStruct => boolean() %% term cut时保留的最大数量
, tcmIsCut => boolean() %% cut trace msg term
, tcmDepth => pos_integer() %% term cut时保留的最大深度
, tcmListSize => pos_integer() %% List term cut时保留的最大数量
, tcmMapSize => pos_integer() %% Map term cut时保留的最大数量
, tcmTupleSize => pos_integer() %% Tuple term cut时保留的最大数量
, tcmBinSize => pos_integer() %% Bin term cut时保留的最大字节数
, tcmBitSize => pos_integer() %% Bits term cut时保留的最大bit数
, tcmNestStruct => pos_integer() %% term cut时保留的最大数量
}.

+ 24
- 25
src/eTpf.erl 查看文件

@ -27,15 +27,14 @@ trace(Input, TracerMod, TracerOpts) ->
-spec trace(userInput(), module(), tracerOpts(), traceOpts()) -> ok.
trace(Input, TracerMod, TracerOpts, TraceOpts) when is_list(Input) ->
do_trace(Input, TracerMod, TracerOpts, TraceOpts);
trace(Input, TracerMod, TracerOpts, TraceOpts) ->
trace([Input], TracerMod, TracerOpts, TraceOpts).
InputList = case is_list(Input) of true -> Input; _ -> [Input] end,
do_trace(InputList, TracerMod, TracerOpts, TraceOpts).
do_trace(Input0, TracerMod, TracerOpts, TraceOpts) ->
do_trace(InputList, TracerMod, TracerOpts, TraceOpts) ->
_ = application:ensure_all_started(eTpf),
%% Start the pool of tracer processes.
PoolID = maps:get(poolId, TraceOpts, default),
PoolID = maps:get(poolId, TraceOpts, ?defPoolId),
PoolSize = maps:get(poolSize, TraceOpts, erlang:system_info(schedulers)),
true = PoolSize > 0,
{ok, PoolPid} = supervisor:start_child(eTpf_sup, #{
@ -47,39 +46,39 @@ do_trace(Input0, TracerMod, TracerOpts, TraceOpts) ->
Tracers = tpTracerPool:tracers(PoolPid),
TracersMap = maps:from_list(lists:zip(lists:seq(0, length(Tracers) - 1), Tracers)),
Mode = maps:get(mode, TraceOpts, trace),
Input1 = flatten(Input0, []),
Input2 = ensure_pattern(Input1),
Input = ensure_scope(Input2),
trace_input(Input, #{mode => Mode, tracers => TracersMap}, TraceOpts),
Tem0InputList = flattenInput(InputList, []),
Tem1InputList = ensurePattern(Tem0InputList),
LastInputList = ensureScope(Tem1InputList),
traceInput(LastInputList, #{mode => Mode, tracers => TracersMap}, TraceOpts),
ok.
flatten([], Acc) ->
flattenInput([], Acc) ->
lists:flatten(Acc);
flatten([{callback, Mod, Fun} | Tail], Acc) when is_atom(Mod), is_atom(Fun) ->
Input = flatten(Mod:Fun(), []),
flatten(Tail, [Input | Acc]);
flatten([{app, App} | Tail], Acc) when is_atom(App) ->
flattenInput([{callback, Mod, Fun} | Tail], Acc) when is_atom(Mod), is_atom(Fun) ->
Input = flattenInput(Mod:Fun(), []),
flattenInput(Tail, [Input | Acc]);
flattenInput([{app, App} | Tail], Acc) when is_atom(App) ->
_ = application:load(App),
{ok, Mods} = application:get_key(App, modules),
flatten(Tail, [Mods | Acc]);
flatten([Input | Tail], Acc) ->
flatten(Tail, [Input | Acc]).
flattenInput(Tail, [Mods | Acc]);
flattenInput([Input | Tail], Acc) ->
flattenInput(Tail, [Input | Acc]).
ensure_pattern(Input) ->
ensurePattern(Input) ->
case [S || S = {scope, _} <- Input] of
Input -> ['_' | Input];
_ -> Input
end.
ensure_scope(Input) ->
ensureScope(Input) ->
case [S || S = {scope, _} <- Input] of
[] -> [{scope, [processes]} | Input];
_ -> Input
end.
trace_input([], _, _) ->
traceInput([], _, _) ->
ok;
trace_input([{scope, Scope} | Tail], TracerState, Opts) ->
traceInput([{scope, Scope} | Tail], TracerState, Opts) ->
%% We currently enable the following trace flags:
%% - call: function calls
%% - procs: process exit events; plus others we ignore
@ -96,8 +95,8 @@ trace_input([{scope, Scope} | Tail], TracerState, Opts) ->
erlang:trace(PidPortSpec, true, [call, procs, timestamp, arity, return_to, set_on_spawn, {tracer, tpTracerNif, TracerState} | ExtraFlags])
|| PidPortSpec <- Scope
],
trace_input(Tail, TracerState, Opts);
trace_input([Mod | Tail], TracerState, Opts) when is_atom(Mod) ->
traceInput(Tail, TracerState, Opts);
traceInput([Mod | Tail], TracerState, Opts) when is_atom(Mod) ->
MatchSpec =
case Opts of
#{process_dump := true} ->
@ -108,10 +107,10 @@ trace_input([Mod | Tail], TracerState, Opts) when is_atom(Mod) ->
%% The module must be loaded before we attempt to trace it.
_ = code:ensure_loaded(Mod),
_ = erlang:trace_pattern({Mod, '_', '_'}, MatchSpec, [local]),
trace_input(Tail, TracerState, Opts).
traceInput(Tail, TracerState, Opts).
stop() ->
stop(default).
stop(?defPoolId).
%% @todo Confirm that we don't need to stop tracing,
%% that just terminating the tracers is enough. The

+ 1
- 1
src/tracer/tpTracerConsole.erl 查看文件

@ -8,7 +8,7 @@
-export([system_terminate/4]).
-export([system_code_change/4]).
start_link(_Nth, _Opts) ->
start_link(_Nth, _TracerOpts) ->
Pid = proc_lib:spawn_link(?MODULE, init, [self()]),
{ok, Pid}.

+ 47
- 15
src/tracer/tpTracerFile.erl 查看文件

@ -1,4 +1,5 @@
-module(tpTracerFile).
-include("eTpf.hrl").
-export([
start_link/2
@ -13,39 +14,70 @@
]).
-record(state, {
parent :: pid(),
fileName :: file:filename_all(),
size = 0 :: non_neg_integer(),
maxSize :: infinity | non_neg_integer(),
ioDevice :: file:io_device(),
eventsPerFrame :: pos_integer(),
eventsThisFrame = 0 :: non_neg_integer(),
buffer = <<>> :: binary()
parent :: pid()
, fBaseName :: file:filename_all()
, size = 0 :: non_neg_integer()
, fMaxSize :: infinity | non_neg_integer()
, ioDevice :: file:io_device()
, fEventFrame :: pos_integer()
, eventsThisFrame = 0 :: non_neg_integer()
, buffer = <<>> :: binary()
, tcmIsCut = false
, tcmDepth = 5
, tcmListSize = 32
, tcmMapSize = 32
, tcmTupleSize = 32
, tcmBinSize = 128
, tcmBitSize = 128 * 8
, tcmNestStruct = 6
}).
start_link(Nth, Prefix) when is_list(Prefix) ->
start_link(Nth, #{filename_prefix => Prefix});
start_link(Nth, #{fBaseName => Prefix});
start_link(Nth, Opts) when is_map(Opts) ->
Pid = proc_lib:spawn_link(?MODULE, init, [self(), Nth, Opts]),
{ok, Pid}.
init(Parent, Nth, Opts) ->
init(Parent, Nth, TracerOpts) ->
process_flag(message_queue_data, off_heap),
process_flag(trap_exit, true),
%% No need to close the file, it'll be closed when the process exits.
Filename = filename:flatten([maps:get(filename_prefix, Opts, "traces.lz4"), ".", integer_to_list(Nth)]),
Filename = filename:flatten([maps:get(fBaseName, TracerOpts, "traces.lz4"), ".", integer_to_list(Nth)]),
{ok, IoDevice} = file:open(Filename, [write, raw]),
State = #state{parent = Parent, fileName = Filename, ioDevice = IoDevice, maxSize = maps:get(max_size, Opts, infinity), eventsPerFrame = maps:get(events_per_frame, Opts, 100000)},
TcmIsCut = maps:get(tcmIsCut, TracerOpts, maps:get(tcmDepth, ?defTcmMap)),
case TcmIsCut of
true ->
erlang:put(tcmDepth, maps:get(tcmDepth, TracerOpts, maps:get(tcmDepth, ?defTcmMap))),
erlang:put(tcmListSize, maps:get(tcmListSize, TracerOpts, maps:get(tcmListSize, ?defTcmMap))),
erlang:put(tcmMapSize, maps:get(tcmMapSize, TracerOpts, maps:get(tcmMapSize, ?defTcmMap))),
erlang:put(tcmTupleSize, maps:get(tcmTupleSize, TracerOpts, maps:get(tcmTupleSize, ?defTcmMap))),
erlang:put(tcmBinSize, maps:get(tcmBinSize, TracerOpts, maps:get(tcmBinSize, ?defTcmMap))),
erlang:put(tcmBitSize, maps:get(tcmBitSize, TracerOpts, maps:get(tcmBitSize, ?defTcmMap))),
erlang:put(tcmNestStruct, maps:get(tcmNestStruct, TracerOpts, maps:get(tcmNestStruct, ?defTcmMap)));
_ ->
ignore
end,
State = #state{
parent = Parent
, fBaseName = Filename
, ioDevice = IoDevice
, fMaxSize = maps:get(fMaxSize, TracerOpts, infinity)
, fEventFrame = maps:get(fEventFrame, TracerOpts, 100000)
, tcmIsCut = TcmIsCut
},
loop(State).
loop(State = #state{parent = Parent, size = Size, ioDevice = IoDevice, eventsPerFrame = MaxEvents, eventsThisFrame = NumEvents0, buffer = Buffer0}) ->
loop(State = #state{parent = Parent, size = Size, ioDevice = IoDevice, fEventFrame = MaxEvents, eventsThisFrame = NumEvents0, buffer = Buffer0, tcmIsCut = TcmIsCut}) ->
receive
{system, From, Request} ->
sys:handle_system_msg(Request, From, Parent, ?MODULE, [], State);
{'EXIT', Parent, Reason} ->
terminate(Reason, State);
RMsg ->
Msg = tpTermCut:cut(RMsg),
Msg = case TcmIsCut of true -> tpTermCut:cut(RMsg); _ -> RMsg end,
Bin = term_to_binary(Msg),
BinSize = byte_size(Bin),
Buffer = <<Buffer0/binary, BinSize:32, Bin/binary>>,
@ -62,7 +94,7 @@ loop(State = #state{parent = Parent, size = Size, ioDevice = IoDevice, eventsPer
end.
%%IMY-todo 使
maybe_rotate(State = #state{fileName = Filename, size = Size, maxSize = MaxSize,
maybe_rotate(State = #state{fBaseName = Filename, size = Size, fMaxSize = MaxSize,
ioDevice = OldIoDevice}) when Size > MaxSize ->
ok = file:close(OldIoDevice),
ok = file:rename(Filename, Filename ++ ".bak"),

+ 0
- 3
src/tracer/tpTracerPool.erl 查看文件

@ -7,7 +7,6 @@
, tracers/1
]).
start_link(NumTracers, TracerMod, Opts) ->
supervisor:start_link(?MODULE, [NumTracers, TracerMod, Opts]).
@ -22,7 +21,5 @@ init([NumTracers, TracerMod, Opts]) ->
SupFlags = #{strategy => one_for_all, intensity => 5, period => 10},
{ok, {SupFlags, ChildSpecs}}.
tracers(PoolPid) ->
[Pid || {_, Pid, _, _} <- supervisor:which_children(PoolPid)].

+ 2
- 1
src/tracer/tpTracerSocket.erl 查看文件

@ -18,7 +18,8 @@
timerRef :: reference() | undefined
}).
start_link(Nth, BasePort) ->
start_link(Nth, TracerOpts) ->
BasePort = maps:get(port, TracerOpts),
Pid = proc_lib:spawn_link(?MODULE, init, [self(), BasePort + Nth - 1]),
{ok, Pid}.

+ 46
- 27
src/utils/tpTermCut.erl 查看文件

@ -6,50 +6,69 @@
-export([cut/1]).
-export([cut/2]).
getTcmValue(Key) ->
case get(Key) of
undefined ->
maps:get(Key, ?defTcmMap);
Value ->
Value
end.
cut(Term) ->
cut(Term, 1).
cut(_, Depth) when Depth > ?tcmDepth ->
'$truncated11';
cut(Bits, _) when is_bitstring(Bits), bit_size(Bits) > ?tcmBitSize ->
<<CutBits:?tcmBinSize/binary, _/bits>> = Bits,
<<CutBits/binary, "$truncated">>;
cut(Term, Depth) when is_list(Term) ->
cutList(Term, Depth, 0, ?tcmListSize, 0, []);
cut(Term, Depth) when is_map(Term), Depth =:= ?tcmDepth ->
#{'$truncated' => '$truncated'};
cut(Term, Depth) when is_map(Term) ->
maps:from_list(cutMap(maps_to_list(Term, ?tcmMapSize), Depth, 0));
cut(Term, Depth) when is_tuple(Term), Depth =:= ?tcmDepth ->
{'$truncated'};
cut(Term, Depth) when is_tuple(Term) ->
list_to_tuple(cutList(tuple_to_list(Term), Depth, 0, ?tcmTupleSize, 0, []));
cut(Term, _) ->
Term.
cut(Term, Depth) ->
TcmDepth = getTcmValue(tcmDepth),
case Depth > TcmDepth of
true ->
'$truncated11';
_ ->
if
is_bitstring(Term) ->
case bit_size(Term) > getTcmValue(tcmBitSize) of
true ->
TcmBinSize = getTcmValue(tcmBinSize),
<<CutBin:TcmBinSize/binary, _/bits>> = Term,
<<CutBin/binary, "$truncated">>;
_ ->
Term
end;
is_list(Term) ->
cutList(Term, Depth, 0, getTcmValue(tcmListSize), getTcmValue(tcmNestStruct), 0, []);
is_map(Term), Depth =:= TcmDepth ->
#{'$truncated' => '$truncated'};
is_map(Term) ->
maps:from_list(cutMap(maps_to_list(Term, getTcmValue(tcmMapSize)), Depth, getTcmValue(tcmNestStruct), 0));
is_tuple(Term), Depth =:= TcmDepth ->
{'$truncated'};
is_tuple(Term) ->
list_to_tuple(cutList(tuple_to_list(Term), Depth, 0, getTcmValue(tcmTupleSize), getTcmValue(tcmNestStruct), 0, []));
true ->
Term
end
end.
cutList([], _, _, _, _, Acc) ->
cutList([], _, _, _, _, _, Acc) ->
lists:reverse(Acc);
cutList([Term | Tail], Depth, Len, MaxLen, NumStructs, Acc) ->
case Len >= MaxLen orelse NumStructs >= ?tcmNestStruct of
cutList([Term | Tail], Depth, Len, TcmTupleSize, TcmNestStruct, NumStructs, Acc) ->
case Len >= TcmTupleSize orelse NumStructs >= TcmNestStruct of
true ->
lists:reverse(['$truncated33' | Acc]);
_ ->
%% if List was a cons, Tail can be anything
io:format("IMY********************1111 ~p~n", [{Len, NumStructs, Term}]),
cutList(Tail, Depth, Len + 1, MaxLen, NumStructs + isStruct(Term), [cut(Term, Depth + 1) | Acc])
cutList(Tail, Depth, Len + 1, TcmTupleSize, TcmNestStruct, NumStructs + isStruct(Term), [cut(Term, Depth + 1) | Acc])
end;
cutList(Term, Depth, _, _, _, Acc) -> %% if List was a cons [[[a,a,a|b],1,2,3]|bbbb]
cutList(Term, Depth, _, _, _, _, Acc) -> %% if List was a cons [[[a,a,a|b],1,2,3]|bbbb]
lists:reverse(Acc) ++ cut(Term, Depth + 1).
cutMap([], _, _) ->
cutMap([], _, _, _) ->
[];
cutMap(_, _, NumStructs) when NumStructs > ?tcmNestStruct ->
cutMap(_, _, TcmNestStruct, NumStructs) when NumStructs > TcmNestStruct ->
[{'$truncated', '$truncated'}];
cutMap([{Key, Value} | Tail], Depth, NumStructs) ->
cutMap([{Key, Value} | Tail], Depth, TcmNestStruct, NumStructs) ->
AddStruct = isStruct(Key) + isStruct(Value),
[{cut(Key, Depth + 1), cut(Value, Depth + 1)} | cutMap(Tail, Depth, NumStructs + AddStruct)].
[{cut(Key, Depth + 1), cut(Value, Depth + 1)} | cutMap(Tail, Depth, TcmNestStruct, NumStructs + AddStruct)].
isStruct(Term) ->
case is_list(Term) orelse is_map(Term) orelse is_tuple(Term) of

+ 3
- 3
test/lg_SUITE.erl 查看文件

@ -135,9 +135,9 @@ file_tracer_rotation(Config) ->
doc("Save events to files on disk; rotate the files if they get too big."),
Prefix = config(priv_dir, Config) ++ "/file_tracer.lz4",
eTpf:trace(lists, tpTracerFile, #{
filename_prefix => Prefix,
max_size => 100, %% Intentionally low.
events_per_frame => 10 %% Needed to trigger the rotation, default is too high.
fBaseName => Prefix,
fMaxSize => 100, %% Intentionally low.
fEventFrame => 10 %% Needed to trigger the rotation, default is too high.
}),
lists:seq(1, 1000),
eTpf:stop(),

Loading…
取消
儲存