소스 검색

Add some documentation, make loggers easier to use.

Sam Jaffe 5 년 전
부모
커밋
75ddb5c076
6개의 변경된 파일64개의 추가작업 그리고 13개의 파일을 삭제
  1. 15 3
      include/logger/c_logger.h
  2. 13 0
      include/logger/log_manager.h
  3. 22 5
      include/logger/logger.h
  4. 3 0
      src/data_accessors.cxx
  5. 8 2
      src/log_manager.cxx
  6. 3 3
      test/log_manager_test.cxx

+ 15 - 3
include/logger/c_logger.h

@@ -37,6 +37,21 @@ namespace logging {
   enum class level : int;
   class logger_impl;
 
+  /**
+   * A simple logger interface that is used for performing C-Style logging a la
+   * printf()/nprintf().
+   * TODO: Add the option to provide location_info with the log_here macro
+   * Unlink the logging::logger class, this class only provides access to its
+   * logging methods through functions like warn(), error(), fatal(), etc.
+   * Each of these functions corresponds to a logging::level enum, and
+   * constructs its message by calling vsnprintf() under the hood.
+   * Overrides for no formatting, std::string inputs, and explicitly sizing the
+   * storage buffer are made available with the following function names e.g.:
+   * error("This is a string")              -> logs "This is a string"
+   * error(std::string("This is a string")) -> logs "This is a string"
+   * errorf("This is a %s", "string")       -> logs "This is a string"
+   * errornf(14, "This is a %s", "string")  -> logs "This is a str"
+   */
   class c_logger {
   private:
     friend class manager;
@@ -55,9 +70,6 @@ namespace logging {
     MAKE_LOGGER_FMT(critical)
     MAKE_LOGGER_FMT(fatal)
 
-    template <typename... Args>
-    inline void log(level ll, std::string const & interp, Args &&... args);
-
     void flush();
 
     ~c_logger();

+ 13 - 0
include/logger/log_manager.h

@@ -21,6 +21,13 @@ namespace logging {
   class logger;
   class properties;
 
+  /**
+   * A singleton object that is designed for use constructing the various
+   * loggers. At program start time, the programmer should provide the
+   * configuration properties to the manager. Once the configuration has been
+   * applied, you can then request loggers from the system.
+   * TODO: Have manager automatically check certain locations for a config file
+   */
   class manager {
   private:
     std::unique_ptr<struct manager_impl> pimpl_;
@@ -28,6 +35,12 @@ namespace logging {
   public:
     static manager & instance();
 
+    /**
+     * Functions to construct logger handles for use. When providing an unknown
+     * logger name, the default logger_impl will be used instead (with the given
+     * name wrapped around it).
+     * TODO: Make it so I can use name = "" instead...
+     */
     logger get();
     logger get(std::string const & name);
     c_logger c_get();

+ 22 - 5
include/logger/logger.h

@@ -34,6 +34,21 @@ namespace logging {
   class logger_impl;
   struct logpacket;
 
+  /*
+   * The main top-level class that should be used when performing logging.
+   * Provides various overrides of the function log() that handle various use
+   * cases. In comparison with the C-Style logger, this one uses a Python style
+   * of string formatting.
+   * Currently, it is only able to support "{}", and cannot use positional,
+   * named, or reflection-based interpolations. Under the hood, the loggers are
+   * configured in a similar fashion to those in Log4J, such as PatternLayout
+   * and FileAppender.
+   * One of the useful features of this logger is the log_here macro. Log here
+   * uses the compiler to generate all of the necessary information for file
+   * name, class/namespace path, method name, and line number. It is not
+   * supported for the logger to learn that information on its own through
+   * creating a backtrace.
+   */
   class logger {
   private:
     friend class manager;
@@ -43,25 +58,27 @@ namespace logging {
   public:
     ~logger();
 
+    void log(level ll, char const * str) { log(ll, message(str)); }
+    void log(level ll, std::string const & str) { log(ll, message(str)); }
+
     template <typename... Args>
-    inline void log(level ll, std::string const & interp, Args &&... args) {
+    void log(level ll, std::string const & interp, Args &&... args) {
       log(ll, message(interp, std::forward<Args>(args)...));
     }
 
     template <typename... Args>
-    inline void log(level ll, location_info const & info,
-                    std::string const & interp, Args &&... args) {
+    void log(level ll, location_info const & info, std::string const & interp,
+             Args &&... args) {
       log(ll, info, message(interp, std::forward<Args>(args)...));
     }
 
-    void log(level ll, message const &);
-
     void flush();
 
   protected:
     logger(std::string const & name, std::shared_ptr<logger_impl> impl);
 
   private:
+    void log(level ll, message const &);
     void log(level ll, location_info const & info, message const &);
   };
 }

+ 3 - 0
src/data_accessors.cxx

@@ -53,6 +53,9 @@ namespace logging { namespace detail {
   std::vector<std::string>
   calling_class_helper::full_name(logpacket const & packet) const {
     std::string pf = packet.info.pretty_function;
+    // Note for the future: If this is missing, search instead for the first
+    // match of the regex /[a-zA-Z]\(/ on GCC (__PRETTY_FUNCTION__ doesn't put
+    // template information between the func name and the parens).
     std::string func = std::string(packet.info.function) + "(";
     // If this is a function in the global namespace, return just the empty str
     if (pf[pf.find(func) - 1] == ' ') { return {""}; }

+ 8 - 2
src/log_manager.cxx

@@ -32,6 +32,7 @@ struct logging::manager_impl {
   template <typename V> using cache = std::unordered_map<std::string, V>;
 
   manager_impl();
+  p_logger logger_for(std::string const & name);
   p_logger get_logger(properties const & props);
   void configure_appenders(properties const & props);
   void configure_loggers(properties const & props);
@@ -46,6 +47,11 @@ manager_impl::manager_impl() {
   configure_loggers(DEFAULT_LOGGER_SCHEMA);
 }
 
+p_logger manager_impl::logger_for(std::string const & name) {
+  auto it = loggers.find(name);
+  return (it != loggers.end()) ? it->second : default_logger;
+}
+
 std::shared_ptr<logger_impl>
 manager_impl::get_logger(properties const & props) {
   auto out = std::make_shared<logger_impl>();
@@ -112,13 +118,13 @@ manager::~manager() {}
 logger manager::get() { return logger("", pimpl_->default_logger); }
 
 logger manager::get(std::string const & name) {
-  return logger(name, pimpl_->loggers.at(name));
+  return logger(name, pimpl_->logger_for(name));
 }
 
 c_logger manager::c_get() { return c_logger("", pimpl_->default_logger); }
 
 c_logger manager::c_get(std::string const & name) {
-  return c_logger(name, pimpl_->loggers.at(name));
+  return c_logger(name, pimpl_->logger_for(name));
 }
 
 void manager::configure(properties const & props) {

+ 3 - 3
test/log_manager_test.cxx

@@ -151,10 +151,10 @@ TEST_F(LogManagerTest, CanFetchLoggerByName) {
   l.error("TEST MESSAGE");
 }
 
-TEST_F(LogManagerTest, ThrowsIfAskingForNonExistantLoggerName) {
+TEST_F(LogManagerTest, ReturnsDefaultLoggerIfUnknownName) {
   manager mgr;
   mgr.configure(MIN_PROPERTY_SCHEMA);
 
-  EXPECT_THROW(mgr.c_get("Mock"), std::out_of_range);
-  EXPECT_THROW(mgr.get("Mock"), std::out_of_range);
+  EXPECT_NO_THROW(mgr.c_get("Mock"));
+  EXPECT_NO_THROW(mgr.get("Mock"));
 }