]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mon: LogMonitor: write log messages on a per-channel basis
authorJoao Eduardo Luis <joao.luis@inktank.com>
Tue, 29 Jul 2014 17:53:28 +0000 (18:53 +0100)
committerJoao Eduardo Luis <joao.luis@inktank.com>
Wed, 27 Aug 2014 18:02:04 +0000 (19:02 +0100)
Instead of dumping everything to the same log file, let us this way
allow a user to specify per-channel log files, levels and syslog
facilities.

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

index 6de269e8b2334e06ed9a57590aa2316b71ee7bd7..a636594fe4a832502021b45415eae3e7870ad97d 100644 (file)
@@ -54,10 +54,11 @@ OPTION(clog_to_syslog, OPT_STR, "false")
 OPTION(clog_to_syslog_level, OPT_STR, "info") // this level and above
 OPTION(clog_to_syslog_facility, OPT_STR, "default=daemon audit=local0")
 
-OPTION(mon_cluster_log_to_syslog, OPT_BOOL, false)
+OPTION(mon_cluster_log_to_syslog, OPT_STR, "default=false")
 OPTION(mon_cluster_log_to_syslog_level, OPT_STR, "info")   // this level and above
 OPTION(mon_cluster_log_to_syslog_facility, OPT_STR, "daemon")
-OPTION(mon_cluster_log_file, OPT_STR, "/var/log/ceph/$cluster.log")
+OPTION(mon_cluster_log_file, OPT_STR,
+    "default=/var/log/ceph/$cluster.$channel.log cluster=/var/log/ceph/$cluster.log")
 OPTION(mon_cluster_log_file_level, OPT_STR, "info")
 
 DEFAULT_SUBSYS(0, 5)
index cfafd279c2a212b8269c7b5882467302a0c80739..b3e2c9d9156ac390f1bd7f9a40cca632e4f7498e 100644 (file)
@@ -30,6 +30,7 @@
 #include "common/config.h"
 #include "include/assert.h"
 #include "include/str_list.h"
+#include "include/str_map.h"
 #include "include/compat.h"
 
 #define dout_subsys ceph_subsys_mon
@@ -102,7 +103,7 @@ void LogMonitor::update_from_paxos(bool *need_bootstrap)
     return;
   assert(version >= summary.version);
 
-  bufferlist blog;
+  map<string,bufferlist> channel_blog;
 
   version_t latest_full = get_version_latest_full();
   dout(10) << __func__ << " latest full " << latest_full << dendl;
@@ -131,17 +132,40 @@ void LogMonitor::update_from_paxos(bool *need_bootstrap)
       le.decode(p);
       dout(7) << "update_from_paxos applying incremental log " << summary.version+1 <<  " " << le << dendl;
 
-      if (g_conf->mon_cluster_log_to_syslog) {
-       le.log_to_syslog(g_conf->mon_cluster_log_to_syslog_level,
-                        g_conf->mon_cluster_log_to_syslog_facility);
+      string channel = le.channel;
+      if (channel.empty()) // keep retrocompatibility
+        channel = CLOG_CHANNEL_CLUSTER;
+
+      if (channels.do_log_to_syslog(channel)) {
+        string level = channels.get_level(channel);
+        string facility = channels.get_facility(facility);
+        if (level.empty() || facility.empty()) {
+          derr << __func__ << " unable to log to syslog -- level or facility"
+               << " not defined (level: " << level << ", facility: "
+               << facility << ")" << dendl;
+          continue;
+        }
+        le.log_to_syslog(channels.get_level(channel),
+                         channels.get_facility(channel));
       }
-      if (g_conf->mon_cluster_log_file.length()) {
-       int min = string_to_syslog_level(g_conf->mon_cluster_log_file_level);
+
+      string log_file = channels.get_log_file(channel);
+      if (!log_file.empty()) {
+        string log_file_level = channels.get_log_file_level(channel);
+        if (log_file_level.empty()) {
+          dout(1) << __func__ << " warning: log file level not defined for"
+                  << " channel '" << channel << "' yet a log file is --"
+                  << " will assume lowest level possible" << dendl;
+        }
+
+       int min = string_to_syslog_level(log_file_level);
        int l = clog_type_to_syslog_level(le.prio);
        if (l <= min) {
          stringstream ss;
          ss << le << "\n";
-         blog.append(ss.str());
+          // init entry if DNE
+          bufferlist &blog = channel_blog[channel];
+          blog.append(ss.str());
        }
       }
 
@@ -151,17 +175,23 @@ void LogMonitor::update_from_paxos(bool *need_bootstrap)
     summary.version++;
   }
 
+  for(map<string,bufferlist>::iterator p = channel_blog.begin();
+      p != channel_blog.end(); ++p) {
+    if (!p->second.length())
+      continue;
+
+    string log_file = channels.get_log_file(p->first);
 
-  if (blog.length()) {
-    int fd = ::open(g_conf->mon_cluster_log_file.c_str(), O_WRONLY|O_APPEND|O_CREAT, 0600);
+    int fd = ::open(log_file.c_str(), O_WRONLY|O_APPEND|O_CREAT, 0600);
     if (fd < 0) {
       int err = -errno;
-      dout(1) << "unable to write to " << g_conf->mon_cluster_log_file << ": " << cpp_strerror(err) << dendl;
+      dout(1) << "unable to write to '" << log_file << "' for channel '"
+              << p->first << "': " << cpp_strerror(err) << dendl;
     } else {
-      int err = blog.write_fd(fd);
+      int err = p->second.write_fd(fd);
       if (err < 0) {
-       dout(1) << "error writing to " << g_conf->mon_cluster_log_file
-               << ": " << cpp_strerror(err) << dendl;
+       dout(1) << "error writing to '" << log_file << "' for channel '"
+                << p->first << ": " << cpp_strerror(err) << dendl;
       }
       VOID_TEMP_FAILURE_RETRY(::close(fd));
     }
@@ -548,3 +578,74 @@ void LogMonitor::_create_sub_incremental(MLog *mlog, int level, version_t sv)
           << mlog->entries.size() << " entries)" << dendl;
 }
 
+void LogMonitor::update_log_channels()
+{
+  ostringstream oss;
+
+  channels.clear();
+
+  int r = get_conf_str_map_helper(g_conf->mon_cluster_log_to_syslog,
+                                  oss, &channels.log_to_syslog,
+                                  CLOG_CHANNEL_DEFAULT);
+  if (r < 0) {
+    derr << __func__ << " error parsing 'mon_cluster_log_to_syslog'" << dendl;
+    return;
+  }
+
+  r = get_conf_str_map_helper(g_conf->mon_cluster_log_to_syslog_level,
+                              oss, &channels.syslog_level,
+                              CLOG_CHANNEL_DEFAULT);
+  if (r < 0) {
+    derr << __func__ << " error parsing 'mon_cluster_log_to_syslog_level'"
+         << dendl;
+    return;
+  }
+
+  r = get_conf_str_map_helper(g_conf->mon_cluster_log_to_syslog_facility,
+                              oss, &channels.syslog_facility,
+                              CLOG_CHANNEL_DEFAULT);
+  if (r < 0) {
+    derr << __func__ << " error parsing 'mon_cluster_log_to_syslog_facility'"
+         << dendl;
+    return;
+  }
+
+  r = get_conf_str_map_helper(g_conf->mon_cluster_log_file, oss,
+                              &channels.log_file,
+                              CLOG_CHANNEL_DEFAULT);
+  if (r < 0) {
+    derr << __func__ << " error parsing 'mon_cluster_log_file'" << dendl;
+    return;
+  }
+
+  r = get_conf_str_map_helper(g_conf->mon_cluster_log_file_level, oss,
+                              &channels.log_file_level,
+                              CLOG_CHANNEL_DEFAULT);
+  if (r < 0) {
+    derr << __func__ << " error parsing 'mon_cluster_log_file_level'"
+         << dendl;
+    return;
+  }
+
+  channels.expand_channel_meta();
+}
+
+void LogMonitor::log_channel_info::expand_channel_meta(map<string,string> &m)
+{
+  generic_dout(10) << __func__ << " expand map: " << m << dendl;
+  for (map<string,string>::iterator p = m.begin(); p != m.end(); ++p) {
+    size_t pos = string::npos;
+    string s = p->second;
+    bool found_meta = false;
+    while ((pos = s.find(LOG_META_CHANNEL)) != string::npos) {
+      found_meta = true;
+      string tmp = s.substr(0, pos-1) + p->first;
+      if (pos+LOG_META_CHANNEL.length() < s.length())
+        tmp = p->second.substr(pos+LOG_META_CHANNEL.length()+1);
+      s = tmp;
+    }
+    if (found_meta)
+      m[p->first] = s;
+  }
+  generic_dout(10) << __func__ << " expanded map: " << m << dendl;
+}
index 439ea4d999b3eb44f0140f6d8961df024bdc142b..a7a40781d3356264434993b60ef746316d8d5af5 100644 (file)
@@ -28,11 +28,66 @@ using namespace std;
 
 class MMonCommand;
 
+static const string LOG_META_CHANNEL = "$channel";
+
 class LogMonitor : public PaxosService {
 private:
   multimap<utime_t,LogEntry> pending_log;
   LogSummary pending_summary, summary;
 
+  struct log_channel_info {
+
+    map<string,string> log_to_syslog;
+    map<string,string> syslog_level;
+    map<string,string> syslog_facility;
+    map<string,string> log_file;
+    map<string,string> log_file_level;
+
+    void clear() {
+      log_to_syslog.clear();
+      syslog_level.clear();
+      syslog_facility.clear();
+      log_file.clear();
+      log_file_level.clear();
+    }
+
+    void expand_channel_meta() {
+      expand_channel_meta(log_to_syslog);
+      expand_channel_meta(syslog_level);
+      expand_channel_meta(syslog_facility);
+      expand_channel_meta(log_file);
+      expand_channel_meta(log_file_level);
+    }
+    void expand_channel_meta(map<string,string> &m);
+
+    bool do_log_to_syslog(const string &channel) {
+      return (get_str_map_key(log_to_syslog, channel,
+                              &CLOG_CHANNEL_DEFAULT) == "true");
+    }
+
+    string get_facility(const string &channel) {
+      return get_str_map_key(syslog_facility, channel,
+                             &CLOG_CHANNEL_DEFAULT);
+    }
+
+    string get_level(const string &channel) {
+      return get_str_map_key(syslog_level, channel,
+                             &CLOG_CHANNEL_DEFAULT);
+    }
+
+    string get_log_file(const string &channel) {
+      return get_str_map_key(log_file, channel,
+                             &CLOG_CHANNEL_DEFAULT);
+    }
+
+    string get_log_file_level(const string &channel) {
+      return get_str_map_key(log_file_level, channel,
+                             &CLOG_CHANNEL_DEFAULT);
+    }
+  } channels;
+
+  void update_log_channels();
+
   void create_initial();
   void update_from_paxos(bool *need_bootstrap);
   void create_pending();  // prepare a new pending
@@ -95,5 +150,4 @@ private:
   int sub_name_to_id(const string& n);
 
 };
-
 #endif