瀏覽代碼

Switching this project to use the interpolation-formatted logger.

Samuel Jaffe 9 年之前
父節點
當前提交
f41beecf7f

+ 0 - 71
console_logger.cpp

@@ -1,71 +0,0 @@
-//
-//  stdout_logger.cpp
-//  logger
-//
-//  Created by Sam Jaffe on 10/2/15.
-//
-//
-
-#include <iostream>
-#include <stdexcept>
-
-#include "logger.hpp"
-#include "default_logger_binding.hpp"
-#include "properties.hpp"
-
-namespace logging {
-  
-  namespace {
-    std::string validate_or_throw(logging::properties const& props) {
-      if (props.type != properties::OBJECT) {
-        throw std::logic_error{"expected properties to be a map"};
-      }
-      auto it = props.obj.find("target");
-      if (it == props.obj.end()) {
-        throw std::logic_error{"expected a console target entry"};
-      } else if (it->second.type != properties::STRING) {
-        throw std::logic_error{"expected properties[\"target\"] to be a string"};
-      }
-      return it->second.value;
-    }
-  }
-  
-  class console_logger : public logger_impl {
-  public:
-    static std::unique_ptr<logger_impl> create(properties const& props);
-    
-    console_logger(std::ostream& os);
-    
-    void write(log_level level, std::string const& msg) override;
-    
-    void flush() override;
-  private:
-    std::ostream& out_;
-  };
-      
-  std::unique_ptr<logger_impl> console_logger::create(properties const& props) {
-    const std::string target = validate_or_throw(props);
-    if (target == "SYSTEM_OUT") {
-      return std::unique_ptr<logger_impl>(new console_logger(std::cout));
-    } else if (target == "SYSTEM_ERR") {
-      return std::unique_ptr<logger_impl>(new console_logger(std::cerr));
-    } else {
-      throw std::logic_error{target + " is not a valid console"};
-    }
-  }
-  
-  console_logger::console_logger(std::ostream& os) : out_(os) {}
-  
-  void console_logger::write(log_level level, std::string const& msg) {
-    out_ << msg;
-  }
-  
-    void console_logger::flush() {
-    out_.flush();
-  }
-
-  
-  namespace {
-    bool _ = default_logger_impl::register_impl("Console", console_logger::create);
-  }
-}

+ 0 - 56
default_logger_binding.cpp

@@ -1,56 +0,0 @@
-//
-//  logger_binding.cpp
-//  logger
-//
-//  Created by Sam Jaffe on 10/3/15.
-//
-//
-
-#include "default_logger_binding.hpp"
-
-#include <functional>
-#include <algorithm>
-
-namespace logging {
-  namespace {
-    void flush(appender & ptr) {
-      ptr.flush();
-    }
-    
-    void write(log_level level, std::string const& msg, appender & ptr) {
-      ptr.write(level, msg);
-    }
-  }
-  
-  logger_impl& default_logger_impl::instance() {
-    static default_logger_impl s;
-    return s;
-  }
-  
-  bool default_logger_impl::register_impl(const std::string &name, std::unique_ptr<logger_impl> (*factory)(const logging::properties &)) {
-    return false; // TODO
-  }
-  
-  void default_logger_impl::write(log_level level, std::string const& msg) {
-    using namespace std::placeholders;
-    std::for_each(streams_.begin(), streams_.end(),
-                  std::bind(logging::write, level, std::ref(msg), _1));
-  }
-  void default_logger_impl::flush() {
-    std::for_each(streams_.begin(), streams_.end(), logging::flush);
-  }
-  
-  _binding _default_logger_impl = &default_logger_impl::instance;
-}
-
-namespace logging {
-  appender::appender(logger_impl* impl) : target_(impl) {}
-  
-  void appender::write(logging::log_level level, const std::string &msg) {
-    target_->write(level, msg);
-  }
-  
-  void appender::flush() {
-    target_->flush();
-  }
-}

+ 0 - 42
default_logger_binding.hpp

@@ -1,42 +0,0 @@
-//
-//  default_logger_binding.hpp
-//  logger
-//
-//  Created by Sam Jaffe on 10/3/15.
-//
-//
-
-#pragma once
-
-#include "logger.hpp"
-
-#include <vector>
-
-namespace logging {
-  struct properties;
-  class appender;
-  
-  class default_logger_impl : public logger_impl {
-  public:
-    static bool register_impl(std::string const&,std::unique_ptr<logger_impl>(*)(logging::properties const&));
-
-    static logger_impl& instance();
-    
-    typedef std::vector<appender> datatype;
-    typedef datatype::iterator iterator;
-    
-    void write(log_level level, std::string const& msg) override;
-    void flush() override;
-  private:
-    datatype streams_;
-  };
-  
-  class appender : public logger_impl {
-  public:
-    appender(logger_impl*);
-    void write(log_level level, std::string const& msg) override;
-    void flush() override;
-  private:
-    logger_impl* target_;
-  };
-}

+ 0 - 46
file_logger.cpp

@@ -1,46 +0,0 @@
-//
-//  file_logger.cpp
-//  logger
-//
-//  Created by Sam Jaffe on 10/2/15.
-//
-//
-
-#include "logger.hpp"
-#include "default_logger_binding.hpp"
-
-#include <fstream>
-
-namespace logging {
-  class file_logger : public logger_impl {
-  public:
-    static std::unique_ptr<logger_impl> create(logging::properties const&);
-  
-    file_logger(const std::string& fname);
-  
-    void write(log_level level, std::string const& msg) override;
-    void flush() override;
-  private:
-    std::ofstream out_;
-  };
-      
-  std::unique_ptr<logger_impl> file_logger::create(properties const&) {
-    return std::unique_ptr<logger_impl>(); // TODO
-  }
-  
-  file_logger::file_logger(const std::string& fname)
-  : out_(fname) {}
-  
-  void file_logger::write(log_level level, std::string const& msg) {
-    out_ << msg;
-  }
-  
-  void file_logger::flush() {
-    out_.flush();
-  }
-  
-
-  namespace {
-    bool _ = default_logger_impl::register_impl("File", file_logger::create);
-  }
-}

+ 212 - 0
format.cpp

@@ -0,0 +1,212 @@
+//
+//  format.cpp
+//  logger
+//
+//  Created by Sam Jaffe on 8/21/16.
+//
+
+#include <cstdint>
+#include <cstring>
+#include <ctime>
+#include <iomanip>
+#include <iostream>
+#include <map>
+#include <stdexcept>
+#include <string>
+
+#include "format.hpp"
+#include "logger.hpp"
+
+#if defined( _WIN32 )
+# define NEWLINE "\r\n"
+#else
+# define NEWLINE "\n"
+#endif
+
+namespace logging {
+  class format_parsing_exception : public std::logic_error {
+  public:
+    using std::logic_error::logic_error;
+  };
+  
+  class unknown_format_specifier : public std::logic_error {
+  public:
+    using std::logic_error::logic_error;
+  };
+}
+
+namespace logging {
+  namespace {
+    std::string fmt_time(struct timeval round, char const * const fmt) {
+      struct tm time;
+      gmtime_r(&round.tv_sec, &time);
+      char buf[64] = {'\0'};
+      std::strftime(buf, sizeof(buf), fmt, &time);
+      return buf;
+    }
+    
+    std::string fmt_time(struct timeval round, std::string const & fmt) {
+      return fmt_time(round, fmt.c_str());
+    }
+    
+    std::string fmt_time_with_milis(struct timeval round, std::string const & fmt) {
+      char buf[64] = {'\0'};
+      snprintf(buf, sizeof(buf), fmt.c_str(), round.tv_usec);
+      return fmt_time(round, buf);
+    }
+  }
+  using string_generator = std::function<std::string(logpacket const &)>;
+  
+  string_generator parse_date_format_string( char const * str ) {
+    char const * const end = strchr(str, '}');
+    if (end == nullptr)
+      throw format_parsing_exception{"expected date-format specifier to terminate"};
+
+    char const * const has_millis = strstr( str, "%_ms");
+    std::string fmtstring{str, end};
+    if ( has_millis && has_millis < end ) {
+      size_t pos = 0;
+      while ( (pos = fmtstring.find("%", pos)) != std::string::npos ) {
+        fmtstring.replace(pos, 1, "%%");
+        pos += 2;
+      }
+      fmtstring.replace(fmtstring.find("%%_ms"), 4, "%.03d");
+      return [=](logpacket const & lp) {
+        return fmt_time_with_milis(lp.time, fmtstring);
+      };
+    } else {
+      return [=](logpacket const & lp) {
+        return fmt_time(lp.time, fmtstring);
+      };
+    }
+  }
+  
+#define is( chr ) *next == chr
+#define is_string( str ) ! strncmp(next, str, strlen(str))
+  string_generator date_token(char const * next) {
+    std::string predef_format;
+    if ( is_string("{ISO8601}")) {
+      predef_format = "%%Y-%%m-%%d %%H:%%M:%%S,%.03d";
+    } else if (is_string("{ABSOLUTE}")) {
+      predef_format = "%%H:%%M:%%S,%.04d";
+    } else if (is_string("{DATE}")) {
+      predef_format = "%%d %%b %%Y %%H:%%M:%%S,%.04d";
+    } else if (is('{')) {
+      return parse_date_format_string(next);
+    }
+    return [=](logpacket const & lp ){
+      return fmt_time_with_milis(lp.time, predef_format);
+    };
+  }
+  
+  string_generator string_token(std::string str) {
+    return [=]( logpacket const & ){
+      return str;
+    };
+  }
+  
+  string_generator handle( char const * & next ) {
+    if (is('c')) {
+      return [](logpacket const & lp){
+        return lp.logger;
+      };
+    } else if (is('p')) {
+      return [](logpacket const & lp){
+        return level_header(lp.level);
+      };
+    } else if (is('m')) {
+      return [](logpacket const & lp){
+        return lp.message;
+      };
+    } else {
+      throw unknown_format_specifier{std::string("unknown format character: '") + *next + "'"};
+    }
+  }
+  
+  format::generator parse_with_bounds( char const * & next ) {
+    bool const is_left = *next == '-';
+    auto align = is_left ? std::left : std::right;
+    bool const trunc = *next == '.';
+    if ( is_left || trunc ) ++next;
+    
+    string_generator gen;
+    size_t chars = 0;
+    int min = std::stoi( next, &chars );
+    size_t max = 0xFFFFFFFF;
+    next += chars;
+    if ( trunc ) {
+      max = min;
+      min = 0;
+    } else if ( *next == '.' ) {
+      max = std::stoi( next + 1, &chars );
+      next += chars + 1;
+    }
+    gen = handle( next );
+    
+    return [=](logpacket const & lp, std::ostream & out) {
+      std::string str = gen( lp );
+      if ( str.length() > max )
+        str.erase(str.begin() + max);
+      out << align << std::setw( min ) << str;
+    };
+  }
+  
+  format::generator convert( string_generator gen ) {
+    return [=](logpacket const & lp, std::ostream & out) {
+      out << gen( lp );
+    };
+  }
+  
+  format format::parse_format_string( std::string const & fmt ) {
+    format out;
+    char const * curr = fmt.c_str();
+    char const * next = nullptr;
+    char const * const end = curr + fmt.size();
+    
+    while ( ( next = std::strchr( curr, '%' ) + 1 )
+           != nullptr ) {
+      if ( end == next ) {
+        throw format_parsing_exception{"expected format specifier, got end of string"}; // TODO
+      }
+      
+      if ( curr < next -  1 ) {
+        out.gen.push_back(convert(string_token({curr, next - 1})));
+      }
+
+      if ( is('d') ) {
+        ++next;
+        if ( is('{') ) curr = std::strchr(next, '}');
+        out.gen.push_back(convert(date_token(next)));
+      } else if ( is('n') ) {
+        out.gen.push_back(convert(string_token(NEWLINE)));
+      } else if ( is('%') ) {
+        ++next;
+        out.gen.push_back(convert(string_token("%")));
+      } else if ( is('.') || is('-') ||
+                 isdigit( *next ) ) {
+        parse_with_bounds( next );
+      } else {
+        handle( next );
+      }
+      curr = ++next;
+    }
+    if ( curr < end ) {
+      out.gen.push_back(convert(string_token({curr, end})));
+    }
+    return out;
+  }
+#undef is
+}
+
+namespace logging {
+  format_point_t get_next_format_specifier( std::string const & interp, size_t pos ) {
+    size_t next = pos;
+    char const * str = interp.c_str();
+    do {
+      pos = interp.find("{}", next);
+      next = pos + 2;
+    } while ( pos > 0 && pos != std::string::npos &&
+             ! strncmp(str + pos - 1, "{{}}", 4) );
+    return { pos, next };
+  }
+}

+ 61 - 0
format.hpp

@@ -0,0 +1,61 @@
+//
+//  format.hpp
+//  logger
+//
+//  Created by Sam Jaffe on 8/21/16.
+//
+
+#pragma once
+
+#include <functional>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "logger_fwd.hpp"
+
+namespace logging {
+  class format {
+  public:
+    enum class token_id {
+      DATE, PRIORITY, CATEGORY, MESSAGE, STRING, NEWLINE
+    };
+    
+    using generator = std::function<void(logpacket const &, std::ostream &)>;
+    
+  private:
+    static format parse_format_string(std::string const &);    
+    std::vector<generator> gen;
+  };
+  
+  inline void format_msg( std::stringstream & msg,
+                         std::string const & interp, size_t pos) {
+    msg << interp.substr(pos);
+  }
+  
+  struct format_point_t {
+    size_t start;
+    size_t end;
+  };
+  
+  format_point_t get_next_format_specifier( std::string const & interp, size_t pos );
+  
+  template <typename Arg0, typename... Args>
+  inline void format_msg( std::stringstream & msg,
+                         std::string const & interp, size_t pos,
+                         Arg0 && arg0, Args && ...args ) {
+    format_point_t next = get_next_format_specifier( interp, pos );
+    msg << interp.substr(pos, next.start) << arg0;
+    if ( next.start == std::string::npos ) return; // throw?
+    format_msg( msg, interp, next.end,
+               std::forward<Args>(args)... );
+  }
+  
+  template <typename... Args>
+  inline std::string format_msg( std::string const & interp,
+                                Args && ...args ) {
+    std::stringstream msg;
+    format_msg<Args...>( msg, interp, 0, std::forward<Args>(args)... );
+    return msg.str();
+  }
+}

+ 46 - 51
logger.cpp

@@ -1,14 +1,11 @@
 //
-//  Logger.cpp
-//  DanmakuRPG
+//  logger.cpp
+//  logger
 //
-//  Created by Sam Jaffe on 7/18/15.
-//  Copyright (c) 2015 Sam Jaffe. All rights reserved.
+//  Created by Sam Jaffe on 9/3/16.
 //
 
-#ifdef _WIN32
-#include <Windows.h>
-#endif
+#include <sys/time.h>
 
 #include <cassert>
 #include <cmath>
@@ -16,6 +13,7 @@
 #include <map>
 #include <stdexcept>
 
+#include "expect/expect.hpp"
 #include "logger.hpp"
 #include "properties.hpp"
 
@@ -24,7 +22,7 @@ namespace logging {
 case logging::L##l: \
 return #l;
   
-  const char* level_header(log_level l) {
+  const char* level_header(ilog_level l) {
     assert(l != logging::LNONE);
     switch (l) {
         X(FATAL)
@@ -39,16 +37,13 @@ return #l;
   }
   
 #undef X
-  
-  std::string timestamp() {
-    time_t round = std::time(NULL);
-    struct tm time = *std::localtime(&round);
-    char buf[32];
-    snprintf(buf, sizeof(buf), "%0.4d-%0.2d-%0.2d %0.2d:%0.2d:%0.2d.%0.3d ",
-             1900 + time.tm_year, time.tm_mon + 1, time.tm_mday,
-             time.tm_hour, time.tm_min, time.tm_sec,
-             static_cast<int>(round % 1000));
-    return buf;
+}
+
+namespace {
+  struct timeval now( ) {
+    struct timeval tv;
+    gettimeofday( &tv, nullptr );
+    return tv;
   }
 }
 
@@ -57,20 +52,18 @@ namespace logging {
     using std::logic_error::logic_error;
   };
   
-//  extern logger_impl& _logger_impl_shared_instance();
+  //  extern logger_impl& _logger_impl_shared_instance();
   extern _binding _default_logger_impl;
   static _binding _impl_binding = nullptr;
   
   bool bind_logger_impl(_binding impl) {
-    assert(_impl_binding == nullptr);
-    if (_impl_binding != nullptr) {
-      throw multiple_bindings{"Only one logger implementation may be bound"};
-    }
+    expects(_impl_binding == nullptr, multiple_bindings,
+            "Only one logger implementation may be bound");
     _impl_binding = impl;
     return true;
   }
   
-  logger_impl& _get_shared_instance() {
+  ilogger_impl& _i_get_shared_instance() {
     if (_impl_binding == nullptr) {
       return _default_logger_impl();
     } else {
@@ -80,54 +73,56 @@ namespace logging {
 }
 
 namespace logging {
-  logger& logger::instance() {
-    static logger instance;
+  ilogger& ilogger::instance() {
+    static ilogger instance;
     return instance;
   }
   
-  logger& logger::instance(const char* name) {
-    static std::map<const char*, std::unique_ptr<logger>> instances;
-    std::map<const char*, std::unique_ptr<logger>>::iterator it;
+  ilogger& ilogger::instance(std::string const & name) {
+    using p_logger = std::unique_ptr<ilogger>;
+    using store = std::map<std::string, p_logger>;
+    static store instances;
+    store::iterator it;
     if ((it = instances.find(name)) != instances.end()) {
       return *(it->second);
     }
-    return *(instances.emplace(std::make_pair(name, std::unique_ptr<logger>(new logger(name)))).first->second);
+    return *(instances.emplace(std::make_pair(name, p_logger(new ilogger(name)))).first->second);
   }
-
   
-  logger::logger(const char* name)
+  
+  ilogger::ilogger(std::string const & name)
   : min_level_(LDEBUG)
   , logger_name_(name)
-  , impl_(_get_shared_instance())
+  , impl_(_i_get_shared_instance())
   {
   }
   
-  logger::~logger() {
+  ilogger::~ilogger() {
     flush();
   }
   
-  std::string logger::get_header(log_level level) {
-    std::string ts = timestamp();
-    char data[64];
-    snprintf(data, sizeof(data), "[%-5s] %s %s - ", level_header(level), logger_name_, ts.c_str());
-    return data;
+  void ilogger::log(ilog_level ll, location_info info, std::string const & msg) {
+    impl_.write({ now( ), ll, info, logger_name_.c_str(), msg });
   }
   
-  void logger::vlognf(log_level level, size_t num_bytes, char const* fmt, va_list args) {
-    if (level < min_level_) return;
-    const std::unique_ptr<char[]> data(new char[num_bytes]);
-    int n = vsnprintf(data.get(), num_bytes, fmt, args);
-    if (n >= 0) {
-      data[num_bytes-1] = '\0';
-      log(level, get_header(level) + data.get());
-    }
+  bool ilogger::should_log( ilog_level ll ) const {
+    return ll < min_level_ && impl_.should_log( ll );
   }
   
-  void logger::log(log_level level, std::string const& msg) {
-    impl_.write(level, msg);
+  void ilogger::flush() {
+    impl_.flush();
   }
+}
+
+namespace logging {
   
-  void logger::flush() {
-    impl_.flush();
+  bool ilogger_impl::should_log( ilog_level ll ) const {
+    return ll < min_log_level;
   }
 }
+
+void test() {
+  logging::ilogger & LOG = logging::ilogger::instance( );
+  LOG.log(logging::LERROR, "{}", 5);
+}
+

+ 47 - 86
logger.hpp

@@ -1,3 +1,12 @@
+//
+//  logger.hpp
+//  logger
+//
+//  Created by Sam Jaffe on 9/3/16.
+//
+
+#pragma once
+
 //
 //  Logger.hpp
 //  DanmakuRPG
@@ -11,111 +20,63 @@
 #include <cstdarg>
 #include <cstdlib>
 #include <cstring>
-#include <string>
 #include <memory>
+#include <string>
 
-#define VA_LOGN(level, size) \
-do { \
-va_list vargs; \
-va_start( vargs, fmt ); \
-vlognf( level, size, fmt, vargs ); \
-va_end( vargs ); \
-} while(0)
+#include "logger_fwd.hpp"
+#include "format.hpp"
 
-#define VA_LOG(level) VA_LOGN(level, logger::LOGF_MAX_SIZE)
+#define log_message( logger, level, ... ) logger.log( level, { __FILE__, __LINE__, STRING( FUNCTION ) }, __VA_ARGS__ )
 
 namespace logging {
-  class logger_impl;
-  typedef logger_impl& (*_binding)(void);
+  class ilogger_impl;
+  typedef ilogger_impl& (*_binding)(void);
   bool bind_logger_impl(_binding impl);
     
-  enum log_level {
-    LTRACE,
-    LDEBUG,
-    LINFO,
-    LWARNING,
-    LERROR,
-    LCRITICAL,
-    LFATAL,
-    LNONE
-  };
+  const char* level_header(ilog_level);
   
-  const char* level_header(log_level);
-  std::string timestamp();
-  
-//  struct logpacket {
-//    struct tm time;
-//    long milliseconds;
-//    int thread_id;
-//    log_level level;
-//    const char* logger;
-//    std::string message;
-//  };
-    
-  class logger {
+  class ilogger {
   public:
-    static const size_t LOGF_MAX_SIZE = 2048;
-    static logger& instance();
-    static logger& instance(const char* key);
-  public:    
-    inline void tracef(char const* fmt, ...) { VA_LOG(LTRACE); }
-    inline void tracenf(size_t n, char const* fmt, ...) { VA_LOGN(LTRACE, n); }
-    inline void trace(char const* msg) { log(LTRACE, msg); }
-    inline void trace(std::string const& msg) { log(LTRACE, msg); }
-    
-    inline void debugf(char const* fmt, ...) { VA_LOG(LDEBUG); }
-    inline void debugnf(size_t n, char const* fmt, ...) { VA_LOGN(LDEBUG, n); }
-    inline void debug(char const* msg) { log(LDEBUG, msg); }
-    inline void debug(std::string const& msg) { log(LDEBUG, msg); }
-    
-    inline void infof(char const* fmt, ...) { VA_LOG(LINFO); }
-    inline void infonf(size_t n, char const* fmt, ...) { VA_LOGN(LINFO, n); }
-    inline void info(char const* msg) { log(LINFO, msg); }
-    inline void info(std::string const& msg) { log(LINFO, msg); }
-    
-    inline void warnf(char const* fmt, ...) { VA_LOG(LWARNING); }
-    inline void warnnf(size_t n, char const* fmt, ...) { VA_LOGN(LWARNING, n); }
-    inline void warn(char const* msg) { log(LWARNING, msg); }
-    inline void warn(std::string const& msg) { log(LWARNING, msg); }
-    
-    inline void errorf(char const* fmt, ...) { VA_LOG(LERROR); }
-    inline void errornf(size_t n, char const* fmt, ...) { VA_LOGN(LERROR, n); }
-    inline void error(char const* msg) { log(LERROR, msg); }
-    inline void error(std::string const& msg) { log(LERROR, msg); }
-    
-    inline void criticalf(char const* fmt, ...) { VA_LOG(LCRITICAL); }
-    inline void criticalnf(size_t n, char const* fmt, ...) { VA_LOGN(LCRITICAL, n); }
-    inline void critical(char const* msg) { log(LCRITICAL, msg); }
-    inline void critical(std::string const& msg) { log(LCRITICAL, msg); }
+    static ilogger& instance();
+    static ilogger& instance(std::string const & key);
+  public:
+    template <typename... Args>
+    inline void log(ilog_level ll,
+                    std::string const & interp, Args && ...args) {
+      log( ll, location_info{}, interp, std::forward<Args>(args)... );
+    }
     
-    inline void fatalf(char const* fmt, ...) { VA_LOG(LFATAL); }
-    inline void fatalnf(size_t n, char const* fmt, ...) { VA_LOGN(LFATAL, n); }
-    inline void fatal(char const* msg) { log(LFATAL, msg); }
-    inline void fatal(std::string const& msg) { log(LFATAL, msg); }
+    template <typename... Args>
+    inline void log(ilog_level ll, location_info info,
+                    std::string const & interp, Args && ...args) {
+      if ( should_log( ll ) ) {
+        log( ll, info, format_msg( interp, std::forward<Args>(args)... ) );
+      }
+    }
     
     void flush();
     
-    ~logger();
+    ~ilogger();
   private:
-    void vlognf(log_level, size_t, char const*, va_list);
-    void log(log_level, std::string const&);
-    std::string get_header(log_level level);
+    bool should_log( ilog_level ) const;
+    void log( ilog_level ll, location_info info, std::string const& );
     
-    logger(const char* name = "");
-    logger(logger const&);
-    logger& operator=(logger const&);
+    explicit ilogger(std::string const & name = "");
+    ilogger(ilogger const&);
+    ilogger& operator=(ilogger const&);
     
-    log_level min_level_;
-    const char* logger_name_;
-    logger_impl& impl_;
+    ilog_level min_level_;
+    std::string const logger_name_;
+    ilogger_impl& impl_;
   };
   
-  class logger_impl {
+  class ilogger_impl {
   public:
-    virtual void write(log_level level, std::string const& msg) = 0;
+    bool should_log( ilog_level ll ) const;
+    virtual void write( logpacket const & pkt ) = 0;
     virtual void flush() = 0;
-    virtual ~logger_impl() = default;
+    virtual ~ilogger_impl() = default;
+  private:
+    ilog_level min_log_level;
   };
 }
-#undef VA_LOG
-#undef LA_LOGN

+ 38 - 31
logger.xcodeproj/project.pbxproj

@@ -7,25 +7,20 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
-		0ECAC4BC1BC012ED00FDAE14 /* properties.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0ECAC4BA1BC012ED00FDAE14 /* properties.cpp */; settings = {ASSET_TAGS = (); }; };
-		0ECAC4BD1BC012ED00FDAE14 /* properties.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0ECAC4BB1BC012ED00FDAE14 /* properties.hpp */; settings = {ASSET_TAGS = (); }; };
-		0ECAC4BE1BC0156000FDAE14 /* logger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0EB833461BBF45E600DDC844 /* logger.cpp */; settings = {ASSET_TAGS = (); }; };
-		0ECAC4BF1BC0156600FDAE14 /* default_logger_binding.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0ECAC4A71BC0051700FDAE14 /* default_logger_binding.cpp */; settings = {ASSET_TAGS = (); }; };
-		0ECAC4C01BC0156900FDAE14 /* file_logger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0EB833661BBF4F9600DDC844 /* file_logger.cpp */; settings = {ASSET_TAGS = (); }; };
-		0ECAC4C11BC0156C00FDAE14 /* console_logger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8336A1BBF4FAC00DDC844 /* console_logger.cpp */; settings = {ASSET_TAGS = (); }; };
+		CD29739B1D7B401F00E37217 /* logger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD2973991D7B401F00E37217 /* logger.cpp */; };
+		CD29739C1D7B401F00E37217 /* logger.hpp in Headers */ = {isa = PBXBuildFile; fileRef = CD29739A1D7B401F00E37217 /* logger.hpp */; };
+		CD3C80C01D6A2CA300ACC795 /* format.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD3C80BE1D6A2CA300ACC795 /* format.cpp */; };
+		CD3C80C11D6A2CA300ACC795 /* format.hpp in Headers */ = {isa = PBXBuildFile; fileRef = CD3C80BF1D6A2CA300ACC795 /* format.hpp */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
-		0EB833461BBF45E600DDC844 /* logger.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = logger.cpp; sourceTree = "<group>"; };
-		0EB833471BBF45E600DDC844 /* logger.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = logger.hpp; sourceTree = "<group>"; };
 		0EB833481BBF45E600DDC844 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
-		0EB833661BBF4F9600DDC844 /* file_logger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_logger.cpp; sourceTree = "<group>"; };
-		0EB8336A1BBF4FAC00DDC844 /* console_logger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = console_logger.cpp; sourceTree = "<group>"; };
-		0ECAC4A71BC0051700FDAE14 /* default_logger_binding.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = default_logger_binding.cpp; sourceTree = "<group>"; };
 		0ECAC4AF1BC00AC500FDAE14 /* liblogging.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = liblogging.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
-		0ECAC4BA1BC012ED00FDAE14 /* properties.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = properties.cpp; sourceTree = "<group>"; };
-		0ECAC4BB1BC012ED00FDAE14 /* properties.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = properties.hpp; sourceTree = "<group>"; };
-		0ECAC4C21BC0193400FDAE14 /* default_logger_binding.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = default_logger_binding.hpp; sourceTree = "<group>"; };
+		CD2973991D7B401F00E37217 /* logger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = logger.cpp; sourceTree = "<group>"; };
+		CD29739A1D7B401F00E37217 /* logger.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = logger.hpp; sourceTree = "<group>"; };
+		CD29739D1D7B40C600E37217 /* logger_fwd.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = logger_fwd.hpp; sourceTree = "<group>"; };
+		CD3C80BE1D6A2CA300ACC795 /* format.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = format.cpp; sourceTree = "<group>"; };
+		CD3C80BF1D6A2CA300ACC795 /* format.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = format.hpp; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -42,14 +37,7 @@
 		0EB833401BBF45E600DDC844 = {
 			isa = PBXGroup;
 			children = (
-				0EB833461BBF45E600DDC844 /* logger.cpp */,
-				0EB833471BBF45E600DDC844 /* logger.hpp */,
-				0ECAC4BA1BC012ED00FDAE14 /* properties.cpp */,
-				0ECAC4BB1BC012ED00FDAE14 /* properties.hpp */,
-				0ECAC4A71BC0051700FDAE14 /* default_logger_binding.cpp */,
-				0ECAC4C21BC0193400FDAE14 /* default_logger_binding.hpp */,
-				0EB833661BBF4F9600DDC844 /* file_logger.cpp */,
-				0EB8336A1BBF4FAC00DDC844 /* console_logger.cpp */,
+				CD2973971D7B3FC600E37217 /* src */,
 				0EB833481BBF45E600DDC844 /* Makefile */,
 				0EB8335A1BBF484800DDC844 /* Products */,
 			);
@@ -63,6 +51,18 @@
 			name = Products;
 			sourceTree = "<group>";
 		};
+		CD2973971D7B3FC600E37217 /* src */ = {
+			isa = PBXGroup;
+			children = (
+				CD29739D1D7B40C600E37217 /* logger_fwd.hpp */,
+				CD2973991D7B401F00E37217 /* logger.cpp */,
+				CD29739A1D7B401F00E37217 /* logger.hpp */,
+				CD3C80BE1D6A2CA300ACC795 /* format.cpp */,
+				CD3C80BF1D6A2CA300ACC795 /* format.hpp */,
+			);
+			name = src;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXHeadersBuildPhase section */
@@ -70,7 +70,8 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				0ECAC4BD1BC012ED00FDAE14 /* properties.hpp in Headers */,
+				CD29739C1D7B401F00E37217 /* logger.hpp in Headers */,
+				CD3C80C11D6A2CA300ACC795 /* format.hpp in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -117,7 +118,7 @@
 		0EB833411BBF45E600DDC844 /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 0700;
+				LastUpgradeCheck = 0720;
 				TargetAttributes = {
 					0ECAC4AE1BC00AC500FDAE14 = {
 						CreatedOnToolsVersion = 7.0.1;
@@ -147,11 +148,8 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				0ECAC4BF1BC0156600FDAE14 /* default_logger_binding.cpp in Sources */,
-				0ECAC4C11BC0156C00FDAE14 /* console_logger.cpp in Sources */,
-				0ECAC4BC1BC012ED00FDAE14 /* properties.cpp in Sources */,
-				0ECAC4BE1BC0156000FDAE14 /* logger.cpp in Sources */,
-				0ECAC4C01BC0156900FDAE14 /* file_logger.cpp in Sources */,
+				CD29739B1D7B401F00E37217 /* logger.cpp in Sources */,
+				CD3C80C01D6A2CA300ACC795 /* format.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -222,12 +220,13 @@
 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COMBINE_HIDPI_IMAGES = YES;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				DYLIB_COMPATIBILITY_VERSION = 1;
 				DYLIB_CURRENT_VERSION = 1;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				EXECUTABLE_PREFIX = lib;
-				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GCC_DYNAMIC_NO_PIC = NO;
 				GCC_ENABLE_CPP_EXCEPTIONS = YES;
 				GCC_ENABLE_CPP_RTTI = YES;
@@ -238,14 +237,17 @@
 					"$(inherited)",
 				);
 				GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_PEDANTIC = NO;
 				GCC_WARN_UNDECLARED_SELECTOR = YES;
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				MACOSX_DEPLOYMENT_TARGET = 10.10;
 				MTL_ENABLE_DEBUG_INFO = YES;
 				PRODUCT_NAME = "$(TARGET_NAME)";
+				USER_HEADER_SEARCH_PATHS = ..;
 			};
 			name = Debug;
 		};
@@ -266,6 +268,7 @@
 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COMBINE_HIDPI_IMAGES = YES;
 				COPY_PHASE_STRIP = NO;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				DYLIB_COMPATIBILITY_VERSION = 1;
@@ -273,19 +276,22 @@
 				ENABLE_NS_ASSERTIONS = NO;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				EXECUTABLE_PREFIX = lib;
-				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GCC_ENABLE_CPP_EXCEPTIONS = YES;
 				GCC_ENABLE_CPP_RTTI = YES;
 				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_PEDANTIC = NO;
 				GCC_WARN_UNDECLARED_SELECTOR = YES;
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				MACOSX_DEPLOYMENT_TARGET = 10.10;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				PRODUCT_NAME = "$(TARGET_NAME)";
+				USER_HEADER_SEARCH_PATHS = ..;
 			};
 			name = Release;
 		};
@@ -317,6 +323,7 @@
 				0ECAC4B91BC00AC500FDAE14 /* Release */,
 			);
 			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
 		};
 /* End XCConfigurationList section */
 	};

+ 2 - 2
logger.xcodeproj/xcuserdata/samjaffe.xcuserdatad/xcschemes/xcschememanagement.plist

@@ -7,12 +7,12 @@
 		<key>logger.xcscheme</key>
 		<dict>
 			<key>orderHint</key>
-			<integer>9</integer>
+			<integer>5</integer>
 		</dict>
 		<key>logging.xcscheme</key>
 		<dict>
 			<key>orderHint</key>
-			<integer>10</integer>
+			<integer>6</integer>
 		</dict>
 	</dict>
 	<key>SuppressBuildableAutocreation</key>

+ 36 - 0
logger_fwd.hpp

@@ -0,0 +1,36 @@
+//
+//  logger_fwd.hpp
+//  logger
+//
+//  Created by Sam Jaffe on 9/3/16.
+//
+
+#pragma once
+
+namespace logging {
+  enum ilog_level {
+    LTRACE,
+    LDEBUG,
+    LINFO,
+    LWARNING,
+    LERROR,
+    LCRITICAL,
+    LFATAL,
+    LNONE
+  };
+  
+  struct location_info {
+    char const * filename = "???";
+    int line = 0;
+    char const * function = "";
+  };
+
+  struct logpacket {
+    struct timeval time;
+    //    int thread_id;
+    ilog_level level;
+    location_info info;
+    const char* logger;
+    std::string message;
+  };
+}

+ 0 - 81
properties.cpp

@@ -1,81 +0,0 @@
-//
-//  properties.cpp
-//  logger
-//
-//  Created by Sam Jaffe on 10/3/15.
-//
-//
-
-#include "properties.hpp"
-
-/*
- {
- {"pattern",{{},"%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"}}
- },
- "PatternLayout"
- }
- */
-namespace logging {
-  
-  namespace {
-    properties _property(std::map<std::string, properties> const& m) {
-      return properties{properties::OBJECT, m, {}, {}};
-    }
-    properties _list(std::vector<properties> const& l) {
-      return properties{properties::ARRAY, {}, l, {}};
-    }
-    properties _value(std::string const& s) {
-      return properties{properties::STRING, {}, {}, s};
-    }
-  }
-  
-  /*
-   * %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
-   *
-   * %d{fmt}     := date(format)
-   * %t          := thread
-   * %-5level    := level (max 5char, align right)
-   * %logger{36} := logsource (max 36char)
-   * %msg        := log message
-   * %n          := platform-specific line separator
-   *
-   */
-  
-  properties const STDOUT_DEFAULT_SCHEMA{
-    _property({
-      {"type", _value("Console")},
-      {"name", _value("Console")},
-      {"target", _value("SYSTEM_OUT")},
-      {
-        "data", _list({
-          _property({
-            {"type", _value("PatternLayout")},
-            {"pattern", _value("%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n")}
-          })
-        })
-      }
-    })
-  };
-  
-  properties const LOGGER_DEFAULT_SCHEMA {
-    _property({
-      {"type", _value("Root")},
-      {"level", _value("Error")},
-      {
-        "data", _list({
-          _property({
-            {"type", _value("AppenderRef")},
-            {"ref", _value("Console")}
-          })
-        })
-      }
-    })
-  };
-  
-  properties const DEFAULT_SCHEMA{
-    _property({
-      {"Appenders",_list({STDOUT_DEFAULT_SCHEMA})},
-      {"Loggers",_list({LOGGER_DEFAULT_SCHEMA})}
-    })
-  };
-}

+ 0 - 22
properties.hpp

@@ -1,22 +0,0 @@
-//
-//  properties.hpp
-//  logger
-//
-//  Created by Sam Jaffe on 10/3/15.
-//
-//
-
-#pragma once
-
-#include <map>
-#include <string>
-#include <vector>
-
-namespace logging {
-  struct properties {
-    const enum { STRING, OBJECT, ARRAY } type;
-    const std::map<std::string, properties> obj;
-    const std::vector<properties> array;
-    const std::string value;
-  };
-}