summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Klishin <michael@novemberain.com>2018-05-22 12:08:32 +0100
committerGitHub <noreply@github.com>2018-05-22 12:08:32 +0100
commite73d8caa01a2c2636d6bc03f61babdf0eaba5396 (patch)
treeb5ac2da6ce45270bba51d15ee76e522b5b033348
parentd0423f958599cba5148864997aa8446c873dad00 (diff)
parente8920ec0c59639c325f18ec7a9b9aa2999aa2c80 (diff)
downloadrabbitmq-server-git-e73d8caa01a2c2636d6bc03f61babdf0eaba5396.tar.gz
Merge pull request #1600 from rabbitmq/syslog
Syslog integration
-rw-r--r--Makefile4
-rw-r--r--priv/schema/rabbit.schema161
-rw-r--r--src/rabbit_lager.erl38
-rw-r--r--test/config_schema_SUITE_data/rabbit.snippets51
-rw-r--r--test/unit_log_config_SUITE.erl20
5 files changed, 252 insertions, 22 deletions
diff --git a/Makefile b/Makefile
index da56b2ad9c..7a7331bb0b 100644
--- a/Makefile
+++ b/Makefile
@@ -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"].