refactor: remove seq from audit record
This commit is contained in:
parent
9bb22507df
commit
995948f0e8
|
@ -32,6 +32,5 @@
|
||||||
|
|
||||||
-define(SHARD, ?COMMON_SHARD).
|
-define(SHARD, ?COMMON_SHARD).
|
||||||
-define(MAX_SIZE, 30).
|
-define(MAX_SIZE, 30).
|
||||||
-define(OWN_KEYS, [level, filters, filter_default, handlers]).
|
|
||||||
|
|
||||||
-endif.
|
-endif.
|
||||||
|
|
|
@ -40,7 +40,9 @@
|
||||||
end
|
end
|
||||||
).
|
).
|
||||||
|
|
||||||
|
-define(AUDIT_HANDLER, emqx_audit).
|
||||||
-define(TRACE_FILTER, emqx_trace_filter).
|
-define(TRACE_FILTER, emqx_trace_filter).
|
||||||
|
-define(OWN_KEYS, [level, filters, filter_default, handlers]).
|
||||||
|
|
||||||
-define(TRACE(Tag, Msg, Meta), ?TRACE(debug, Tag, Msg, Meta)).
|
-define(TRACE(Tag, Msg, Meta), ?TRACE(debug, Tag, Msg, Meta)).
|
||||||
|
|
||||||
|
@ -62,15 +64,15 @@
|
||||||
end).
|
end).
|
||||||
|
|
||||||
-define(AUDIT(_LevelFun_, _MetaFun_), begin
|
-define(AUDIT(_LevelFun_, _MetaFun_), begin
|
||||||
case emqx_config:get([log, audit], #{enable => false}) of
|
case logger_config:get(logger, ?AUDIT_HANDLER) of
|
||||||
#{enable := false} ->
|
{error, {not_found, _}} ->
|
||||||
ok;
|
ok;
|
||||||
#{enable := true, level := _AllowLevel_} ->
|
{ok, Handler = #{level := _AllowLevel_}} ->
|
||||||
_Level_ = _LevelFun_,
|
_Level_ = _LevelFun_,
|
||||||
case logger:compare_levels(_AllowLevel_, _Level_) of
|
case logger:compare_levels(_AllowLevel_, _Level_) of
|
||||||
_R_ when _R_ == lt; _R_ == eq ->
|
_R_ when _R_ == lt; _R_ == eq ->
|
||||||
emqx_audit:log(_Level_, _MetaFun_);
|
emqx_audit:log(_Level_, _MetaFun_, Handler);
|
||||||
gt ->
|
_ ->
|
||||||
ok
|
ok
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
-include("logger.hrl").
|
-include("logger.hrl").
|
||||||
|
|
||||||
-define(LOG, [log]).
|
-define(LOG, [log]).
|
||||||
-define(AUDIT_HANDLER, emqx_audit).
|
|
||||||
|
|
||||||
add_handler() ->
|
add_handler() ->
|
||||||
ok = emqx_config_handler:add_handler(?LOG, ?MODULE),
|
ok = emqx_config_handler:add_handler(?LOG, ?MODULE),
|
||||||
|
@ -97,8 +96,11 @@ update_log_handlers(NewHandlers) ->
|
||||||
ok = application:set_env(kernel, logger, NewHandlers),
|
ok = application:set_env(kernel, logger, NewHandlers),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
%% Don't remove audit log handler here, we need record this removed action into audit log file.
|
||||||
|
%% we will remove audit log handler after audit log is record in emqx_audit:log/3.
|
||||||
|
update_log_handler({removed, ?AUDIT_HANDLER}) ->
|
||||||
|
ok;
|
||||||
update_log_handler({removed, Id}) ->
|
update_log_handler({removed, Id}) ->
|
||||||
audit("audit_disabled", Id),
|
|
||||||
log_to_console("Config override: ~s is removed~n", [id_for_log(Id)]),
|
log_to_console("Config override: ~s is removed~n", [id_for_log(Id)]),
|
||||||
logger:remove_handler(Id);
|
logger:remove_handler(Id);
|
||||||
update_log_handler({Action, {handler, Id, Mod, Conf}}) ->
|
update_log_handler({Action, {handler, Id, Mod, Conf}}) ->
|
||||||
|
@ -107,7 +109,6 @@ update_log_handler({Action, {handler, Id, Mod, Conf}}) ->
|
||||||
_ = logger:remove_handler(Id),
|
_ = logger:remove_handler(Id),
|
||||||
case logger:add_handler(Id, Mod, Conf) of
|
case logger:add_handler(Id, Mod, Conf) of
|
||||||
ok ->
|
ok ->
|
||||||
audit("audit_enabled", Id),
|
|
||||||
ok;
|
ok;
|
||||||
%% Don't crash here, otherwise the cluster rpc will retry the wrong handler forever.
|
%% Don't crash here, otherwise the cluster rpc will retry the wrong handler forever.
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
|
@ -118,23 +119,6 @@ update_log_handler({Action, {handler, Id, Mod, Conf}}) ->
|
||||||
end,
|
end,
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
-ifdef(EMQX_RELEASE_EDITION).
|
|
||||||
|
|
||||||
-if(?EMQX_RELEASE_EDITION == ee).
|
|
||||||
audit(Event, ?AUDIT_HANDLER) ->
|
|
||||||
emqx_audit:log(alert, #{event => Event, from => event});
|
|
||||||
audit(_, _) ->
|
|
||||||
ok.
|
|
||||||
-else.
|
|
||||||
audit(_, _) ->
|
|
||||||
ok.
|
|
||||||
-endif.
|
|
||||||
|
|
||||||
-else.
|
|
||||||
audit(_, _) ->
|
|
||||||
ok.
|
|
||||||
-endif.
|
|
||||||
|
|
||||||
id_for_log(console) -> "log.console";
|
id_for_log(console) -> "log.console";
|
||||||
id_for_log(Other) -> "log.file." ++ atom_to_list(Other).
|
id_for_log(Other) -> "log.file." ++ atom_to_list(Other).
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,7 @@ log_filter([{Id, FilterFun, Filter, Name} | Rest], Log0) ->
|
||||||
ignore ->
|
ignore ->
|
||||||
ignore;
|
ignore;
|
||||||
Log ->
|
Log ->
|
||||||
case logger_config:get(ets:whereis(logger), Id) of
|
case logger_config:get(logger, Id) of
|
||||||
{ok, #{module := Module} = HandlerConfig0} ->
|
{ok, #{module := Module} = HandlerConfig0} ->
|
||||||
HandlerConfig = maps:without(?OWN_KEYS, HandlerConfig0),
|
HandlerConfig = maps:without(?OWN_KEYS, HandlerConfig0),
|
||||||
try
|
try
|
||||||
|
|
|
@ -12,9 +12,9 @@
|
||||||
|
|
||||||
%% API
|
%% API
|
||||||
-export([start_link/0]).
|
-export([start_link/0]).
|
||||||
-export([log/1, log/2]).
|
-export([log/3]).
|
||||||
|
|
||||||
-export([dirty_clean_expired/1]).
|
-export([trans_clean_expired/2]).
|
||||||
|
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
-export([
|
-export([
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
-ifdef(TEST).
|
-ifdef(TEST).
|
||||||
-define(INTERVAL, 100).
|
-define(INTERVAL, 100).
|
||||||
-else.
|
-else.
|
||||||
-define(INTERVAL, 2500).
|
-define(INTERVAL, 10000).
|
||||||
-endif.
|
-endif.
|
||||||
|
|
||||||
to_audit(#{from := cli, cmd := Cmd, args := Args, duration_ms := DurationMs}) ->
|
to_audit(#{from := cli, cmd := Cmd, args := Args, duration_ms := DurationMs}) ->
|
||||||
|
@ -50,8 +50,6 @@ to_audit(#{from := cli, cmd := Cmd, args := Args, duration_ms := DurationMs}) ->
|
||||||
http_method = <<"">>,
|
http_method = <<"">>,
|
||||||
http_request = <<"">>
|
http_request = <<"">>
|
||||||
};
|
};
|
||||||
to_audit(#{http_method := get}) ->
|
|
||||||
ok;
|
|
||||||
to_audit(#{from := From} = Log) when From =:= dashboard orelse From =:= rest_api ->
|
to_audit(#{from := From} = Log) when From =:= dashboard orelse From =:= rest_api ->
|
||||||
#{
|
#{
|
||||||
source := Source,
|
source := Source,
|
||||||
|
@ -82,23 +80,6 @@ to_audit(#{from := From} = Log) when From =:= dashboard orelse From =:= rest_api
|
||||||
duration_ms = DurationMs,
|
duration_ms = DurationMs,
|
||||||
args = <<"">>
|
args = <<"">>
|
||||||
};
|
};
|
||||||
to_audit(#{from := event, event := Event}) ->
|
|
||||||
#?AUDIT{
|
|
||||||
from = event,
|
|
||||||
source = <<"">>,
|
|
||||||
source_ip = <<"">>,
|
|
||||||
%% operation info
|
|
||||||
operation_id = iolist_to_binary(Event),
|
|
||||||
operation_type = <<"">>,
|
|
||||||
operation_result = <<"">>,
|
|
||||||
failure = <<"">>,
|
|
||||||
%% request detail
|
|
||||||
http_status_code = <<"">>,
|
|
||||||
http_method = <<"">>,
|
|
||||||
http_request = <<"">>,
|
|
||||||
duration_ms = 0,
|
|
||||||
args = <<"">>
|
|
||||||
};
|
|
||||||
to_audit(#{from := erlang_console, function := F, args := Args}) ->
|
to_audit(#{from := erlang_console, function := F, args := Args}) ->
|
||||||
#?AUDIT{
|
#?AUDIT{
|
||||||
from = erlang_console,
|
from = erlang_console,
|
||||||
|
@ -117,15 +98,22 @@ to_audit(#{from := erlang_console, function := F, args := Args}) ->
|
||||||
args = iolist_to_binary(io_lib:format("~p: ~p~n", [F, Args]))
|
args = iolist_to_binary(io_lib:format("~p: ~p~n", [F, Args]))
|
||||||
}.
|
}.
|
||||||
|
|
||||||
log(_Level, undefined) ->
|
log(_Level, undefined, _Handler) ->
|
||||||
ok;
|
ok;
|
||||||
log(Level, Meta1) ->
|
log(Level, Meta1, Handler) ->
|
||||||
Meta2 = Meta1#{time => logger:timestamp(), level => Level},
|
Meta2 = Meta1#{time => logger:timestamp(), level => Level},
|
||||||
Filter = [{emqx_audit, fun(L, _) -> L end, undefined, undefined}],
|
log_to_file(Level, Meta2, Handler),
|
||||||
emqx_trace:log(Level, Filter, undefined, Meta2),
|
log_to_db(Meta2),
|
||||||
emqx_audit:log(Meta2).
|
remove_handler_when_disabled().
|
||||||
|
|
||||||
log(Log) ->
|
remove_handler_when_disabled() ->
|
||||||
|
case emqx_config:get([log, audit, enable], false) of
|
||||||
|
true -> ok;
|
||||||
|
false -> _ = logger:remove_handler(?AUDIT_HANDLER)
|
||||||
|
end,
|
||||||
|
ok.
|
||||||
|
|
||||||
|
log_to_db(Log) ->
|
||||||
Audit0 = to_audit(Log),
|
Audit0 = to_audit(Log),
|
||||||
Audit = Audit0#?AUDIT{
|
Audit = Audit0#?AUDIT{
|
||||||
node = node(),
|
node = node(),
|
||||||
|
@ -144,68 +132,112 @@ init([]) ->
|
||||||
{record_name, ?AUDIT},
|
{record_name, ?AUDIT},
|
||||||
{attributes, record_info(fields, ?AUDIT)}
|
{attributes, record_info(fields, ?AUDIT)}
|
||||||
]),
|
]),
|
||||||
case mria_rlog:role() of
|
{ok, #{}, {continue, setup}}.
|
||||||
core -> {ok, #{}, {continue, setup}};
|
|
||||||
_ -> {ok, #{}}
|
|
||||||
end.
|
|
||||||
|
|
||||||
handle_continue(setup, State) ->
|
handle_continue(setup, State) ->
|
||||||
ok = mria:wait_for_tables([?AUDIT]),
|
ok = mria:wait_for_tables([?AUDIT]),
|
||||||
clean_expired(),
|
NewState = State#{role => mria_rlog:role()},
|
||||||
Interval = clean_expired_interval(),
|
?AUDIT(alert, #{
|
||||||
{noreply, State#{interval => Interval}, Interval}.
|
cmd => emqx,
|
||||||
|
args => ["start"],
|
||||||
|
version => emqx_release:version(),
|
||||||
|
from => cli,
|
||||||
|
duration_ms => 0
|
||||||
|
}),
|
||||||
|
{noreply, NewState, interval(NewState)}.
|
||||||
|
|
||||||
handle_call(_Request, _From, State = #{interval := Interval}) ->
|
handle_call(_Request, _From, State) ->
|
||||||
{reply, ignore, State, Interval}.
|
{reply, ignore, State, interval(State)}.
|
||||||
|
|
||||||
handle_cast(_Request, State = #{interval := Interval}) ->
|
handle_cast(_Request, State) ->
|
||||||
{noreply, State, Interval}.
|
{noreply, State, interval(State)}.
|
||||||
|
|
||||||
handle_info(timeout, State = #{interval := Interval}) ->
|
handle_info(timeout, State) ->
|
||||||
clean_expired(),
|
ExtraWait = clean_expired_logs(),
|
||||||
{noreply, State, Interval};
|
{noreply, State, interval(State) + ExtraWait};
|
||||||
handle_info(_Info, State = #{interval := Interval}) ->
|
handle_info(_Info, State) ->
|
||||||
{noreply, State, Interval}.
|
{noreply, State, interval(State)}.
|
||||||
|
|
||||||
terminate(_Reason, _State = #{}) ->
|
terminate(_Reason, _State) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
code_change(_OldVsn, State = #{}, _Extra) ->
|
code_change(_OldVsn, State, _Extra) ->
|
||||||
{ok, State}.
|
{ok, State}.
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% Internal functions
|
%%% Internal functions
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
|
|
||||||
clean_expired() ->
|
%% if clean_expired transaction aborted, it will be scheduled with extra 60 seconds.
|
||||||
|
clean_expired_logs() ->
|
||||||
MaxSize = max_size(),
|
MaxSize = max_size(),
|
||||||
|
Oldest = mnesia:dirty_first(?AUDIT),
|
||||||
CurSize = mnesia:table_info(?AUDIT, size),
|
CurSize = mnesia:table_info(?AUDIT, size),
|
||||||
case CurSize - MaxSize of
|
case CurSize - MaxSize of
|
||||||
DelCount when DelCount > 0 ->
|
DelSize when DelSize > 0 ->
|
||||||
mria:async_dirty(
|
case
|
||||||
?COMMON_SHARD,
|
mria:transaction(
|
||||||
fun ?MODULE:dirty_clean_expired/1,
|
?COMMON_SHARD,
|
||||||
[DelCount]
|
fun ?MODULE:trans_clean_expired/2,
|
||||||
);
|
[Oldest, DelSize]
|
||||||
|
)
|
||||||
|
of
|
||||||
|
{atomic, ok} ->
|
||||||
|
0;
|
||||||
|
{aborted, Reason} ->
|
||||||
|
?SLOG(error, #{
|
||||||
|
msg => "clean_expired_audit_aborted",
|
||||||
|
reason => Reason,
|
||||||
|
delete_size => DelSize,
|
||||||
|
current_size => CurSize,
|
||||||
|
max_count => MaxSize
|
||||||
|
}),
|
||||||
|
60000
|
||||||
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
ok
|
0
|
||||||
end.
|
end.
|
||||||
|
|
||||||
dirty_clean_expired(DelCount) ->
|
trans_clean_expired(Oldest, DelCount) ->
|
||||||
dirty_clean_expired(mnesia:dirty_first(?AUDIT), DelCount).
|
First = mnesia:first(?AUDIT),
|
||||||
|
%% Other node already clean from the oldest record.
|
||||||
|
%% ensure not delete twice, otherwise records that should not be deleted will be deleted.
|
||||||
|
case First =:= Oldest of
|
||||||
|
true -> do_clean_expired(First, DelCount);
|
||||||
|
false -> ok
|
||||||
|
end.
|
||||||
|
|
||||||
dirty_clean_expired(_, DelCount) when DelCount =< 0 -> ok;
|
do_clean_expired(_, DelSize) when DelSize =< 0 -> ok;
|
||||||
dirty_clean_expired('$end_of_table', _DelCount) ->
|
do_clean_expired('$end_of_table', _DelSize) ->
|
||||||
ok;
|
ok;
|
||||||
dirty_clean_expired(CurKey, DeleteCount) ->
|
do_clean_expired(CurKey, DeleteSize) ->
|
||||||
mnesia:dirty_delete(?AUDIT, CurKey),
|
mnesia:delete(?AUDIT, CurKey, sticky_write),
|
||||||
dirty_clean_expired(mnesia:dirty_next(?AUDIT, CurKey), DeleteCount - 1).
|
do_clean_expired(mnesia:next(?AUDIT, CurKey), DeleteSize - 1).
|
||||||
|
|
||||||
max_size() ->
|
max_size() ->
|
||||||
emqx_conf:get([log, audit, max_filter_size], 5000).
|
emqx_conf:get([log, audit, max_filter_size], 5000).
|
||||||
|
|
||||||
%% Try to make the time interval of each node is different.
|
interval(#{role := replicant}) -> hibernate;
|
||||||
%% 2 * Interval ~ 3 * Interval (5000~7500)
|
interval(#{role := core}) -> ?INTERVAL + rand:uniform(?INTERVAL).
|
||||||
clean_expired_interval() ->
|
|
||||||
Interval = ?INTERVAL,
|
log_to_file(Level, Meta, #{module := Module} = Handler) ->
|
||||||
Interval * 2 + erlang:phash2(node(), Interval).
|
Log = #{level => Level, meta => Meta, msg => undefined},
|
||||||
|
Handler1 = maps:without(?OWN_KEYS, Handler),
|
||||||
|
try
|
||||||
|
erlang:apply(Module, log, [Log, Handler1])
|
||||||
|
catch
|
||||||
|
C:R:S ->
|
||||||
|
case logger:remove_handler(?AUDIT_HANDLER) of
|
||||||
|
ok ->
|
||||||
|
logger:internal_log(
|
||||||
|
error, {removed_failing_handler, ?AUDIT_HANDLER, C, R, S}
|
||||||
|
);
|
||||||
|
{error, {not_found, _}} ->
|
||||||
|
ok;
|
||||||
|
{error, Reason} ->
|
||||||
|
logger:internal_log(
|
||||||
|
error,
|
||||||
|
{removed_handler_failed, ?AUDIT_HANDLER, Reason, C, R, S}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
|
@ -59,7 +59,7 @@ schema("/audit") ->
|
||||||
desc => ?DESC(filter_node)
|
desc => ?DESC(filter_node)
|
||||||
})},
|
})},
|
||||||
{from,
|
{from,
|
||||||
?HOCON(?ENUM([dashboard, rest_api, cli, erlang_console, event]), #{
|
?HOCON(?ENUM([dashboard, rest_api, cli, erlang_console]), #{
|
||||||
in => query,
|
in => query,
|
||||||
required => false,
|
required => false,
|
||||||
example => <<"dashboard">>,
|
example => <<"dashboard">>,
|
||||||
|
@ -175,7 +175,7 @@ fields(audit) ->
|
||||||
desc => "The node name to which the log is created"
|
desc => "The node name to which the log is created"
|
||||||
})},
|
})},
|
||||||
{from,
|
{from,
|
||||||
?HOCON(?ENUM([dashboard, rest_api, cli, erlang_console, event]), #{
|
?HOCON(?ENUM([dashboard, rest_api, cli, erlang_console]), #{
|
||||||
desc => "The source type of the log"
|
desc => "The source type of the log"
|
||||||
})},
|
})},
|
||||||
{source,
|
{source,
|
||||||
|
|
|
@ -49,6 +49,7 @@ init_per_suite(Config) ->
|
||||||
emqx_mgmt_api_test_util:init_suite([emqx_ctl, emqx_conf, emqx_audit]),
|
emqx_mgmt_api_test_util:init_suite([emqx_ctl, emqx_conf, emqx_audit]),
|
||||||
ok = emqx_common_test_helpers:load_config(emqx_enterprise_schema, ?CONF_DEFAULT),
|
ok = emqx_common_test_helpers:load_config(emqx_enterprise_schema, ?CONF_DEFAULT),
|
||||||
emqx_config:save_schema_mod_and_names(emqx_enterprise_schema),
|
emqx_config:save_schema_mod_and_names(emqx_enterprise_schema),
|
||||||
|
ok = emqx_config_logger:refresh_config(),
|
||||||
application:set_env(emqx, boot_modules, []),
|
application:set_env(emqx, boot_modules, []),
|
||||||
emqx_conf_cli:load(),
|
emqx_conf_cli:load(),
|
||||||
Config.
|
Config.
|
||||||
|
@ -144,7 +145,7 @@ t_max_size(_Config) ->
|
||||||
?assert(Size1 - InitSize >= 100, {Size1, InitSize}),
|
?assert(Size1 - InitSize >= 100, {Size1, InitSize}),
|
||||||
{ok, _} = emqx:update_config([log, audit, max_filter_size], 10),
|
{ok, _} = emqx:update_config([log, audit, max_filter_size], 10),
|
||||||
%% wait for clean_expired
|
%% wait for clean_expired
|
||||||
timer:sleep(500),
|
timer:sleep(250),
|
||||||
ExpectSize = emqx:get_config([log, audit, max_filter_size]),
|
ExpectSize = emqx:get_config([log, audit, max_filter_size]),
|
||||||
Size2 = SizeFun(),
|
Size2 = SizeFun(),
|
||||||
?assertEqual(ExpectSize, Size2, {sys:get_state(emqx_audit)}),
|
?assertEqual(ExpectSize, Size2, {sys:get_state(emqx_audit)}),
|
||||||
|
|
|
@ -40,7 +40,10 @@
|
||||||
load() ->
|
load() ->
|
||||||
emqx_ctl:register_command(?CLUSTER_CALL, {?MODULE, admins}, [hidden]),
|
emqx_ctl:register_command(?CLUSTER_CALL, {?MODULE, admins}, [hidden]),
|
||||||
emqx_ctl:register_command(?CONF, {?MODULE, conf}, []),
|
emqx_ctl:register_command(?CONF, {?MODULE, conf}, []),
|
||||||
emqx_ctl:register_command(?AUDIT_MOD, {?MODULE, audit}, [hidden]),
|
case emqx_release:edition() of
|
||||||
|
ee -> emqx_ctl:register_command(?AUDIT_MOD, {?MODULE, audit}, [hidden]);
|
||||||
|
ce -> ok
|
||||||
|
end,
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
unload() ->
|
unload() ->
|
||||||
|
|
|
@ -72,7 +72,7 @@ start_listeners(Listeners) ->
|
||||||
base_path => emqx_dashboard_swagger:base_path(),
|
base_path => emqx_dashboard_swagger:base_path(),
|
||||||
modules => minirest_api:find_api_modules(apps()),
|
modules => minirest_api:find_api_modules(apps()),
|
||||||
authorization => Authorization,
|
authorization => Authorization,
|
||||||
log => fun emqx_dashboard_audit:log/2,
|
log => audit_log_fun(),
|
||||||
security => [#{'basicAuth' => []}, #{'bearerAuth' => []}],
|
security => [#{'basicAuth' => []}, #{'bearerAuth' => []}],
|
||||||
swagger_global_spec => GlobalSpec,
|
swagger_global_spec => GlobalSpec,
|
||||||
dispatch => dispatch(),
|
dispatch => dispatch(),
|
||||||
|
@ -210,9 +210,17 @@ filter_false(K, V, S) -> [{K, V} | S].
|
||||||
listener_name(Protocol) ->
|
listener_name(Protocol) ->
|
||||||
list_to_atom(atom_to_list(Protocol) ++ ":dashboard").
|
list_to_atom(atom_to_list(Protocol) ++ ":dashboard").
|
||||||
|
|
||||||
|
audit_log_fun() ->
|
||||||
|
case emqx_release:edition() of
|
||||||
|
ee -> fun emqx_dashboard_audit:log/2;
|
||||||
|
ce -> undefined
|
||||||
|
end.
|
||||||
|
|
||||||
-if(?EMQX_RELEASE_EDITION =/= ee).
|
-if(?EMQX_RELEASE_EDITION =/= ee).
|
||||||
|
|
||||||
%% dialyzer complains about the `unauthorized_role' clause...
|
%% dialyzer complains about the `unauthorized_role' clause...
|
||||||
-dialyzer({no_match, [authorize/1, api_key_authorize/3]}).
|
-dialyzer({no_match, [authorize/1, api_key_authorize/3]}).
|
||||||
|
|
||||||
-endif.
|
-endif.
|
||||||
|
|
||||||
authorize(Req) ->
|
authorize(Req) ->
|
||||||
|
|
|
@ -37,10 +37,11 @@ log(#{code := Code, method := Method} = Meta, Req) ->
|
||||||
?AUDIT(level(Method, Code), log_meta(Meta, Req)).
|
?AUDIT(level(Method, Code), log_meta(Meta, Req)).
|
||||||
|
|
||||||
log_meta(Meta, Req) ->
|
log_meta(Meta, Req) ->
|
||||||
#{operation_id := OperationId} = Meta,
|
#{operation_id := OperationId, method := Method} = Meta,
|
||||||
case
|
case
|
||||||
lists:member(OperationId, ?HIGH_FREQUENCY_REQUESTS) andalso
|
Method =:= get orelse
|
||||||
ignore_high_frequency_request()
|
(lists:member(OperationId, ?HIGH_FREQUENCY_REQUESTS) andalso
|
||||||
|
ignore_high_frequency_request())
|
||||||
of
|
of
|
||||||
true ->
|
true ->
|
||||||
undefined;
|
undefined;
|
||||||
|
@ -53,7 +54,7 @@ log_meta(Meta, Req) ->
|
||||||
source_ip => source_ip(Req),
|
source_ip => source_ip(Req),
|
||||||
operation_type => operation_type(Meta),
|
operation_type => operation_type(Meta),
|
||||||
%% method for http filter api.
|
%% method for http filter api.
|
||||||
http_method => maps:get(method, Meta),
|
http_method => Method,
|
||||||
http_request => http_request(Meta),
|
http_request => http_request(Meta),
|
||||||
http_status_code => maps:get(code, Meta),
|
http_status_code => maps:get(code, Meta),
|
||||||
operation_result => operation_result(Meta),
|
operation_result => operation_result(Meta),
|
||||||
|
|
|
@ -47,10 +47,6 @@ post_boot() ->
|
||||||
ok = ensure_apps_started(),
|
ok = ensure_apps_started(),
|
||||||
ok = print_vsn(),
|
ok = print_vsn(),
|
||||||
ok = start_autocluster(),
|
ok = start_autocluster(),
|
||||||
?AUDIT(alert, #{
|
|
||||||
event => "emqx_start",
|
|
||||||
from => event
|
|
||||||
}),
|
|
||||||
ignore.
|
ignore.
|
||||||
|
|
||||||
-ifdef(TEST).
|
-ifdef(TEST).
|
||||||
|
|
|
@ -68,8 +68,11 @@ graceful() ->
|
||||||
%% @doc Shutdown the Erlang VM and wait indefinitely.
|
%% @doc Shutdown the Erlang VM and wait indefinitely.
|
||||||
graceful_wait() ->
|
graceful_wait() ->
|
||||||
?AUDIT(alert, #{
|
?AUDIT(alert, #{
|
||||||
event => "emqx_gracefully_stop",
|
cmd => emqx,
|
||||||
from => event
|
args => ["stop"],
|
||||||
|
version => emqx_release:version(),
|
||||||
|
from => cli,
|
||||||
|
duration_ms => element(1, erlang:statistics(wall_clock))
|
||||||
}),
|
}),
|
||||||
ok = graceful(),
|
ok = graceful(),
|
||||||
exit_loop().
|
exit_loop().
|
||||||
|
|
|
@ -17,13 +17,12 @@ filter_from.desc:
|
||||||
`rest_api`: API KEY request logs.
|
`rest_api`: API KEY request logs.
|
||||||
`cli`: The emqx command line logs.
|
`cli`: The emqx command line logs.
|
||||||
`erlang_console`: The emqx remote_console run function logs.
|
`erlang_console`: The emqx remote_console run function logs.
|
||||||
`event`: Logs related to events such as emqx_start, emqx_gracefully_stop, audit_enabled, and audit_disabled."""
|
|
||||||
|
|
||||||
filter_source.desc:
|
filter_source.desc:
|
||||||
""""Filter logs based on source, Possible values are:
|
""""Filter logs based on source, Possible values are:
|
||||||
The login username when logs are generated from the dashboard.
|
The login username when logs are generated from the dashboard.
|
||||||
The API Keys when logs are generated from the REST API.
|
The API Keys when logs are generated from the REST API.
|
||||||
empty string when logs are generated from CLI, Erlang console, or an event."""
|
empty string when logs are generated from CLI, Erlang console."""
|
||||||
|
|
||||||
filter_source_ip.desc:
|
filter_source_ip.desc:
|
||||||
"Filter logs based on source ip when logs are generated from dashboard and REST API."
|
"Filter logs based on source ip when logs are generated from dashboard and REST API."
|
||||||
|
|
|
@ -726,7 +726,9 @@ audit_handler_level.label:
|
||||||
"""Log Level"""
|
"""Log Level"""
|
||||||
|
|
||||||
audit_log_max_filter_limit.desc:
|
audit_log_max_filter_limit.desc:
|
||||||
"""Store the latest N log entries in a database for allow `/audit` HTTP API to filter and retrieval of log data."""
|
"""Store the latest N log entries in a database for allow `/audit` HTTP API to filter and retrieval of log data.
|
||||||
|
The interval for purging redundant log records is maintained within a range of 10~20 seconds.
|
||||||
|
"""
|
||||||
|
|
||||||
audit_log_max_filter_limit.label:
|
audit_log_max_filter_limit.label:
|
||||||
"""Max Filter Limit"""
|
"""Max Filter Limit"""
|
||||||
|
|
Loading…
Reference in New Issue