From 91d8d4670924e04ba2a4155f17d556a55031d267 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Wed, 15 Jul 2015 15:54:49 +0300 Subject: [PATCH 1/2] logger: support for syslog() Note that while syslog() may block, we still call it synchronously via the reactor thread. Anything else would make logging a nightmare. --- log.cc | 44 ++++++++++++++++++++++++++++++++++++++++---- log.hh | 4 ++++ 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/log.cc b/log.cc index 0a849b8be2..4fd7e70ca1 100644 --- a/log.cc +++ b/log.cc @@ -3,10 +3,12 @@ */ #include "log.hh" +#include "core/array_map.hh" #include #include #include #include +#include namespace logging { @@ -46,6 +48,9 @@ std::istream& operator>>(std::istream& in, log_level& level) { namespace logging { +std::atomic logger::_stdout = { true }; +std::atomic logger::_syslog = { false }; + logger::logger(sstring name) : _name(std::move(name)) { logger_registry().register_logger(this); } @@ -60,21 +65,52 @@ logger::~logger() { void logger::really_do_log(log_level level, const char* fmt, stringer** s, size_t n) { + std::ostringstream out; const char* p = fmt; while (*p != '\0') { if (*p == '{' && *(p+1) == '}') { p += 2; if (n > 0) { - (*s++)->append(std::cout); + (*s++)->append(out); --n; } else { - std::cout << "???"; + out << "???"; } } else { - std::cout << *p++; + out << *p++; } } - std::cout << "\n"; + out << "\n"; + auto msg = out.str(); + if (_stdout.load(std::memory_order_relaxed)) { + std::cout << out; + } + if (_syslog.load(std::memory_order_relaxed)) { + static array_map level_map = { + { int(log_level::debug), LOG_DEBUG }, + { int(log_level::info), LOG_INFO }, + { int(log_level::trace), LOG_DEBUG }, // no LOG_TRACE + { int(log_level::warn), LOG_WARNING }, + { int(log_level::error), LOG_ERR }, + }; + // NOTE: syslog() can block, which will stall the reactor thread. + // this should be rare (will have to fill the pipe buffer + // before syslogd can clear it) but can happen. If it does, + // we'll have to implement some internal buffering (which + // still means the problem can happen, just less frequently). + // syslog() interprets % characters, so send msg as a parameter + syslog(level_map[int(level)], "%s", msg.c_str()); + } +} + +void +logger::set_stdout_enabled(bool enabled) { + _stdout.store(enabled, std::memory_order_relaxed); +} + +void +logger::set_syslog_enabled(bool enabled) { + _syslog.store(enabled, std::memory_order_relaxed); } void diff --git a/log.hh b/log.hh index e49c788c34..34e71ca8c5 100644 --- a/log.hh +++ b/log.hh @@ -46,6 +46,8 @@ class registry; class logger { sstring _name; std::atomic _level = { log_level::warn }; + static std::atomic _stdout; + static std::atomic _syslog; private: struct stringer { // no need for virtual dtor, since not dynamically destroyed @@ -104,6 +106,8 @@ public: void set_level(log_level level) { _level.store(level, std::memory_order_relaxed); } + static void set_stdout_enabled(bool enabled); + static void set_syslog_enabled(bool enabled); }; class registry { From f8a7c5bd2bd4271cead1d86bc568208a9798df0c Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Wed, 15 Jul 2015 16:18:10 +0300 Subject: [PATCH 2/2] main: allow configuring log destination (stdout and/or syslog) --- db/config.hh | 2 ++ main.cc | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/db/config.hh b/db/config.hh index 865cb95539..8cbcda246b 100644 --- a/db/config.hh +++ b/db/config.hh @@ -682,6 +682,8 @@ public: val(logger_log_level, string_map, /* none */, Used,\ "map of logger name to log level. Valid values are trace, debug, info, warn, error. " \ "Use --help-loggers for a list of logger names") \ + val(log_to_stdout, bool, true, Used, "Send log output to stdout") \ + val(log_to_syslog, bool, false, Used, "Send log output to syslog") \ /* done! */ #define _make_value_member(name, type, deflt, status, desc, ...) \ diff --git a/main.cc b/main.cc index da6662ae77..5e48af78ea 100644 --- a/main.cc +++ b/main.cc @@ -36,13 +36,16 @@ void do_help_loggers() { } } -void apply_logger_settings(sstring default_level, db::config::string_map levels) { +void apply_logger_settings(sstring default_level, db::config::string_map levels, + bool log_to_stdout, bool log_to_syslog) { logging::logger_registry().set_all_loggers_level(boost::lexical_cast(std::string(default_level))); for (auto&& kv: levels) { auto&& k = kv.first; auto&& v = kv.second; logging::logger_registry().set_logger_level(k, boost::lexical_cast(std::string(v))); } + logging::logger::set_stdout_enabled(log_to_stdout); + logging::logger::set_syslog_enabled(log_to_syslog); } int main(int ac, char** av) { @@ -75,7 +78,8 @@ int main(int ac, char** av) { auto&& opts = app.configuration(); return read_config(opts, *cfg).then([&cfg, &db, &qp, &proxy, &ctx, &opts]() { - apply_logger_settings(cfg->default_log_level(), cfg->logger_log_level()); + apply_logger_settings(cfg->default_log_level(), cfg->logger_log_level(), + cfg->log_to_stdout(), cfg->log_to_syslog()); dht::set_global_partitioner(cfg->partitioner()); uint16_t thrift_port = cfg->rpc_port(); uint16_t cql_port = cfg->native_transport_port();