]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
common: LogClient: allow specifying facility for LogClient
authorJoao Eduardo Luis <joao.luis@inktank.com>
Wed, 16 Jul 2014 17:14:18 +0000 (18:14 +0100)
committerJoao Eduardo Luis <joao.luis@inktank.com>
Wed, 27 Aug 2014 18:01:54 +0000 (19:01 +0100)
Instead of allowing only one LogClient, we will now allow any daemon to
have any number of LogClients.  They may either all log to the default
facility and level, or they may see their facility and level specified
upon creation (via a new constructor).

This patch also changes 'handle_log_ack' in such a way that the LogClient
will handle all acks with bearing the LogClient's facility, or will
otherwise simply ignore them.  The function will return true whenever the
message has been handled or false if that was not the case.  It will fall
on the caller the responsibility of deciding whether the message will be
passed to other LogClients or not, and when it is to be release.

Signed-off-by: Joao Eduardo Luis <joao.luis@inktank.com>
src/common/LogClient.cc
src/common/LogClient.h

index 77effcf58762257496a630942fcd8c682cd63fae..1a4a76960d4821f258fadbb8717d2eac09d8f00e 100644 (file)
@@ -15,6 +15,7 @@
 
 
 #include "include/types.h"
+#include "include/str_map.h"
 
 #include "msg/Messenger.h"
 #include "msg/Message.h"
 #include "common/config.h"
 
 #define dout_subsys ceph_subsys_monc
+#undef dout_prefix
+#define dout_prefix _prefix(_dout, this)
+static ostream& _prefix(std::ostream *_dout, LogClient *logc) {
+  return *_dout << "log_client ";
+}
+
+static ostream& _prefix(std::ostream *_dout, LogChannel *lc) {
+  return *_dout << "log_channel(" << lc->get_log_channel() << ") ";
+}
+
+LogChannel::LogChannel(CephContext *cct, LogClient *lc, const string &channel)
+  : cct(cct), parent(lc), channel_lock("LogChannel::channel_lock"),
+    log_channel(channel), log_to_syslog(false), log_to_monitors(false)
+{
+}
+
+LogChannel::LogChannel(CephContext *cct, LogClient *lc,
+                       const string &channel, const string &facility,
+                       const string &prio)
+  : cct(cct), parent(lc), channel_lock("LogChannel::channel_lock"),
+    log_channel(channel), log_prio(prio), syslog_facility(facility),
+    log_to_syslog(false), log_to_monitors(false)
+{
+}
 
 LogClient::LogClient(CephContext *cct, Messenger *m, MonMap *mm,
                     enum logclient_flag_t flags)
@@ -46,7 +71,7 @@ LogClient::LogClient(CephContext *cct, Messenger *m, MonMap *mm,
 {
 }
 
-LogClientTemp::LogClientTemp(clog_type type_, LogClient &parent_)
+LogClientTemp::LogClientTemp(clog_type type_, LogChannel &parent_)
   : type(type_), parent(parent_)
 {
 }
@@ -63,7 +88,7 @@ LogClientTemp::~LogClientTemp()
     parent.do_log(type, ss);
 }
 
-void LogClient::do_log(clog_type prio, std::stringstream& ss)
+void LogChannel::do_log(clog_type prio, std::stringstream& ss)
 {
   while (!ss.eof()) {
     string s;
@@ -73,35 +98,30 @@ void LogClient::do_log(clog_type prio, std::stringstream& ss)
   }
 }
 
-void LogClient::do_log(clog_type prio, const std::string& s)
+void LogChannel::do_log(clog_type prio, const std::string& s)
 {
-  Mutex::Locker l(log_lock);
+  Mutex::Locker l(channel_lock);
   int lvl = (prio == CLOG_ERROR ? -1 : 0);
   ldout(cct,lvl) << "log " << prio << " : " << s << dendl;
   LogEntry e;
-  e.who = messenger->get_myinst();
+  // who will be set when we queue the entry on LogClient
+  //e.who = messenger->get_myinst();
   e.stamp = ceph_clock_now(cct);
-  e.seq = ++last_log;
+  // seq will be set when we queue the entry on LogClient
+  // e.seq = ++last_log;
   e.prio = prio;
   e.msg = s;
+  e.channel = get_log_channel();
 
   // log to syslog?
-  if (cct->_conf->clog_to_syslog) {
-    e.log_to_syslog(cct->_conf->clog_to_syslog_level,
-                   cct->_conf->clog_to_syslog_facility);
+  if (do_log_to_syslog()) {
+    ldout(cct,0) << __func__ << " log to syslog"  << dendl;
+    e.log_to_syslog(get_log_prio(), get_syslog_facility());
   }
 
   // log to monitor?
-  if (cct->_conf->clog_to_monitors) {
-    log_queue.push_back(e);
-
-    // if we are a monitor, queue for ourselves, synchronously
-    if (is_mon) {
-      assert(messenger->get_myname().is_mon());
-      ldout(cct,10) << "send_log to self" << dendl;
-      Message *log = _get_mon_log_message();
-      messenger->get_loopback_connection()->send_message(log);
-    }
+  if (log_to_monitors) {
+    parent->queue(e);
   }
 }
 
@@ -169,6 +189,30 @@ Message *LogClient::_get_mon_log_message()
   return log;
 }
 
+void LogClient::_send_to_mon()
+{
+  assert(log_lock.is_locked());
+  assert(is_mon);
+  assert(messenger->get_myname().is_mon());
+  ldout(cct,10) << __func__ << "log to self" << dendl;
+  Message *log = _get_mon_log_message();
+  messenger->get_loopback_connection()->send_message(log);
+}
+
+version_t LogClient::queue(LogEntry &entry)
+{
+  Mutex::Locker l(log_lock);
+  entry.seq = ++last_log;
+  entry.who = messenger->get_myinst();
+  log_queue.push_back(entry);
+
+  if (is_mon) {
+    _send_to_mon();
+  }
+
+  return entry.seq;
+}
+
 bool LogClient::handle_log_ack(MLogAck *m)
 {
   Mutex::Locker l(log_lock);
index c803604f04efa86745e1a2a60523124d03260054..8d808239992ff7964b1c79124c25a6d36407c884 100644 (file)
@@ -29,10 +29,12 @@ class MonMap;
 class Message;
 struct Connection;
 
+class LogChannel;
+
 class LogClientTemp
 {
 public:
-  LogClientTemp(clog_type type_, LogClient &parent_);
+  LogClientTemp(clog_type type_, LogChannel &parent_);
   LogClientTemp(const LogClientTemp &rhs);
   ~LogClientTemp();
 
@@ -44,22 +46,28 @@ public:
 
 private:
   clog_type type;
-  LogClient &parent;
+  LogChannel &parent;
   stringstream ss;
 };
 
-class LogClient
+/** Manage where we output to and at which priority
+ *
+ * Not to be confused with the LogClient, which is the almighty coordinator
+ * of channels.  We just deal with the boring part of the logging: send to
+ * syslog, send to file, generate LogEntry and queue it for the LogClient.
+ *
+ * Past queueing the LogEntry, the LogChannel is done with the whole thing.
+ * LogClient will deal with sending and handling of LogEntries.
+ */
+class LogChannel
 {
 public:
-  enum logclient_flag_t {
-    NO_FLAGS = 0,
-    FLAG_MON = 0x1,
-  };
 
-  LogClient(CephContext *cct, Messenger *m, MonMap *mm,
-           enum logclient_flag_t flags);
-
-  bool handle_log_ack(MLogAck *m);
+  LogChannel(CephContext *cct, LogClient *lc, const std::string &channel);
+  LogChannel(CephContext *cct, LogClient *lc,
+             const std::string &channel,
+             const std::string &facility,
+             const std::string &prio);
 
   LogClientTemp debug() {
     return LogClientTemp(CLOG_DEBUG, *this);
@@ -92,14 +100,106 @@ public:
     do_log(CLOG_SEC, s);
   }
 
+  void set_log_to_monitors(bool v) {
+    log_to_monitors = v;
+  }
+  void set_log_to_syslog(bool v) {
+    log_to_syslog = v;
+  }
+  void set_log_channel(const std::string& v) {
+    log_channel = v;
+  }
+  void set_log_prio(const std::string& v) {
+    log_prio = v;
+  }
+  void set_syslog_facility(const std::string& v) {
+    syslog_facility = v;
+  }
+  std::string get_log_prio() { return log_prio; }
+  std::string get_log_channel() { return log_channel; }
+  std::string get_syslog_facility() { return syslog_facility; }
+  bool must_log_to_syslog() { return log_to_syslog; }
+  /**
+   * Do we want to log to syslog?
+   *
+   * @return true if log_to_syslog is true and both channel and prio
+   *         are not empty; false otherwise.
+   */
+  bool do_log_to_syslog() {
+    return must_log_to_syslog() &&
+          !log_prio.empty() && !log_channel.empty();
+  }
+  bool must_log_to_monitors() { return log_to_monitors; }
+
+  typedef shared_ptr<LogChannel> Ref;
+
+private:
+  void do_log(clog_type prio, std::stringstream& ss);
+  void do_log(clog_type prio, const std::string& s);
+
+  CephContext *cct;
+  LogClient *parent;
+  Mutex channel_lock;
+  std::string log_channel;
+  std::string log_prio;
+  std::string syslog_facility;
+  bool log_to_syslog;
+  bool log_to_monitors;
+
+
+  friend class LogClientTemp;
+};
+
+typedef LogChannel::Ref LogChannelRef;
+
+class LogClient
+{
+public:
+  enum logclient_flag_t {
+    NO_FLAGS = 0,
+    FLAG_MON = 0x1,
+  };
+
+  LogClient(CephContext *cct, Messenger *m, MonMap *mm,
+           enum logclient_flag_t flags);
+  virtual ~LogClient() {
+    channels.clear();
+  }
+
+  bool handle_log_ack(MLogAck *m);
   void reset_session();
   Message *get_mon_log_message();
   bool are_pending();
 
+  LogChannelRef create_channel() {
+    return create_channel(CLOG_CHANNEL_DEFAULT);
+  }
+
+  LogChannelRef create_channel(const std::string& name) {
+    LogChannelRef c;
+    if (channels.count(name))
+      c = channels[name];
+    else {
+      c = LogChannelRef(new LogChannel(cct, this, name));
+      channels[name] = c;
+    }
+    return c;
+  }
+
+  void destroy_channel(const std::string& name) {
+    if (channels.count(name))
+      channels.erase(name);
+  }
+
+  void shutdown() {
+    channels.clear();
+  }
+  
+  version_t queue(LogEntry &entry);
+
 private:
-  void do_log(clog_type prio, std::stringstream& ss);
-  void do_log(clog_type prio, const std::string& s);
   Message *_get_mon_log_message();
+  void _send_to_mon();
 
   CephContext *cct;
   Messenger *messenger;
@@ -110,7 +210,7 @@ private:
   version_t last_log;
   std::deque<LogEntry> log_queue;
 
-  friend class LogClientTemp;
-};
+  std::map<std::string, LogChannelRef> channels;
 
+};
 #endif