Browse Source

Initial commit of a generic logging platform ala Log4J or SLF4J

Samuel Jaffe 9 years ago
commit
d048c1d73a

+ 75 - 0
Makefile

@@ -0,0 +1,75 @@
+WARNINGS := -Wall -pedantic  -pedantic-errors -Wextra -Wcast-align \
+  -Wcast-qual  -Wchar-subscripts  -Wcomment -Wconversion \
+  -Wdisabled-optimization -Werror -Wfloat-equal  -Wformat  -Wformat=2 \
+  -Wformat-nonliteral -Wformat-security  -Wformat-y2k \
+  -Wimport  -Winit-self  -Winline -Winvalid-pch   \
+  -Wunsafe-loop-optimizations  -Wno-long-long -Wmissing-braces \
+  -Wmissing-field-initializers -Wmissing-format-attribute   \
+  -Wmissing-include-dirs -Wmissing-noreturn -Wmissing-declarations \
+  -Wpacked -Wparentheses  -Wpointer-arith \
+  -Wredundant-decls -Wreturn-type \
+  -Wsequence-point  -Wshadow -Wsign-compare  -Wstack-protector \
+  -Wstrict-aliasing -Wstrict-aliasing=2 -Wswitch  -Wswitch-default \
+  -Wswitch-enum -Wtrigraphs  -Wuninitialized \
+  -Wunknown-pragmas  -Wunreachable-code -Wunused \
+  -Wunused-function  -Wunused-label  -Wunused-parameter \
+  -Wunused-value  -Wunused-variable  -Wvariadic-macros \
+  -Wvolatile-register-var  -Wwrite-strings
+
+CWARNINGS := $(WARNINGS) -Wimplicit
+CPPWARNINGS := $(WARNINGS)
+
+CFLAGS   := $(CWARNINGS)
+CPPFLAGS := $(CPPWARNINGS)
+LDFLAGS  :=
+
+HDRFILES := 
+SRCFILES := 
+TSTFILES := 
+
+BINARY   :=
+
+DEPFILES := $(patsubst %.cpp,.%.d,$(SRCFILES))
+OBJFILES := $(patsubst %.cpp,%.o,$(SRCFILES))
+TSTFILES := $(patsubst %.h,%.cpp,$(TSTSUITE))
+TSTDRIVR := $(patsubst %.cpp,%,$(TSTFILES))
+
+ALLFILES := $(SRCFILES) $(HDRFILES) $(AUXFILES)
+
+.PHONY: all clean debug release check coverage
+
+all: $(BINARY) $(LNBINARY)
+
+debug: CFLAGS += -DDEBUG -g
+debug: CPPFLAGS += -DDEBUG -g
+debug: all
+
+release: CFLAGS += -O2
+release: CPPFLAGS += -O2
+release: all
+
+coverage: CFLAGS += -fprofile-arcs -ftest-coverage
+coverage: CPPFLAGS += -fprofile-arcs -ftest-coverage
+coverage: check
+
+clean: check-clean
+	@$(RM) $(BINARY) $(wildcard $(OBJFILES)) $(LNBINARY)
+
+check-clean:
+	@$(RM) $(TSTDRIVR) $(TSTFILES)
+
+check: check-clean $(TSTDRIVR)
+
+.h.cpp:
+	@cxxtestgen --error-printer $< -o $@
+
+.cpp.o: Makefile
+	$(CXX) $(CPPFLAGS) -MMD -MP -MF $(patsubst %.cpp,.%.d,$<) -c $< -o $@
+
+$(BINARY): $(OBJFILES) 
+	$(CXX) $(LDFLAGS) -o $@ $(OBJFILES)
+
+$(TSTDRIVR): $(TSTFILES)
+	@$(CXX) $(CPPFLAGS) -I$(CXXTEST) -w $@.cpp -o $@
+	@echo Running TestDriver: ./$@
+	@./$@

+ 71 - 0
console_logger.cpp

@@ -0,0 +1,71 @@
+//
+//  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);
+  }
+}

+ 56 - 0
default_logger_binding.cpp

@@ -0,0 +1,56 @@
+//
+//  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();
+  }
+}

+ 42 - 0
default_logger_binding.hpp

@@ -0,0 +1,42 @@
+//
+//  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_;
+  };
+}

+ 46 - 0
file_logger.cpp

@@ -0,0 +1,46 @@
+//
+//  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);
+  }
+}

+ 133 - 0
logger.cpp

@@ -0,0 +1,133 @@
+//
+//  Logger.cpp
+//  DanmakuRPG
+//
+//  Created by Sam Jaffe on 7/18/15.
+//  Copyright (c) 2015 Sam Jaffe. All rights reserved.
+//
+
+#ifdef _WIN32
+#include <Windows.h>
+#endif
+
+#include <cassert>
+#include <cmath>
+#include <ctime>
+#include <map>
+#include <stdexcept>
+
+#include "logger.hpp"
+#include "properties.hpp"
+
+namespace logging {
+#define X(l) \
+case logging::L##l: \
+return #l;
+  
+  const char* level_header(log_level l) {
+    assert(l != logging::LNONE);
+    switch (l) {
+        X(FATAL)
+        X(CRITICAL)
+        X(ERROR)
+        X(WARNING)
+        X(INFO)
+        X(DEBUG)
+        X(TRACE)
+        X(NONE)
+    }
+  }
+  
+#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 logging {
+  class multiple_bindings : public std::logic_error {
+    using std::logic_error::logic_error;
+  };
+  
+//  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"};
+    }
+    _impl_binding = impl;
+    return true;
+  }
+  
+  logger_impl& _get_shared_instance() {
+    if (_impl_binding == nullptr) {
+      return _default_logger_impl();
+    } else {
+      return _impl_binding();
+    }
+  }
+}
+
+namespace logging {
+  logger& logger::instance() {
+    static logger 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;
+    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);
+  }
+
+  
+  logger::logger(const char* name)
+  : min_level_(LDEBUG)
+  , logger_name_(name)
+  , impl_(_get_shared_instance())
+  {
+  }
+  
+  logger::~logger() {
+    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 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());
+    }
+  }
+  
+  void logger::log(log_level level, std::string const& msg) {
+    impl_.write(level, msg);
+  }
+  
+  void logger::flush() {
+    impl_.flush();
+  }
+}

+ 121 - 0
logger.hpp

@@ -0,0 +1,121 @@
+//
+//  Logger.hpp
+//  DanmakuRPG
+//
+//  Created by Sam Jaffe on 7/18/15.
+//  Copyright (c) 2015 Sam Jaffe. All rights reserved.
+//
+
+#pragma once
+
+#include <cstdarg>
+#include <cstdlib>
+#include <cstring>
+#include <string>
+#include <memory>
+
+#define VA_LOGN(level, size) \
+do { \
+va_list vargs; \
+va_start( vargs, fmt ); \
+vlognf( level, size, fmt, vargs ); \
+va_end( vargs ); \
+} while(0)
+
+#define VA_LOG(level) VA_LOGN(level, logger::LOGF_MAX_SIZE)
+
+namespace logging {
+  class logger_impl;
+  typedef logger_impl& (*_binding)(void);
+  bool bind_logger_impl(_binding impl);
+    
+  enum log_level {
+    LTRACE,
+    LDEBUG,
+    LINFO,
+    LWARNING,
+    LERROR,
+    LCRITICAL,
+    LFATAL,
+    LNONE
+  };
+  
+  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 {
+  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); }
+    
+    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); }
+    
+    void flush();
+    
+    ~logger();
+  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);
+    
+    logger(const char* name = "");
+    logger(logger const&);
+    logger& operator=(logger const&);
+    
+    log_level min_level_;
+    const char* logger_name_;
+    logger_impl& impl_;
+  };
+  
+  class logger_impl {
+  public:
+    virtual void write(log_level level, std::string const& msg) = 0;
+    virtual void flush() = 0;
+    virtual ~logger_impl() = default;
+  };
+}
+#undef VA_LOG
+#undef LA_LOGN

+ 324 - 0
logger.xcodeproj/project.pbxproj

@@ -0,0 +1,324 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	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 = (); }; };
+/* 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>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		0ECAC4AC1BC00AC500FDAE14 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		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 */,
+				0EB833481BBF45E600DDC844 /* Makefile */,
+				0EB8335A1BBF484800DDC844 /* Products */,
+			);
+			sourceTree = "<group>";
+		};
+		0EB8335A1BBF484800DDC844 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				0ECAC4AF1BC00AC500FDAE14 /* liblogging.dylib */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+		0ECAC4AD1BC00AC500FDAE14 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				0ECAC4BD1BC012ED00FDAE14 /* properties.hpp in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXLegacyTarget section */
+		0EB833451BBF45E600DDC844 /* logger */ = {
+			isa = PBXLegacyTarget;
+			buildArgumentsString = "$(ACTION)";
+			buildConfigurationList = 0EB833491BBF45E600DDC844 /* Build configuration list for PBXLegacyTarget "logger" */;
+			buildPhases = (
+			);
+			buildToolPath = /usr/bin/make;
+			buildWorkingDirectory = "/Users/leumasjaffe/Documents/Programming/XTools Workspace/C:C++/misc/logger";
+			dependencies = (
+			);
+			name = logger;
+			passBuildSettingsInEnvironment = 1;
+			productName = logger;
+		};
+/* End PBXLegacyTarget section */
+
+/* Begin PBXNativeTarget section */
+		0ECAC4AE1BC00AC500FDAE14 /* logging */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 0ECAC4B71BC00AC500FDAE14 /* Build configuration list for PBXNativeTarget "logging" */;
+			buildPhases = (
+				0ECAC4AB1BC00AC500FDAE14 /* Sources */,
+				0ECAC4AC1BC00AC500FDAE14 /* Frameworks */,
+				0ECAC4AD1BC00AC500FDAE14 /* Headers */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = logging;
+			productName = logging;
+			productReference = 0ECAC4AF1BC00AC500FDAE14 /* liblogging.dylib */;
+			productType = "com.apple.product-type.library.dynamic";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		0EB833411BBF45E600DDC844 /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 0700;
+				TargetAttributes = {
+					0ECAC4AE1BC00AC500FDAE14 = {
+						CreatedOnToolsVersion = 7.0.1;
+					};
+				};
+			};
+			buildConfigurationList = 0EB833441BBF45E600DDC844 /* Build configuration list for PBXProject "logger" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+			);
+			mainGroup = 0EB833401BBF45E600DDC844;
+			productRefGroup = 0EB8335A1BBF484800DDC844 /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				0EB833451BBF45E600DDC844 /* logger */,
+				0ECAC4AE1BC00AC500FDAE14 /* logging */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+		0ECAC4AB1BC00AC500FDAE14 /* Sources */ = {
+			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 */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		0EB833421BBF45E600DDC844 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				COPY_PHASE_STRIP = NO;
+				ENABLE_TESTABILITY = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = macosx;
+			};
+			name = Debug;
+		};
+		0EB833431BBF45E600DDC844 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				COPY_PHASE_STRIP = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				SDKROOT = macosx;
+			};
+			name = Release;
+		};
+		0EB8334A1BBF45E600DDC844 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				COPY_PHASE_STRIP = NO;
+				DEBUGGING_SYMBOLS = YES;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				OTHER_CFLAGS = "";
+				OTHER_LDFLAGS = "";
+				PRODUCT_NAME = logger;
+			};
+			name = Debug;
+		};
+		0EB8334B1BBF45E600DDC844 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				COPY_PHASE_STRIP = YES;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				OTHER_CFLAGS = "";
+				OTHER_LDFLAGS = "";
+				PRODUCT_NAME = logger;
+			};
+			name = Release;
+		};
+		0ECAC4B81BC00AC500FDAE14 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = 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_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_CPP_EXCEPTIONS = YES;
+				GCC_ENABLE_CPP_RTTI = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				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)";
+			};
+			name = Debug;
+		};
+		0ECAC4B91BC00AC500FDAE14 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				EXECUTABLE_PREFIX = lib;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_ENABLE_CPP_EXCEPTIONS = YES;
+				GCC_ENABLE_CPP_RTTI = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				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)";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		0EB833441BBF45E600DDC844 /* Build configuration list for PBXProject "logger" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				0EB833421BBF45E600DDC844 /* Debug */,
+				0EB833431BBF45E600DDC844 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		0EB833491BBF45E600DDC844 /* Build configuration list for PBXLegacyTarget "logger" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				0EB8334A1BBF45E600DDC844 /* Debug */,
+				0EB8334B1BBF45E600DDC844 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		0ECAC4B71BC00AC500FDAE14 /* Build configuration list for PBXNativeTarget "logging" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				0ECAC4B81BC00AC500FDAE14 /* Debug */,
+				0ECAC4B91BC00AC500FDAE14 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 0EB833411BBF45E600DDC844 /* Project object */;
+}

+ 80 - 0
logger.xcodeproj/xcuserdata/leumasjaffe.xcuserdatad/xcschemes/logger.xcscheme

@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0700"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "0EB833451BBF45E600DDC844"
+               BuildableName = "logger"
+               BlueprintName = "logger"
+               ReferencedContainer = "container:logger.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+      </Testables>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "0EB833451BBF45E600DDC844"
+            BuildableName = "logger"
+            BlueprintName = "logger"
+            ReferencedContainer = "container:logger.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "0EB833451BBF45E600DDC844"
+            BuildableName = "logger"
+            BlueprintName = "logger"
+            ReferencedContainer = "container:logger.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

+ 80 - 0
logger.xcodeproj/xcuserdata/leumasjaffe.xcuserdatad/xcschemes/logging.xcscheme

@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0700"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "0ECAC4AE1BC00AC500FDAE14"
+               BuildableName = "liblogging.dylib"
+               BlueprintName = "logging"
+               ReferencedContainer = "container:logger.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+      </Testables>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "0ECAC4AE1BC00AC500FDAE14"
+            BuildableName = "liblogging.dylib"
+            BlueprintName = "logging"
+            ReferencedContainer = "container:logger.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "0ECAC4AE1BC00AC500FDAE14"
+            BuildableName = "liblogging.dylib"
+            BlueprintName = "logging"
+            ReferencedContainer = "container:logger.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

+ 37 - 0
logger.xcodeproj/xcuserdata/leumasjaffe.xcuserdatad/xcschemes/xcschememanagement.plist

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>SchemeUserState</key>
+	<dict>
+		<key>logger.xcscheme</key>
+		<dict>
+			<key>orderHint</key>
+			<integer>9</integer>
+		</dict>
+		<key>logging.xcscheme</key>
+		<dict>
+			<key>orderHint</key>
+			<integer>11</integer>
+		</dict>
+	</dict>
+	<key>SuppressBuildableAutocreation</key>
+	<dict>
+		<key>0EB833451BBF45E600DDC844</key>
+		<dict>
+			<key>primary</key>
+			<true/>
+		</dict>
+		<key>0EB833581BBF484700DDC844</key>
+		<dict>
+			<key>primary</key>
+			<true/>
+		</dict>
+		<key>0ECAC4AE1BC00AC500FDAE14</key>
+		<dict>
+			<key>primary</key>
+			<true/>
+		</dict>
+	</dict>
+</dict>
+</plist>

+ 80 - 0
logger.xcodeproj/xcuserdata/samjaffe.xcuserdatad/xcschemes/logger.xcscheme

@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0720"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "0EB833451BBF45E600DDC844"
+               BuildableName = "logger"
+               BlueprintName = "logger"
+               ReferencedContainer = "container:logger.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+      </Testables>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "0EB833451BBF45E600DDC844"
+            BuildableName = "logger"
+            BlueprintName = "logger"
+            ReferencedContainer = "container:logger.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "0EB833451BBF45E600DDC844"
+            BuildableName = "logger"
+            BlueprintName = "logger"
+            ReferencedContainer = "container:logger.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

+ 80 - 0
logger.xcodeproj/xcuserdata/samjaffe.xcuserdatad/xcschemes/logging.xcscheme

@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0720"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "0ECAC4AE1BC00AC500FDAE14"
+               BuildableName = "liblogging.dylib"
+               BlueprintName = "logging"
+               ReferencedContainer = "container:logger.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+      </Testables>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "0ECAC4AE1BC00AC500FDAE14"
+            BuildableName = "liblogging.dylib"
+            BlueprintName = "logging"
+            ReferencedContainer = "container:logger.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "0ECAC4AE1BC00AC500FDAE14"
+            BuildableName = "liblogging.dylib"
+            BlueprintName = "logging"
+            ReferencedContainer = "container:logger.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

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

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>SchemeUserState</key>
+	<dict>
+		<key>logger.xcscheme</key>
+		<dict>
+			<key>orderHint</key>
+			<integer>9</integer>
+		</dict>
+		<key>logging.xcscheme</key>
+		<dict>
+			<key>orderHint</key>
+			<integer>10</integer>
+		</dict>
+	</dict>
+	<key>SuppressBuildableAutocreation</key>
+	<dict>
+		<key>0EB833451BBF45E600DDC844</key>
+		<dict>
+			<key>primary</key>
+			<true/>
+		</dict>
+		<key>0ECAC4AE1BC00AC500FDAE14</key>
+		<dict>
+			<key>primary</key>
+			<true/>
+		</dict>
+	</dict>
+</dict>
+</plist>

+ 81 - 0
properties.cpp

@@ -0,0 +1,81 @@
+//
+//  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})}
+    })
+  };
+}

+ 22 - 0
properties.hpp

@@ -0,0 +1,22 @@
+//
+//  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;
+  };
+}