Merge pull request #13348 from lafirest/fix/drop_payload
feat(log): allows custom the encoding of payload in the log
This commit is contained in:
commit
3f0d59300b
|
@ -238,8 +238,9 @@ log_formatter(HandlerName, Conf) ->
|
||||||
conf_get("formatter", Conf)
|
conf_get("formatter", Conf)
|
||||||
end,
|
end,
|
||||||
TsFormat = timstamp_format(Conf),
|
TsFormat = timstamp_format(Conf),
|
||||||
|
PayloadEncode = conf_get("payload_encode", Conf, text),
|
||||||
do_formatter(
|
do_formatter(
|
||||||
Format, CharsLimit, SingleLine, TimeOffSet, Depth, TsFormat
|
Format, CharsLimit, SingleLine, TimeOffSet, Depth, TsFormat, PayloadEncode
|
||||||
).
|
).
|
||||||
|
|
||||||
%% auto | epoch | rfc3339
|
%% auto | epoch | rfc3339
|
||||||
|
@ -247,22 +248,24 @@ timstamp_format(Conf) ->
|
||||||
conf_get("timestamp_format", Conf).
|
conf_get("timestamp_format", Conf).
|
||||||
|
|
||||||
%% helpers
|
%% helpers
|
||||||
do_formatter(json, CharsLimit, SingleLine, TimeOffSet, Depth, TsFormat) ->
|
do_formatter(json, CharsLimit, SingleLine, TimeOffSet, Depth, TsFormat, PayloadEncode) ->
|
||||||
{emqx_logger_jsonfmt, #{
|
{emqx_logger_jsonfmt, #{
|
||||||
chars_limit => CharsLimit,
|
chars_limit => CharsLimit,
|
||||||
single_line => SingleLine,
|
single_line => SingleLine,
|
||||||
time_offset => TimeOffSet,
|
time_offset => TimeOffSet,
|
||||||
depth => Depth,
|
depth => Depth,
|
||||||
timestamp_format => TsFormat
|
timestamp_format => TsFormat,
|
||||||
|
payload_encode => PayloadEncode
|
||||||
}};
|
}};
|
||||||
do_formatter(text, CharsLimit, SingleLine, TimeOffSet, Depth, TsFormat) ->
|
do_formatter(text, CharsLimit, SingleLine, TimeOffSet, Depth, TsFormat, PayloadEncode) ->
|
||||||
{emqx_logger_textfmt, #{
|
{emqx_logger_textfmt, #{
|
||||||
template => ["[", level, "] ", msg, "\n"],
|
template => ["[", level, "] ", msg, "\n"],
|
||||||
chars_limit => CharsLimit,
|
chars_limit => CharsLimit,
|
||||||
single_line => SingleLine,
|
single_line => SingleLine,
|
||||||
time_offset => TimeOffSet,
|
time_offset => TimeOffSet,
|
||||||
depth => Depth,
|
depth => Depth,
|
||||||
timestamp_format => TsFormat
|
timestamp_format => TsFormat,
|
||||||
|
payload_encode => PayloadEncode
|
||||||
}}.
|
}}.
|
||||||
|
|
||||||
%% Don't record all logger message
|
%% Don't record all logger message
|
||||||
|
|
|
@ -55,7 +55,8 @@
|
||||||
depth => pos_integer() | unlimited,
|
depth => pos_integer() | unlimited,
|
||||||
report_cb => logger:report_cb(),
|
report_cb => logger:report_cb(),
|
||||||
single_line => boolean(),
|
single_line => boolean(),
|
||||||
chars_limit => unlimited | pos_integer()
|
chars_limit => unlimited | pos_integer(),
|
||||||
|
payload_encode => text | hidden | hex
|
||||||
}.
|
}.
|
||||||
|
|
||||||
-define(IS_STRING(String), (is_list(String) orelse is_binary(String))).
|
-define(IS_STRING(String), (is_list(String) orelse is_binary(String))).
|
||||||
|
@ -103,7 +104,8 @@ format(Msg, Meta, Config) ->
|
||||||
|
|
||||||
maybe_format_msg(undefined, _Meta, _Config) ->
|
maybe_format_msg(undefined, _Meta, _Config) ->
|
||||||
#{};
|
#{};
|
||||||
maybe_format_msg({report, Report} = Msg, #{report_cb := Cb} = Meta, Config) ->
|
maybe_format_msg({report, Report0} = Msg, #{report_cb := Cb} = Meta, Config) ->
|
||||||
|
Report = emqx_logger_textfmt:try_encode_payload(Report0, Config),
|
||||||
case is_map(Report) andalso Cb =:= ?DEFAULT_FORMATTER of
|
case is_map(Report) andalso Cb =:= ?DEFAULT_FORMATTER of
|
||||||
true ->
|
true ->
|
||||||
%% reporting a map without a customised format function
|
%% reporting a map without a customised format function
|
||||||
|
|
|
@ -20,11 +20,12 @@
|
||||||
|
|
||||||
-export([format/2]).
|
-export([format/2]).
|
||||||
-export([check_config/1]).
|
-export([check_config/1]).
|
||||||
-export([try_format_unicode/1]).
|
-export([try_format_unicode/1, try_encode_payload/2]).
|
||||||
%% Used in the other log formatters
|
%% Used in the other log formatters
|
||||||
-export([evaluate_lazy_values_if_dbg_level/1, evaluate_lazy_values/1]).
|
-export([evaluate_lazy_values_if_dbg_level/1, evaluate_lazy_values/1]).
|
||||||
|
|
||||||
check_config(X) -> logger_formatter:check_config(maps:without([timestamp_format], X)).
|
check_config(X) ->
|
||||||
|
logger_formatter:check_config(maps:without([timestamp_format, payload_encode], X)).
|
||||||
|
|
||||||
%% Principle here is to delegate the formatting to logger_formatter:format/2
|
%% Principle here is to delegate the formatting to logger_formatter:format/2
|
||||||
%% as much as possible, and only enrich the report with clientid, peername, topic, username
|
%% as much as possible, and only enrich the report with clientid, peername, topic, username
|
||||||
|
@ -32,7 +33,7 @@ format(#{msg := {report, ReportMap0}, meta := _Meta} = Event0, Config) when is_m
|
||||||
#{msg := {report, ReportMap}, meta := Meta} = Event = evaluate_lazy_values_if_dbg_level(Event0),
|
#{msg := {report, ReportMap}, meta := Meta} = Event = evaluate_lazy_values_if_dbg_level(Event0),
|
||||||
%% The most common case, when entering from SLOG macro
|
%% The most common case, when entering from SLOG macro
|
||||||
%% i.e. logger:log(Level, #{msg => "my_msg", foo => bar})
|
%% i.e. logger:log(Level, #{msg => "my_msg", foo => bar})
|
||||||
ReportList = enrich_report(ReportMap, Meta),
|
ReportList = enrich_report(ReportMap, Meta, Config),
|
||||||
Report =
|
Report =
|
||||||
case is_list_report_acceptable(Meta) of
|
case is_list_report_acceptable(Meta) of
|
||||||
true ->
|
true ->
|
||||||
|
@ -101,9 +102,10 @@ is_list_report_acceptable(#{report_cb := Cb}) ->
|
||||||
is_list_report_acceptable(_) ->
|
is_list_report_acceptable(_) ->
|
||||||
false.
|
false.
|
||||||
|
|
||||||
enrich_report(ReportRaw, Meta) ->
|
enrich_report(ReportRaw0, Meta, Config) ->
|
||||||
%% clientid and peername always in emqx_conn's process metadata.
|
%% clientid and peername always in emqx_conn's process metadata.
|
||||||
%% topic and username can be put in meta using ?SLOG/3, or put in msg's report by ?SLOG/2
|
%% topic and username can be put in meta using ?SLOG/3, or put in msg's report by ?SLOG/2
|
||||||
|
ReportRaw = try_encode_payload(ReportRaw0, Config),
|
||||||
Topic =
|
Topic =
|
||||||
case maps:get(topic, Meta, undefined) of
|
case maps:get(topic, Meta, undefined) of
|
||||||
undefined -> maps:get(topic, ReportRaw, undefined);
|
undefined -> maps:get(topic, ReportRaw, undefined);
|
||||||
|
@ -169,3 +171,15 @@ enrich_topic({Fmt, Args}, #{topic := Topic}) when is_list(Fmt) ->
|
||||||
{" topic: ~ts" ++ Fmt, [Topic | Args]};
|
{" topic: ~ts" ++ Fmt, [Topic | Args]};
|
||||||
enrich_topic(Msg, _) ->
|
enrich_topic(Msg, _) ->
|
||||||
Msg.
|
Msg.
|
||||||
|
|
||||||
|
try_encode_payload(#{payload := Payload} = Report, #{payload_encode := Encode}) ->
|
||||||
|
Report#{payload := encode_payload(Payload, Encode)};
|
||||||
|
try_encode_payload(Report, _Config) ->
|
||||||
|
Report.
|
||||||
|
|
||||||
|
encode_payload(Payload, text) ->
|
||||||
|
Payload;
|
||||||
|
encode_payload(_Payload, hidden) ->
|
||||||
|
"******";
|
||||||
|
encode_payload(Payload, hex) ->
|
||||||
|
binary:encode_hex(Payload).
|
||||||
|
|
|
@ -36,12 +36,18 @@ t_text_fmt_lazy_values(_) ->
|
||||||
t_text_fmt_lazy_values_only_in_debug_level_events(_) ->
|
t_text_fmt_lazy_values_only_in_debug_level_events(_) ->
|
||||||
check_fmt_lazy_values_only_in_debug_level_events(emqx_logger_textfmt).
|
check_fmt_lazy_values_only_in_debug_level_events(emqx_logger_textfmt).
|
||||||
|
|
||||||
|
t_text_payload(_) ->
|
||||||
|
check_fmt_payload(emqx_logger_textfmt).
|
||||||
|
|
||||||
t_json_fmt_lazy_values(_) ->
|
t_json_fmt_lazy_values(_) ->
|
||||||
check_fmt_lazy_values(emqx_logger_jsonfmt).
|
check_fmt_lazy_values(emqx_logger_jsonfmt).
|
||||||
|
|
||||||
t_json_fmt_lazy_values_only_in_debug_level_events(_) ->
|
t_json_fmt_lazy_values_only_in_debug_level_events(_) ->
|
||||||
check_fmt_lazy_values_only_in_debug_level_events(emqx_logger_jsonfmt).
|
check_fmt_lazy_values_only_in_debug_level_events(emqx_logger_jsonfmt).
|
||||||
|
|
||||||
|
t_json_payload(_) ->
|
||||||
|
check_fmt_payload(emqx_logger_jsonfmt).
|
||||||
|
|
||||||
check_fmt_lazy_values(FormatModule) ->
|
check_fmt_lazy_values(FormatModule) ->
|
||||||
LogEntryIOData = FormatModule:format(event_with_lazy_value(), conf()),
|
LogEntryIOData = FormatModule:format(event_with_lazy_value(), conf()),
|
||||||
LogEntryBin = unicode:characters_to_binary(LogEntryIOData),
|
LogEntryBin = unicode:characters_to_binary(LogEntryIOData),
|
||||||
|
@ -62,6 +68,18 @@ check_fmt_lazy_values_only_in_debug_level_events(FormatModule) ->
|
||||||
?assertNotEqual(nomatch, binary:match(LogEntryBin, [<<"emqx_trace_format_func_data">>])),
|
?assertNotEqual(nomatch, binary:match(LogEntryBin, [<<"emqx_trace_format_func_data">>])),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
check_fmt_payload(FormatModule) ->
|
||||||
|
%% For performace reason we only search for lazy values to evaluate if log level is debug
|
||||||
|
WarningEvent = (event_with_lazy_value())#{level => info},
|
||||||
|
Conf = conf(),
|
||||||
|
LogEntryIOData = FormatModule:format(WarningEvent, Conf#{payload_encode => hidden}),
|
||||||
|
LogEntryBin = unicode:characters_to_binary(LogEntryIOData),
|
||||||
|
%% The input data for the formatting should exist
|
||||||
|
?assertEqual(nomatch, binary:match(LogEntryBin, [<<"content">>])),
|
||||||
|
%% The lazy value should not have been evaluated
|
||||||
|
?assertNotEqual(nomatch, binary:match(LogEntryBin, [<<"******">>])),
|
||||||
|
ok.
|
||||||
|
|
||||||
conf() ->
|
conf() ->
|
||||||
#{
|
#{
|
||||||
time_offset => [],
|
time_offset => [],
|
||||||
|
@ -84,7 +102,8 @@ event_with_lazy_value() ->
|
||||||
{report, #{
|
{report, #{
|
||||||
reason =>
|
reason =>
|
||||||
#emqx_trace_format_func_data{function = fun(Data) -> Data end, data = hej},
|
#emqx_trace_format_func_data{function = fun(Data) -> Data end, data = hej},
|
||||||
msg => hej
|
msg => hej,
|
||||||
|
payload => <<"content">>
|
||||||
}},
|
}},
|
||||||
level => debug
|
level => debug
|
||||||
}.
|
}.
|
||||||
|
|
|
@ -1358,7 +1358,13 @@ log_handler_common_confs(Handler, Default) ->
|
||||||
desc => ?DESC("common_handler_max_depth"),
|
desc => ?DESC("common_handler_max_depth"),
|
||||||
importance => ?IMPORTANCE_HIDDEN
|
importance => ?IMPORTANCE_HIDDEN
|
||||||
}
|
}
|
||||||
)}
|
)},
|
||||||
|
{"payload_encode",
|
||||||
|
sc(hoconsc:enum([hex, text, hidden]), #{
|
||||||
|
default => text,
|
||||||
|
importance => ?IMPORTANCE_HIDDEN,
|
||||||
|
desc => ?DESC(emqx_schema, fields_trace_payload_encode)
|
||||||
|
})}
|
||||||
].
|
].
|
||||||
|
|
||||||
crash_dump_file_default() ->
|
crash_dump_file_default() ->
|
||||||
|
|
|
@ -133,7 +133,8 @@ log.file_handlers {
|
||||||
single_line => true,
|
single_line => true,
|
||||||
template => ["[", level, "] ", msg, "\n"],
|
template => ["[", level, "] ", msg, "\n"],
|
||||||
time_offset => TimeOffset,
|
time_offset => TimeOffset,
|
||||||
timestamp_format => auto
|
timestamp_format => auto,
|
||||||
|
payload_encode => text
|
||||||
}}
|
}}
|
||||||
).
|
).
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Added a new field `payload_encode` to the log configuration to determine the format of the payload in the log data.
|
Loading…
Reference in New Issue