From: Joao Eduardo Luis Date: Tue, 29 Jul 2014 17:53:28 +0000 (+0100) Subject: mon: LogMonitor: write log messages on a per-channel basis X-Git-Tag: v0.86~167^2~5 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=b97b06e17f96f79911c860fac71c35e874afca65;p=ceph.git mon: LogMonitor: write log messages on a per-channel basis 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 --- diff --git a/src/common/config_opts.h b/src/common/config_opts.h index 6de269e8b233..a636594fe4a8 100644 --- a/src/common/config_opts.h +++ b/src/common/config_opts.h @@ -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) diff --git a/src/mon/LogMonitor.cc b/src/mon/LogMonitor.cc index cfafd279c2a2..b3e2c9d9156a 100644 --- a/src/mon/LogMonitor.cc +++ b/src/mon/LogMonitor.cc @@ -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 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::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 &m) +{ + generic_dout(10) << __func__ << " expand map: " << m << dendl; + for (map::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; +} diff --git a/src/mon/LogMonitor.h b/src/mon/LogMonitor.h index 439ea4d999b3..a7a40781d335 100644 --- a/src/mon/LogMonitor.h +++ b/src/mon/LogMonitor.h @@ -28,11 +28,66 @@ using namespace std; class MMonCommand; +static const string LOG_META_CHANNEL = "$channel"; + class LogMonitor : public PaxosService { private: multimap pending_log; LogSummary pending_summary, summary; + struct log_channel_info { + + map log_to_syslog; + map syslog_level; + map syslog_facility; + map log_file; + map 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 &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