summaryrefslogtreecommitdiffstats
path: root/src/common/LogEntry.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/LogEntry.cc')
-rw-r--r--src/common/LogEntry.cc385
1 files changed, 385 insertions, 0 deletions
diff --git a/src/common/LogEntry.cc b/src/common/LogEntry.cc
new file mode 100644
index 000000000..dfa1ab2fa
--- /dev/null
+++ b/src/common/LogEntry.cc
@@ -0,0 +1,385 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+//
+#include <syslog.h>
+#include <boost/algorithm/string/predicate.hpp>
+
+#include "LogEntry.h"
+#include "Formatter.h"
+#include "include/stringify.h"
+
+using std::list;
+using std::map;
+using std::make_pair;
+using std::pair;
+using std::string;
+
+using ceph::bufferlist;
+using ceph::decode;
+using ceph::encode;
+using ceph::Formatter;
+
+// ----
+// LogEntryKey
+
+void LogEntryKey::dump(Formatter *f) const
+{
+ f->dump_stream("rank") << rank;
+ f->dump_stream("stamp") << stamp;
+ f->dump_unsigned("seq", seq);
+}
+
+void LogEntryKey::generate_test_instances(list<LogEntryKey*>& o)
+{
+ o.push_back(new LogEntryKey);
+ o.push_back(new LogEntryKey(entity_name_t::CLIENT(1234), utime_t(1,2), 34));
+}
+
+clog_type LogEntry::str_to_level(std::string const &str)
+{
+ std::string level_str = str;
+ std::transform(level_str.begin(), level_str.end(), level_str.begin(),
+ [](char c) {return std::tolower(c);});
+
+ if (level_str == "debug") {
+ return CLOG_DEBUG;
+ } else if (level_str == "info") {
+ return CLOG_INFO;
+ } else if (level_str == "sec") {
+ return CLOG_SEC;
+ } else if (level_str == "warn" || level_str == "warning") {
+ return CLOG_WARN;
+ } else if (level_str == "error" || level_str == "err") {
+ return CLOG_ERROR;
+ } else {
+ return CLOG_UNKNOWN;
+ }
+}
+
+// ----
+
+int clog_type_to_syslog_level(clog_type t)
+{
+ switch (t) {
+ case CLOG_DEBUG:
+ return LOG_DEBUG;
+ case CLOG_INFO:
+ return LOG_INFO;
+ case CLOG_WARN:
+ return LOG_WARNING;
+ case CLOG_ERROR:
+ return LOG_ERR;
+ case CLOG_SEC:
+ return LOG_CRIT;
+ default:
+ ceph_abort();
+ return 0;
+ }
+}
+
+clog_type string_to_clog_type(const string& s)
+{
+ if (boost::iequals(s, "debug") ||
+ boost::iequals(s, "dbg"))
+ return CLOG_DEBUG;
+ if (boost::iequals(s, "info") ||
+ boost::iequals(s, "inf"))
+ return CLOG_INFO;
+ if (boost::iequals(s, "warning") ||
+ boost::iequals(s, "warn") ||
+ boost::iequals(s, "wrn"))
+ return CLOG_WARN;
+ if (boost::iequals(s, "error") ||
+ boost::iequals(s, "err"))
+ return CLOG_ERROR;
+ if (boost::iequals(s, "security") ||
+ boost::iequals(s, "sec"))
+ return CLOG_SEC;
+
+ return CLOG_UNKNOWN;
+}
+
+int string_to_syslog_level(string s)
+{
+ if (boost::iequals(s, "debug"))
+ return LOG_DEBUG;
+ if (boost::iequals(s, "info") ||
+ boost::iequals(s, "notice"))
+ return LOG_INFO;
+ if (boost::iequals(s, "warning") ||
+ boost::iequals(s, "warn"))
+ return LOG_WARNING;
+ if (boost::iequals(s, "error") ||
+ boost::iequals(s, "err"))
+ return LOG_ERR;
+ if (boost::iequals(s, "crit") ||
+ boost::iequals(s, "critical") ||
+ boost::iequals(s, "emerg"))
+ return LOG_CRIT;
+
+ // err on the side of noise!
+ return LOG_DEBUG;
+}
+
+int string_to_syslog_facility(string s)
+{
+ if (boost::iequals(s, "auth"))
+ return LOG_AUTH;
+ if (boost::iequals(s, "authpriv"))
+ return LOG_AUTHPRIV;
+ if (boost::iequals(s, "cron"))
+ return LOG_CRON;
+ if (boost::iequals(s, "daemon"))
+ return LOG_DAEMON;
+ if (boost::iequals(s, "ftp"))
+ return LOG_FTP;
+ if (boost::iequals(s, "kern"))
+ return LOG_KERN;
+ if (boost::iequals(s, "local0"))
+ return LOG_LOCAL0;
+ if (boost::iequals(s, "local1"))
+ return LOG_LOCAL1;
+ if (boost::iequals(s, "local2"))
+ return LOG_LOCAL2;
+ if (boost::iequals(s, "local3"))
+ return LOG_LOCAL3;
+ if (boost::iequals(s, "local4"))
+ return LOG_LOCAL4;
+ if (boost::iequals(s, "local5"))
+ return LOG_LOCAL5;
+ if (boost::iequals(s, "local6"))
+ return LOG_LOCAL6;
+ if (boost::iequals(s, "local7"))
+ return LOG_LOCAL7;
+ if (boost::iequals(s, "lpr"))
+ return LOG_LPR;
+ if (boost::iequals(s, "mail"))
+ return LOG_MAIL;
+ if (boost::iequals(s, "news"))
+ return LOG_NEWS;
+ if (boost::iequals(s, "syslog"))
+ return LOG_SYSLOG;
+ if (boost::iequals(s, "user"))
+ return LOG_USER;
+ if (boost::iequals(s, "uucp"))
+ return LOG_UUCP;
+
+ // default to USER
+ return LOG_USER;
+}
+
+string clog_type_to_string(clog_type t)
+{
+ switch (t) {
+ case CLOG_DEBUG:
+ return "debug";
+ case CLOG_INFO:
+ return "info";
+ case CLOG_WARN:
+ return "warn";
+ case CLOG_ERROR:
+ return "err";
+ case CLOG_SEC:
+ return "crit";
+ default:
+ ceph_abort();
+ return 0;
+ }
+}
+
+void LogEntry::log_to_syslog(string level, string facility)
+{
+ int min = string_to_syslog_level(level);
+ int l = clog_type_to_syslog_level(prio);
+ if (l <= min) {
+ int f = string_to_syslog_facility(facility);
+ syslog(l | f, "%s %s %llu : %s",
+ name.to_cstr(),
+ stringify(rank).c_str(),
+ (long long unsigned)seq,
+ msg.c_str());
+ }
+}
+
+void LogEntry::encode(bufferlist& bl, uint64_t features) const
+{
+ if (!HAVE_FEATURE(features, SERVER_NAUTILUS)) {
+ ENCODE_START(4, 2, bl);
+ __u16 t = prio;
+ entity_inst_t who;
+ who.name = rank;
+ who.addr = addrs.as_legacy_addr();
+ encode(who, bl, features);
+ encode(stamp, bl);
+ encode(seq, bl);
+ encode(t, bl);
+ encode(msg, bl);
+ encode(channel, bl);
+ encode(name, bl);
+ ENCODE_FINISH(bl);
+ return;
+ }
+ ENCODE_START(5, 5, bl);
+ __u16 t = prio;
+ encode(name, bl);
+ encode(rank, bl);
+ encode(addrs, bl, features);
+ encode(stamp, bl);
+ encode(seq, bl);
+ encode(t, bl);
+ encode(msg, bl);
+ encode(channel, bl);
+ ENCODE_FINISH(bl);
+}
+
+void LogEntry::decode(bufferlist::const_iterator& bl)
+{
+ DECODE_START_LEGACY_COMPAT_LEN(5, 2, 2, bl);
+ if (struct_v < 5) {
+ __u16 t;
+ entity_inst_t who;
+ decode(who, bl);
+ rank = who.name;
+ addrs.v.clear();
+ addrs.v.push_back(who.addr);
+ decode(stamp, bl);
+ decode(seq, bl);
+ decode(t, bl);
+ prio = (clog_type)t;
+ decode(msg, bl);
+ if (struct_v >= 3) {
+ decode(channel, bl);
+ } else {
+ // prior to having logging channels we only had a cluster log.
+ // Ensure we keep that appearance when the other party has no
+ // clue of what a 'channel' is.
+ channel = CLOG_CHANNEL_CLUSTER;
+ }
+ if (struct_v >= 4) {
+ decode(name, bl);
+ }
+ } else {
+ __u16 t;
+ decode(name, bl);
+ decode(rank, bl);
+ decode(addrs, bl);
+ decode(stamp, bl);
+ decode(seq, bl);
+ decode(t, bl);
+ prio = (clog_type)t;
+ decode(msg, bl);
+ decode(channel, bl);
+ }
+ DECODE_FINISH(bl);
+}
+
+void LogEntry::dump(Formatter *f) const
+{
+ f->dump_stream("name") << name;
+ f->dump_stream("rank") << rank;
+ f->dump_object("addrs", addrs);
+ f->dump_stream("stamp") << stamp;
+ f->dump_unsigned("seq", seq);
+ f->dump_string("channel", channel);
+ f->dump_stream("priority") << prio;
+ f->dump_string("message", msg);
+}
+
+void LogEntry::generate_test_instances(list<LogEntry*>& o)
+{
+ o.push_back(new LogEntry);
+}
+
+
+// -----
+
+void LogSummary::build_ordered_tail(list<LogEntry> *tail) const
+{
+ tail->clear();
+ // channel -> (begin, end)
+ map<string,pair<list<pair<uint64_t,LogEntry>>::const_iterator,
+ list<pair<uint64_t,LogEntry>>::const_iterator>> pos;
+ for (auto& i : tail_by_channel) {
+ pos.emplace(i.first, make_pair(i.second.begin(), i.second.end()));
+ }
+ while (true) {
+ uint64_t min_seq = 0;
+ list<pair<uint64_t,LogEntry>>::const_iterator *minp = 0;
+ for (auto& i : pos) {
+ if (i.second.first == i.second.second) {
+ continue;
+ }
+ if (min_seq == 0 || i.second.first->first < min_seq) {
+ min_seq = i.second.first->first;
+ minp = &i.second.first;
+ }
+ }
+ if (min_seq == 0) {
+ break; // done
+ }
+ tail->push_back((*minp)->second);
+ ++(*minp);
+ }
+}
+
+void LogSummary::encode(bufferlist& bl, uint64_t features) const
+{
+ if (!HAVE_FEATURE(features, SERVER_MIMIC)) {
+ ENCODE_START(2, 2, bl);
+ encode(version, bl);
+ list<LogEntry> tail;
+ build_ordered_tail(&tail);
+ encode(tail, bl, features);
+ ENCODE_FINISH(bl);
+ return;
+ }
+ ENCODE_START(3, 3, bl);
+ encode(version, bl);
+ encode(seq, bl);
+ encode(tail_by_channel, bl, features);
+ ENCODE_FINISH(bl);
+}
+
+void LogSummary::decode(bufferlist::const_iterator& bl)
+{
+ DECODE_START_LEGACY_COMPAT_LEN(3, 2, 2, bl);
+ decode(version, bl);
+ if (struct_v < 3) {
+ list<LogEntry> tail;
+ decode(tail, bl);
+ for (auto& i : tail) {
+ add(i);
+ }
+ } else {
+ decode(seq, bl);
+ decode(tail_by_channel, bl);
+ }
+ DECODE_FINISH(bl);
+ keys.clear();
+ for (auto& i : tail_by_channel) {
+ for (auto& e : i.second) {
+ keys.insert(e.second.key());
+ }
+ }
+}
+
+void LogSummary::dump(Formatter *f) const
+{
+ f->dump_unsigned("version", version);
+ f->open_object_section("tail_by_channel");
+ for (auto& i : tail_by_channel) {
+ f->open_object_section(i.first.c_str());
+ for (auto& j : i.second) {
+ string s = stringify(j.first);
+ f->dump_object(s.c_str(), j.second);
+ }
+ f->close_section();
+ }
+ f->close_section();
+}
+
+void LogSummary::generate_test_instances(list<LogSummary*>& o)
+{
+ o.push_back(new LogSummary);
+ // more!
+}