fix: name must be printable unicode and len < 256
This commit is contained in:
parent
d76275d17d
commit
30fb9dd7ae
|
@ -128,7 +128,7 @@ create(Trace) ->
|
||||||
{error, Reason} -> {error, Reason}
|
{error, Reason} -> {error, Reason}
|
||||||
end;
|
end;
|
||||||
false ->
|
false ->
|
||||||
{error, "The number of traces created has reached the maximum"
|
{error, "The number of traces created has reache the maximum"
|
||||||
" please delete the useless ones first"}
|
" please delete the useless ones first"}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -379,11 +379,16 @@ to_trace(TraceParam) ->
|
||||||
{error, "type=[topic,clientid,ip_address] required"};
|
{error, "type=[topic,clientid,ip_address] required"};
|
||||||
{ok, #?TRACE{filter = undefined}} ->
|
{ok, #?TRACE{filter = undefined}} ->
|
||||||
{error, "topic/clientid/ip_address filter required"};
|
{error, "topic/clientid/ip_address filter required"};
|
||||||
{ok, TraceRec0} ->
|
{ok, TraceRec0 = #?TRACE{name = Name, type = Type}} ->
|
||||||
case fill_default(TraceRec0) of
|
case emqx_trace_handler:handler_id(Name, Type) of
|
||||||
#?TRACE{start_at = Start, end_at = End} when End =< Start ->
|
{ok, _} ->
|
||||||
{error, "failed by start_at >= end_at"};
|
case fill_default(TraceRec0) of
|
||||||
TraceRec -> {ok, TraceRec}
|
#?TRACE{start_at = Start, end_at = End} when End =< Start ->
|
||||||
|
{error, "failed by start_at >= end_at"};
|
||||||
|
TraceRec -> {ok, TraceRec}
|
||||||
|
end;
|
||||||
|
{error, Reason} ->
|
||||||
|
{error, Reason}
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -403,10 +408,13 @@ fill_default(Trace) -> Trace.
|
||||||
|
|
||||||
to_trace([], Rec) -> {ok, Rec};
|
to_trace([], Rec) -> {ok, Rec};
|
||||||
to_trace([{name, Name} | Trace], Rec) ->
|
to_trace([{name, Name} | Trace], Rec) ->
|
||||||
case binary:match(Name, [<<"/">>], []) of
|
case io_lib:printable_unicode_list(binary_to_list(Name)) of
|
||||||
nomatch when byte_size(Name) < 200 -> to_trace(Trace, Rec#?TRACE{name = Name});
|
true ->
|
||||||
nomatch -> {error, "name(latin1) length must < 200"};
|
case binary:match(Name, [<<"/">>], []) of
|
||||||
_ -> {error, "name cannot contain /"}
|
nomatch -> to_trace(Trace, Rec#?TRACE{name = Name});
|
||||||
|
_ -> {error, "name cannot contain /"}
|
||||||
|
end;
|
||||||
|
false -> {error, "name must printable unicode"}
|
||||||
end;
|
end;
|
||||||
to_trace([{type, Type} | Trace], Rec) ->
|
to_trace([{type, Type} | Trace], Rec) ->
|
||||||
case lists:member(Type, [<<"clientid">>, <<"topic">>, <<"ip_address">>]) of
|
case lists:member(Type, [<<"clientid">>, <<"topic">>, <<"ip_address">>]) of
|
||||||
|
|
|
@ -35,6 +35,8 @@
|
||||||
, filter_ip_address/2
|
, filter_ip_address/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
-export([handler_id/2]).
|
||||||
|
|
||||||
-type tracer() :: #{
|
-type tracer() :: #{
|
||||||
name := binary(),
|
name := binary(),
|
||||||
type := clientid | topic | ip_address,
|
type := clientid | topic | ip_address,
|
||||||
|
@ -111,8 +113,10 @@ install(Who, Level, LogFile) ->
|
||||||
-spec uninstall(Type :: clientid | topic | ip_address,
|
-spec uninstall(Type :: clientid | topic | ip_address,
|
||||||
Name :: binary() | list()) -> ok | {error, term()}.
|
Name :: binary() | list()) -> ok | {error, term()}.
|
||||||
uninstall(Type, Name) ->
|
uninstall(Type, Name) ->
|
||||||
HandlerId = handler_id(#{type => Type, name => ensure_bin(Name)}),
|
case handler_id(ensure_bin(Name), Type) of
|
||||||
uninstall(HandlerId).
|
{ok, HandlerId} -> uninstall(HandlerId);
|
||||||
|
{error, Reason} -> {error, Reason}
|
||||||
|
end.
|
||||||
|
|
||||||
-spec uninstall(HandlerId :: atom()) -> ok | {error, term()}.
|
-spec uninstall(HandlerId :: atom()) -> ok | {error, term()}.
|
||||||
uninstall(HandlerId) ->
|
uninstall(HandlerId) ->
|
||||||
|
@ -135,64 +139,74 @@ uninstall(HandlerId) ->
|
||||||
running() ->
|
running() ->
|
||||||
lists:foldl(fun filter_traces/2, [], emqx_logger:get_log_handlers(started)).
|
lists:foldl(fun filter_traces/2, [], emqx_logger:get_log_handlers(started)).
|
||||||
|
|
||||||
-spec filter_clientid(logger:log_event(), string()) -> logger:log_event() | ignore.
|
-spec filter_clientid(logger:log_event(), {string(), atom()}) -> logger:log_event() | ignore.
|
||||||
filter_clientid(#{meta := #{clientid := ClientId}} = Log, ClientId) -> Log;
|
filter_clientid(#{meta := #{clientid := ClientId}} = Log, {ClientId, _Name}) -> Log;
|
||||||
filter_clientid(_Log, _ExpectId) -> ignore.
|
filter_clientid(_Log, _ExpectId) -> ignore.
|
||||||
|
|
||||||
-spec filter_topic(logger:log_event(), string()) -> logger:log_event() | ignore.
|
-spec filter_topic(logger:log_event(), {string(), atom()}) -> logger:log_event() | ignore.
|
||||||
filter_topic(#{meta := #{topic := Topic}} = Log, TopicFilter) ->
|
filter_topic(#{meta := #{topic := Topic}} = Log, {TopicFilter, _Name}) ->
|
||||||
case emqx_topic:match(Topic, TopicFilter) of
|
case emqx_topic:match(Topic, TopicFilter) of
|
||||||
true -> Log;
|
true -> Log;
|
||||||
false -> ignore
|
false -> ignore
|
||||||
end;
|
end;
|
||||||
filter_topic(_Log, _ExpectId) -> ignore.
|
filter_topic(_Log, _ExpectId) -> ignore.
|
||||||
|
|
||||||
-spec filter_ip_address(logger:log_event(), string()) -> logger:log_event() | ignore.
|
-spec filter_ip_address(logger:log_event(), {string(), atom()}) -> logger:log_event() | ignore.
|
||||||
filter_ip_address(#{meta := #{peername := Peername}} = Log, IP) ->
|
filter_ip_address(#{meta := #{peername := Peername}} = Log, {IP, _Name}) ->
|
||||||
case lists:prefix(IP, Peername) of
|
case lists:prefix(IP, Peername) of
|
||||||
true -> Log;
|
true -> Log;
|
||||||
false -> ignore
|
false -> ignore
|
||||||
end;
|
end;
|
||||||
filter_ip_address(_Log, _ExpectId) -> ignore.
|
filter_ip_address(_Log, _ExpectId) -> ignore.
|
||||||
|
|
||||||
install_handler(Who, Level, LogFile) ->
|
install_handler(Who = #{name := Name, type := Type}, Level, LogFile) ->
|
||||||
HandlerId = handler_id(Who),
|
case handler_id(Name, Type) of
|
||||||
Config = #{
|
{ok, HandlerId} ->
|
||||||
level => Level,
|
Config = #{
|
||||||
formatter => ?FORMAT,
|
level => Level,
|
||||||
filter_default => stop,
|
formatter => ?FORMAT,
|
||||||
filters => filters(Who),
|
filter_default => stop,
|
||||||
config => ?CONFIG(LogFile)
|
filters => filters(Who),
|
||||||
},
|
config => ?CONFIG(LogFile)
|
||||||
Res = logger:add_handler(HandlerId, logger_disk_log_h, Config),
|
},
|
||||||
show_prompts(Res, Who, "Start trace"),
|
Res = logger:add_handler(HandlerId, logger_disk_log_h, Config),
|
||||||
Res.
|
show_prompts(Res, Who, "Start trace"),
|
||||||
|
Res;
|
||||||
|
{error, _Reason} = Error ->
|
||||||
|
show_prompts(Error, Who, "Start trace"),
|
||||||
|
Error
|
||||||
|
end.
|
||||||
|
|
||||||
filters(#{type := clientid, filter := Filter}) ->
|
filters(#{type := clientid, filter := Filter, name := Name}) ->
|
||||||
[{clientid, {fun ?MODULE:filter_clientid/2, ensure_list(Filter)}}];
|
[{clientid, {fun ?MODULE:filter_clientid/2, {ensure_list(Filter), Name}}}];
|
||||||
filters(#{type := topic, filter := Filter}) ->
|
filters(#{type := topic, filter := Filter, name := Name}) ->
|
||||||
[{topic, {fun ?MODULE:filter_topic/2, ensure_bin(Filter)}}];
|
[{topic, {fun ?MODULE:filter_topic/2, {ensure_bin(Filter), Name}}}];
|
||||||
filters(#{type := ip_address, filter := Filter}) ->
|
filters(#{type := ip_address, filter := Filter, name := Name}) ->
|
||||||
[{ip_address, {fun ?MODULE:filter_ip_address/2, ensure_list(Filter)}}].
|
[{ip_address, {fun ?MODULE:filter_ip_address/2, {ensure_list(Filter), Name}}}].
|
||||||
|
|
||||||
filter_traces(#{id := Id, level := Level, dst := Dst, filters := Filters}, Acc) ->
|
filter_traces(#{id := Id, level := Level, dst := Dst, filters := Filters}, Acc) ->
|
||||||
Init = #{id => Id, level => Level, dst => Dst},
|
Init = #{id => Id, level => Level, dst => Dst},
|
||||||
case Filters of
|
case Filters of
|
||||||
[{topic, {_FilterFun, Filter}}] ->
|
[{Type, {_FilterFun, {Filter, Name}}}] when
|
||||||
<<"trace_topic_", Name/binary>> = atom_to_binary(Id),
|
Type =:= topic orelse
|
||||||
[Init#{type => topic, filter => Filter, name => Name} | Acc];
|
Type =:= clientid orelse
|
||||||
[{clientid, {_FilterFun, Filter}}] ->
|
Type =:= ip_address ->
|
||||||
<<"trace_clientid_", Name/binary>> = atom_to_binary(Id),
|
[Init#{type => Type, filter => Filter, name => Name} | Acc];
|
||||||
[Init#{type => clientid, filter => Filter, name => Name} | Acc];
|
|
||||||
[{ip_address, {_FilterFun, Filter}}] ->
|
|
||||||
<<"trace_ip_address_", Name/binary>> = atom_to_binary(Id),
|
|
||||||
[Init#{type => ip_address, filter => Filter, name => Name} | Acc];
|
|
||||||
_ ->
|
_ ->
|
||||||
Acc
|
Acc
|
||||||
end.
|
end.
|
||||||
|
|
||||||
handler_id(#{type := Type, name := Name}) ->
|
handler_id(Name, Type) ->
|
||||||
binary_to_atom(<<"trace_", (atom_to_binary(Type))/binary, "_", Name/binary>>).
|
TypeBin = atom_to_binary(Type),
|
||||||
|
case io_lib:printable_unicode_list(binary_to_list(Name)) of
|
||||||
|
true when byte_size(Name) < 256 ->
|
||||||
|
NameHash = base64:encode(crypto:hash(sha, Name)),
|
||||||
|
{ok, binary_to_atom(<<"trace_", TypeBin/binary, "_", NameHash/binary>>)};
|
||||||
|
true ->
|
||||||
|
{error, <<"Name length must < 256">>};
|
||||||
|
false ->
|
||||||
|
{error, <<"Name must printable unicode">>}
|
||||||
|
end.
|
||||||
|
|
||||||
ensure_bin(List) when is_list(List) -> iolist_to_binary(List);
|
ensure_bin(List) when is_list(List) -> iolist_to_binary(List);
|
||||||
ensure_bin(Bin) when is_binary(Bin) -> Bin.
|
ensure_bin(Bin) when is_binary(Bin) -> Bin.
|
||||||
|
@ -203,4 +217,4 @@ ensure_list(List) when is_list(List) -> List.
|
||||||
show_prompts(ok, Who, Msg) ->
|
show_prompts(ok, Who, Msg) ->
|
||||||
?LOG(info, Msg ++ " ~p " ++ "successfully~n", [Who]);
|
?LOG(info, Msg ++ " ~p " ++ "successfully~n", [Who]);
|
||||||
show_prompts({error, Reason}, Who, Msg) ->
|
show_prompts({error, Reason}, Who, Msg) ->
|
||||||
?LOG(error, Msg ++ " ~p " ++ "failed by ~p~n", [Who, Reason]).
|
?LOG(error, Msg ++ " ~p " ++ "failed with ~p~n", [Who, Reason]).
|
||||||
|
|
|
@ -70,12 +70,12 @@ t_trace_clientid(_Config) ->
|
||||||
?assert(filelib:is_regular("tmp/client3.log")),
|
?assert(filelib:is_regular("tmp/client3.log")),
|
||||||
|
|
||||||
%% Get current traces
|
%% Get current traces
|
||||||
?assertEqual([#{type => clientid, filter => "client", name => <<"client">>,
|
?assertMatch([#{type := clientid, filter := "client", name := <<"client">>,
|
||||||
id => trace_clientid_client, level => debug, dst => "tmp/client.log"},
|
level := debug, dst := "tmp/client.log"},
|
||||||
#{type => clientid, filter => "client2", name => <<"client2">>,
|
#{type := clientid, filter := "client2", name := <<"client2">>
|
||||||
id => trace_clientid_client2, level => debug, dst => "tmp/client2.log"},
|
, level := debug, dst := "tmp/client2.log"},
|
||||||
#{type => clientid, filter => "client3", name => <<"client3">>,
|
#{type := clientid, filter := "client3", name := <<"client3">>,
|
||||||
id => trace_clientid_client3, level => debug, dst => "tmp/client3.log"}
|
level := debug, dst := "tmp/client3.log"}
|
||||||
], emqx_trace_handler:running()),
|
], emqx_trace_handler:running()),
|
||||||
|
|
||||||
%% Client with clientid = "client" publishes a "hi" message to "a/b/c".
|
%% Client with clientid = "client" publishes a "hi" message to "a/b/c".
|
||||||
|
@ -116,10 +116,10 @@ t_trace_topic(_Config) ->
|
||||||
?assert(filelib:is_regular("tmp/topic_trace_y.log")),
|
?assert(filelib:is_regular("tmp/topic_trace_y.log")),
|
||||||
|
|
||||||
%% Get current traces
|
%% Get current traces
|
||||||
?assertEqual([#{type => topic, filter => <<"x/#">>, id => 'trace_topic_x/#',
|
?assertMatch([#{type := topic, filter := <<"x/#">>,
|
||||||
level => debug, dst => "tmp/topic_trace_x.log", name => <<"x/#">>},
|
level := debug, dst := "tmp/topic_trace_x.log", name := <<"x/#">>},
|
||||||
#{type => topic, filter => <<"y/#">>, id => 'trace_topic_y/#',
|
#{type := topic, filter := <<"y/#">>,
|
||||||
name => <<"y/#">>, level => debug, dst => "tmp/topic_trace_y.log"}
|
name := <<"y/#">>, level := debug, dst := "tmp/topic_trace_y.log"}
|
||||||
],
|
],
|
||||||
emqx_trace_handler:running()),
|
emqx_trace_handler:running()),
|
||||||
|
|
||||||
|
@ -159,12 +159,12 @@ t_trace_ip_address(_Config) ->
|
||||||
?assert(filelib:is_regular("tmp/ip_trace_y.log")),
|
?assert(filelib:is_regular("tmp/ip_trace_y.log")),
|
||||||
|
|
||||||
%% Get current traces
|
%% Get current traces
|
||||||
?assertEqual([#{type => ip_address, filter => "127.0.0.1",
|
?assertMatch([#{type := ip_address, filter := "127.0.0.1",
|
||||||
id => 'trace_ip_address_127.0.0.1', name => <<"127.0.0.1">>,
|
name := <<"127.0.0.1">>,
|
||||||
level => debug, dst => "tmp/ip_trace_x.log"},
|
level := debug, dst := "tmp/ip_trace_x.log"},
|
||||||
#{type => ip_address, filter => "192.168.1.1",
|
#{type := ip_address, filter := "192.168.1.1",
|
||||||
id => 'trace_ip_address_192.168.1.1', name => <<"192.168.1.1">>,
|
name := <<"192.168.1.1">>,
|
||||||
level => debug, dst => "tmp/ip_trace_y.log"}
|
level := debug, dst := "tmp/ip_trace_y.log"}
|
||||||
],
|
],
|
||||||
emqx_trace_handler:running()),
|
emqx_trace_handler:running()),
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue