From: Marcel Lauhoff Date: Fri, 3 Oct 2014 17:09:19 +0000 (+0200) Subject: Graylog2 logging X-Git-Tag: v10.0.4~72^2~5 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=a483168a2f77c1c92d9e87ad05a5fda55cf4a1e2;p=ceph.git Graylog2 logging Add graylog2 as logger target. Format log entries as GELF and send them via UDP to log server New config options - log_to_graylog - err_to_graylog - log_graylog_host - log_graylog_port [0] https://www.graylog2.org/resources/gelf Signed-off-by: Marcel Lauhoff --- diff --git a/configure.ac b/configure.ac index 906ad015a7b4..2b3fc7a437de 100644 --- a/configure.ac +++ b/configure.ac @@ -907,6 +907,10 @@ AC_CHECK_LIB(boost_system-mt, main, [], [AC_CHECK_LIB(boost_system, main, [], AC_MSG_NOTICE(["Boost system library not found."]))]) +AC_CHECK_LIB(boost_iostreams-mt, main, [], + [AC_CHECK_LIB(boost_iostreams, main, [], + AC_MSG_NOTICE(["Boost iostreams library not found."]))]) + # Find the right boost_thread library. BOOST_THREAD_LIBS="" saved_LIBS="${LIBS}" diff --git a/src/common/Makefile.am b/src/common/Makefile.am index c94232210e2a..71fccd5ba1da 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -86,7 +86,7 @@ endif if LINUX libcommon_internal_la_SOURCES += \ - common/linux_version.c + common/linux_version.c endif if SOLARIS @@ -161,7 +161,8 @@ LIBCOMMON_DEPS += \ $(LIBCOMPRESSOR) \ $(LIBMSG) $(LIBAUTH) \ $(LIBCRUSH) $(LIBJSON_SPIRIT) $(LIBLOG) $(LIBARCH) \ - $(BOOST_RANDOM_LIBS) + $(BOOST_RANDOM_LIBS) \ + -luuid if LINUX LIBCOMMON_DEPS += -lrt -lblkid diff --git a/src/common/ceph_context.cc b/src/common/ceph_context.cc index 91d6b97d0c56..dc9600fc279a 100644 --- a/src/common/ceph_context.cc +++ b/src/common/ceph_context.cc @@ -160,6 +160,12 @@ public: "err_to_syslog", "log_to_stderr", "err_to_stderr", + "log_to_graylog", + "err_to_graylog", + "log_graylog_host", + "log_graylog_port", + "fsid", + "host", NULL }; return KEYS; @@ -186,12 +192,33 @@ public: } if (changed.count("log_max_new")) { + log->set_max_new(conf->log_max_new); } if (changed.count("log_max_recent")) { log->set_max_recent(conf->log_max_recent); } + + // graylog + if (changed.count("log_to_graylog") || changed.count("err_to_graylog")) { + int l = conf->log_to_graylog ? 99 : (conf->err_to_graylog ? -1 : -2); + log->set_graylog_level(l, l); + } + + if (changed.count("log_graylog_host") || changed.count("log_graylog_port")) { + log->set_graylog_destination(conf->log_graylog_host, conf->log_graylog_port); + } + + // metadata + if (changed.count("host")) { + log->set_host(conf->host); + } + + if (changed.count("fsid")) { + log->set_fsid(conf->fsid); + } + } }; diff --git a/src/common/config_opts.h b/src/common/config_opts.h index 9107b220e4bf..6311e789430d 100644 --- a/src/common/config_opts.h +++ b/src/common/config_opts.h @@ -50,6 +50,10 @@ OPTION(log_to_syslog, OPT_BOOL, false) OPTION(err_to_syslog, OPT_BOOL, false) OPTION(log_flush_on_exit, OPT_BOOL, true) // default changed by common_preinit() OPTION(log_stop_at_utilization, OPT_FLOAT, .97) // stop logging at (near) full +OPTION(log_to_graylog, OPT_BOOL, false) +OPTION(err_to_graylog, OPT_BOOL, false) +OPTION(log_graylog_host, OPT_STR, "127.0.0.1") +OPTION(log_graylog_port, OPT_INT, 12201) // options will take k/v pairs, or single-item that will be assumed as general // default for all, regardless of channel. diff --git a/src/log/Log.cc b/src/log/Log.cc index eb9c545623ec..037c1d7acf39 100644 --- a/src/log/Log.cc +++ b/src/log/Log.cc @@ -8,14 +8,22 @@ #include #include +#include + +#include +#include +#include +#include #include "common/errno.h" #include "common/safe_io.h" #include "common/Clock.h" #include "common/valgrind.h" +#include "common/Formatter.h" #include "include/assert.h" #include "include/compat.h" #include "include/on_exit.h" +#include "include/uuid.h" #define DEFAULT_MAX_NEW 100 #define DEFAULT_MAX_RECENT 10000 @@ -45,6 +53,10 @@ Log::Log(SubsystemMap *s) m_fd(-1), m_syslog_log(-2), m_syslog_crash(-2), m_stderr_log(1), m_stderr_crash(-1), + m_graylog_log(-3), m_graylog_crash(-3), + m_host(""), m_fsid(), + m_graylog_endpoint(), + m_graylog_io_service(), m_stop(false), m_max_new(DEFAULT_MAX_NEW), m_max_recent(DEFAULT_MAX_RECENT), @@ -151,6 +163,32 @@ void Log::set_stderr_level(int log, int crash) pthread_mutex_unlock(&m_flush_mutex); } +void Log::set_graylog_level(int log, int crash) +{ + pthread_mutex_lock(&m_flush_mutex); + m_graylog_log = log; + m_graylog_crash = crash; + pthread_mutex_unlock(&m_flush_mutex); +} + +void Log::set_host(string host) +{ + m_host = host; +} + +void Log::set_fsid(uuid_d fsid) +{ + m_fsid = fsid; +} + +void Log::set_graylog_destination(string host, int port) +{ + boost::asio::ip::udp::resolver resolver(m_graylog_io_service); + boost::asio::ip::udp::resolver::query query(host, + boost::lexical_cast(port)); + m_graylog_endpoint = *resolver.resolve(query); +} + void Log::submit_entry(Entry *e) { pthread_mutex_lock(&m_queue_mutex); @@ -240,6 +278,7 @@ void Log::_flush(EntryQueue *t, EntryQueue *requeue, bool crash) bool do_fd = m_fd >= 0 && should_log; bool do_syslog = m_syslog_crash >= e->m_prio && should_log; bool do_stderr = m_stderr_crash >= e->m_prio && should_log; + bool do_graylog2 = m_graylog_crash >= e->m_prio && should_log; e->hint_size(); if (do_fd || do_syslog || do_stderr) { @@ -271,8 +310,52 @@ void Log::_flush(EntryQueue *t, EntryQueue *requeue, bool crash) if (r < 0) cerr << "problem writing to " << m_log_file << ": " << cpp_strerror(r) << std::endl; } - } + if (do_graylog2) { + std::auto_ptr f(Formatter::create("json")); + + char fsid_str[40]; + m_fsid.print(fsid_str); + + // GELF format + // http://www.graylog2.org/resources/gelf/specification + f->open_object_section(""); + f->dump_string("version", "1.1"); + f->dump_string("host", m_host); + f->dump_string("short_message", s); + f->dump_string("_app", "ceph"); + f->dump_float("timestamp", e->m_stamp.sec() + (e->m_stamp.usec() / 1000000.0)); + f->dump_int("_thread", e->m_thread); + f->dump_int("_prio", e->m_prio); + f->dump_string("_subsys_name", m_subs->get_name(sub)); + f->dump_int("_subsys_id", sub); + f->dump_int("_crash", crash); + f->dump_string("_fsid", fsid_str); + if (crash) f->dump_int("_crash_entry_queue_len", -t->m_len); + f->close_section(); + + std::stringstream zos(std::stringstream::in | + std::stringstream::out | + std::stringstream::binary); + + { + boost::iostreams::filtering_ostream os; + os.push(boost::iostreams::zlib_compressor()); + os.push(zos); + + f->flush(os); + os << std::endl; + } + + try { + boost::asio::ip::udp::socket socket(m_graylog_io_service); + socket.open(m_graylog_endpoint.protocol()); + socket.send_to(boost::asio::buffer(zos.str()), m_graylog_endpoint); + } catch (boost::system::system_error const& e) { + /* The above code fails until the configuration is set */ + } + } + } requeue->enqueue(e); } } @@ -289,7 +372,7 @@ void Log::_log_message(const char *s, bool crash) if ((crash ? m_syslog_crash : m_syslog_log) >= 0) { syslog(LOG_USER|LOG_DEBUG, "%s", s); } - + if ((crash ? m_stderr_crash : m_stderr_log) >= 0) { cerr << s << std::endl; } diff --git a/src/log/Log.h b/src/log/Log.h index 57727d312bc9..8b6851f71548 100644 --- a/src/log/Log.h +++ b/src/log/Log.h @@ -7,6 +7,7 @@ #include "common/Thread.h" #include +#include #include "Entry.h" #include "EntryQueue.h" @@ -37,6 +38,13 @@ class Log : private Thread int m_syslog_log, m_syslog_crash; int m_stderr_log, m_stderr_crash; + int m_graylog_log, m_graylog_crash; + + std::string m_host; + uuid_d m_fsid; + + boost::asio::ip::udp::endpoint m_graylog_endpoint; + boost::asio::io_service m_graylog_io_service; bool m_stop; @@ -61,12 +69,13 @@ public: void set_log_file(std::string fn); void reopen_log_file(); - void flush(); + void flush(); void dump_recent(); void set_syslog_level(int log, int crash); void set_stderr_level(int log, int crash); + void set_graylog_level(int log, int crash); Entry *create_entry(int level, int subsys); Entry *create_entry(int level, int subsys, size_t* expected_size); @@ -75,6 +84,11 @@ public: void start(); void stop(); + void set_host(std::string host); + void set_fsid(uuid_d fdid); + + void set_graylog_destination(std::string host, int port); + /// true if the log lock is held by our thread bool is_inside_log_lock(); diff --git a/src/test/Makefile.am b/src/test/Makefile.am index 6abfa4327905..85691d4f0efc 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -138,7 +138,8 @@ UNITTEST_LDADD = \ $(top_builddir)/src/gmock/lib/libgmock_main.la \ $(top_builddir)/src/gmock/lib/libgmock.la \ $(top_builddir)/src/gmock/gtest/lib/libgtest.la \ - $(PTHREAD_LIBS) + $(PTHREAD_LIBS) \ + -luuid if SOLARIS UNITTEST_LDADD += \