feat: add GET /trace/:name/detail HTTP API
This commit is contained in:
parent
683bec16a3
commit
4e362d2d0a
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
-include_lib("emqx/include/emqx.hrl").
|
-include_lib("emqx/include/emqx.hrl").
|
||||||
-include_lib("emqx/include/logger.hrl").
|
-include_lib("emqx/include/logger.hrl").
|
||||||
|
-include_lib("kernel/include/file.hrl").
|
||||||
|
|
||||||
-logger_header("[Tracer]").
|
-logger_header("[Tracer]").
|
||||||
|
|
||||||
|
@ -42,6 +43,7 @@
|
||||||
, filename/2
|
, filename/2
|
||||||
, trace_dir/0
|
, trace_dir/0
|
||||||
, trace_file/1
|
, trace_file/1
|
||||||
|
, trace_file_detail/1
|
||||||
, delete_files_after_send/2
|
, delete_files_after_send/2
|
||||||
, is_enable/0
|
, is_enable/0
|
||||||
]).
|
]).
|
||||||
|
@ -180,6 +182,14 @@ trace_file(File) ->
|
||||||
{error, Reason} -> {error, Node, Reason}
|
{error, Reason} -> {error, Node, Reason}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
trace_file_detail(File) ->
|
||||||
|
FileName = filename:join(trace_dir(), File),
|
||||||
|
Node = atom_to_binary(node()),
|
||||||
|
case file:read_file_info(FileName, [{'time', 'posix'}]) of
|
||||||
|
{ok, #file_info{size = Size, mtime = Mtime}} -> {ok, Node, #{size => Size, mtime => Mtime}};
|
||||||
|
{error, Reason} -> {error, Node, Reason}
|
||||||
|
end.
|
||||||
|
|
||||||
delete_files_after_send(TraceLog, Zips) ->
|
delete_files_after_send(TraceLog, Zips) ->
|
||||||
gen_server:cast(?MODULE, {delete_tag, self(), [TraceLog | Zips]}).
|
gen_server:cast(?MODULE, {delete_tag, self(), [TraceLog | Zips]}).
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
, update_trace/2
|
, update_trace/2
|
||||||
, delete_trace/2
|
, delete_trace/2
|
||||||
, clear_traces/2
|
, clear_traces/2
|
||||||
|
, trace_file_detail/2
|
||||||
, download_zip_log/2
|
, download_zip_log/2
|
||||||
, stream_log_file/2
|
, stream_log_file/2
|
||||||
]).
|
]).
|
||||||
|
@ -105,6 +106,15 @@ download_zip_log(#{name := Name}, _Param) ->
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
trace_file_detail(#{name := Name}, _Param) ->
|
||||||
|
case emqx_trace:get_trace_filename(Name) of
|
||||||
|
{ok, TraceLog} ->
|
||||||
|
TraceFiles = collect_trace_file_detail(TraceLog),
|
||||||
|
{ok, group_trace_file_detail(TraceLog, TraceFiles)};
|
||||||
|
{error, Reason} ->
|
||||||
|
{error, Reason}
|
||||||
|
end.
|
||||||
|
|
||||||
group_trace_file(ZipDir, TraceLog, TraceFiles) ->
|
group_trace_file(ZipDir, TraceLog, TraceFiles) ->
|
||||||
lists:foldl(fun(Res, Acc) ->
|
lists:foldl(fun(Res, Acc) ->
|
||||||
case Res of
|
case Res of
|
||||||
|
@ -121,9 +131,23 @@ group_trace_file(ZipDir, TraceLog, TraceFiles) ->
|
||||||
end
|
end
|
||||||
end, [], TraceFiles).
|
end, [], TraceFiles).
|
||||||
|
|
||||||
|
group_trace_file_detail(TraceLog, TraceFiles) ->
|
||||||
|
lists:foldl(fun(Res, Acc) ->
|
||||||
|
case Res of
|
||||||
|
{ok, Node, Info} ->
|
||||||
|
[Info#{node => Node} | Acc];
|
||||||
|
{error, Node, Reason} ->
|
||||||
|
?LOG(error, "read trace file detail failed:~p", [{Node, TraceLog, Reason}]),
|
||||||
|
Acc
|
||||||
|
end
|
||||||
|
end, [], TraceFiles).
|
||||||
|
|
||||||
collect_trace_file(TraceLog) ->
|
collect_trace_file(TraceLog) ->
|
||||||
cluster_call(emqx_trace, trace_file, [TraceLog], 60000).
|
cluster_call(emqx_trace, trace_file, [TraceLog], 60000).
|
||||||
|
|
||||||
|
collect_trace_file_detail(TraceLog) ->
|
||||||
|
cluster_call(emqx_trace, trace_file_detail, [TraceLog], 25000).
|
||||||
|
|
||||||
cluster_call(Mod, Fun, Args, Timeout) ->
|
cluster_call(Mod, Fun, Args, Timeout) ->
|
||||||
Nodes = ekka_mnesia:running_nodes(),
|
Nodes = ekka_mnesia:running_nodes(),
|
||||||
{GoodRes, BadNodes} = rpc:multicall(Nodes, Mod, Fun, Args, Timeout),
|
{GoodRes, BadNodes} = rpc:multicall(Nodes, Mod, Fun, Args, Timeout),
|
||||||
|
|
|
@ -314,6 +314,25 @@ t_download_log(_Config) ->
|
||||||
ok = emqtt:disconnect(Client),
|
ok = emqtt:disconnect(Client),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
t_trace_file_detail(_Config) ->
|
||||||
|
ClientId = <<"client-test1">>,
|
||||||
|
Now = erlang:system_time(second),
|
||||||
|
Start = to_rfc3339(Now),
|
||||||
|
Name = <<"test_client_id1">>,
|
||||||
|
ok = emqx_trace:create([{<<"name">>, Name},
|
||||||
|
{<<"type">>, <<"clientid">>}, {<<"clientid">>, ClientId}, {<<"start_at">>, Start}]),
|
||||||
|
{ok, Client} = emqtt:start_link([{clean_start, true}, {clientid, ClientId}]),
|
||||||
|
{ok, _} = emqtt:connect(Client),
|
||||||
|
[begin _ = emqtt:ping(Client) end ||_ <- lists:seq(1, 5)],
|
||||||
|
ok = emqx_trace_handler_SUITE:filesync(Name, clientid),
|
||||||
|
{ok, [#{mtime := Mtime, node := Node, size := Size}]}
|
||||||
|
= emqx_trace_api:trace_file_detail(#{name => Name}, []),
|
||||||
|
?assertEqual(atom_to_binary(node()), Node),
|
||||||
|
?assert(Size > 0),
|
||||||
|
?assert(Mtime >= Now),
|
||||||
|
ok = emqtt:disconnect(Client),
|
||||||
|
ok.
|
||||||
|
|
||||||
t_find_closed_time(_Config) ->
|
t_find_closed_time(_Config) ->
|
||||||
DefaultMs = 60 * 15000,
|
DefaultMs = 60 * 15000,
|
||||||
Now = erlang:system_time(second),
|
Now = erlang:system_time(second),
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
, disable_trace/2
|
, disable_trace/2
|
||||||
, delete_trace/2
|
, delete_trace/2
|
||||||
, clear_traces/2
|
, clear_traces/2
|
||||||
|
, trace_file_detail/2
|
||||||
, download_zip_log/2
|
, download_zip_log/2
|
||||||
, stream_log_file/2
|
, stream_log_file/2
|
||||||
]).
|
]).
|
||||||
|
@ -58,6 +59,12 @@
|
||||||
func => disable_trace,
|
func => disable_trace,
|
||||||
descr => "stop trace"}).
|
descr => "stop trace"}).
|
||||||
|
|
||||||
|
-rest_api(#{name => trace_file_detail,
|
||||||
|
method => 'GET',
|
||||||
|
path => "/trace/:bin:name/detail",
|
||||||
|
func => trace_file_detail,
|
||||||
|
descr => "view trace file's detail"}).
|
||||||
|
|
||||||
-rest_api(#{name => download_zip_log,
|
-rest_api(#{name => download_zip_log,
|
||||||
method => 'GET',
|
method => 'GET',
|
||||||
path => "/trace/:bin:name/download",
|
path => "/trace/:bin:name/download",
|
||||||
|
@ -101,6 +108,12 @@ disable_trace(#{name := Name}, Params) ->
|
||||||
false -> return(?NOT_STARTED)
|
false -> return(?NOT_STARTED)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
trace_file_detail(Path, Params) ->
|
||||||
|
case emqx_trace_api:trace_file_detail(Path, Params) of
|
||||||
|
{ok, Detail} -> return({ok, Detail});
|
||||||
|
{error, Reason} -> return({error, 'NOT_FOUND', Reason})
|
||||||
|
end.
|
||||||
|
|
||||||
download_zip_log(Path, Params) ->
|
download_zip_log(Path, Params) ->
|
||||||
case emqx_trace_api:download_zip_log(Path, Params) of
|
case emqx_trace_api:download_zip_log(Path, Params) of
|
||||||
{ok, File} -> minirest:return_file(File);
|
{ok, File} -> minirest:return_file(File);
|
||||||
|
|
|
@ -141,6 +141,13 @@ t_stream_log(_Config) ->
|
||||||
#{<<"code">> := 0, <<"data">> := #{<<"meta">> := Meta1, <<"items">> := Bin1}} = json(Binary1),
|
#{<<"code">> := 0, <<"data">> := #{<<"meta">> := Meta1, <<"items">> := Bin1}} = json(Binary1),
|
||||||
?assertEqual(#{<<"position">> => 30, <<"bytes">> => 10}, Meta1),
|
?assertEqual(#{<<"position">> => 30, <<"bytes">> => 10}, Meta1),
|
||||||
?assertEqual(10, byte_size(Bin1)),
|
?assertEqual(10, byte_size(Bin1)),
|
||||||
|
|
||||||
|
{ok, Detail} = request_api(get, api_path("trace/test_stream_log/detail"), Header),
|
||||||
|
#{<<"data">> := [#{<<"size">> := Size, <<"node">> := Node, <<"mtime">> := Mtime}],
|
||||||
|
<<"code">> := 0} = json(Detail),
|
||||||
|
?assertEqual(atom_to_binary(node()), Node),
|
||||||
|
?assert(Size > 0),
|
||||||
|
?assert(Mtime >= Now),
|
||||||
unload(),
|
unload(),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue