Merge pull request #8668 from zhongwencool/add-trace-detail-api

feat: add GET /trace/:name/detail HTTP API
This commit is contained in:
zhongwencool 2022-08-10 23:16:33 +08:00 committed by GitHub
commit 9a1beb1148
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 101 additions and 8 deletions

View File

@ -1,12 +1,16 @@
# EMQX 4.4 Changes # EMQX 4.4 Changes
## v4.4.7
### Enhancements (synced from v4.3.18) ## v4.4.8
### Enhancements (synced from v4.3.19)
* Support HTTP API `/trace/:name/detail`.
### Bug fixes ### Bug fixes
- Fix: Check if emqx_mod_trace is enabled when the trace file is not found. - Fix: Check if emqx_mod_trace is enabled when the trace file is not found.
## v4.4.5 ## v4.4.5
### Enhancements (synced from v4.3.16) ### Enhancements (synced from v4.3.16)

View File

@ -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
]). ]).
@ -186,6 +188,14 @@ trace_file(File) ->
{error, Node, 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]}).

View File

@ -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
@ -124,9 +134,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),

View File

@ -300,7 +300,7 @@ t_trace_file(_Config) ->
t_download_log(_Config) -> t_download_log(_Config) ->
ClientId = <<"client-test">>, ClientId = <<"client-test">>,
Now = erlang:system_time(second), Now = erlang:system_time(second) - 2,
Start = to_rfc3339(Now), Start = to_rfc3339(Now),
Name = <<"test_client_id">>, Name = <<"test_client_id">>,
ok = emqx_trace:create([{<<"name">>, Name}, ok = emqx_trace:create([{<<"name">>, Name},
@ -314,6 +314,27 @@ 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) - 10,
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, 10)],
ct:sleep(200),
ok = emqx_trace_handler_SUITE:filesync(Name, clientid),
{ok, [#{mtime := Mtime, node := Node, size := Size} = Detail]}
= emqx_trace_api:trace_file_detail(#{name => Name}, []),
ct:pal("~p detail:~p~n", [{Name, Now}, Detail]),
?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),

View File

@ -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);

View File

@ -1,6 +1,6 @@
{application, emqx_modules, {application, emqx_modules,
[{description, "EMQ X Module Management"}, [{description, "EMQ X Module Management"},
{vsn, "4.4.5"}, {vsn, "4.4.6"},
{modules, []}, {modules, []},
{applications, [kernel,stdlib]}, {applications, [kernel,stdlib]},
{mod, {emqx_modules_app, []}}, {mod, {emqx_modules_app, []}},

View File

@ -1,15 +1,22 @@
%% -*- mode: erlang -*- %% -*- mode: erlang -*-
%% Unless you know what you are doing, DO NOT edit manually!! %% Unless you know what you are doing, DO NOT edit manually!!
{VSN, {VSN,
[{"4.4.4",[{load_module,emqx_mod_rewrite,brutal_purge,soft_purge,[]}]}, [{"4.4.5",[{load_module,emqx_mod_trace_api,brutal_purge,soft_purge,[]}]},
{"4.4.3",[{load_module,emqx_mod_rewrite,brutal_purge,soft_purge,[]}]}, {"4.4.4",
[{load_module,emqx_mod_rewrite,brutal_purge,soft_purge,[]},
{load_module,emqx_mod_trace_api,brutal_purge,soft_purge,[]}]},
{"4.4.3",
[{load_module,emqx_mod_rewrite,brutal_purge,soft_purge,[]},
{load_module,emqx_mod_trace_api,brutal_purge,soft_purge,[]}]},
{"4.4.2", {"4.4.2",
[{load_module,emqx_mod_rewrite,brutal_purge,soft_purge,[]}, [{load_module,emqx_mod_rewrite,brutal_purge,soft_purge,[]},
{load_module,emqx_mod_trace_api,brutal_purge,soft_purge,[]},
{load_module,emqx_modules,brutal_purge,soft_purge,[]}]}, {load_module,emqx_modules,brutal_purge,soft_purge,[]}]},
{"4.4.1", {"4.4.1",
[{load_module,emqx_mod_rewrite,brutal_purge,soft_purge,[]}, [{load_module,emqx_mod_rewrite,brutal_purge,soft_purge,[]},
{load_module,emqx_modules,brutal_purge,soft_purge,[]}, {load_module,emqx_modules,brutal_purge,soft_purge,[]},
{load_module,emqx_mod_subscription,brutal_purge,soft_purge,[]}, {load_module,emqx_mod_subscription,brutal_purge,soft_purge,[]},
{load_module,emqx_mod_trace_api,brutal_purge,soft_purge,[]},
{load_module,emqx_mod_delayed,brutal_purge,soft_purge,[]}]}, {load_module,emqx_mod_delayed,brutal_purge,soft_purge,[]}]},
{"4.4.0", {"4.4.0",
[{load_module,emqx_mod_rewrite,brutal_purge,soft_purge,[]}, [{load_module,emqx_mod_rewrite,brutal_purge,soft_purge,[]},
@ -20,15 +27,22 @@
{load_module,emqx_mod_sup,brutal_purge,soft_purge,[]}, {load_module,emqx_mod_sup,brutal_purge,soft_purge,[]},
{load_module,emqx_mod_trace_api,brutal_purge,soft_purge,[]}]}, {load_module,emqx_mod_trace_api,brutal_purge,soft_purge,[]}]},
{<<".*">>,[]}], {<<".*">>,[]}],
[{"4.4.4",[{load_module,emqx_mod_rewrite,brutal_purge,soft_purge,[]}]}, [{"4.4.5",[{load_module,emqx_mod_trace_api,brutal_purge,soft_purge,[]}]},
{"4.4.3",[{load_module,emqx_mod_rewrite,brutal_purge,soft_purge,[]}]}, {"4.4.4",
[{load_module,emqx_mod_rewrite,brutal_purge,soft_purge,[]},
{load_module,emqx_mod_trace_api,brutal_purge,soft_purge,[]}]},
{"4.4.3",
[{load_module,emqx_mod_rewrite,brutal_purge,soft_purge,[]},
{load_module,emqx_mod_trace_api,brutal_purge,soft_purge,[]}]},
{"4.4.2", {"4.4.2",
[{load_module,emqx_mod_rewrite,brutal_purge,soft_purge,[]}, [{load_module,emqx_mod_rewrite,brutal_purge,soft_purge,[]},
{load_module,emqx_mod_trace_api,brutal_purge,soft_purge,[]},
{load_module,emqx_modules,brutal_purge,soft_purge,[]}]}, {load_module,emqx_modules,brutal_purge,soft_purge,[]}]},
{"4.4.1", {"4.4.1",
[{load_module,emqx_mod_rewrite,brutal_purge,soft_purge,[]}, [{load_module,emqx_mod_rewrite,brutal_purge,soft_purge,[]},
{load_module,emqx_modules,brutal_purge,soft_purge,[]}, {load_module,emqx_modules,brutal_purge,soft_purge,[]},
{load_module,emqx_mod_subscription,brutal_purge,soft_purge,[]}, {load_module,emqx_mod_subscription,brutal_purge,soft_purge,[]},
{load_module,emqx_mod_trace_api,brutal_purge,soft_purge,[]},
{load_module,emqx_mod_delayed,brutal_purge,soft_purge,[]}]}, {load_module,emqx_mod_delayed,brutal_purge,soft_purge,[]}]},
{"4.4.0", {"4.4.0",
[{load_module,emqx_mod_rewrite,brutal_purge,soft_purge,[]}, [{load_module,emqx_mod_rewrite,brutal_purge,soft_purge,[]},

View 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.