summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Sébastien Pédron <jean-sebastien.pedron@dumbbell.fr>2021-03-25 17:08:09 +0100
committerJean-Sébastien Pédron <jean-sebastien.pedron@dumbbell.fr>2021-03-26 12:55:52 +0100
commit5cac1a6dcb2a23b4638149df4bbb960bfe6bbc53 (patch)
treea9621341dbe4bf7d87c8a17ebbd1588f8bdf13b4
parent63e3a128661f2bd6dc30650a0c58c9a6751a8de1 (diff)
downloadrabbitmq-server-git-use-erlang-systemd-dep.tar.gz
-rw-r--r--deps/rabbit/Makefile3
-rw-r--r--deps/rabbit/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_early_logging.erl82
-rw-r--r--deps/rabbit/priv/schema/rabbit.schema15
-rw-r--r--deps/rabbit/src/rabbit_prelaunch_logging.erl158
4 files changed, 225 insertions, 33 deletions
diff --git a/deps/rabbit/Makefile b/deps/rabbit/Makefile
index 259a7c9123..5a46f256ec 100644
--- a/deps/rabbit/Makefile
+++ b/deps/rabbit/Makefile
@@ -133,7 +133,7 @@ APPS_DIR := $(CURDIR)/apps
LOCAL_DEPS = sasl rabbitmq_prelaunch os_mon inets compiler public_key crypto ssl syntax_tools xmerl
BUILD_DEPS = rabbitmq_cli
-DEPS = cuttlefish ranch rabbit_common ra sysmon_handler stdout_formatter recon observer_cli osiris amqp10_common syslog
+DEPS = cuttlefish ranch rabbit_common ra sysmon_handler stdout_formatter recon observer_cli osiris amqp10_common syslog systemd
TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers amqp_client meck proper
PLT_APPS += mnesia
@@ -141,6 +141,7 @@ PLT_APPS += mnesia
dep_cuttlefish = git https://github.com/Kyorai/cuttlefish master
dep_syslog = git https://github.com/schlagert/syslog 4.0.0
dep_osiris = git https://github.com/rabbitmq/osiris master
+dep_systemd = hex 0.6.0
define usage_xml_to_erl
$(subst __,_,$(patsubst $(DOCS_DIR)/rabbitmq%.1.xml, src/rabbit_%_usage.erl, $(subst -,_,$(1))))
diff --git a/deps/rabbit/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_early_logging.erl b/deps/rabbit/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_early_logging.erl
index 89c5c6c3d5..1be0eff801 100644
--- a/deps/rabbit/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_early_logging.erl
+++ b/deps/rabbit/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_early_logging.erl
@@ -15,11 +15,13 @@
default_formatter/1,
default_console_formatter/1,
default_file_formatter/1,
+ default_journald_formatter/1,
default_syslog_formatter/1,
enable_quick_dbg/1,
use_colored_logging/0,
use_colored_logging/1,
- translate_formatter_conf/2]).
+ translate_formatter_conf/2,
+ translate_journald_fields_conf/2]).
-export([filter_log_event/2]).
-ifdef(TEST).
@@ -121,6 +123,10 @@ default_console_formatter(Context) ->
default_file_formatter(Context) ->
default_formatter(Context#{output_supports_colors => false}).
+default_journald_formatter(_Context) ->
+ {rabbit_logger_text_fmt, #{prefix_format => [],
+ use_colors => false}}.
+
default_syslog_formatter(Context) ->
{Module, Config} = default_file_formatter(Context),
case Module of
@@ -155,8 +161,8 @@ enable_quick_dbg(#{dbg_output := Output, dbg_mods := Mods}) ->
{rabbit_logger_text_fmt, formatter_plaintext_conf()} |
{rabbit_logger_json_fmt, formatter_json_conf()}.
%% @doc
-%% Called from the Cuttlefish schema to derive the actual configuration from
-%% several Cuttlefish variables.
+%% Called from the Cuttlefish schema to derive the actual formatter
+%% configuration from several Cuttlefish variables.
translate_formatter_conf(Var, Conf) when is_list(Var) ->
try
@@ -401,7 +407,7 @@ translate_json_formatter_conf(Var, Conf, GenericConfig) ->
-spec parse_json_field_mapping(string()) -> json_field_map().
%% @doc
-%% Parses the field_map pattern.
+%% Parses the JSON formatter field_map pattern.
%%
%% The pattern is of the form: `time:ts level msg *:-'.
%%
@@ -493,5 +499,73 @@ parse_json_verbosity_mapping([], #{'$REST' := Default} = Mapping) ->
parse_json_verbosity_mapping([], Mapping) ->
Mapping.
+-spec translate_journald_fields_conf(string(), cuttlefish_conf:conf()) ->
+ proplists:proplist().
+%% @doc
+%% Called from the Cuttlefish schema to create the actual journald handler
+%% configuration.
+
+translate_journald_fields_conf(Var, Conf) when is_list(Var) ->
+ try
+ RawFieldMapping = cuttlefish:conf_get(Var, Conf),
+ parse_journald_field_mapping(RawFieldMapping)
+ catch
+ Class:Reason:Stacktrace ->
+ ?LOG_ERROR(
+ rabbit_prelaunch_errors:format_exception(
+ Class, Reason, Stacktrace),
+ #{domain => ?RMQLOG_DOMAIN_PRELAUNCH}),
+ throw({configuration_translation_failure, Reason})
+ end.
+
+-spec parse_journald_field_mapping(string()) ->
+ [atom() | {atom(), atom()}].
+%% @doc
+%% Parses the journald fields pattern.
+%%
+%% The pattern is of the form: `SYSLOG_IDENTIFIER="rabbitmq-server" pid
+%% CODE_FILE=file'.
+%%
+%% `SYSLOG_IDENTIFIER="rabbitmq"' means the `SYSLOG_IDENTIFIER' field should
+%% be set to the string `rabbitmq-server'.
+%%
+%% `pid' means that field should be kept as-is.
+%%
+%% `CODE_FILE=file' means the `CODE_FILE' field should be set to the value of
+%% the `pid' field.
+
+parse_journald_field_mapping(RawMapping) ->
+ parse_journald_field_mapping(string:split(RawMapping, " ", all), []).
+
+parse_journald_field_mapping([Entry | Rest], Mapping) ->
+ Mapping1 = case string:split(Entry, "=", leading) of
+ [[$_ | _], _] ->
+ throw({bad_journald_mapping,
+ leading_underscore_forbidden,
+ Entry});
+ [Name, Value] ->
+ case re:run(Name, "^[A-Z0-9_]+$", [{capture, none}]) of
+ match ->
+ ReOpts = [{capture, all_but_first, list}],
+ case re:run(Value, "^\"(.+)\"$", ReOpts) of
+ {match, [Data]} ->
+ [{Name, Data} | Mapping];
+ nomatch ->
+ Field = list_to_atom(Value),
+ [{Name, Field} | Mapping]
+ end;
+ nomatch ->
+ throw({bad_journald_mapping,
+ name_with_invalid_characters,
+ Entry})
+ end;
+ [FieldS] ->
+ Field = list_to_atom(FieldS),
+ [Field | Mapping]
+ end,
+ parse_journald_field_mapping(Rest, Mapping1);
+parse_journald_field_mapping([], Mapping) ->
+ lists:reverse(Mapping).
+
levels() ->
[debug, info, notice, warning, error, critical, alert, emergency].
diff --git a/deps/rabbit/priv/schema/rabbit.schema b/deps/rabbit/priv/schema/rabbit.schema
index a32157b370..d7e5bb3c69 100644
--- a/deps/rabbit/priv/schema/rabbit.schema
+++ b/deps/rabbit/priv/schema/rabbit.schema
@@ -1304,6 +1304,21 @@ end}.
rabbit_prelaunch_early_logging:translate_formatter_conf("log.exchange.formatter", Conf)
end}.
+{mapping, "log.journald", "rabbit.log.journald.enabled", [
+ {datatype, {enum, [true, false]}}
+]}.
+{mapping, "log.journald.level", "rabbit.log.journald.level", [
+ {datatype, {enum, [debug, info, notice, warning, error, critical, alert, emergency, none]}}
+]}.
+{mapping, "log.journald.fields", "rabbit.log.journald.fields", [
+ {default, "SYSLOG_IDENTIFIER=\"rabbitmq-server\" syslog_timestamp syslog_pid priority ERL_PID=pid CODE_FILE=file CODE_LINE=line CODE_MFA=mfa"},
+ {datatype, string}
+]}.
+{translation, "rabbit.log.journald.fields",
+ fun(Conf) ->
+ rabbit_prelaunch_early_logging:translate_journald_fields_conf("log.journald.fields", Conf)
+ end}.
+
{mapping, "log.syslog", "rabbit.log.syslog.enabled", [
{datatype, {enum, [true, false]}}
]}.
diff --git a/deps/rabbit/src/rabbit_prelaunch_logging.erl b/deps/rabbit/src/rabbit_prelaunch_logging.erl
index 8195bfed4b..0dae47adde 100644
--- a/deps/rabbit/src/rabbit_prelaunch_logging.erl
+++ b/deps/rabbit/src/rabbit_prelaunch_logging.erl
@@ -71,6 +71,12 @@
%% {count, RotationCount},
%% ]},
%%
+%% {journald, [
+%% {level, Level},
+%% {enabled, boolean()},
+%% {fields, proplists:proplist()}
+%% ]}
+%%
%% {syslog, [
%% {level, Level},
%% {enabled, boolean()}
@@ -115,6 +121,8 @@
%%
%% If the output is a file, the location is the absolute filename.
%%
+%% If the output is journald, the location is `"<journald>"'.
+%%
%% If the output is syslog, the location is the string `"syslog:"' with the
%% syslog server hostname appended.
@@ -147,6 +155,12 @@
%% File properties are the parameters in the configuration file for a
%% file-based handler.
+-type journald_props() :: [{level, logger:level()} |
+ {enabled, boolean()} |
+ {fields, proplists:proplist()}].
+%% journald properties are the parameters in the configuration file for a
+%% journald-based handler.
+
-type syslog_props() :: [{level, logger:level()} |
{enabled, boolean()} |
{formatter, {atom(), term()}}].
@@ -156,6 +170,7 @@
-type main_log_env() :: [{console, console_props()} |
{exchange, exchange_props()} |
{file, file_props()} |
+ {journald, journald_props()} |
{syslog, syslog_props()}].
%% The main log environment is the parameters in the configuration file for
%% the main log handler (i.e. where all messages go by default).
@@ -309,14 +324,16 @@ set_log_level(Level) ->
%% For console-based handlers, a string literal is returned; either
%% `"<stdout>"' or `"<stderr>"'.
%%
+%% For exchange-based handlers, a string of the form `"exchange:Exchange"' is
+%% returned, where `Exchange' is the name of the exchange.
+%%
+%% For journald-based handlers, a string literal is returned; `"<journald>"'.
+%%
%% For syslog-based handlers, a string of the form `"syslog:Hostname"' is
%% returned, where `Hostname' is either the hostname of the remote syslog
%% server, or an empty string if none were configured (which means log to
%% localhost).
%%
-%% For exchange-based handlers, a string of the form `"exchange:Exchange"' is
-%% returned, where `Exchange' is the name of the exchange.
-%%
%% @returns the list of output locations.
%%
%% @see log_location()
@@ -344,6 +361,10 @@ log_locations([#{module := Mod,
when ?IS_STD_H_COMPAT(Mod) ->
Locations1 = add_once(Locations, "<stderr>"),
log_locations(Rest, Locations1);
+log_locations([#{module := systemd_journal_h} | Rest],
+ Locations) ->
+ Locations1 = add_once(Locations, "<journald>"),
+ log_locations(Rest, Locations1);
log_locations([#{module := syslog_logger_h} | Rest],
Locations) ->
Host = application:get_env(syslog, dest_host, ""),
@@ -538,24 +559,29 @@ compute_implicitly_enabled_output(Props) ->
console, Props),
{ExchangeEnabled, Props2} = compute_implicitly_enabled_output(
exchange, Props1),
- {SyslogEnabled, Props3} = compute_implicitly_enabled_output(
- syslog, Props2),
+ {JournaldEnabled, Props3} = compute_implicitly_enabled_output(
+ journald, Props2),
+ {SyslogEnabled, Props4} = compute_implicitly_enabled_output(
+ syslog, Props3),
FileDisabledByDefault =
- ConsoleEnabled orelse ExchangeEnabled orelse SyslogEnabled,
+ ConsoleEnabled orelse
+ ExchangeEnabled orelse
+ JournaldEnabled orelse
+ SyslogEnabled,
- FileProps = proplists:get_value(file, Props3, []),
+ FileProps = proplists:get_value(file, Props4, []),
case is_output_explicitely_enabled(FileProps) of
true ->
- Props3;
+ Props4;
false ->
case FileDisabledByDefault of
true ->
FileProps1 = lists:keystore(
file, 1, FileProps, {file, false}),
lists:keystore(
- file, 1, Props3, {file, FileProps1});
+ file, 1, Props4, {file, FileProps1});
false ->
- Props3
+ Props4
end
end.
@@ -598,32 +624,40 @@ normalize_main_log_config1([], LogConfig) ->
[logger:handler_config()];
(file, file_props(), [logger:handler_config()]) ->
[logger:handler_config()];
+(journald, journald_props(), [logger:handler_config()]) ->
+ [logger:handler_config()];
(syslog, syslog_props(), [logger:handler_config()]) ->
[logger:handler_config()].
+normalize_main_output(console, Props, Outputs) ->
+ normalize_main_console_output(
+ Props,
+ #{module => rabbit_logger_std_h,
+ config => #{type => standard_io}},
+ Outputs);
+normalize_main_output(exchange, Props, Outputs) ->
+ normalize_main_exchange_output(
+ Props,
+ #{module => rabbit_logger_exchange_h,
+ config => #{}},
+ Outputs);
normalize_main_output(file, Props, Outputs) ->
normalize_main_file_output(
Props,
#{module => rabbit_logger_std_h,
config => #{type => file}},
Outputs);
-normalize_main_output(console, Props, Outputs) ->
- normalize_main_console_output(
+normalize_main_output(journald, Props, Outputs) ->
+ normalize_main_journald_output(
Props,
- #{module => rabbit_logger_std_h,
- config => #{type => standard_io}},
+ #{module => systemd_journal_h,
+ config => #{}},
Outputs);
normalize_main_output(syslog, Props, Outputs) ->
normalize_main_syslog_output(
Props,
#{module => syslog_logger_h,
config => #{}},
- Outputs);
-normalize_main_output(exchange, Props, Outputs) ->
- normalize_main_exchange_output(
- Props,
- #{module => rabbit_logger_exchange_h,
- config => #{}},
Outputs).
-spec normalize_main_file_output(file_props(), logger:handler_config(),
@@ -789,6 +823,53 @@ remove_main_exchange_output(
(_) -> true
end, Outputs).
+-spec normalize_main_journald_output(journald_props(), logger:handler_config(),
+ [logger:handler_config()]) ->
+ [logger:handler_config()].
+
+normalize_main_journald_output(Props, Output, Outputs) ->
+ Enabled = proplists:get_value(enabled, Props),
+ case Enabled of
+ true -> normalize_main_journald_output1(Props, Output, Outputs);
+ false -> remove_main_journald_output(Output, Outputs)
+ end.
+
+normalize_main_journald_output1(
+ [{enabled, true} | Rest],
+ Output, Outputs) ->
+ normalize_main_journald_output1(Rest, Output, Outputs);
+normalize_main_journald_output1(
+ [{level, Level} | Rest],
+ Output, Outputs) ->
+ Output1 = Output#{level => Level},
+ normalize_main_journald_output1(Rest, Output1, Outputs);
+normalize_main_journald_output1(
+ [{fields, FieldMapping} | Rest],
+ #{config := Config} = Output, Outputs) ->
+ Config1 = Config#{fields => FieldMapping},
+ Output1 = Output#{config => Config1},
+ normalize_main_journald_output1(Rest, Output1, Outputs);
+normalize_main_journald_output1(
+ [{formatter, undefined} | Rest],
+ Output, Outputs) ->
+ normalize_main_journald_output1(Rest, Output, Outputs);
+normalize_main_journald_output1(
+ [{formatter, Formatter} | Rest],
+ Output, Outputs) ->
+ Output1 = Output#{formatter => Formatter},
+ normalize_main_journald_output1(Rest, Output1, Outputs);
+normalize_main_journald_output1([], Output, Outputs) ->
+ [Output | Outputs].
+
+remove_main_journald_output(
+ #{module := systemd_journal_h},
+ Outputs) ->
+ lists:filter(
+ fun
+ (#{module := systemd_journal_h}) -> false;
+ (_) -> true
+ end, Outputs).
+
-spec normalize_main_syslog_output(
syslog_props(), logger:handler_config(),
[logger:handler_config()]) ->
@@ -939,6 +1020,9 @@ log_file_var_to_output("-stderr") ->
log_file_var_to_output("exchange:" ++ _) ->
#{module => rabbit_logger_exchange_h,
config => #{}};
+log_file_var_to_output("journald:" ++ _) ->
+ #{module => systemd_journal_h,
+ config => #{}};
log_file_var_to_output("syslog:" ++ _) ->
#{module => syslog_logger_h,
config => #{}};
@@ -1067,6 +1151,8 @@ configure_formatters1(#{outputs := Outputs} = Config, Context) ->
rabbit_prelaunch_early_logging:default_console_formatter(Context),
FileFormatter =
rabbit_prelaunch_early_logging:default_file_formatter(Context),
+ JournaldFormatter =
+ rabbit_prelaunch_early_logging:default_journald_formatter(Context),
SyslogFormatter =
rabbit_prelaunch_early_logging:default_syslog_formatter(Context),
Outputs1 = lists:map(
@@ -1079,6 +1165,11 @@ configure_formatters1(#{outputs := Outputs} = Config, Context) ->
true -> Output;
false -> Output#{formatter => ConsFormatter}
end;
+ (#{module := systemd_journal_h} = Output) ->
+ case maps:is_key(formatter, Output) of
+ true -> Output;
+ false -> Output#{formatter => JournaldFormatter}
+ end;
(#{module := syslog_logger_h} = Output) ->
case maps:is_key(formatter, Output) of
true -> Output;
@@ -1187,11 +1278,14 @@ create_handler_key(
when ?IS_STD_H_COMPAT(Mod) ->
{console, standard_error};
create_handler_key(
- #{module := syslog_logger_h}) ->
- syslog;
-create_handler_key(
#{module := rabbit_logger_exchange_h}) ->
- exchange.
+ exchange;
+create_handler_key(
+ #{module := systemd_journal_h}) ->
+ journald;
+create_handler_key(
+ #{module := syslog_logger_h}) ->
+ syslog.
-spec create_handler_conf(
logger:handler_config(), global | category_name(),
@@ -1375,19 +1469,27 @@ assign_handler_ids(
Handler1 = Handler#{id => Id},
assign_handler_ids(Rest, State, [Handler1 | Result]);
assign_handler_ids(
- [#{module := syslog_logger_h} = Handler
+ [#{module := rabbit_logger_exchange_h} = Handler
| Rest],
State,
Result) ->
- Id = format_id("syslog", [], State),
+ Id = format_id("exchange", [], State),
Handler1 = Handler#{id => Id},
assign_handler_ids(Rest, State, [Handler1 | Result]);
assign_handler_ids(
- [#{module := rabbit_logger_exchange_h} = Handler
+ [#{module := systemd_journal_h} = Handler
| Rest],
State,
Result) ->
- Id = format_id("exchange", [], State),
+ Id = format_id("journald", [], State),
+ Handler1 = Handler#{id => Id},
+ assign_handler_ids(Rest, State, [Handler1 | Result]);
+assign_handler_ids(
+ [#{module := syslog_logger_h} = Handler
+ | Rest],
+ State,
+ Result) ->
+ Id = format_id("syslog", [], State),
Handler1 = Handler#{id => Id},
assign_handler_ids(Rest, State, [Handler1 | Result]);
assign_handler_ids([], _, Result) ->