summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2017-07-06 20:43:13 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2017-07-10 16:03:37 +0100
commit8979de6a10b523df671d4709b8e26495a88d7223 (patch)
treefbfcd2d72c0ceab42b43e49b5ccc5144fc595b81
parentAdd test to prove a Logger can be a static member with global initialisation (diff)
downloadicetray-8979de6a10b523df671d4709b8e26495a88d7223.tar.bz2
icetray-8979de6a10b523df671d4709b8e26495a88d7223.tar.xz
icetray-8979de6a10b523df671d4709b8e26495a88d7223.zip
Make the logging domain a string sequence and implement log4j style domain folding when width is limited
-rw-r--r--icetray/icetray/logWriter.ice6
-rw-r--r--icetray/icetray/logWriterConsole.cpp86
-rw-r--r--icetray/icetray/logWriterConsole.h22
-rw-r--r--icetray/icetray/logger.cpp18
-rw-r--r--icetray/icetray/logger.h18
-rw-r--r--icetray/unittests/testIceTrayLogger.cpp125
6 files changed, 215 insertions, 60 deletions
diff --git a/icetray/icetray/logWriter.ice b/icetray/icetray/logWriter.ice
index 3d68f64..e55179b 100644
--- a/icetray/icetray/logWriter.ice
+++ b/icetray/icetray/logWriter.ice
@@ -14,11 +14,13 @@ module IceTray {
INFO = 6,
DEBUG = 7
};
+ ["slicer:ignore"]
+ sequence<string> Domain;
interface LogWriter {
optional(0) LogLevel lowestLevel();
- optional(0) LogLevel level(string domain);
- void message(LogLevel level, string domain, string message);
+ optional(0) LogLevel level(Domain domain);
+ void message(LogLevel level, Domain domain, string message);
};
};
};
diff --git a/icetray/icetray/logWriterConsole.cpp b/icetray/icetray/logWriterConsole.cpp
index 06c72eb..387c2d3 100644
--- a/icetray/icetray/logWriterConsole.cpp
+++ b/icetray/icetray/logWriterConsole.cpp
@@ -1,24 +1,82 @@
#include <logWriter.h>
-#include "logger.h"
+#include "logWriterConsole.h"
#include <compileTimeFormatter.h>
#include <slicer/modelPartsTypes.h>
+namespace AdHoc {
+ AdHocFormatter(DomainFmt, ".%?");
+ StreamWriterT('d') {
+ template<typename ... Pn>
+ static void write(stream & s, int width, const IceTray::Logging::Domain & domain, const Pn & ... pn)
+ {
+ auto di = domain.begin();
+ if (di == domain.end()) {
+ return StreamWriter::next(s, pn...);
+ }
+
+ if (width == -1) {
+ s << *di++;
+ while (di != domain.end()) {
+ DomainFmt::write(s, *di++);
+ }
+ }
+ else {
+ int target = width;
+ while (di != domain.end()) {
+ int total = di == domain.begin() ? -1 : 0;
+ for (auto dic = di; dic != domain.end(); dic++) {
+ total += 1 + dic->length();
+ }
+ if (di == domain.begin()) {
+ if (total > target) {
+ s << di->front();
+ target -= 1;
+ }
+ else {
+ s << *di;
+ target -= di->length();
+ }
+ }
+ else {
+ if (total > target) {
+ DomainFmt::write(s, di->front());
+ target -= 2;
+ }
+ else {
+ DomainFmt::write(s, *di);
+ target -= 1 + di->length();
+ }
+ }
+ di++;
+ }
+ }
+ StreamWriter::next(s, pn...);
+ }
+ };
+}
+
namespace IceTray {
namespace Logging {
- AdHocFormatter(LogMsg, "%?: %?: %?\n");
- class ConsoleLogWriter : public AbstractLogWriter {
- public:
- ConsoleLogWriter(Ice::Properties * p) :
- AbstractLogWriter("logging.console", p)
- {
- }
+ AdHocFormatter(LogMsg, "%?: %d: %?\n");
+ ConsoleLogWriter::ConsoleLogWriter(Ice::Properties * p) :
+ AbstractLogWriter("logging.console", p),
+ width(p ? p->getPropertyAsIntWithDefault("logging.console.width", -1) : -1)
+ {
+ }
- void message(LogLevel priority, const std::string & domain, const std::string & message, const Ice::Current &) override
- {
- LogMsg::write(priority < WARNING ? std::cerr : std::cout,
- Slicer::ModelPartForEnum<LogLevel>::lookup(priority), domain, message);
- }
- };
+ void
+ ConsoleLogWriter::message(LogLevel priority, const Domain & domain, const std::string & message, const Ice::Current &)
+ {
+ writeStream(priority < WARNING ? std::cerr : std::cout,
+ width, priority, domain, message);
+ }
+
+ std::ostream &
+ ConsoleLogWriter::writeStream(std::ostream & s, int width, LogLevel priority, const Domain & domain, const std::string & message)
+ {
+ return LogMsg::write(s,
+ Slicer::ModelPartForEnum<LogLevel>::lookup(priority), width, domain, message);
+ }
FACTORY(ConsoleLogWriter, LogWriterFactory);
}
}
diff --git a/icetray/icetray/logWriterConsole.h b/icetray/icetray/logWriterConsole.h
new file mode 100644
index 0000000..1c5cf3b
--- /dev/null
+++ b/icetray/icetray/logWriterConsole.h
@@ -0,0 +1,22 @@
+#ifndef ICETRAY_LOGGING_CONSOLE_H
+#define ICETRAY_LOGGING_CONSOLE_H
+
+#include "logger.h"
+
+namespace IceTray {
+ namespace Logging {
+ class ConsoleLogWriter : public AbstractLogWriter {
+ public:
+ ConsoleLogWriter(Ice::Properties * p);
+
+ void message(LogLevel priority, const Domain & domain, const std::string & message, const Ice::Current &) override;
+
+ static DLL_PUBLIC std::ostream & writeStream(std::ostream &, int width, LogLevel priority, const Domain & domain, const std::string & message);
+
+ const int width;
+ };
+ }
+}
+
+#endif
+
diff --git a/icetray/icetray/logger.cpp b/icetray/icetray/logger.cpp
index e36e193..8c5c36b 100644
--- a/icetray/icetray/logger.cpp
+++ b/icetray/icetray/logger.cpp
@@ -14,7 +14,7 @@ template class ::AdHoc::GlobalStatic<::IceTray::Logging::LogManager>;
namespace IceTray {
namespace Logging {
- LoggerBase::LoggerBase(const std::string & domain) :
+ LoggerBase::LoggerBase(const Domain & domain) :
domain(domain)
{
}
@@ -23,13 +23,13 @@ namespace IceTray {
{
}
- const std::string &
+ const Domain &
LoggerBase::getDomain() const
{
return domain;
}
- Logger::Logger(const std::string & domain) : LoggerBase(domain) { }
+ Logger::Logger(const Domain & domain) : LoggerBase(domain) { }
void
Logger::message(LogLevel priority, const std::string & msg) const
@@ -108,14 +108,15 @@ namespace IceTray {
LoggerPtr
LogManager::getLogger(const std::string & domain)
{
- auto logger = LoggerPtr(new Logger(domain));
- logger->logs = getLogsForDomain(domain);
+ auto domainTokens = AbstractLogWriter::splitDomain(domain);
+ auto logger = LoggerPtr(new Logger(domainTokens));
+ logger->logs = getLogsForDomain(domainTokens);
loggers.insert(logger.get());
return logger;
}
LogLevelWriters
- LogManager::getLogsForDomain(const std::string & domain) const
+ LogManager::getLogsForDomain(const Domain & domain) const
{
SharedLock(_lock);
LogLevelWriters logs;
@@ -206,11 +207,10 @@ namespace IceTray {
}
IceUtil::Optional<LogLevel>
- AbstractLogWriter::level(const std::string & domain, const Ice::Current &)
+ AbstractLogWriter::level(const Domain & domain, const Ice::Current &)
{
- auto domainTokens = splitDomain(domain);
for (auto d = logDomains.rbegin(); d != logDomains.rend(); d++) {
- if (boost::algorithm::starts_with(domainTokens, d->first)) {
+ if (boost::algorithm::starts_with(domain, d->first)) {
return d->second;
}
}
diff --git a/icetray/icetray/logger.h b/icetray/icetray/logger.h
index 81d650c..0420415 100644
--- a/icetray/icetray/logger.h
+++ b/icetray/icetray/logger.h
@@ -22,21 +22,21 @@ namespace IceTray {
class DLL_PUBLIC LoggerBase {
public:
- LoggerBase(const std::string & domain);
+ LoggerBase(const Domain & domain);
~LoggerBase();
- const std::string & getDomain() const;
+ const Domain & getDomain() const;
protected:
friend class LogManager;
mutable boost::shared_mutex _lock;
LogLevelWriters logs;
- const std::string domain;
+ const Domain domain;
};
class DLL_PUBLIC Logger : public LoggerBase {
public:
- Logger(const std::string & domain);
+ Logger(const Domain & domain);
void message(LogLevel priority, const std::string & msg) const;
void messagef(LogLevel priority, const char * msgfmt, ...) const __attribute__ ((format (printf, 3, 4)));
@@ -78,7 +78,7 @@ namespace IceTray {
}
LoggerPtr getLogger(const std::type_info &);
LoggerPtr getLogger(const std::string &);
- LogLevelWriters getLogsForDomain(const std::string &) const;
+ LogLevelWriters getLogsForDomain(const Domain &) const;
void addWriter(LogWriterPrx writer);
void removeWriter(LogWriterPrx writer);
@@ -94,18 +94,18 @@ namespace IceTray {
class DLL_PUBLIC AbstractLogWriter : public LogWriter {
public:
IceUtil::Optional<LogLevel> lowestLevel(const Ice::Current &) override;
- IceUtil::Optional<LogLevel> level(const std::string &, const Ice::Current &) override;
+ IceUtil::Optional<LogLevel> level(const Domain &, const Ice::Current &) override;
protected:
AbstractLogWriter();
AbstractLogWriter(LogLevel level);
AbstractLogWriter(const std::string & prefix, Ice::PropertiesPtr p);
- typedef std::map<Ice::StringSeq, LogLevel> LogDomains;
+ typedef std::map<Domain, LogLevel> LogDomains;
LogDomains logDomains;
- private:
- static Ice::StringSeq splitDomain(const std::string &);
+ public:
+ static Domain splitDomain(const std::string &);
};
typedef AdHoc::Factory<LogWriter, Ice::Properties *> LogWriterFactory;
diff --git a/icetray/unittests/testIceTrayLogger.cpp b/icetray/unittests/testIceTrayLogger.cpp
index 2a7fa50..81f0023 100644
--- a/icetray/unittests/testIceTrayLogger.cpp
+++ b/icetray/unittests/testIceTrayLogger.cpp
@@ -9,12 +9,13 @@
#include <compileTimeFormatter.h>
#include <boost/format.hpp>
#include <slicer/common.h>
+#include <logWriterConsole.h>
using namespace IceTray::Logging;
struct LogEntry {
LogLevel priority;
- std::string domain;
+ Domain domain;
std::string message;
};
@@ -31,7 +32,7 @@ class TestLogWriter : public AbstractLogWriter {
{
}
- void message(LogLevel priority, const std::string & domain, const std::string & message, const Ice::Current &) override
+ void message(LogLevel priority, const Domain & domain, const std::string & message, const Ice::Current &) override
{
msgs.push_back({priority, domain, message});
}
@@ -40,16 +41,32 @@ class TestLogWriter : public AbstractLogWriter {
};
FACTORY(TestLogWriter, LogWriterFactory);
+namespace std {
+ ostream &
+ operator<<(ostream & s, const Domain & domain) {
+ for (const auto & d : domain) {
+ s << "::" << d;
+ }
+ return s;
+ }
+}
+
class StaticLogTest {
public:
static IceTray::Logging::LoggerPtr staticLog;
};
IceTray::Logging::LoggerPtr staticLog = LOGMANAGER()->getLogger<IceTray::Service>();
+Domain other = {"other"};
+Domain test = {"test"};
+Domain testDomain = {"test", "domain"};
+Domain testDebug = {"test", "debug"};
+
BOOST_AUTO_TEST_CASE( staticLogInit )
{
BOOST_REQUIRE(staticLog);
- BOOST_REQUIRE_EQUAL("IceTray::Service", staticLog->getDomain());
+ Domain expected = {"IceTray", "Service"};
+ BOOST_REQUIRE_EQUAL(expected, staticLog->getDomain());
}
class TestLogImpl {
@@ -90,6 +107,12 @@ BOOST_AUTO_TEST_CASE(no_writers) {
log->message(DEBUG, "");
}
+BOOST_AUTO_TEST_CASE(ostreamDomain) {
+ std::stringstream str;
+ str << testDomain;
+ BOOST_REQUIRE_EQUAL("::test::domain", str.str());
+}
+
BOOST_AUTO_TEST_CASE(priority_filtering) {
auto w = new TestLogWriter(WARNING);
auto e = new TestLogWriter(ERR);
@@ -154,7 +177,7 @@ BOOST_AUTO_TEST_CASE(formatter_plain)
log->message(DEBUG, "plain message.");
BOOST_REQUIRE_EQUAL(1, d->msgs.size());
BOOST_REQUIRE_EQUAL("plain message.", d->msgs.front().message);
- BOOST_REQUIRE_EQUAL("test.domain", d->msgs.front().domain);
+ BOOST_REQUIRE_EQUAL(testDomain, d->msgs.front().domain);
}
BOOST_AUTO_TEST_CASE(formatter_libc)
@@ -164,7 +187,7 @@ BOOST_AUTO_TEST_CASE(formatter_libc)
log->messagef(DEBUG, "plain %s.", "message");
BOOST_REQUIRE_EQUAL(1, d->msgs.size());
BOOST_REQUIRE_EQUAL("plain message.", d->msgs.front().message);
- BOOST_REQUIRE_EQUAL("test.domain", d->msgs.front().domain);
+ BOOST_REQUIRE_EQUAL(testDomain, d->msgs.front().domain);
}
BOOST_AUTO_TEST_CASE(formatter_boost_format)
@@ -174,7 +197,7 @@ BOOST_AUTO_TEST_CASE(formatter_boost_format)
log->messagebf(DEBUG, "plain %s", std::string("message"));
BOOST_REQUIRE_EQUAL(1, d->msgs.size());
BOOST_REQUIRE_EQUAL("plain message", d->msgs.front().message);
- BOOST_REQUIRE_EQUAL("test.domain", d->msgs.front().domain);
+ BOOST_REQUIRE_EQUAL(testDomain, d->msgs.front().domain);
}
AdHocFormatter(Plain, "plain %?.");
@@ -185,15 +208,15 @@ BOOST_AUTO_TEST_CASE(formatter_adhoc_compiletime)
log->messagectf<Plain>(DEBUG, "message");
BOOST_REQUIRE_EQUAL(1, d->msgs.size());
BOOST_REQUIRE_EQUAL("plain message.", d->msgs.front().message);
- BOOST_REQUIRE_EQUAL("test.domain", d->msgs.front().domain);
+ BOOST_REQUIRE_EQUAL(testDomain, d->msgs.front().domain);
}
BOOST_AUTO_TEST_CASE( domains_none )
{
// No domains
auto l = add(new TestLogWriter());
- BOOST_REQUIRE(!l->level("test"));
- BOOST_REQUIRE(!l->level("test.domain"));
+ BOOST_REQUIRE(!l->level(test));
+ BOOST_REQUIRE(!l->level(testDomain));
BOOST_REQUIRE(!l->lowestLevel());
}
@@ -201,8 +224,8 @@ BOOST_AUTO_TEST_CASE( domains_single )
{
// A single catch-all domain at the given level
auto l = add(new TestLogWriter(ERR));
- BOOST_REQUIRE_EQUAL(ERR, *l->level("test"));
- BOOST_REQUIRE_EQUAL(ERR, *l->level("test.domain"));
+ BOOST_REQUIRE_EQUAL(ERR, *l->level(test));
+ BOOST_REQUIRE_EQUAL(ERR, *l->level(testDomain));
BOOST_REQUIRE(l->lowestLevel());
BOOST_REQUIRE_EQUAL(ERR, *l->lowestLevel());
}
@@ -211,8 +234,8 @@ BOOST_AUTO_TEST_CASE( domains_fromNullProperties )
{
// A single catch-all domain at the default level (WARNING)
auto l = add(new TestLogWriter("", Ice::PropertiesPtr()));
- BOOST_REQUIRE_EQUAL(WARNING, *l->level("test"));
- BOOST_REQUIRE_EQUAL(WARNING, *l->level("test.domain"));
+ BOOST_REQUIRE_EQUAL(WARNING, *l->level(test));
+ BOOST_REQUIRE_EQUAL(WARNING, *l->level(testDomain));
BOOST_REQUIRE(l->lowestLevel());
BOOST_REQUIRE_EQUAL(WARNING, *l->lowestLevel());
}
@@ -226,10 +249,10 @@ BOOST_AUTO_TEST_CASE( domains_fromProperties )
p->setProperty("TestLogWriter.domains", "ignored");
p->setProperty("TestLogWriter.default", "WARNING");
auto l = add(new TestLogWriter("TestLogWriter", p));
- BOOST_REQUIRE_EQUAL(WARNING, *l->level("test"));
- BOOST_REQUIRE_EQUAL(WARNING, *l->level("other"));
- BOOST_REQUIRE_EQUAL(EMERG, *l->level("test.domain"));
- BOOST_REQUIRE_EQUAL(DEBUG, *l->level("test.debug"));
+ BOOST_REQUIRE_EQUAL(WARNING, *l->level(test));
+ BOOST_REQUIRE_EQUAL(WARNING, *l->level(other));
+ BOOST_REQUIRE_EQUAL(EMERG, *l->level(testDomain));
+ BOOST_REQUIRE_EQUAL(DEBUG, *l->level(testDebug));
BOOST_REQUIRE(l->lowestLevel());
BOOST_REQUIRE_EQUAL(DEBUG, *l->lowestLevel());
}
@@ -241,8 +264,8 @@ BOOST_AUTO_TEST_CASE( domains_fromProperties_noDefault )
p->setProperty("TestLogWriter.domains.test.domain", "EMERG");
p->setProperty("TestLogWriter.domains.test.debug", "DEBUG");
auto l = add(new TestLogWriter("TestLogWriter", p));
- BOOST_REQUIRE_EQUAL(EMERG, *l->level("test.domain"));
- BOOST_REQUIRE_EQUAL(DEBUG, *l->level("test.debug"));
+ BOOST_REQUIRE_EQUAL(EMERG, *l->level(testDomain));
+ BOOST_REQUIRE_EQUAL(DEBUG, *l->level(testDebug));
BOOST_REQUIRE(l->lowestLevel());
BOOST_REQUIRE_EQUAL(DEBUG, *l->lowestLevel());
}
@@ -253,10 +276,10 @@ BOOST_AUTO_TEST_CASE( domains_fromProperties_onlyDefault )
Ice::PropertiesPtr p = ic->getProperties();
p->setProperty("TestLogWriter.default", "INFO");
auto l = add(new TestLogWriter("TestLogWriter", p));
- BOOST_REQUIRE_EQUAL(INFO, *l->level("test"));
- BOOST_REQUIRE_EQUAL(INFO, *l->level("other"));
- BOOST_REQUIRE_EQUAL(INFO, *l->level("test.domain"));
- BOOST_REQUIRE_EQUAL(INFO, *l->level("test.debug"));
+ BOOST_REQUIRE_EQUAL(INFO, *l->level(test));
+ BOOST_REQUIRE_EQUAL(INFO, *l->level(other));
+ BOOST_REQUIRE_EQUAL(INFO, *l->level(testDomain));
+ BOOST_REQUIRE_EQUAL(INFO, *l->level(testDebug));
BOOST_REQUIRE(l->lowestLevel());
BOOST_REQUIRE_EQUAL(INFO, *l->lowestLevel());
}
@@ -289,7 +312,7 @@ BOOST_AUTO_TEST_CASE( getLogger )
this->start("test", ic, {});
auto logger = LOGMANAGER()->getLogger("test.domain");
BOOST_REQUIRE(logger);
- BOOST_REQUIRE_EQUAL("test.domain", logger->getDomain());
+ BOOST_REQUIRE_EQUAL(testDomain, logger->getDomain());
this->stop();
ic->destroy();
}
@@ -298,7 +321,8 @@ BOOST_AUTO_TEST_CASE( getLoggerForType )
{
auto logger = LOGMANAGER()->getLogger<IceTray::Service>();
BOOST_REQUIRE(logger);
- BOOST_REQUIRE_EQUAL("IceTray::Service", logger->getDomain());
+ Domain expected = {"IceTray", "Service"};
+ BOOST_REQUIRE_EQUAL(expected, logger->getDomain());
}
BOOST_AUTO_TEST_SUITE_END();
@@ -307,6 +331,55 @@ BOOST_AUTO_TEST_CASE( console )
{
IceTray::Logging::LogWriterPtr lwp =
IceTray::Logging::LogWriterFactory::createNew("ConsoleLogWriter", NULL);
- lwp->message(DEBUG, "some.domain", "some message");
+ lwp->message(DEBUG, testDomain, "some message");
+}
+
+BOOST_AUTO_TEST_CASE( consoleNoWidth )
+{
+ std::stringstream str;
+ ConsoleLogWriter::writeStream(str, -1, DEBUG, testDomain, "message");
+ BOOST_REQUIRE_EQUAL("DEBUG: test.domain: message\n", str.str());
+}
+
+BOOST_AUTO_TEST_CASE( consoleWidthJustRight )
+{
+ std::stringstream str;
+ ConsoleLogWriter::writeStream(str, 11, DEBUG, testDomain, "message");
+ BOOST_REQUIRE_EQUAL("DEBUG: test.domain: message\n", str.str());
+}
+
+BOOST_AUTO_TEST_CASE( consoleWidthSmall )
+{
+ std::stringstream str;
+ ConsoleLogWriter::writeStream(str, 10, DEBUG, testDomain, "message");
+ BOOST_REQUIRE_EQUAL("DEBUG: t.domain: message\n", str.str());
+}
+
+BOOST_AUTO_TEST_CASE( consoleWidthTiny )
+{
+ std::stringstream str;
+ ConsoleLogWriter::writeStream(str, 8, DEBUG, testDomain, "message");
+ BOOST_REQUIRE_EQUAL("DEBUG: t.domain: message\n", str.str());
+}
+
+BOOST_AUTO_TEST_CASE( consoleWidthTooTiny )
+{
+ std::stringstream str;
+ ConsoleLogWriter::writeStream(str, 7, DEBUG, testDomain, "message");
+ BOOST_REQUIRE_EQUAL("DEBUG: t.d: message\n", str.str());
+}
+
+BOOST_AUTO_TEST_CASE( consoleWidthOverflow )
+{
+ std::stringstream str;
+ ConsoleLogWriter::writeStream(str, 1, DEBUG, testDomain, "message");
+ BOOST_REQUIRE_EQUAL("DEBUG: t.d: message\n", str.str());
+}
+
+BOOST_AUTO_TEST_CASE( consoleNoDomain )
+{
+ std::stringstream str;
+ ConsoleLogWriter::writeStream(str, 0, DEBUG, {}, "message");
+ BOOST_REQUIRE_EQUAL("DEBUG: : message\n", str.str());
}