Forráskód Böngészése

Add tests and fix things to get support for log level in config

Sam Jaffe 6 éve
szülő
commit
a08986ed42

+ 1 - 3
include/logger/detail/appender.h

@@ -3,8 +3,7 @@
 #include "logger/logger_fwd.h"
 
 namespace logging {
-  class appender {
-  public:
+  struct appender {
     virtual ~appender() = default;
     virtual void write(std::string const & msg) = 0;
     virtual void flush() = 0;
@@ -13,7 +12,6 @@ namespace logging {
       return ll >= min_log_level;
     }
     
-  protected:
     level min_log_level;
   };
 }

+ 2 - 2
include/logger/detail/logger_impl.h

@@ -18,7 +18,7 @@ namespace logging {
     void write(logpacket const & pkt);
     void flush();
 
-    std::vector<std::pair<p_appender, p_layout>> impls_;
-    level min_log_level_;
+    std::vector<std::pair<p_appender, p_layout>> impls;
+    level min_log_level;
   };
 }

+ 5 - 0
include/logger/exception.h

@@ -21,4 +21,9 @@ namespace logging {
   public:
     using std::logic_error::logic_error;
   };
+
+  class invalid_property : public std::logic_error {
+  public:
+    using std::logic_error::logic_error;
+  };
 }

+ 2 - 2
include/logger/logger_fwd.h

@@ -11,10 +11,10 @@
 
 namespace logging {
 #define LIST_OF_LOGGING_LEVELS \
-  X(trace) X(debug) X(info) X(warning) X(error) X(critical) X(fatal)
+  X(trace) X(debug) X(info) X(warning) X(error) X(critical) X(fatal) X(none)
 #define X(token) token,
   enum class level : int {
-    LIST_OF_LOGGING_LEVELS none, warn = warning
+    LIST_OF_LOGGING_LEVELS warn = warning
   };
 #undef X
   std::ostream & operator<<(std::ostream & os, level l);

+ 0 - 1
src/c_logger.cxx

@@ -34,7 +34,6 @@ void c_logger::vlognf(level level, size_t num_bytes, char const* fmt,
 }
 
 void c_logger::log(level level, std::string const& msg) {
-  if (!impl_->should_log(level)) return;
   impl_->write({ now(), level, {}, logger_name_, msg });
 }
 

+ 6 - 3
src/common.cxx

@@ -10,6 +10,8 @@
 #include <cassert>
 #include <ctime>
 
+#include "logger/exception.h"
+
 namespace logging {
   timeval now() {
     struct timeval tv;
@@ -20,16 +22,17 @@ namespace logging {
 #define X(token) if (lower_case == #token) return level::token; else
   level level_from_string(std::string const & str) {
     std::string lower_case;
-    std::transform(str.begin(), str.end(), lower_case.begin(), &tolower);
+    std::transform(str.begin(), str.end(),
+                   std::back_inserter(lower_case), &tolower);
     LIST_OF_LOGGING_LEVELS
-    return level::none;
+    throw invalid_property{str + " is not a log level"};
   }
 #undef X
   
 #define X(token) if (lvl == level::token) return #token; else
   char const * level_to_string(level lvl) {
     LIST_OF_LOGGING_LEVELS
-    return "";
+    throw std::domain_error{"unknown logging level in switch"};
   }
 #undef X
   

+ 18 - 4
src/log_manager.cxx

@@ -13,7 +13,9 @@
 #include "../../../paradigm/declarative/expect/include/expect/expect.hpp"
 #include "../../../types/resource_factory/include/resource_factory/prototype_factory.hpp"
 
+#include "common.h"
 #include "logger/c_logger.h"
+#include "logger/detail/appender.h"
 #include "logger/exception.h"
 #include "logger/logger.h"
 #include "logger/properties.h"
@@ -43,10 +45,10 @@ manager_impl::get_logger(properties const & props) {
   auto out = std::make_shared<logger_impl>();
   if (props.type == properties::OBJECT) {
     // TODO include settings on the parent
-    out->impls_.push_back(appenders.at(props["ref"]));
+    out->impls.push_back(appenders.at(props["ref"]));
   } else if (props.type == properties::ARRAY) {
     for (auto & part : props.array) {
-      out->impls_.push_back(appenders.at(part["ref"]));
+      out->impls.push_back(appenders.at(part["ref"]));
     }
   } else {
     throw invalid_property_type{"appenders cannot be a STRING"};
@@ -73,6 +75,13 @@ static p_layout load_layout(std::string const & source,
   return layouts::instance().get("default", {});
 }
 
+template <typename T>
+void inject_log_level(properties const & props, T & val) {
+  if (props.obj.count("level")) {
+    val.min_log_level = level_from_string(props["level"]);
+  }
+}
+
 void manager_impl::configure_appenders(properties const & props) {
   // TODO: Load logger_impl here
   // TODO: Support multiple File loggers, etc.
@@ -80,6 +89,7 @@ void manager_impl::configure_appenders(properties const & props) {
   for (auto & app : props["appenders"].obj) {
     auto pair = std::make_pair(load_appender(app.first, app.second),
                                load_layout(app.first, app.second));
+    inject_log_level(app.second, *pair.first);
     appenders.emplace(app.first, pair);
   }
 }
@@ -87,9 +97,13 @@ void manager_impl::configure_appenders(properties const & props) {
 void manager_impl::configure_loggers(properties const & props) {
   expects(props["loggers"].type == properties::OBJECT);
   for (auto & log : props["loggers"].obj) {
-    loggers.emplace(log.first, get_logger(log.second["appenders"]));
+    auto plog = get_logger(log.second["appenders"]);
+    inject_log_level(log.second, *plog);
+    loggers.emplace(log.first, plog);
+  }
+  if (loggers.count("root")) {
+    default_logger = loggers["root"];
   }
-  default_logger = get_logger(props["loggers"]["root"]["appenders"]);
 }
 
 manager::manager() : pimpl_(new manager_impl) {}

+ 4 - 3
src/logger_impl.cxx

@@ -13,11 +13,12 @@
 using namespace logging;
 
 bool logger_impl::should_log(level ll) const {
-  return ll >= min_log_level_;
+  return ll >= min_log_level;
 }
 
 void logger_impl::write(logpacket const & pkt) {
-  for (auto & pair : impls_) {
+  if (!should_log(pkt.level)) return;
+  for (auto & pair : impls) {
     if (pair.first->should_log(pkt.level)) {
       pair.first->write(pair.second->format(pkt));
     }
@@ -25,7 +26,7 @@ void logger_impl::write(logpacket const & pkt) {
 }
 
 void logger_impl::flush() {
-  for (auto & pair : impls_) {
+  for (auto & pair : impls) {
     pair.first->flush();
   }
 }

+ 2 - 2
test/c_logger_test.cxx

@@ -63,14 +63,14 @@ TEST_F(CLoggerTest, LogsRawData) {
 
 TEST_F(CLoggerTest, DoesNotLogAboveLevel) {
   using testing::_;
-  pimpl->min_log_level_ = level::fatal;
+  pimpl->min_log_level = level::fatal;
   EXPECT_CALL(*appender, write(_)).Times(0);
   t_logger("", pimpl).errorf("%d", 5);
 }
 
 TEST_F(CLoggerTest, DoesNotRawLogAboveLevel) {
   using testing::_;
-  pimpl->min_log_level_ = level::fatal;
+  pimpl->min_log_level = level::fatal;
   EXPECT_CALL(*appender, write(_)).Times(0);
   t_logger("", pimpl).error("5");
 }

+ 31 - 6
test/log_manager_test.cxx

@@ -43,6 +43,8 @@ void LogManagerTest::TearDown() {
   lbinding_.reset();
 }
 
+extern properties const APPENDER_LEVEL_PROPERTY_SCHEMA;
+extern properties const LOGGER_LEVEL_PROPERTY_SCHEMA;
 extern properties const MIN_PROPERTY_SCHEMA;
 extern properties const MULTIPLEX_PROPERTY_SCHEMA;
 
@@ -54,13 +56,13 @@ TEST_F(LogManagerTest, CanInjectMock) {
   EXPECT_THAT(appender, ::testing::NotNull());
 }
 
+using ::testing::_;
+using ::testing::AnyNumber;
+
 TEST_F(LogManagerTest, CanFetchInjectedMock) {
   manager mgr;
   mgr.configure(MIN_PROPERTY_SCHEMA);
   
-  using ::testing::_;
-  using ::testing::AnyNumber;
-  using ::testing::Field;
   EXPECT_CALL(*appender, flush()).Times(AnyNumber());
   EXPECT_CALL(*appender, write("TEST MESSAGE"));
   EXPECT_CALL(*layout, format(_)).WillRepeatedly(ReturnMessage());
@@ -73,9 +75,6 @@ TEST_F(LogManagerTest, MultiplexMockLogsToMultipleImpls) {
   manager mgr;
   mgr.configure(MULTIPLEX_PROPERTY_SCHEMA);
   
-  using ::testing::_;
-  using ::testing::AnyNumber;
-  using ::testing::Field;
   EXPECT_CALL(*appender, flush()).Times(AnyNumber());
   EXPECT_CALL(*appender, write("TEST MESSAGE")).Times(2);
   EXPECT_CALL(*layout, format(_)).WillRepeatedly(ReturnMessage());
@@ -83,3 +82,29 @@ TEST_F(LogManagerTest, MultiplexMockLogsToMultipleImpls) {
   c_logger l = mgr.c_get();
   l.error("TEST MESSAGE");
 }
+
+TEST_F(LogManagerTest, LevelCanBeBakedIntoAppenderProperties) {
+  manager mgr;
+  mgr.configure(APPENDER_LEVEL_PROPERTY_SCHEMA);
+  
+  EXPECT_CALL(*appender, flush()).Times(AnyNumber());
+  EXPECT_CALL(*appender, write("TEST MESSAGE")).Times(1);
+  EXPECT_CALL(*appender, write("LOWER MESSAGE")).Times(0);
+  EXPECT_CALL(*layout, format(_)).WillRepeatedly(ReturnMessage());
+  
+  c_logger l = mgr.c_get();
+  l.warn("TEST MESSAGE");
+  l.info("LOWER MESSAGE");
+}
+
+TEST_F(LogManagerTest, LevelCanBeBakedIntoLoggerProperties) {
+  manager mgr;
+  mgr.configure(LOGGER_LEVEL_PROPERTY_SCHEMA);
+  
+  EXPECT_CALL(*appender, flush()).Times(AnyNumber());
+  EXPECT_CALL(*appender, write("TEST MESSAGE")).Times(0);
+  EXPECT_CALL(*layout, format(_)).Times(0);
+  
+  c_logger l = mgr.c_get();
+  l.warn("TEST MESSAGE");
+}

+ 1 - 1
test/logger_test.cxx

@@ -36,7 +36,7 @@ TEST_F(LoggerTest, LogsWithBraceFmtCode) {
 
 TEST_F(LoggerTest, DoesNotLogAboveLevel) {
   using testing::_;
-  pimpl->min_log_level_ = level::fatal;
+  pimpl->min_log_level = level::fatal;
   EXPECT_CALL(*appender, write(_)).Times(0);
   t_logger("", pimpl).log(level::error, "{}", 5);
 }

+ 1 - 1
test/mock_logger.h

@@ -51,7 +51,7 @@ struct LoggerTest : public testing::Test {
     appender.reset(new MockAppender);
     layout.reset(new MockLayout);
     pimpl = std::make_shared<logging::logger_impl>();
-    pimpl->impls_.push_back({appender, layout});
+    pimpl->impls.push_back({appender, layout});
     
     using testing::_;
     using testing::AnyNumber;

+ 39 - 0
test/test_properties.cxx

@@ -21,6 +21,8 @@ namespace {
   }
 }
 
+extern properties const APPENDER_LEVEL_PROPERTY_SCHEMA;
+extern properties const LOGGER_LEVEL_PROPERTY_SCHEMA;
 extern properties const MIN_PROPERTY_SCHEMA;
 extern properties const MULTIPLEX_PROPERTY_SCHEMA;
 
@@ -41,6 +43,43 @@ properties const MIN_PROPERTY_SCHEMA{_property({
   })}
 })};
 
+properties const APPENDER_LEVEL_PROPERTY_SCHEMA{_property({
+  {"configuration", _property({
+    {"appenders", _property({
+      {"Mock", _property({
+        {"level", _value("Warning")},
+        {"MockLayout", _value("")}
+      })}
+    })},
+    {"loggers", _property({
+      {"root", _property({
+        {"appenders", _property({
+          {"ref", _value("Mock")}
+        })}
+      })}
+    })}
+  })}
+})};
+
+properties const LOGGER_LEVEL_PROPERTY_SCHEMA{_property({
+  {"configuration", _property({
+    {"appenders", _property({
+      {"Mock", _property({
+        {"level", _value("Warning")},
+        {"MockLayout", _value("")}
+      })}
+    })},
+    {"loggers", _property({
+      {"root", _property({
+        {"level", _value("Error")},
+        {"appenders", _property({
+          {"ref", _value("Mock")}
+        })}
+      })}
+    })}
+  })}
+})};
+
 properties const MULTIPLEX_PROPERTY_SCHEMA{_property({
   {"configuration", _property({
     {"appenders", _property({