diff options
| -rw-r--r-- | Makefile | 4 | ||||
| -rw-r--r-- | priv/schema/rabbit.schema | 161 | ||||
| -rw-r--r-- | src/rabbit_lager.erl | 38 | ||||
| -rw-r--r-- | test/config_schema_SUITE_data/rabbit.snippets | 51 | ||||
| -rw-r--r-- | test/unit_log_config_SUITE.erl | 20 |
5 files changed, 252 insertions, 22 deletions
@@ -133,9 +133,11 @@ endef LOCAL_DEPS = sasl mnesia os_mon inets BUILD_DEPS = rabbitmq_cli -DEPS = ranch lager rabbit_common +DEPS = ranch syslog lager rabbit_common TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers amqp_client meck proper +dep_syslog = git https://github.com/schlagert/syslog 3.4.2 + define usage_xml_to_erl $(subst __,_,$(patsubst $(DOCS_DIR)/rabbitmq%.1.xml, src/rabbit_%_usage.erl, $(subst -,_,$(1)))) endef diff --git a/priv/schema/rabbit.schema b/priv/schema/rabbit.schema index 181e20447e..862537bf61 100644 --- a/priv/schema/rabbit.schema +++ b/priv/schema/rabbit.schema @@ -1070,13 +1070,168 @@ end}. {mapping, "log.syslog.level", "rabbit.log.syslog.level", [ {datatype, {enum, [debug, info, notice, warning, error, critical, alert, emergency, none]}} ]}. -{mapping, "log.syslog.identity", "rabbit.log.syslog.identity", [ + +{mapping, "log.syslog.identity", "syslog.app_name", [ {datatype, string} ]}. -{mapping, "log.syslog.facility", "rabbit.log.syslog.facility", [ - {datatype, atom} + +{mapping, "log.syslog.facility", "syslog.facility", [ + {datatype, {enum, [kern, kernel, user, mail, daemon, auth, syslog, lpr, + news, uucp, cron, authpriv, ftp, ntp, audit, alert, + clock, local0, local1, local2, local3, local4, + local5, local6, local7]}} +]}. + +{mapping, "log.syslog.multiline_mode", "syslog.multiline_mode", [ + {datatype, {enum, [true, false]}} +]}. + +{mapping, "log.syslog.ip", "syslog.dest_host", [ + {datatype, string}, + {validators, ["is_ip"]} ]}. +{mapping, "log.syslog.port", "syslog.dest_port", [ + {datatype, integer} +]}. + +{mapping, "log.syslog.transport", "syslog.protocol", [ + {datatype, {enum, [udp, tcp, tls, ssl]}} +]}. +{mapping, "log.syslog.protocol", "syslog.protocol", [ + {datatype, {enum, [rfc3164, rfc5424]}} +]}. +{mapping, "log.syslog.ssl_options.verify", "syslog.protocol", [ + {datatype, {enum, [verify_peer, verify_none]}}]}. + +{mapping, "log.syslog.ssl_options.fail_if_no_peer_cert", "syslog.protocol", [ + {datatype, {enum, [true, false]}}]}. + +{mapping, "log.syslog.ssl_options.cacertfile", "syslog.protocol", + [{datatype, string}, {validators, ["file_accessible"]}]}. + +{mapping, "log.syslog.ssl_options.certfile", "syslog.protocol", + [{datatype, string}, {validators, ["file_accessible"]}]}. + +{mapping, "log.syslog.ssl_options.cacerts.$name", "syslog.protocol", + [{datatype, string}]}. + +{mapping, "log.syslog.ssl_options.cert", "syslog.protocol", + [{datatype, string}]}. + +{mapping, "log.syslog.ssl_options.client_renegotiation", "syslog.protocol", + [{datatype, {enum, [true, false]}}]}. + +{mapping, "log.syslog.ssl_options.crl_check", "syslog.protocol", + [{datatype, [{enum, [true, false, peer, best_effort]}]}]}. + +{mapping, "log.syslog.ssl_options.depth", "syslog.protocol", + [{datatype, integer}, {validators, ["byte"]}]}. + +{mapping, "log.syslog.ssl_options.dh", "syslog.protocol", + [{datatype, string}]}. + +{mapping, "log.syslog.ssl_options.dhfile", "syslog.protocol", + [{datatype, string}, {validators, ["file_accessible"]}]}. + +{mapping, "log.syslog.ssl_options.honor_cipher_order", "syslog.protocol", + [{datatype, {enum, [true, false]}}]}. + +{mapping, "log.syslog.ssl_options.honor_ecc_order", "syslog.protocol", + [{datatype, {enum, [true, false]}}]}. + +{mapping, "log.syslog.ssl_options.key.RSAPrivateKey", "syslog.protocol", + [{datatype, string}]}. + +{mapping, "log.syslog.ssl_options.key.DSAPrivateKey", "syslog.protocol", + [{datatype, string}]}. + +{mapping, "log.syslog.ssl_options.key.PrivateKeyInfo", "syslog.protocol", + [{datatype, string}]}. + +{mapping, "log.syslog.ssl_options.keyfile", "syslog.protocol", + [{datatype, string}, {validators, ["file_accessible"]}]}. + +{mapping, "log.syslog.ssl_options.log_alert", "syslog.protocol", + [{datatype, {enum, [true, false]}}]}. + +{mapping, "log.syslog.ssl_options.password", "syslog.protocol", + [{datatype, string}]}. + +{mapping, "log.syslog.ssl_options.psk_identity", "syslog.protocol", + [{datatype, string}]}. + +{mapping, "log.syslog.ssl_options.reuse_sessions", "syslog.protocol", + [{datatype, {enum, [true, false]}}]}. + +{mapping, "log.syslog.ssl_options.secure_renegotiate", "syslog.protocol", + [{datatype, {enum, [true, false]}}]}. + +{mapping, "log.syslog.ssl_options.versions.$version", "syslog.protocol", + [{datatype, atom}]}. + +{translation, "syslog.protocol", +fun(Conf) -> + ParseSslOptions = fun() -> + RawSettings = [ + {verify, cuttlefish:conf_get("log.syslog.ssl_options.verify", Conf, undefined)}, + {fail_if_no_peer_cert, cuttlefish:conf_get("log.syslog.ssl_options.fail_if_no_peer_cert", Conf, undefined)}, + {cacertfile, cuttlefish:conf_get("log.syslog.ssl_options.cacertfile", Conf, undefined)}, + {certfile, cuttlefish:conf_get("log.syslog.ssl_options.certfile", Conf, undefined)}, + {cert, cuttlefish:conf_get("log.syslog.ssl_options.cert", Conf, undefined)}, + {client_renegotiation, cuttlefish:conf_get("log.syslog.ssl_options.client_renegotiation", Conf, undefined)}, + {crl_check, cuttlefish:conf_get("log.syslog.ssl_options.crl_check", Conf, undefined)}, + {depth, cuttlefish:conf_get("log.syslog.ssl_options.depth", Conf, undefined)}, + {dh, cuttlefish:conf_get("log.syslog.ssl_options.dh", Conf, undefined)}, + {dhfile, cuttlefish:conf_get("log.syslog.ssl_options.dhfile", Conf, undefined)}, + {honor_cipher_order, cuttlefish:conf_get("log.syslog.ssl_options.honor_cipher_order", Conf, undefined)}, + {honor_ecc_order, cuttlefish:conf_get("log.syslog.ssl_options.honor_ecc_order", Conf, undefined)}, + + {keyfile, cuttlefish:conf_get("log.syslog.ssl_options.keyfile", Conf, undefined)}, + {log_alert, cuttlefish:conf_get("log.syslog.ssl_options.log_alert", Conf, undefined)}, + {password, cuttlefish:conf_get("log.syslog.ssl_options.password", Conf, undefined)}, + {psk_identity, cuttlefish:conf_get("log.syslog.ssl_options.psk_identity", Conf, undefined)}, + {reuse_sessions, cuttlefish:conf_get("log.syslog.ssl_options.reuse_sessions", Conf, undefined)}, + {secure_renegotiate, cuttlefish:conf_get("log.syslog.ssl_options.secure_renegotiate", Conf, undefined)} + ], + DefinedSettings = [{K, V} || {K, V} <- RawSettings, V =/= undefined], + + lists:map( + fun({K, Val}) when K == dh; K == cert -> {K, list_to_binary(Val)}; + ({K, Val}) -> {K, Val} + end, + DefinedSettings) ++ + [ {K, V} + || {K, V} <- + [{cacerts, [ list_to_binary(V) || {_, V} <- cuttlefish_variable:filter_by_prefix("log.syslog.ssl_options.cacerts", Conf)]}, + {versions, [ V || {_, V} <- cuttlefish_variable:filter_by_prefix("log.syslog.ssl_options.versions", Conf) ]}, + {key, case cuttlefish_variable:filter_by_prefix("log.syslog.ssl_options.key", Conf) of + [{[_,_,Key], Val}|_] -> {list_to_atom(Key), list_to_binary(Val)}; + _ -> undefined + end}], + V =/= undefined, + V =/= []] + end, + + Proto = cuttlefish:conf_get("log.syslog.protocol", Conf, undefined), + Transport = cuttlefish:conf_get("log.syslog.transport", Conf, udp), + case Transport of + TLS when TLS == tls; TLS == ssl -> + case Proto of + rfc3164 -> + cuttlefish:invalid("Syslog protocol rfc3164 is not compatible with TLS"); + _ -> + {rfc5424, tls, ParseSslOptions()} + end; + _ when Transport == udp; Transport == tcp -> + case Proto of + undefined -> {rfc3164, Transport}; + _ -> {Proto, Transport} + end; + _ -> cuttlefish:invalid("Invalid syslog transport ~p~n", [Transport]) + end +end}. + {mapping, "log.file", "rabbit.log.file.file", [ {datatype, [{enum, [false]}, string]} ]}. diff --git a/src/rabbit_lager.erl b/src/rabbit_lager.erl index 9af1ed198b..e510db89b3 100644 --- a/src/rabbit_lager.erl +++ b/src/rabbit_lager.erl @@ -27,7 +27,9 @@ start_logger() -> application:stop(lager), + application:stop(syslog), ensure_lager_configured(), + application:ensure_all_started(syslog), lager:start(), fold_sinks( fun @@ -163,15 +165,19 @@ ensure_lager_configured() -> end. %% Lager should have handlers and sinks +%% Error logger forwarding to syslog should be disabled lager_configured() -> Sinks = lager:list_all_sinks(), ExpectedSinks = list_expected_sinks(), application:get_env(lager, handlers) =/= undefined andalso - lists:all(fun(S) -> lists:member(S, Sinks) end, ExpectedSinks). + lists:all(fun(S) -> lists:member(S, Sinks) end, ExpectedSinks) + andalso + application:get_env(syslog, syslog_error_logger) =/= undefined. configure_lager() -> application:load(lager), + application:load(syslog), %% Turn off reformatting for error_logger messages case application:get_env(lager, error_logger_format_raw) of undefined -> application:set_env(lager, error_logger_format_raw, true); @@ -192,6 +198,8 @@ configure_lager() -> end, %% Set rabbit.log config variable based on environment. prepare_rabbit_log_config(), + %% Configure syslog library. + configure_syslog(), %% At this point we should have rabbit.log application variable %% configured to generate RabbitMQ log handlers. GeneratedHandlers = generate_lager_handlers(), @@ -261,6 +269,13 @@ configure_lager() -> end, ok. +configure_syslog() -> + %% Disable error_logger forwarding to syslog if it's not configured + case application:get_env(syslog, syslog_error_logger) of + undefined -> application:set_env(syslog, syslog_error_logger, false); + _ -> ok + end. + remove_rabbit_handlers(Handlers, FormerHandlers) -> lists:filter(fun(Handler) -> not lists:member(Handler, FormerHandlers) @@ -296,19 +311,23 @@ generate_lager_handlers(LogHandlersConfig) -> lager_backend(file) -> lager_file_backend; lager_backend(console) -> lager_console_backend; -lager_backend(syslog) -> lager_syslog_backend; +lager_backend(syslog) -> syslog_lager_backend; lager_backend(exchange) -> lager_exchange_backend. +%% Syslog backend is using an old API for configuration and +%% does not support proplists. +generate_handler(syslog_lager_backend, HandlerConfig) -> + Level = proplists:get_value(level, HandlerConfig, + default_config_value(level)), + [{syslog_lager_backend, + [Level, + {}, + {lager_default_formatter, syslog_formatter_config()}]}]; generate_handler(Backend, HandlerConfig) -> [{Backend, lists:ukeymerge(1, lists:ukeysort(1, HandlerConfig), lists:ukeysort(1, default_handler_config(Backend)))}]. -default_handler_config(lager_syslog_backend) -> - [{level, default_config_value(level)}, - {identity, "rabbitmq"}, - {facility, daemon}, - {formatter_config, default_config_value(formatter_config)}]; default_handler_config(lager_console_backend) -> [{level, default_config_value(level)}, {formatter_config, default_config_value(formatter_config)}]; @@ -327,6 +346,11 @@ default_config_value(formatter_config) -> {pid, ""}, " ", message, "\n"]. +syslog_formatter_config() -> + [color, "[", severity, "] ", + {pid, ""}, + " ", message, "\n"]. + prepare_rabbit_log_config() -> %% If RABBIT_LOGS is not set, we should ignore it. DefaultFile = application:get_env(rabbit, lager_default_file, undefined), diff --git a/test/config_schema_SUITE_data/rabbit.snippets b/test/config_schema_SUITE_data/rabbit.snippets index e4dda9f368..3dce388b79 100644 --- a/test/config_schema_SUITE_data/rabbit.snippets +++ b/test/config_schema_SUITE_data/rabbit.snippets @@ -534,5 +534,54 @@ credential_validator.regexp = ^abc\\d+", [{kernel, [ {net_ticktime, 20} ]}], - []} + []}, + {log_syslog_settings, + "log.syslog = true + log.syslog.identity = rabbitmq + log.syslog.facility = user + log.syslog.multiline_mode = true + log.syslog.ip = 10.10.10.10 + log.syslog.port = 123", + [ + {rabbit,[{log, [{syslog, [{enabled, true}]}]}]}, + {syslog, [{app_name, "rabbitmq"}, + {facility, user}, + {multiline_mode, true}, + {dest_host, "10.10.10.10"}, + {dest_port, 123}]} + ], + []}, + {log_syslog_tcp, + "log.syslog = true + log.syslog.transport = tcp + log.syslog.protocol = rfc5424", + [ + {rabbit,[{log, [{syslog, [{enabled, true}]}]}]}, + {syslog, [{protocol, {rfc5424, tcp}}]} + ], + []}, + {log_syslog_udp_default, + "log.syslog = true + log.syslog.protocol = rfc3164", + [ + {rabbit,[{log, [{syslog, [{enabled, true}]}]}]}, + {syslog, [{protocol, {rfc3164, udp}}]} + ], + []}, + {log_syslog_tls, + "log.syslog = true + log.syslog.transport = tls + log.syslog.ssl_options.cacertfile = test/config_schema_SUITE_data/certs/cacert.pem + log.syslog.ssl_options.certfile = test/config_schema_SUITE_data/certs/cert.pem + log.syslog.ssl_options.keyfile = test/config_schema_SUITE_data/certs/key.pem + log.syslog.ssl_options.verify = verify_peer + log.syslog.ssl_options.fail_if_no_peer_cert = false", + [{rabbit, [{log, [{syslog, [{enabled, true}]}]}]}, + {syslog, [{protocol, {rfc5424, tls, + [{verify,verify_peer}, + {fail_if_no_peer_cert,false}, + {cacertfile,"test/config_schema_SUITE_data/certs/cacert.pem"}, + {certfile,"test/config_schema_SUITE_data/certs/cert.pem"}, + {keyfile,"test/config_schema_SUITE_data/certs/key.pem"}]}}]}], + []} ]. diff --git a/test/unit_log_config_SUITE.erl b/test/unit_log_config_SUITE.erl index a09143cd97..b753c4075c 100644 --- a/test/unit_log_config_SUITE.erl +++ b/test/unit_log_config_SUITE.erl @@ -394,7 +394,7 @@ config_multiple_handlers(_) -> ConsoleHandlers = expected_console_handler(), RabbitHandlers = expected_rabbit_handler(), - SyslogHandlers = expected_syslog_handler(error, "rabbitmq", daemon), + SyslogHandlers = expected_syslog_handler(error), ExpectedHandlers = sort_handlers(SyslogHandlers ++ ConsoleHandlers ++ RabbitHandlers), @@ -464,14 +464,12 @@ config_syslog_handler_options(_) -> DefaultLogFile = "rabbit_default.log", application:set_env(rabbit, lager_default_file, DefaultLogFile), application:set_env(rabbit, log, [{syslog, [{enabled, true}, - {identity, "foo"}, - {facility, local1}, {level, warning}]}]), rabbit_lager:configure_lager(), FileHandlers = default_expected_handlers(DefaultLogFile), - SyslogHandlers = expected_syslog_handler(warning, "foo", local1), + SyslogHandlers = expected_syslog_handler(warning), ExpectedHandlers = sort_handlers(FileHandlers ++ SyslogHandlers), @@ -479,13 +477,12 @@ config_syslog_handler_options(_) -> ?assertEqual(ExpectedHandlers, sort_handlers(application:get_env(lager, rabbit_handlers, undefined))). expected_syslog_handler() -> - expected_syslog_handler(info, "rabbitmq", daemon). + expected_syslog_handler(info). -expected_syslog_handler(Level, Identity, Facility) -> - [{lager_syslog_backend, [{level, Level}, - {facility, Facility}, - {formatter_config, formatter_config()}, - {identity, Identity}]}]. +expected_syslog_handler(Level) -> + [{syslog_lager_backend, [Level, + {}, + {lager_default_formatter, syslog_formatter_config()}]}]. env_var_overrides_config(_) -> EnvLogFile = "rabbit_default.log", @@ -694,3 +691,6 @@ sort_handlers(Handlers) -> formatter_config() -> [date," ",time," ",color,"[",severity, "] ", {pid,[]}, " ",message,"\n"]. + +syslog_formatter_config() -> + [color,"[",severity, "] ", {pid,[]}, " ",message,"\n"]. |
