diff options
author | Jean-Sébastien Pédron <jean-sebastien.pedron@dumbbell.fr> | 2021-03-25 17:08:09 +0100 |
---|---|---|
committer | Jean-Sébastien Pédron <jean-sebastien.pedron@dumbbell.fr> | 2021-03-26 12:55:52 +0100 |
commit | 5cac1a6dcb2a23b4638149df4bbb960bfe6bbc53 (patch) | |
tree | a9621341dbe4bf7d87c8a17ebbd1588f8bdf13b4 | |
parent | 63e3a128661f2bd6dc30650a0c58c9a6751a8de1 (diff) | |
download | rabbitmq-server-git-use-erlang-systemd-dep.tar.gz |
-rw-r--r-- | deps/rabbit/Makefile | 3 | ||||
-rw-r--r-- | deps/rabbit/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_early_logging.erl | 82 | ||||
-rw-r--r-- | deps/rabbit/priv/schema/rabbit.schema | 15 | ||||
-rw-r--r-- | deps/rabbit/src/rabbit_prelaunch_logging.erl | 158 |
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) -> |