From d45efb9de474b625fddaab5914c5c5c6955e9c7a Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 12 Jun 2017 20:44:02 +0100 Subject: Add support for configured installed log writers on start-up from properties in the Communicator --- icetray/icetray/Jamfile.jam | 1 + icetray/icetray/icetrayService.cpp | 4 + icetray/icetray/logger.cpp | 57 +++++++++++++- icetray/icetray/logger.h | 19 ++++- icetray/unittests/testIceTrayLogger.cpp | 127 ++++++++++++++++++++++++-------- 5 files changed, 174 insertions(+), 34 deletions(-) diff --git a/icetray/icetray/Jamfile.jam b/icetray/icetray/Jamfile.jam index 42f5389..7944202 100644 --- a/icetray/icetray/Jamfile.jam +++ b/icetray/icetray/Jamfile.jam @@ -15,6 +15,7 @@ lib icetray : ..//boost_thread ../..//glibmm yes + yes : : . ..//dbppcore diff --git a/icetray/icetray/icetrayService.cpp b/icetray/icetray/icetrayService.cpp index 8353fd2..d540d7a 100644 --- a/icetray/icetray/icetrayService.cpp +++ b/icetray/icetray/icetrayService.cpp @@ -29,6 +29,10 @@ namespace IceTray { void Service::start(const std::string & name, const Ice::CommunicatorPtr & ic, const Ice::StringSeq & args) { adp = ic->createObjectAdapter(name); + for (auto logWriterFactory : AdHoc::PluginManager::getDefault()->getAll()) { + auto logWriter = logWriterFactory->implementation()->create(ic->getProperties().get()); + logManager.addWriter(Logging::LogWriterPrx::uncheckedCast(adp->addWithUUID(logWriter))); + } addObjects(name, ic, args, adp); adp->activate(); } diff --git a/icetray/icetray/logger.cpp b/icetray/icetray/logger.cpp index b4cf629..aac966a 100644 --- a/icetray/icetray/logger.cpp +++ b/icetray/icetray/logger.cpp @@ -2,8 +2,12 @@ #include #include #include +#include +#include +#include +#include -INSTANTIATEFACTORY(IceTray::Logging::LogWriter, Ice::CommunicatorPtr); +INSTANTIATEFACTORY(IceTray::Logging::LogWriter, Ice::Properties *); namespace IceTray { namespace Logging { @@ -131,6 +135,57 @@ namespace IceTray { logger->logs = getLogsForDomain(logger->domain); } } + + AbstractLogWriter::AbstractLogWriter() + { + } + + AbstractLogWriter::AbstractLogWriter(LogLevel level) + { + logDomains.insert({ { }, level }); + } + + AbstractLogWriter::AbstractLogWriter(const std::string & prefix, Ice::PropertiesPtr p) + { + if (!p || prefix.empty()) { + logDomains.insert({ { }, WARNING }); + return; + } + auto domainsPrefix = prefix + ".domains."; + auto map = p->getPropertiesForPrefix(domainsPrefix); + for (const auto & d : map) { + auto level = Slicer::ModelPartForEnum::lookup(d.second); + auto domain = d.first.substr(domainsPrefix.length()); + logDomains.insert({ splitDomain(domain), level }); + } + auto defaultLevel = p->getProperty(prefix + ".default"); + if (!defaultLevel.empty()) { + auto level = Slicer::ModelPartForEnum::lookup(defaultLevel); + logDomains.insert({ {}, level }); + } + } + + IceUtil::Optional + AbstractLogWriter::level(const std::string & 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)) { + return d->second; + } + } + return IceUtil::None; + } + + Ice::StringSeq + AbstractLogWriter::splitDomain(const std::string & domain) + { + if (domain.empty()) return Ice::StringSeq(); + + Ice::StringSeq domainTokens; + boost::algorithm::split(domainTokens, domain, boost::algorithm::is_any_of(".:"), boost::algorithm::token_compress_on); + return domainTokens; + } } } diff --git a/icetray/icetray/logger.h b/icetray/icetray/logger.h index cb16852..c435644 100644 --- a/icetray/icetray/logger.h +++ b/icetray/icetray/logger.h @@ -8,6 +8,7 @@ #include #include #include +#include namespace IceTray { namespace Logging { @@ -79,7 +80,23 @@ namespace IceTray { LogWriters logWriters; }; - typedef AdHoc::Factory LogWriterFactory; + class DLL_PUBLIC AbstractLogWriter : public LogWriter { + public: + IceUtil::Optional level(const std::string &, const Ice::Current &) override; + + protected: + AbstractLogWriter(); + AbstractLogWriter(LogLevel level); + AbstractLogWriter(const std::string & prefix, Ice::PropertiesPtr p); + + typedef std::map LogDomains; + LogDomains logDomains; + + private: + static Ice::StringSeq splitDomain(const std::string &); + }; + + typedef AdHoc::Factory LogWriterFactory; } } diff --git a/icetray/unittests/testIceTrayLogger.cpp b/icetray/unittests/testIceTrayLogger.cpp index 321a878..e1a62a5 100644 --- a/icetray/unittests/testIceTrayLogger.cpp +++ b/icetray/unittests/testIceTrayLogger.cpp @@ -8,40 +8,37 @@ #include #include #include +#include using namespace IceTray::Logging; struct LogEntry { + LogLevel priority; std::string domain; std::string message; }; -class TestLogWriter : public LogWriter { +class TestLogWriter : public AbstractLogWriter { public: - TestLogWriter(LogLevel ll) : - calls(0), - l(ll) + template + TestLogWriter(const T & ... t) : + AbstractLogWriter(t...) { } - IceUtil::Optional level(const std::string &, const Ice::Current &) override + TestLogWriter(Ice::Properties * p) : + AbstractLogWriter("TestLogWriter", p) { - return l; } void message(LogLevel priority, const std::string & domain, const std::string & message, const Ice::Current &) override { - calls += 1; - BOOST_REQUIRE(l >= priority); - msgs.push_back({domain, message}); + msgs.push_back({priority, domain, message}); } std::vector msgs; - unsigned int calls; - - private: - const LogLevel l; }; +FACTORY(TestLogWriter, LogWriterFactory); class TestLogImpl { public: @@ -68,9 +65,9 @@ class TestLogImpl { protected: LoggerPtr log; LogManager manager; + Ice::CommunicatorPtr ic; private: - Ice::CommunicatorPtr ic; Ice::ObjectAdapterPtr adp; }; @@ -94,57 +91,48 @@ BOOST_AUTO_TEST_CASE(priority_filtering) { log->message(DEBUG, "debug"); BOOST_REQUIRE(w->msgs.empty()); BOOST_REQUIRE(e->msgs.empty()); - BOOST_REQUIRE_EQUAL(0, w->calls); - BOOST_REQUIRE_EQUAL(0, e->calls); log->message(INFO, "into"); BOOST_REQUIRE(w->msgs.empty()); BOOST_REQUIRE(e->msgs.empty()); - BOOST_REQUIRE_EQUAL(0, w->calls); - BOOST_REQUIRE_EQUAL(0, e->calls); log->message(NOTICE, "notice"); BOOST_REQUIRE(w->msgs.empty()); BOOST_REQUIRE(e->msgs.empty()); - BOOST_REQUIRE_EQUAL(0, w->calls); - BOOST_REQUIRE_EQUAL(0, e->calls); log->message(WARNING, "warning"); BOOST_REQUIRE_EQUAL(1, w->msgs.size()); BOOST_REQUIRE(e->msgs.empty()); - BOOST_REQUIRE_EQUAL(1, w->calls); - BOOST_REQUIRE_EQUAL(0, e->calls); log->message(ERR, "err"); BOOST_REQUIRE_EQUAL(2, w->msgs.size()); BOOST_REQUIRE_EQUAL(1, e->msgs.size()); - BOOST_REQUIRE_EQUAL(2, w->calls); - BOOST_REQUIRE_EQUAL(1, e->calls); log->message(CRIT, "crit"); BOOST_REQUIRE_EQUAL(3, w->msgs.size()); BOOST_REQUIRE_EQUAL(2, e->msgs.size()); - BOOST_REQUIRE_EQUAL(3, w->calls); - BOOST_REQUIRE_EQUAL(2, e->calls); log->message(ALERT, "alert"); BOOST_REQUIRE_EQUAL(4, w->msgs.size()); BOOST_REQUIRE_EQUAL(3, e->msgs.size()); - BOOST_REQUIRE_EQUAL(4, w->calls); - BOOST_REQUIRE_EQUAL(3, e->calls); log->message(EMERG, "emerg"); BOOST_REQUIRE_EQUAL(5, w->msgs.size()); BOOST_REQUIRE_EQUAL(4, e->msgs.size()); - BOOST_REQUIRE_EQUAL(5, w->calls); - BOOST_REQUIRE_EQUAL(4, e->calls); manager.removeWriter(wp); log->message(ERR, "err2"); BOOST_REQUIRE_EQUAL(5, w->msgs.size()); BOOST_REQUIRE_EQUAL(5, e->msgs.size()); - BOOST_REQUIRE_EQUAL(5, w->calls); - BOOST_REQUIRE_EQUAL(5, e->calls); +} + +BOOST_AUTO_TEST_CASE( no_domains ) +{ + auto d = new TestLogWriter(); + manager.addWriter(add(d)); + log->message(DEBUG, "debug message."); + log->message(EMERG, "emergency message."); + BOOST_REQUIRE(d->msgs.empty()); } BOOST_AUTO_TEST_CASE(formatter_plain) @@ -188,6 +176,77 @@ BOOST_AUTO_TEST_CASE(formatter_adhoc_compiletime) BOOST_REQUIRE_EQUAL("test.domain", 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_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_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_AUTO_TEST_CASE( domains_fromProperties ) +{ + // Domains configured according to properties + Ice::PropertiesPtr p = ic->getProperties(); + p->setProperty("TestLogWriter.domains.test.domain", "EMERG"); + p->setProperty("TestLogWriter.domains.test.debug", "DEBUG"); + 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_AUTO_TEST_CASE( domains_fromProperties_noDefault ) +{ + // Domains configured according to properties + Ice::PropertiesPtr p = ic->getProperties(); + 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_AUTO_TEST_CASE( domains_fromProperties_onlyDefault ) +{ + // Domains configured according to properties + 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_AUTO_TEST_CASE( domains_fromProperties_badLevel ) +{ + Ice::PropertiesPtr p = ic->getProperties(); + p->setProperty("TestLogWriter.domains.test.domain", "BAD"); + BOOST_REQUIRE_THROW({ + TestLogWriter tlw("TestLogWriter", p); + }, Slicer::InvalidEnumerationSymbol); +} + BOOST_AUTO_TEST_SUITE_END(); class TestService : public IceTray::Service { @@ -201,8 +260,12 @@ BOOST_FIXTURE_TEST_SUITE( ts, TestService ); BOOST_AUTO_TEST_CASE( getLogger ) { + auto ic = Ice::initialize(); + ic->getProperties()->setProperty("test.Endpoints", "default"); + this->start("test", ic, {}); auto logger = LOGMANAGER()->getLogger("test.domain"); BOOST_REQUIRE(logger); + ic->destroy(); } BOOST_AUTO_TEST_SUITE_END(); -- cgit v1.2.3