]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
Graylog2 logging
authorMarcel Lauhoff <ml@irq0.org>
Fri, 3 Oct 2014 17:09:19 +0000 (19:09 +0200)
committerMarcel Lauhoff <lauhoff@uni-mainz.de>
Fri, 29 Jan 2016 14:32:47 +0000 (15:32 +0100)
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 <ml@irq0.org>
configure.ac
src/common/Makefile.am
src/common/ceph_context.cc
src/common/config_opts.h
src/log/Log.cc
src/log/Log.h
src/test/Makefile.am

index 906ad015a7b40cdd71f492e4f931a6f5fe35dbfd..2b3fc7a437de302d24f7d668ed9d2fef9a6b1f93 100644 (file)
@@ -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}"
index c94232210e2ad4090b767f114d0e36b45900f225..71fccd5ba1da0318fc01e5611579de09f7157df8 100644 (file)
@@ -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
index 91d6b97d0c56c77186514c08839b1d312c4dc0a7..dc9600fc279a90377133bc2bf641496eed72353a 100644 (file)
@@ -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);
+    }
+
   }
 };
 
index 9107b220e4bf44fc8fd45f3888d0f0e1581d6960..6311e789430d8bb50b7531a5f5a02d010704c361 100644 (file)
@@ -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.
index eb9c545623ec5326c0be6d2f01d98e5906f1c8fa..037c1d7acf39365daa7a5ef9ffd8ad38d232e9b2 100644 (file)
@@ -8,14 +8,22 @@
 
 #include <iostream>
 #include <sstream>
+#include <memory>
+
+#include <boost/lexical_cast.hpp>
+#include <boost/asio.hpp>
+#include <boost/iostreams/filtering_stream.hpp>
+#include <boost/iostreams/filter/zlib.hpp>
 
 #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<string>(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<Formatter> 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;
   }
index 57727d312bc913ec180053e537bd0e7e4ac59382..8b6851f71548eadaf84e8d48e0d131ff1c2eb3ba 100644 (file)
@@ -7,6 +7,7 @@
 #include "common/Thread.h"
 
 #include <pthread.h>
+#include <boost/asio.hpp>
 
 #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();
 
index 6abfa43279056ab1a9f500565b81698882a16537..85691d4f0efcc1b3d10aeb1a4b12a80cbb47dbeb 100644 (file)
@@ -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 += \