fix(audit): only support audit log on enterprise edition
Fixes https://emqx.atlassian.net/browse/EMQX-11039
This commit is contained in:
parent
ff7f37ccf5
commit
5d212e1086
|
@ -43,6 +43,9 @@
|
||||||
]).
|
]).
|
||||||
-export([conf_get/2, conf_get/3, keys/2, filter/1]).
|
-export([conf_get/2, conf_get/3, keys/2, filter/1]).
|
||||||
|
|
||||||
|
%% internal exports for `emqx_enterprise_schema' only.
|
||||||
|
-export([ensure_unicode_path/2, convert_rotation/2, log_handler_common_confs/2]).
|
||||||
|
|
||||||
%% Static apps which merge their configs into the merged emqx.conf
|
%% Static apps which merge their configs into the merged emqx.conf
|
||||||
%% The list can not be made a dynamic read at run-time as it is used
|
%% The list can not be made a dynamic read at run-time as it is used
|
||||||
%% by nodetool to generate app.<time>.config before EMQX is started
|
%% by nodetool to generate app.<time>.config before EMQX is started
|
||||||
|
@ -962,15 +965,6 @@ fields("log") ->
|
||||||
aliases => [file_handlers],
|
aliases => [file_handlers],
|
||||||
importance => ?IMPORTANCE_HIGH
|
importance => ?IMPORTANCE_HIGH
|
||||||
}
|
}
|
||||||
)},
|
|
||||||
{"audit",
|
|
||||||
sc(
|
|
||||||
?R_REF("log_audit_handler"),
|
|
||||||
#{
|
|
||||||
desc => ?DESC("log_audit_handler"),
|
|
||||||
importance => ?IMPORTANCE_HIGH,
|
|
||||||
default => #{<<"enable">> => true, <<"level">> => <<"info">>}
|
|
||||||
}
|
|
||||||
)}
|
)}
|
||||||
];
|
];
|
||||||
fields("console_handler") ->
|
fields("console_handler") ->
|
||||||
|
@ -1012,49 +1006,6 @@ fields("log_file_handler") ->
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
] ++ log_handler_common_confs(file, #{});
|
] ++ log_handler_common_confs(file, #{});
|
||||||
fields("log_audit_handler") ->
|
|
||||||
[
|
|
||||||
{"path",
|
|
||||||
sc(
|
|
||||||
file(),
|
|
||||||
#{
|
|
||||||
desc => ?DESC("audit_file_handler_path"),
|
|
||||||
default => <<"${EMQX_LOG_DIR}/audit.log">>,
|
|
||||||
importance => ?IMPORTANCE_HIGH,
|
|
||||||
converter => fun(Path, Opts) ->
|
|
||||||
emqx_schema:naive_env_interpolation(ensure_unicode_path(Path, Opts))
|
|
||||||
end
|
|
||||||
}
|
|
||||||
)},
|
|
||||||
{"rotation_count",
|
|
||||||
sc(
|
|
||||||
range(1, 128),
|
|
||||||
#{
|
|
||||||
default => 10,
|
|
||||||
converter => fun convert_rotation/2,
|
|
||||||
desc => ?DESC("log_rotation_count"),
|
|
||||||
importance => ?IMPORTANCE_MEDIUM
|
|
||||||
}
|
|
||||||
)},
|
|
||||||
{"rotation_size",
|
|
||||||
sc(
|
|
||||||
hoconsc:union([infinity, emqx_schema:bytesize()]),
|
|
||||||
#{
|
|
||||||
default => <<"50MB">>,
|
|
||||||
desc => ?DESC("log_file_handler_max_size"),
|
|
||||||
importance => ?IMPORTANCE_MEDIUM
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
] ++
|
|
||||||
%% Only support json
|
|
||||||
lists:keydelete(
|
|
||||||
"formatter",
|
|
||||||
1,
|
|
||||||
log_handler_common_confs(
|
|
||||||
file,
|
|
||||||
#{level => info, level_desc => "audit_handler_level"}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
fields("log_overload_kill") ->
|
fields("log_overload_kill") ->
|
||||||
[
|
[
|
||||||
{"enable",
|
{"enable",
|
||||||
|
@ -1145,8 +1096,6 @@ desc("console_handler") ->
|
||||||
?DESC("desc_console_handler");
|
?DESC("desc_console_handler");
|
||||||
desc("log_file_handler") ->
|
desc("log_file_handler") ->
|
||||||
?DESC("desc_log_file_handler");
|
?DESC("desc_log_file_handler");
|
||||||
desc("log_audit_handler") ->
|
|
||||||
?DESC("desc_audit_log_handler");
|
|
||||||
desc("log_rotation") ->
|
desc("log_rotation") ->
|
||||||
?DESC("desc_log_rotation");
|
?DESC("desc_log_rotation");
|
||||||
desc("log_overload_kill") ->
|
desc("log_overload_kill") ->
|
||||||
|
|
|
@ -78,16 +78,7 @@ t_log_conf(_Conf) ->
|
||||||
<<"time_offset">> => <<"system">>
|
<<"time_offset">> => <<"system">>
|
||||||
},
|
},
|
||||||
<<"file">> =>
|
<<"file">> =>
|
||||||
#{<<"default">> => FileExpect},
|
#{<<"default">> => FileExpect}
|
||||||
<<"audit">> =>
|
|
||||||
#{
|
|
||||||
<<"enable">> => true,
|
|
||||||
<<"level">> => <<"info">>,
|
|
||||||
<<"path">> => <<"log/audit.log">>,
|
|
||||||
<<"rotation_count">> => 10,
|
|
||||||
<<"rotation_size">> => <<"50MB">>,
|
|
||||||
<<"time_offset">> => <<"system">>
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
?assertEqual(ExpectLog1, emqx_conf:get_raw([<<"log">>])),
|
?assertEqual(ExpectLog1, emqx_conf:get_raw([<<"log">>])),
|
||||||
UpdateLog0 = emqx_utils_maps:deep_remove([<<"file">>, <<"default">>], ExpectLog1),
|
UpdateLog0 = emqx_utils_maps:deep_remove([<<"file">>, <<"default">>], ExpectLog1),
|
||||||
|
|
|
@ -181,23 +181,8 @@ validate_log(Conf) ->
|
||||||
}},
|
}},
|
||||||
FileHandler
|
FileHandler
|
||||||
),
|
),
|
||||||
AuditHandler = lists:keyfind(emqx_audit, 2, FileHandlers),
|
%% audit is an EE-only feature
|
||||||
%% default is enable and log level is info.
|
?assertNot(lists:keyfind(emqx_audit, 2, FileHandlers)),
|
||||||
?assertMatch(
|
|
||||||
{handler, emqx_audit, logger_disk_log_h, #{
|
|
||||||
config := #{
|
|
||||||
type := wrap,
|
|
||||||
file := "log/audit.log",
|
|
||||||
max_no_bytes := _,
|
|
||||||
max_no_files := _
|
|
||||||
},
|
|
||||||
filesync_repeat_interval := no_repeat,
|
|
||||||
filters := [{filter_audit, {_, stop}}],
|
|
||||||
formatter := _,
|
|
||||||
level := info
|
|
||||||
}},
|
|
||||||
AuditHandler
|
|
||||||
),
|
|
||||||
ConsoleHandler = lists:keyfind(logger_std_h, 3, Loggers),
|
ConsoleHandler = lists:keyfind(logger_std_h, 3, Loggers),
|
||||||
?assertEqual(
|
?assertEqual(
|
||||||
{handler, console, logger_std_h, #{
|
{handler, console, logger_std_h, #{
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
|
|
||||||
-behaviour(hocon_schema).
|
-behaviour(hocon_schema).
|
||||||
|
|
||||||
|
-include_lib("typerefl/include/types.hrl").
|
||||||
|
-include_lib("hocon/include/hoconsc.hrl").
|
||||||
|
|
||||||
-export([namespace/0, roots/0, fields/1, translations/0, translation/1, desc/1, validations/0]).
|
-export([namespace/0, roots/0, fields/1, translations/0, translation/1, desc/1, validations/0]).
|
||||||
|
|
||||||
-define(EE_SCHEMA_MODULES, [
|
-define(EE_SCHEMA_MODULES, [
|
||||||
|
@ -22,6 +25,53 @@ roots() ->
|
||||||
|
|
||||||
fields("node") ->
|
fields("node") ->
|
||||||
redefine_node(emqx_conf_schema:fields("node"));
|
redefine_node(emqx_conf_schema:fields("node"));
|
||||||
|
fields("log") ->
|
||||||
|
redefine_log(emqx_conf_schema:fields("log"));
|
||||||
|
fields("log_audit_handler") ->
|
||||||
|
[
|
||||||
|
{"path",
|
||||||
|
hoconsc:mk(
|
||||||
|
emqx_conf_schema:file(),
|
||||||
|
#{
|
||||||
|
desc => ?DESC(emqx_conf_schema, "audit_file_handler_path"),
|
||||||
|
default => <<"${EMQX_LOG_DIR}/audit.log">>,
|
||||||
|
importance => ?IMPORTANCE_HIGH,
|
||||||
|
converter => fun(Path, Opts) ->
|
||||||
|
emqx_schema:naive_env_interpolation(
|
||||||
|
emqx_conf_schema:ensure_unicode_path(Path, Opts)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
)},
|
||||||
|
{"rotation_count",
|
||||||
|
hoconsc:mk(
|
||||||
|
range(1, 128),
|
||||||
|
#{
|
||||||
|
default => 10,
|
||||||
|
converter => fun emqx_conf_schema:convert_rotation/2,
|
||||||
|
desc => ?DESC(emqx_conf_schema, "log_rotation_count"),
|
||||||
|
importance => ?IMPORTANCE_MEDIUM
|
||||||
|
}
|
||||||
|
)},
|
||||||
|
{"rotation_size",
|
||||||
|
hoconsc:mk(
|
||||||
|
hoconsc:union([infinity, emqx_schema:bytesize()]),
|
||||||
|
#{
|
||||||
|
default => <<"50MB">>,
|
||||||
|
desc => ?DESC(emqx_conf_schema, "log_file_handler_max_size"),
|
||||||
|
importance => ?IMPORTANCE_MEDIUM
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
] ++
|
||||||
|
%% Only support json
|
||||||
|
lists:keydelete(
|
||||||
|
"formatter",
|
||||||
|
1,
|
||||||
|
emqx_conf_schema:log_handler_common_confs(
|
||||||
|
file,
|
||||||
|
#{level => info, level_desc => "audit_handler_level"}
|
||||||
|
)
|
||||||
|
);
|
||||||
fields(Name) ->
|
fields(Name) ->
|
||||||
ee_delegate(fields, ?EE_SCHEMA_MODULES, Name).
|
ee_delegate(fields, ?EE_SCHEMA_MODULES, Name).
|
||||||
|
|
||||||
|
@ -31,6 +81,8 @@ translations() ->
|
||||||
translation(Name) ->
|
translation(Name) ->
|
||||||
emqx_conf_schema:translation(Name).
|
emqx_conf_schema:translation(Name).
|
||||||
|
|
||||||
|
desc("log_audit_handler") ->
|
||||||
|
?DESC(emqx_conf_schema, "desc_audit_log_handler");
|
||||||
desc(Name) ->
|
desc(Name) ->
|
||||||
ee_delegate(desc, ?EE_SCHEMA_MODULES, Name).
|
ee_delegate(desc, ?EE_SCHEMA_MODULES, Name).
|
||||||
|
|
||||||
|
@ -60,13 +112,20 @@ ee_delegate(Method, [], Name) ->
|
||||||
apply(emqx_conf_schema, Method, [Name]).
|
apply(emqx_conf_schema, Method, [Name]).
|
||||||
|
|
||||||
redefine_roots(Roots) ->
|
redefine_roots(Roots) ->
|
||||||
Overrides = [{"node", #{type => hoconsc:ref(?MODULE, "node")}}],
|
Overrides = [
|
||||||
|
{"node", #{type => hoconsc:ref(?MODULE, "node")}},
|
||||||
|
{"log", #{type => hoconsc:ref(?MODULE, "log")}}
|
||||||
|
],
|
||||||
override(Roots, Overrides).
|
override(Roots, Overrides).
|
||||||
|
|
||||||
redefine_node(Fields) ->
|
redefine_node(Fields) ->
|
||||||
Overrides = [],
|
Overrides = [],
|
||||||
override(Fields, Overrides).
|
override(Fields, Overrides).
|
||||||
|
|
||||||
|
redefine_log(Fields) ->
|
||||||
|
Overrides = [],
|
||||||
|
override(Fields, Overrides) ++ audit_log_conf().
|
||||||
|
|
||||||
override(Fields, []) ->
|
override(Fields, []) ->
|
||||||
Fields;
|
Fields;
|
||||||
override(Fields, [{Name, Override} | More]) ->
|
override(Fields, [{Name, Override} | More]) ->
|
||||||
|
@ -81,3 +140,19 @@ find_schema(Name, Fields) ->
|
||||||
|
|
||||||
replace_schema(Name, Schema, Fields) ->
|
replace_schema(Name, Schema, Fields) ->
|
||||||
lists:keyreplace(Name, 1, Fields, {Name, Schema}).
|
lists:keyreplace(Name, 1, Fields, {Name, Schema}).
|
||||||
|
|
||||||
|
audit_log_conf() ->
|
||||||
|
[
|
||||||
|
{"audit",
|
||||||
|
hoconsc:mk(
|
||||||
|
hoconsc:ref(?MODULE, "log_audit_handler"),
|
||||||
|
#{
|
||||||
|
%% note: we need to keep the descriptions associated with
|
||||||
|
%% `emqx_conf_schema' module hocon i18n file because that's what
|
||||||
|
%% `emqx_conf:gen_config_md' seems to expect.
|
||||||
|
desc => ?DESC(emqx_conf_schema, "log_audit_handler"),
|
||||||
|
importance => ?IMPORTANCE_HIGH,
|
||||||
|
default => #{<<"enable">> => true, <<"level">> => <<"info">>}
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
].
|
||||||
|
|
|
@ -13,6 +13,25 @@
|
||||||
all() ->
|
all() ->
|
||||||
emqx_common_test_helpers:all(?MODULE).
|
emqx_common_test_helpers:all(?MODULE).
|
||||||
|
|
||||||
|
init_per_testcase(t_audit_log_conf, Config) ->
|
||||||
|
Apps = emqx_cth_suite:start(
|
||||||
|
[
|
||||||
|
emqx_enterprise,
|
||||||
|
{emqx_conf, #{schema_mod => emqx_enterprise_schema}}
|
||||||
|
],
|
||||||
|
#{work_dir => emqx_cth_suite:work_dir(Config)}
|
||||||
|
),
|
||||||
|
[{apps, Apps} | Config];
|
||||||
|
init_per_testcase(_TestCase, Config) ->
|
||||||
|
Config.
|
||||||
|
|
||||||
|
end_per_testcase(t_audit_log_conf, Config) ->
|
||||||
|
Apps = ?config(apps, Config),
|
||||||
|
ok = emqx_cth_suite:stop(Apps),
|
||||||
|
ok;
|
||||||
|
end_per_testcase(_TestCase, _Config) ->
|
||||||
|
ok.
|
||||||
|
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
%% Tests
|
%% Tests
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
|
@ -50,3 +69,36 @@ t_translations(_Config) ->
|
||||||
emqx_conf_schema:translation(Root),
|
emqx_conf_schema:translation(Root),
|
||||||
emqx_enterprise_schema:translation(Root)
|
emqx_enterprise_schema:translation(Root)
|
||||||
).
|
).
|
||||||
|
|
||||||
|
t_audit_log_conf(_Config) ->
|
||||||
|
FileExpect = #{
|
||||||
|
<<"enable">> => true,
|
||||||
|
<<"formatter">> => <<"text">>,
|
||||||
|
<<"level">> => <<"warning">>,
|
||||||
|
<<"rotation_count">> => 10,
|
||||||
|
<<"rotation_size">> => <<"50MB">>,
|
||||||
|
<<"time_offset">> => <<"system">>,
|
||||||
|
<<"path">> => <<"log/emqx.log">>
|
||||||
|
},
|
||||||
|
ExpectLog1 = #{
|
||||||
|
<<"console">> =>
|
||||||
|
#{
|
||||||
|
<<"enable">> => false,
|
||||||
|
<<"formatter">> => <<"text">>,
|
||||||
|
<<"level">> => <<"warning">>,
|
||||||
|
<<"time_offset">> => <<"system">>
|
||||||
|
},
|
||||||
|
<<"file">> =>
|
||||||
|
#{<<"default">> => FileExpect},
|
||||||
|
<<"audit">> =>
|
||||||
|
#{
|
||||||
|
<<"enable">> => true,
|
||||||
|
<<"level">> => <<"info">>,
|
||||||
|
<<"path">> => <<"log/audit.log">>,
|
||||||
|
<<"rotation_count">> => 10,
|
||||||
|
<<"rotation_size">> => <<"50MB">>,
|
||||||
|
<<"time_offset">> => <<"system">>
|
||||||
|
}
|
||||||
|
},
|
||||||
|
?assertEqual(ExpectLog1, emqx_conf:get_raw([<<"log">>])),
|
||||||
|
ok.
|
||||||
|
|
|
@ -16,3 +16,38 @@ doc_gen_test() ->
|
||||||
ok = emqx_conf:dump_schema(Dir, emqx_enterprise_schema)
|
ok = emqx_conf:dump_schema(Dir, emqx_enterprise_schema)
|
||||||
end
|
end
|
||||||
}.
|
}.
|
||||||
|
|
||||||
|
audit_log_test() ->
|
||||||
|
ensure_acl_conf(),
|
||||||
|
Conf0 = <<"node {cookie = aaa, data_dir = \"/tmp\"}">>,
|
||||||
|
{ok, ConfMap0} = hocon:binary(Conf0, #{format => richmap}),
|
||||||
|
ConfList = hocon_tconf:generate(emqx_enterprise_schema, ConfMap0),
|
||||||
|
Kernel = proplists:get_value(kernel, ConfList),
|
||||||
|
Loggers = proplists:get_value(logger, Kernel),
|
||||||
|
FileHandlers = lists:filter(fun(L) -> element(3, L) =:= logger_disk_log_h end, Loggers),
|
||||||
|
AuditHandler = lists:keyfind(emqx_audit, 2, FileHandlers),
|
||||||
|
%% default is enable and log level is info.
|
||||||
|
?assertMatch(
|
||||||
|
{handler, emqx_audit, logger_disk_log_h, #{
|
||||||
|
config := #{
|
||||||
|
type := wrap,
|
||||||
|
file := "log/audit.log",
|
||||||
|
max_no_bytes := _,
|
||||||
|
max_no_files := _
|
||||||
|
},
|
||||||
|
filesync_repeat_interval := no_repeat,
|
||||||
|
filters := [{filter_audit, {_, stop}}],
|
||||||
|
formatter := _,
|
||||||
|
level := info
|
||||||
|
}},
|
||||||
|
AuditHandler
|
||||||
|
),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
ensure_acl_conf() ->
|
||||||
|
File = emqx_schema:naive_env_interpolation(<<"${EMQX_ETC_DIR}/acl.conf">>),
|
||||||
|
ok = filelib:ensure_dir(filename:dirname(File)),
|
||||||
|
case filelib:is_regular(File) of
|
||||||
|
true -> ok;
|
||||||
|
false -> file:write_file(File, <<"">>)
|
||||||
|
end.
|
||||||
|
|
|
@ -841,7 +841,4 @@ Defaults to 100000."""
|
||||||
node_channel_cleanup_batch_size.label:
|
node_channel_cleanup_batch_size.label:
|
||||||
"""Node Channel Cleanup Batch Size"""
|
"""Node Channel Cleanup Batch Size"""
|
||||||
|
|
||||||
prevent_overlapping_partitions.desc:
|
|
||||||
"""https://www.erlang.org/doc/man/global.html#description"""
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue