Bläddra i källkod

Merge branch 'f/LotroDat-7-FixUp-Easylogging' of LotRO_Legacy/LotroDat into dev

Ivan Arkhipov 5 år sedan
förälder
incheckning
103fbef1e0
3 ändrade filer med 322 tillägg och 240 borttagningar
  1. 198 82
      Third_party/EasyLogging++/easylogging++.cc
  2. 117 154
      Third_party/EasyLogging++/easylogging++.h
  3. 7 4
      src/DatFile.cpp

+ 198 - 82
Third_party/EasyLogging++/easylogging++.cc

@@ -1,16 +1,16 @@
 //
 //  Bismillah ar-Rahmaan ar-Raheem
 //
-//  Easylogging++ v9.95.3
+//  Easylogging++ v9.96.7
 //  Cross-platform logging library for C++ applications
 //
-//  Copyright (c) 2017 muflihun.com
+//  Copyright (c) 2012-2018 Zuhd Web Services
+//  Copyright (c) 2012-2018 @abumusamq
 //
 //  This library is released under the MIT Licence.
-//  http://labs.muflihun.com/easyloggingpp/licence.php
+//  https://github.com/zuhd-org/easyloggingpp/blob/master/LICENSE
 //
-//  https://github.com/muflihun/easyloggingpp
-//  https://muflihun.github.io/easyloggingpp
+//  https://zuhd.org
 //  http://muflihun.com
 //
 
@@ -22,8 +22,95 @@ INITIALIZE_EASYLOGGINGPP
 
 namespace el {
 
-// el::base::utils
+// el::base
 namespace base {
+// el::base::consts
+namespace consts {
+
+// Level log values - These are values that are replaced in place of %level format specifier
+// Extra spaces after format specifiers are only for readability purposes in log files
+static const base::type::char_t* kInfoLevelLogValue     =   ELPP_LITERAL("INFO");
+static const base::type::char_t* kDebugLevelLogValue    =   ELPP_LITERAL("DEBUG");
+static const base::type::char_t* kWarningLevelLogValue  =   ELPP_LITERAL("WARNING");
+static const base::type::char_t* kErrorLevelLogValue    =   ELPP_LITERAL("ERROR");
+static const base::type::char_t* kFatalLevelLogValue    =   ELPP_LITERAL("FATAL");
+static const base::type::char_t* kVerboseLevelLogValue  =
+  ELPP_LITERAL("VERBOSE"); // will become VERBOSE-x where x = verbose level
+static const base::type::char_t* kTraceLevelLogValue    =   ELPP_LITERAL("TRACE");
+static const base::type::char_t* kInfoLevelShortLogValue     =   ELPP_LITERAL("I");
+static const base::type::char_t* kDebugLevelShortLogValue    =   ELPP_LITERAL("D");
+static const base::type::char_t* kWarningLevelShortLogValue  =   ELPP_LITERAL("W");
+static const base::type::char_t* kErrorLevelShortLogValue    =   ELPP_LITERAL("E");
+static const base::type::char_t* kFatalLevelShortLogValue    =   ELPP_LITERAL("F");
+static const base::type::char_t* kVerboseLevelShortLogValue  =   ELPP_LITERAL("V");
+static const base::type::char_t* kTraceLevelShortLogValue    =   ELPP_LITERAL("T");
+// Format specifiers - These are used to define log format
+static const base::type::char_t* kAppNameFormatSpecifier          =      ELPP_LITERAL("%app");
+static const base::type::char_t* kLoggerIdFormatSpecifier         =      ELPP_LITERAL("%logger");
+static const base::type::char_t* kThreadIdFormatSpecifier         =      ELPP_LITERAL("%thread");
+static const base::type::char_t* kSeverityLevelFormatSpecifier    =      ELPP_LITERAL("%level");
+static const base::type::char_t* kSeverityLevelShortFormatSpecifier    =      ELPP_LITERAL("%levshort");
+static const base::type::char_t* kDateTimeFormatSpecifier         =      ELPP_LITERAL("%datetime");
+static const base::type::char_t* kLogFileFormatSpecifier          =      ELPP_LITERAL("%file");
+static const base::type::char_t* kLogFileBaseFormatSpecifier      =      ELPP_LITERAL("%fbase");
+static const base::type::char_t* kLogLineFormatSpecifier          =      ELPP_LITERAL("%line");
+static const base::type::char_t* kLogLocationFormatSpecifier      =      ELPP_LITERAL("%loc");
+static const base::type::char_t* kLogFunctionFormatSpecifier      =      ELPP_LITERAL("%func");
+static const base::type::char_t* kCurrentUserFormatSpecifier      =      ELPP_LITERAL("%user");
+static const base::type::char_t* kCurrentHostFormatSpecifier      =      ELPP_LITERAL("%host");
+static const base::type::char_t* kMessageFormatSpecifier          =      ELPP_LITERAL("%msg");
+static const base::type::char_t* kVerboseLevelFormatSpecifier     =      ELPP_LITERAL("%vlevel");
+static const char* kDateTimeFormatSpecifierForFilename            =      "%datetime";
+// Date/time
+static const char* kDays[7]                         =      { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
+static const char* kDaysAbbrev[7]                   =      { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
+static const char* kMonths[12]                      =      { "January", "February", "March", "Apri", "May", "June", "July", "August",
+                                                             "September", "October", "November", "December"
+                                                           };
+static const char* kMonthsAbbrev[12]                =      { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+static const char* kDefaultDateTimeFormat           =      "%Y-%M-%d %H:%m:%s,%g";
+static const char* kDefaultDateTimeFormatInFilename =      "%Y-%M-%d_%H-%m";
+static const int kYearBase                          =      1900;
+static const char* kAm                              =      "AM";
+static const char* kPm                              =      "PM";
+// Miscellaneous constants
+
+static const char* kNullPointer                            =      "nullptr";
+#if ELPP_VARIADIC_TEMPLATES_SUPPORTED
+#endif  // ELPP_VARIADIC_TEMPLATES_SUPPORTED
+static const base::type::VerboseLevel kMaxVerboseLevel     =      9;
+static const char* kUnknownUser                            =      "user";
+static const char* kUnknownHost                            =      "unknown-host";
+
+
+//---------------- DEFAULT LOG FILE -----------------------
+
+#if defined(ELPP_NO_DEFAULT_LOG_FILE)
+#  if ELPP_OS_UNIX
+static const char* kDefaultLogFile                         =      "/dev/null";
+#  elif ELPP_OS_WINDOWS
+static const char* kDefaultLogFile                         =      "nul";
+#  endif  // ELPP_OS_UNIX
+#elif defined(ELPP_DEFAULT_LOG_FILE)
+static const char* kDefaultLogFile                         =      ELPP_DEFAULT_LOG_FILE;
+#else
+static const char* kDefaultLogFile                         =      "myeasylog.log";
+#endif // defined(ELPP_NO_DEFAULT_LOG_FILE)
+
+
+#if !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG)
+static const char* kDefaultLogFileParam                    =      "--default-log-file";
+#endif  // !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG)
+#if defined(ELPP_LOGGING_FLAGS_FROM_ARG)
+static const char* kLoggingFlagsParam                      =      "--logging-flags";
+#endif  // defined(ELPP_LOGGING_FLAGS_FROM_ARG)
+static const char* kValidLoggerIdSymbols                   =
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._";
+static const char* kConfigurationComment                   =      "##";
+static const char* kConfigurationLevel                     =      "*";
+static const char* kConfigurationLoggerId                  =      "--";
+}
+// el::base::utils
 namespace utils {
 
 /// @brief Aborts application due with user-defined status
@@ -276,11 +363,7 @@ void Configurations::set(Configuration* conf) {
 
 void Configurations::setToDefault(void) {
   setGlobally(ConfigurationType::Enabled, std::string("true"), true);
-#if !defined(ELPP_NO_DEFAULT_LOG_FILE)
   setGlobally(ConfigurationType::Filename, std::string(base::consts::kDefaultLogFile), true);
-#else
-  ELPP_UNUSED(base::consts::kDefaultLogFile);
-#endif  // !defined(ELPP_NO_DEFAULT_LOG_FILE)
 #if defined(ELPP_NO_LOG_TO_FILE)
   setGlobally(ConfigurationType::ToFile, std::string("false"), true);
 #else
@@ -309,9 +392,7 @@ void Configurations::setRemainingToDefault(void) {
 #else
   unsafeSetIfNotExist(Level::Global, ConfigurationType::Enabled, std::string("true"));
 #endif // defined(ELPP_NO_LOG_TO_FILE)
-#if !defined(ELPP_NO_DEFAULT_LOG_FILE)
   unsafeSetIfNotExist(Level::Global, ConfigurationType::Filename, std::string(base::consts::kDefaultLogFile));
-#endif  // !defined(ELPP_NO_DEFAULT_LOG_FILE)
   unsafeSetIfNotExist(Level::Global, ConfigurationType::ToStandardOutput, std::string("true"));
   unsafeSetIfNotExist(Level::Global, ConfigurationType::SubsecondPrecision, std::string("3"));
   unsafeSetIfNotExist(Level::Global, ConfigurationType::PerformanceTracking, std::string("true"));
@@ -569,7 +650,6 @@ void Logger::configure(const Configurations& configurations) {
   if (m_typedConfigurations != nullptr) {
     Configurations* c = const_cast<Configurations*>(m_typedConfigurations->configurations());
     if (c->hasConfiguration(Level::Global, ConfigurationType::Filename)) {
-      // This check is definitely needed for cases like ELPP_NO_DEFAULT_LOG_FILE
       flush();
     }
   }
@@ -613,10 +693,11 @@ void Logger::flush(Level level, base::type::fstream_t* fs) {
   }
   if (fs != nullptr) {
     fs->flush();
-    std::map<Level, unsigned int>::iterator iter = m_unflushedCount.find(level);
+    std::unordered_map<Level, unsigned int>::iterator iter = m_unflushedCount.find(level);
     if (iter != m_unflushedCount.end()) {
       iter->second = 0;
     }
+    Helpers::validateFileRolling(this, level);
   }
 }
 
@@ -675,10 +756,9 @@ std::size_t File::getSizeOfFile(base::type::fstream_t* fs) {
   if (fs == nullptr) {
     return 0;
   }
-  std::streampos currPos = fs->tellg();
-  fs->seekg(0, fs->end);
+  // Since the file stream is appended to or truncated, the current
+  // offset is the file size.
   std::size_t size = static_cast<std::size_t>(fs->tellg());
-  fs->seekg(currPos);
   return size;
 }
 
@@ -850,7 +930,7 @@ void Str::replaceFirstWithEscape(base::type::string_t& str, const base::type::st
   std::size_t foundAt = base::type::string_t::npos;
   while ((foundAt = str.find(replaceWhat, foundAt + 1)) != base::type::string_t::npos) {
     if (foundAt > 0 && str[foundAt - 1] == base::consts::kFormatSpecifierChar) {
-      str.erase(foundAt > 0 ? foundAt - 1 : 0, 1);
+      str.erase(foundAt - 1, 1);
       ++foundAt;
     } else {
       str.replace(foundAt, replaceWhat.length(), replaceWith);
@@ -997,8 +1077,9 @@ const std::string OS::getBashOutput(const char* command) {
   char hBuff[4096];
   if (fgets(hBuff, sizeof(hBuff), proc) != nullptr) {
     pclose(proc);
-    if (hBuff[strlen(hBuff) - 1] == '\n') {
-      hBuff[strlen(hBuff) - 1] = '\0';
+    const std::size_t buffLen = strlen(hBuff);
+    if (buffLen > 0 && hBuff[buffLen - 1] == '\n') {
+      hBuff[buffLen - 1] = '\0';
     }
     return std::string(hBuff);
   } else {
@@ -1272,7 +1353,7 @@ bool CommandLineArgs::hasParamWithValue(const char* paramKey) const {
 }
 
 const char* CommandLineArgs::getParamValue(const char* paramKey) const {
-  std::map<std::string, std::string>::const_iterator iter = m_paramsWithValue.find(std::string(paramKey));
+  std::unordered_map<std::string, std::string>::const_iterator iter = m_paramsWithValue.find(std::string(paramKey));
   return iter != m_paramsWithValue.end() ? iter->second.c_str() : "";
 }
 
@@ -1418,7 +1499,7 @@ void LogFormat::parseFromFormat(const base::type::string_t& userFormat) {
         if (hasFlag(flag)) {
           // If we already have flag we remove the escape chars so that '%%' is turned to '%'
           // even after specifier resolution - this is because we only replaceFirst specifier
-          formatCopy.erase(foundAt > 0 ? foundAt - 1 : 0, 1);
+          formatCopy.erase(foundAt - 1, 1);
           ++foundAt;
         }
       } else {
@@ -1621,10 +1702,11 @@ void TypedConfigurations::build(Configurations* configurations) {
     } else if (conf->configurationType() == ConfigurationType::PerformanceTracking) {
       setValue(Level::Global, getBool(conf->value()), &m_performanceTrackingMap);
     } else if (conf->configurationType() == ConfigurationType::MaxLogFileSize) {
-      setValue(conf->level(), static_cast<std::size_t>(getULong(conf->value())), &m_maxLogFileSizeMap);
-#if !defined(ELPP_NO_DEFAULT_LOG_FILE)
-      withFileSizeLimit.push_back(conf);
-#endif  // !defined(ELPP_NO_DEFAULT_LOG_FILE)
+      auto v = getULong(conf->value());
+      setValue(conf->level(), static_cast<std::size_t>(v), &m_maxLogFileSizeMap);
+      if (v != 0) {
+        withFileSizeLimit.push_back(conf);
+      }
     } else if (conf->configurationType() == ConfigurationType::LogFlushThreshold) {
       setValue(conf->level(), static_cast<std::size_t>(getULong(conf->value())), &m_logFlushThresholdMap);
     }
@@ -1698,12 +1780,6 @@ std::string TypedConfigurations::resolveFilename(const std::string& filename) {
 }
 
 void TypedConfigurations::insertFile(Level level, const std::string& fullFilename) {
-#if defined(ELPP_NO_LOG_TO_FILE)
-  setValue(level, false, &m_toFileMap);
-  ELPP_UNUSED(fullFilename);
-  m_fileStreamMap.insert(std::make_pair(level, base::FileStreamPtr(nullptr)));
-  return;
-#endif
   std::string resolvedFilename = resolveFilename(fullFilename);
   if (resolvedFilename.empty()) {
     std::cerr << "Could not load empty file for logging, please re-check your configurations for level ["
@@ -1839,8 +1915,10 @@ bool RegisteredLoggers::remove(const std::string& id) {
   if (id == base::consts::kDefaultLoggerId) {
     return false;
   }
+  // get has internal lock
   Logger* logger = base::utils::Registry<Logger, std::string>::get(id);
   if (logger != nullptr) {
+    // unregister has internal lock
     unregister(logger);
   }
   return true;
@@ -1948,7 +2026,7 @@ bool VRegistry::allowed(base::type::VerboseLevel vlevel, const char* file) {
   } else {
     char baseFilename[base::consts::kSourceFilenameMaxLength] = "";
     base::utils::File::buildBaseFilename(file, baseFilename);
-    std::map<std::string, base::type::VerboseLevel>::iterator it = m_modules.begin();
+    std::unordered_map<std::string, base::type::VerboseLevel>::iterator it = m_modules.begin();
     for (; it != m_modules.end(); ++it) {
       if (base::utils::Str::wildCardMatch(baseFilename, it->first.c_str())) {
         return vlevel <= it->second;
@@ -1989,20 +2067,26 @@ Storage::Storage(const LogBuilderPtr& defaultLogBuilder) :
   m_registeredLoggers(new base::RegisteredLoggers(defaultLogBuilder)),
   m_flags(ELPP_DEFAULT_LOGGING_FLAGS),
   m_vRegistry(new base::VRegistry(0, &m_flags)),
+
 #if ELPP_ASYNC_LOGGING
   m_asyncLogQueue(new base::AsyncLogQueue()),
   m_asyncDispatchWorker(asyncDispatchWorker),
 #endif  // ELPP_ASYNC_LOGGING
+
   m_preRollOutCallback(base::defaultPreRollOutCallback) {
   // Register default logger
   m_registeredLoggers->get(std::string(base::consts::kDefaultLoggerId));
   // We register default logger anyway (worse case it's not going to register) just in case
   m_registeredLoggers->get("default");
+
+#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
   // Register performance logger and reconfigure format
   Logger* performanceLogger = m_registeredLoggers->get(std::string(base::consts::kPerformanceLoggerId));
   m_registeredLoggers->get("performance");
   performanceLogger->configurations()->setGlobally(ConfigurationType::Format, std::string("%datetime %level %msg"));
   performanceLogger->reconfigure();
+#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
+
 #if defined(ELPP_SYSLOG)
   // Register syslog logger and reconfigure format
   Logger* sysLogLogger = m_registeredLoggers->get(std::string(base::consts::kSysLogLoggerId));
@@ -2045,7 +2129,7 @@ Storage::~Storage(void) {
 }
 
 bool Storage::hasCustomFormatSpecifier(const char* formatSpecifier) {
-  base::threading::ScopedLock scopedLock(lock());
+  base::threading::ScopedLock scopedLock(customFormatSpecifiersLock());
   return std::find(m_customFormatSpecifiers.begin(), m_customFormatSpecifiers.end(),
                    formatSpecifier) != m_customFormatSpecifiers.end();
 }
@@ -2054,12 +2138,12 @@ void Storage::installCustomFormatSpecifier(const CustomFormatSpecifier& customFo
   if (hasCustomFormatSpecifier(customFormatSpecifier.formatSpecifier())) {
     return;
   }
-  base::threading::ScopedLock scopedLock(lock());
+  base::threading::ScopedLock scopedLock(customFormatSpecifiersLock());
   m_customFormatSpecifiers.push_back(customFormatSpecifier);
 }
 
 bool Storage::uninstallCustomFormatSpecifier(const char* formatSpecifier) {
-  base::threading::ScopedLock scopedLock(lock());
+  base::threading::ScopedLock scopedLock(customFormatSpecifiersLock());
   std::vector<CustomFormatSpecifier>::iterator it = std::find(m_customFormatSpecifiers.begin(),
       m_customFormatSpecifiers.end(), formatSpecifier);
   if (it != m_customFormatSpecifiers.end() && strcmp(formatSpecifier, it->formatSpecifier()) == 0) {
@@ -2097,9 +2181,33 @@ void Storage::setApplicationArguments(int argc, char** argv) {
 #endif  // defined(ELPP_LOGGING_FLAGS_FROM_ARG)
 }
 
+} // namespace base
+
+// LogDispatchCallback
+void LogDispatchCallback::handle(const LogDispatchData* data) {
+#if defined(ELPP_THREAD_SAFE)
+  base::threading::ScopedLock scopedLock(m_fileLocksMapLock);
+  std::string filename = data->logMessage()->logger()->typedConfigurations()->filename(data->logMessage()->level());
+  auto lock = m_fileLocks.find(filename);
+  if (lock == m_fileLocks.end()) {
+    m_fileLocks.emplace(std::make_pair(filename, std::unique_ptr<base::threading::Mutex>(new base::threading::Mutex)));
+  }
+#endif
+}
+
+base::threading::Mutex& LogDispatchCallback::fileHandle(const LogDispatchData* data) {
+  auto it = m_fileLocks.find(data->logMessage()->logger()->typedConfigurations()->filename(data->logMessage()->level()));
+  return *(it->second.get());
+}
+
+namespace base {
 // DefaultLogDispatchCallback
 
 void DefaultLogDispatchCallback::handle(const LogDispatchData* data) {
+#if defined(ELPP_THREAD_SAFE)
+  LogDispatchCallback::handle(data);
+  base::threading::ScopedLock scopedLock(fileHandle(data));
+#endif
   m_data = data;
   dispatch(m_data->logMessage()->logger()->logBuilder()->build(m_data->logMessage(),
            m_data->dispatchAction() == base::DispatchAction::NormalLog));
@@ -2348,7 +2456,7 @@ base::type::string_t DefaultLogBuilder::build(const LogMessage* logMessage, bool
     base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kMessageFormatSpecifier, logMessage->message());
   }
 #if !defined(ELPP_DISABLE_CUSTOM_FORMAT_SPECIFIERS)
-  el::base::threading::ScopedLock lock_(ELPP->lock());
+  el::base::threading::ScopedLock lock_(ELPP->customFormatSpecifiersLock());
   ELPP_UNUSED(lock_);
   for (std::vector<CustomFormatSpecifier>::const_iterator it = ELPP->customFormatSpecifiers()->begin();
        it != ELPP->customFormatSpecifiers()->end(); ++it) {
@@ -2370,9 +2478,15 @@ void LogDispatcher::dispatch(void) {
   if (!m_proceed) {
     return;
   }
-  base::TypedConfigurations* tc = m_logMessage.logger()->m_typedConfigurations;
+#ifndef ELPP_NO_GLOBAL_LOCK
+  // see https://github.com/muflihun/easyloggingpp/issues/580
+  // global lock is turned off by default unless
+  // ELPP_NO_GLOBAL_LOCK is defined
+  base::threading::ScopedLock scopedLock(ELPP->lock());
+#endif
+  base::TypedConfigurations* tc = m_logMessage->logger()->m_typedConfigurations;
   if (ELPP->hasFlag(LoggingFlag::StrictLogFileSizeCheck)) {
-    tc->validateFileRolling(m_logMessage.level(), ELPP->preRollOutCallback());
+    tc->validateFileRolling(m_logMessage->level(), ELPP->preRollOutCallback());
   }
   LogDispatchCallback* callback = nullptr;
   LogDispatchData data;
@@ -2380,7 +2494,7 @@ void LogDispatcher::dispatch(void) {
        : ELPP->m_logDispatchCallbacks) {
     callback = h.second.get();
     if (callback != nullptr && callback->enabled()) {
-      data.setLogMessage(&m_logMessage);
+      data.setLogMessage(m_logMessage);
       data.setDispatchAction(m_dispatchAction);
       callback->handle(&data);
     }
@@ -2427,6 +2541,7 @@ Writer& Writer::construct(int count, const char* loggerIds, ...) {
     va_list loggersList;
     va_start(loggersList, loggerIds);
     const char* id = loggerIds;
+    m_loggerIds.reserve(count);
     for (int i = 0; i < count; ++i) {
       m_loggerIds.push_back(std::string(id));
       id = va_arg(loggersList, const char*);
@@ -2446,7 +2561,6 @@ void Writer::initializeLogger(const std::string& loggerId, bool lookup, bool nee
   }
   if (m_logger == nullptr) {
     {
-      base::threading::ScopedLock scopedLock(ELPP->lock());
       if (!ELPP->registeredLoggers()->has(std::string(base::consts::kDefaultLoggerId))) {
         // Somehow default logger has been unregistered. Not good! Register again
         ELPP->registeredLoggers()->get(std::string(base::consts::kDefaultLoggerId));
@@ -2512,8 +2626,13 @@ void Writer::processDispatch() {
 
 void Writer::triggerDispatch(void) {
   if (m_proceed) {
-    base::LogDispatcher(m_proceed, LogMessage(m_level, m_file, m_line, m_func, m_verboseLevel,
-                        m_logger), m_dispatchAction).dispatch();
+    if (m_msg == nullptr) {
+      LogMessage msg(m_level, m_file, m_line, m_func, m_verboseLevel,
+                     m_logger);
+      base::LogDispatcher(m_proceed, &msg, m_dispatchAction).dispatch();
+    } else {
+      base::LogDispatcher(m_proceed, m_msg, m_dispatchAction).dispatch();
+    }
   }
   if (m_logger != nullptr) {
     m_logger->stream().str(ELPP_LITERAL(""));
@@ -2642,18 +2761,19 @@ namespace debug {
 
 // StackTrace
 
-StackTrace::StackTraceEntry::StackTraceEntry(std::size_t index, const char* loc, const char* demang, const char* hex,
-    const char* addr) {
-  m_index = index;
-  m_location = std::string(loc);
-  m_demangled = std::string(demang);
-  m_hex = std::string(hex);
-  m_addr = std::string(addr);
+StackTrace::StackTraceEntry::StackTraceEntry(std::size_t index, const std::string& loc, const std::string& demang,
+    const std::string& hex,
+    const std::string& addr) :
+  m_index(index),
+  m_location(loc),
+  m_demangled(demang),
+  m_hex(hex),
+  m_addr(addr) {
 }
 
 std::ostream& operator<<(std::ostream& ss, const StackTrace::StackTraceEntry& si) {
-  ss << "[" << si.m_index << "] " << si.m_location << (si.m_demangled.empty() ? "" : ":") << si.m_demangled
-     << (si.m_hex.empty() ? "" : "+") << si.m_hex << si.m_addr;
+  ss << "[" << si.m_index << "] " << si.m_location << (si.m_hex.empty() ? "" : "+") << si.m_hex << " " << si.m_addr <<
+     (si.m_demangled.empty() ? "" : ":") << si.m_demangled;
   return ss;
 }
 
@@ -2673,44 +2793,40 @@ void StackTrace::generateNew(void) {
   char** strings = backtrace_symbols(stack, size);
   if (size > kStackStart) {  // Skip StackTrace c'tor and generateNew
     for (std::size_t i = kStackStart; i < size; ++i) {
-      char* mangName = nullptr;
-      char* hex = nullptr;
-      char* addr = nullptr;
-      for (char* c = strings[i]; *c; ++c) {
-        switch (*c) {
-        case '(':
-          mangName = c;
-          break;
-        case '+':
-          hex = c;
-          break;
-        case ')':
-          addr = c;
-          break;
-        default:
-          break;
-        }
+      std::string mangName;
+      std::string location;
+      std::string hex;
+      std::string addr;
+
+      // entry: 2   crash.cpp.bin                       0x0000000101552be5 _ZN2el4base5debug10StackTraceC1Ev + 21
+      const std::string line(strings[i]);
+      auto p = line.find("_");
+      if (p != std::string::npos) {
+        mangName = line.substr(p);
+        mangName = mangName.substr(0, mangName.find(" +"));
+      }
+      p = line.find("0x");
+      if (p != std::string::npos) {
+        addr = line.substr(p);
+        addr = addr.substr(0, addr.find("_"));
       }
       // Perform demangling if parsed properly
-      if (mangName != nullptr && hex != nullptr && addr != nullptr && mangName < hex) {
-        *mangName++ = '\0';
-        *hex++ = '\0';
-        *addr++ = '\0';
+      if (!mangName.empty()) {
         int status = 0;
-        char* demangName = abi::__cxa_demangle(mangName, 0, 0, &status);
+        char* demangName = abi::__cxa_demangle(mangName.data(), 0, 0, &status);
         // if demangling is successful, output the demangled function name
         if (status == 0) {
           // Success (see http://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html)
-          StackTraceEntry entry(i - 1, strings[i], demangName, hex, addr);
+          StackTraceEntry entry(i - 1, location, demangName, hex, addr);
           m_stack.push_back(entry);
         } else {
           // Not successful - we will use mangled name
-          StackTraceEntry entry(i - 1, strings[i], mangName, hex, addr);
+          StackTraceEntry entry(i - 1, location, mangName, hex, addr);
           m_stack.push_back(entry);
         }
         free(demangName);
       } else {
-        StackTraceEntry entry(i - 1, strings[i]);
+        StackTraceEntry entry(i - 1, line);
         m_stack.push_back(entry);
       }
     }
@@ -2744,6 +2860,9 @@ static std::string crashReason(int sig) {
 }
 /// @brief Logs reason of crash from sig
 static void logCrashReason(int sig, bool stackTraceIfAvailable, Level level, const char* logger) {
+  if (sig == SIGINT && ELPP->hasFlag(el::LoggingFlag::IgnoreSigInt)) {
+    return;
+  }
   std::stringstream ss;
   ss << "CRASH HANDLED; ";
   ss << crashReason(sig);
@@ -2822,7 +2941,6 @@ void Helpers::logCrashReason(int sig, bool stackTraceIfAvailable, Level level, c
 // Loggers
 
 Logger* Loggers::getLogger(const std::string& identity, bool registerIfNotAvailable) {
-  base::threading::ScopedLock scopedLock(ELPP->lock());
   return ELPP->registeredLoggers()->get(identity, registerIfNotAvailable);
 }
 
@@ -2831,12 +2949,10 @@ void Loggers::setDefaultLogBuilder(el::LogBuilderPtr& logBuilderPtr) {
 }
 
 bool Loggers::unregisterLogger(const std::string& identity) {
-  base::threading::ScopedLock scopedLock(ELPP->lock());
   return ELPP->registeredLoggers()->remove(identity);
 }
 
 bool Loggers::hasLogger(const std::string& identity) {
-  base::threading::ScopedLock scopedLock(ELPP->lock());
   return ELPP->registeredLoggers()->has(identity);
 }
 
@@ -2986,11 +3102,11 @@ void Loggers::clearVModules(void) {
 // VersionInfo
 
 const std::string VersionInfo::version(void) {
-  return std::string("9.95.3");
+  return std::string("9.96.7");
 }
 /// @brief Release date of current version
 const std::string VersionInfo::releaseDate(void) {
-  return std::string("13-10-2017 1134hrs");
+  return std::string("24-11-2018 0728hrs");
 }
 
 } // namespace el

+ 117 - 154
Third_party/EasyLogging++/easylogging++.h

@@ -1,25 +1,25 @@
 //
 //  Bismillah ar-Rahmaan ar-Raheem
 //
-//  Easylogging++ v9.95.3
+//  Easylogging++ v9.96.7
 //  Single-header only, cross-platform logging library for C++ applications
 //
-//  Copyright (c) 2017 muflihun.com
+//  Copyright (c) 2012-2018 Zuhd Web Services
+//  Copyright (c) 2012-2018 @abumusamq
 //
 //  This library is released under the MIT Licence.
-//  http://labs.muflihun.com/easyloggingpp/licence.php
+//  https://github.com/zuhd-org/easyloggingpp/blob/master/LICENSE
 //
-//  https://github.com/muflihun/easyloggingpp
-//  https://muflihun.github.io/easyloggingpp
+//  https://zuhd.org
 //  http://muflihun.com
 //
+
 #ifndef EASYLOGGINGPP_H
 #define EASYLOGGINGPP_H
 
-#define ELPP_FEATURE_CRASH_LOG
-#define ELPP_HANDLE_SIGABRT
-#define ELPP_DEFAULT_LOG_FILE "dat_library.log"
-#define ELPP_DEBUG_ERRORS
+#define ELPP_HANDLE_SIGABRT 
+#define ELPP_UNICODE
+#define ELPP_NO_DEFAULT_LOG_FILE
 
 // Compilers and C++0x/C++11 Evaluation
 #if __cplusplus >= 201103L
@@ -119,8 +119,13 @@
 #else
 #  define ELPP_OS_NETBSD 0
 #endif
+#if defined(__EMSCRIPTEN__)
+#  define ELPP_OS_EMSCRIPTEN 1
+#else
+#  define ELPP_OS_EMSCRIPTEN 0
+#endif
 // Unix
-#if ((ELPP_OS_LINUX || ELPP_OS_MAC || ELPP_OS_FREEBSD || ELPP_OS_NETBSD || ELPP_OS_SOLARIS || ELPP_OS_AIX) && (!ELPP_OS_WINDOWS))
+#if ((ELPP_OS_LINUX || ELPP_OS_MAC || ELPP_OS_FREEBSD || ELPP_OS_NETBSD || ELPP_OS_SOLARIS || ELPP_OS_AIX || ELPP_OS_EMSCRIPTEN) && (!ELPP_OS_WINDOWS))
 #  define ELPP_OS_UNIX 1
 #else
 #  define ELPP_OS_UNIX 0
@@ -205,7 +210,7 @@ ELPP_INTERNAL_DEBUGGING_OUT_INFO << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStre
 #  define ELPP_INTERNAL_INFO(lvl, msg)
 #endif  // (defined(ELPP_DEBUG_INFO))
 #if (defined(ELPP_FEATURE_ALL)) || (defined(ELPP_FEATURE_CRASH_LOG))
-#  if (ELPP_COMPILER_GCC && !ELPP_MINGW && !ELPP_OS_ANDROID)
+#  if (ELPP_COMPILER_GCC && !ELPP_MINGW && !ELPP_OS_ANDROID && !ELPP_OS_EMSCRIPTEN)
 #    define ELPP_STACKTRACE 1
 #  else
 #      if ELPP_COMPILER_MSVC
@@ -384,6 +389,7 @@ ELPP_INTERNAL_DEBUGGING_OUT_INFO << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStre
 #include <string>
 #include <vector>
 #include <map>
+#include <unordered_map>
 #include <utility>
 #include <functional>
 #include <algorithm>
@@ -421,9 +427,6 @@ ELPP_INTERNAL_DEBUGGING_OUT_INFO << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStre
 #  if defined(ELPP_LOG_STD_ARRAY)
 #      include <array>
 #  endif  // defined(ELPP_LOG_STD_ARRAY)
-#  if defined(ELPP_LOG_UNORDERED_MAP)
-#      include <unordered_map>
-#  endif  // defined(ELPP_LOG_UNORDERED_MAP)
 #  if defined(ELPP_LOG_UNORDERED_SET)
 #      include <unordered_set>
 #  endif  // defined(ELPP_UNORDERED_SET)
@@ -591,6 +594,16 @@ enum class Level : base::type::EnumType {
   /// @brief Represents unknown level
   Unknown = 1010
 };
+} // namespace el
+namespace std {
+template<> struct hash<el::Level> {
+ public:
+  std::size_t operator()(const el::Level& l) const {
+    return hash<el::base::type::EnumType> {}(static_cast<el::base::type::EnumType>(l));
+  }
+};
+}
+namespace el {
 /// @brief Static class that contains helper functions for el::Level
 class LevelHelper : base::StaticClass {
  public:
@@ -713,115 +726,43 @@ enum class LoggingFlag : base::type::EnumType {
   /// @brief Adds spaces b/w logs that separated by left-shift operator
   AutoSpacing = 8192,
   /// @brief Preserves time format and does not convert it to sec, hour etc (performance tracking only)
-  FixedTimeFormat = 16384
+  FixedTimeFormat = 16384,
+  // @brief Ignore SIGINT or crash
+  IgnoreSigInt = 32768,
 };
 namespace base {
 /// @brief Namespace containing constants used internally.
 namespace consts {
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-variable"
-#endif
-// Level log values - These are values that are replaced in place of %level format specifier
-// Extra spaces after format specifiers are only for readability purposes in log files
-static const base::type::char_t* kInfoLevelLogValue     =   ELPP_LITERAL("INFO");
-static const base::type::char_t* kDebugLevelLogValue    =   ELPP_LITERAL("DEBUG");
-static const base::type::char_t* kWarningLevelLogValue  =   ELPP_LITERAL("WARNING");
-static const base::type::char_t* kErrorLevelLogValue    =   ELPP_LITERAL("ERROR");
-static const base::type::char_t* kFatalLevelLogValue    =   ELPP_LITERAL("FATAL");
-static const base::type::char_t* kVerboseLevelLogValue  =
-  ELPP_LITERAL("VERBOSE"); // will become VERBOSE-x where x = verbose level
-static const base::type::char_t* kTraceLevelLogValue    =   ELPP_LITERAL("TRACE");
-static const base::type::char_t* kInfoLevelShortLogValue     =   ELPP_LITERAL("I");
-static const base::type::char_t* kDebugLevelShortLogValue    =   ELPP_LITERAL("D");
-static const base::type::char_t* kWarningLevelShortLogValue  =   ELPP_LITERAL("W");
-static const base::type::char_t* kErrorLevelShortLogValue    =   ELPP_LITERAL("E");
-static const base::type::char_t* kFatalLevelShortLogValue    =   ELPP_LITERAL("F");
-static const base::type::char_t* kVerboseLevelShortLogValue  =   ELPP_LITERAL("V");
-static const base::type::char_t* kTraceLevelShortLogValue    =   ELPP_LITERAL("T");
-// Format specifiers - These are used to define log format
-static const base::type::char_t* kAppNameFormatSpecifier          =      ELPP_LITERAL("%app");
-static const base::type::char_t* kLoggerIdFormatSpecifier         =      ELPP_LITERAL("%logger");
-static const base::type::char_t* kThreadIdFormatSpecifier         =      ELPP_LITERAL("%thread");
-static const base::type::char_t* kSeverityLevelFormatSpecifier    =      ELPP_LITERAL("%level");
-static const base::type::char_t* kSeverityLevelShortFormatSpecifier    =      ELPP_LITERAL("%levshort");
-static const base::type::char_t* kDateTimeFormatSpecifier         =      ELPP_LITERAL("%datetime");
-static const base::type::char_t* kLogFileFormatSpecifier          =      ELPP_LITERAL("%file");
-static const base::type::char_t* kLogFileBaseFormatSpecifier      =      ELPP_LITERAL("%fbase");
-static const base::type::char_t* kLogLineFormatSpecifier          =      ELPP_LITERAL("%line");
-static const base::type::char_t* kLogLocationFormatSpecifier      =      ELPP_LITERAL("%loc");
-static const base::type::char_t* kLogFunctionFormatSpecifier      =      ELPP_LITERAL("%func");
-static const base::type::char_t* kCurrentUserFormatSpecifier      =      ELPP_LITERAL("%user");
-static const base::type::char_t* kCurrentHostFormatSpecifier      =      ELPP_LITERAL("%host");
-static const base::type::char_t* kMessageFormatSpecifier          =      ELPP_LITERAL("%msg");
-static const base::type::char_t* kVerboseLevelFormatSpecifier     =      ELPP_LITERAL("%vlevel");
-static const char* kDateTimeFormatSpecifierForFilename            =      "%datetime";
-// Date/time
-static const char* kDays[7]                         =      { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
-static const char* kDaysAbbrev[7]                   =      { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
-static const char* kMonths[12]                      =      { "January", "February", "March", "Apri", "May", "June", "July", "August",
-                                                             "September", "October", "November", "December"
-                                                           };
-static const char* kMonthsAbbrev[12]                =      { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
-static const char* kDefaultDateTimeFormat           =      "%Y-%M-%d %H:%m:%s,%g";
-static const char* kDefaultDateTimeFormatInFilename =      "%Y-%M-%d_%H-%m";
-static const int kYearBase                          =      1900;
-static const char* kAm                              =      "AM";
-static const char* kPm                              =      "PM";
-// Miscellaneous constants
+static const char  kFormatSpecifierCharValue               =      'v';
+static const char  kFormatSpecifierChar                    =      '%';
+static const unsigned int kMaxLogPerCounter                =      100000;
+static const unsigned int kMaxLogPerContainer              =      100;
+static const unsigned int kDefaultSubsecondPrecision       =      3;
+
 #ifdef ELPP_DEFAULT_LOGGER
 static const char* kDefaultLoggerId                        =      ELPP_DEFAULT_LOGGER;
 #else
 static const char* kDefaultLoggerId                        =      "default";
 #endif
+
+#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
 #ifdef ELPP_DEFAULT_PERFORMANCE_LOGGER
 static const char* kPerformanceLoggerId                    =      ELPP_DEFAULT_PERFORMANCE_LOGGER;
 #else
 static const char* kPerformanceLoggerId                    =      "performance";
+#endif // ELPP_DEFAULT_PERFORMANCE_LOGGER
 #endif
+
 #if defined(ELPP_SYSLOG)
 static const char* kSysLogLoggerId                         =      "syslog";
 #endif  // defined(ELPP_SYSLOG)
-static const char* kNullPointer                            =      "nullptr";
-static const char  kFormatSpecifierChar                    =      '%';
-#if ELPP_VARIADIC_TEMPLATES_SUPPORTED
-static const char  kFormatSpecifierCharValue               =      'v';
-#endif  // ELPP_VARIADIC_TEMPLATES_SUPPORTED
-static const unsigned int kMaxLogPerContainer              =      100;
-static const unsigned int kMaxLogPerCounter                =      100000;
-static const unsigned int kDefaultSubsecondPrecision       =      3;
-static const base::type::VerboseLevel kMaxVerboseLevel     =      9;
-static const char* kUnknownUser                            =      "user";
-static const char* kUnknownHost                            =      "unknown-host";
-#if defined(ELPP_DEFAULT_LOG_FILE)
-static const char* kDefaultLogFile                         =      ELPP_DEFAULT_LOG_FILE;
-#else
-#  if ELPP_OS_UNIX
-#      if ELPP_OS_ANDROID
-static const char* kDefaultLogFile                         =      "logs/myeasylog.log";
-#      else
-static const char* kDefaultLogFile                         =      "logs/myeasylog.log";
-#      endif  // ELPP_OS_ANDROID
-#  elif ELPP_OS_WINDOWS
-static const char* kDefaultLogFile                         =      "logs\\myeasylog.log";
-#  endif  // ELPP_OS_UNIX
-#endif  // defined(ELPP_DEFAULT_LOG_FILE)
-#if !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG)
-static const char* kDefaultLogFileParam                    =      "--default-log-file";
-#endif  // !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG)
-#if defined(ELPP_LOGGING_FLAGS_FROM_ARG)
-static const char* kLoggingFlagsParam                      =      "--logging-flags";
-#endif  // defined(ELPP_LOGGING_FLAGS_FROM_ARG)
+
 #if ELPP_OS_WINDOWS
 static const char* kFilePathSeperator                      =      "\\";
 #else
 static const char* kFilePathSeperator                      =      "/";
 #endif  // ELPP_OS_WINDOWS
-static const char* kValidLoggerIdSymbols                   =
-  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._";
-static const char* kConfigurationComment                   =      "##";
-static const char* kConfigurationLevel                     =      "*";
-static const char* kConfigurationLoggerId                  =      "--";
+
 static const std::size_t kSourceFilenameMaxLength          =      100;
 static const std::size_t kSourceLineMaxLength              =      10;
 static const Level kPerformanceTrackerDefaultLevel         =      Level::Info;
@@ -866,9 +807,6 @@ const struct {
   },
 };
 static const int kCrashSignalsCount                          =      sizeof(kCrashSignals) / sizeof(kCrashSignals[0]);
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
 }  // namespace consts
 }  // namespace base
 typedef std::function<void(const char*, std::size_t)> PreRollOutCallback;
@@ -1268,8 +1206,8 @@ class DateTime : base::StaticClass {
       base::TimestampUnit timestampUnit);
 
 
- private:
   static struct ::tm* buildTimeInfo(struct timeval* currTime, struct ::tm* timeInfo);
+ private:
   static char* parseFormat(char* buf, std::size_t bufSz, const char* format, const struct tm* tInfo,
                            std::size_t msec, const base::SubsecondPrecision* ssPrec);
 };
@@ -1308,7 +1246,7 @@ class CommandLineArgs {
  private:
   int m_argc;
   char** m_argv;
-  std::map<std::string, std::string> m_paramsWithValue;
+  std::unordered_map<std::string, std::string> m_paramsWithValue;
   std::vector<std::string> m_params;
 };
 /// @brief Abstract registry (aka repository) that provides basic interface for pointer repository specified by T_Ptr type.
@@ -1433,7 +1371,7 @@ class AbstractRegistry : public base::threading::ThreadSafe {
 ///         of AbstractRegistry<T_Ptr, Container>. Any implementation of this class should be
 ///         explicitly (by using lock functions)
 template <typename T_Ptr, typename T_Key = const char*>
-class Registry : public AbstractRegistry<T_Ptr, std::map<T_Key, T_Ptr*>> {
+class Registry : public AbstractRegistry<T_Ptr, std::unordered_map<T_Key, T_Ptr*>> {
  public:
   typedef typename Registry<T_Ptr, T_Key>::iterator iterator;
   typedef typename Registry<T_Ptr, T_Key>::const_iterator const_iterator;
@@ -1497,7 +1435,7 @@ class Registry : public AbstractRegistry<T_Ptr, std::map<T_Key, T_Ptr*>> {
   }
 
  private:
-  virtual void deepCopy(const AbstractRegistry<T_Ptr, std::map<T_Key, T_Ptr*>>& sr) ELPP_FINAL {
+  virtual void deepCopy(const AbstractRegistry<T_Ptr, std::unordered_map<T_Key, T_Ptr*>>& sr) ELPP_FINAL {
     for (const_iterator it = sr.cbegin(); it != sr.cend(); ++it) {
       registerNew(it->first, new T_Ptr(*it->second));
     }
@@ -1597,7 +1535,7 @@ class RegistryWithPred : public AbstractRegistry<T_Ptr, std::vector<T_Ptr*>> {
 class Utils {
  public:
   template <typename T, typename TPtr>
-  static bool installCallback(const std::string& id, std::map<std::string, TPtr>* mapT) {
+  static bool installCallback(const std::string& id, std::unordered_map<std::string, TPtr>* mapT) {
     if (mapT->find(id) == mapT->end()) {
       mapT->insert(std::make_pair(id, TPtr(new T())));
       return true;
@@ -1606,15 +1544,15 @@ class Utils {
   }
 
   template <typename T, typename TPtr>
-  static void uninstallCallback(const std::string& id, std::map<std::string, TPtr>* mapT) {
+  static void uninstallCallback(const std::string& id, std::unordered_map<std::string, TPtr>* mapT) {
     if (mapT->find(id) != mapT->end()) {
       mapT->erase(id);
     }
   }
 
   template <typename T, typename TPtr>
-  static T* callback(const std::string& id, std::map<std::string, TPtr>* mapT) {
-    typename std::map<std::string, TPtr>::iterator iter = mapT->find(id);
+  static T* callback(const std::string& id, std::unordered_map<std::string, TPtr>* mapT) {
+    typename std::unordered_map<std::string, TPtr>::iterator iter = mapT->find(id);
     if (iter != mapT->end()) {
       return static_cast<T*>(iter->second.get());
     }
@@ -1959,7 +1897,7 @@ class Configurations : public base::utils::RegistryWithPred<Configuration, Confi
 
 namespace base {
 typedef std::shared_ptr<base::type::fstream_t> FileStreamPtr;
-typedef std::map<std::string, FileStreamPtr> LogStreamsReferenceMap;
+typedef std::unordered_map<std::string, FileStreamPtr> LogStreamsReferenceMap;
 /// @brief Configurations with data types.
 ///
 /// @detail el::Configurations have string based values. This is whats used internally in order to read correct configurations.
@@ -1996,16 +1934,16 @@ class TypedConfigurations : public base::threading::ThreadSafe {
 
  private:
   Configurations* m_configurations;
-  std::map<Level, bool> m_enabledMap;
-  std::map<Level, bool> m_toFileMap;
-  std::map<Level, std::string> m_filenameMap;
-  std::map<Level, bool> m_toStandardOutputMap;
-  std::map<Level, base::LogFormat> m_logFormatMap;
-  std::map<Level, base::SubsecondPrecision> m_subsecondPrecisionMap;
-  std::map<Level, bool> m_performanceTrackingMap;
-  std::map<Level, base::FileStreamPtr> m_fileStreamMap;
-  std::map<Level, std::size_t> m_maxLogFileSizeMap;
-  std::map<Level, std::size_t> m_logFlushThresholdMap;
+  std::unordered_map<Level, bool> m_enabledMap;
+  std::unordered_map<Level, bool> m_toFileMap;
+  std::unordered_map<Level, std::string> m_filenameMap;
+  std::unordered_map<Level, bool> m_toStandardOutputMap;
+  std::unordered_map<Level, base::LogFormat> m_logFormatMap;
+  std::unordered_map<Level, base::SubsecondPrecision> m_subsecondPrecisionMap;
+  std::unordered_map<Level, bool> m_performanceTrackingMap;
+  std::unordered_map<Level, base::FileStreamPtr> m_fileStreamMap;
+  std::unordered_map<Level, std::size_t> m_maxLogFileSizeMap;
+  std::unordered_map<Level, std::size_t> m_logFlushThresholdMap;
   base::LogStreamsReferenceMap* m_logStreamsReference;
 
   friend class el::Helpers;
@@ -2015,21 +1953,21 @@ class TypedConfigurations : public base::threading::ThreadSafe {
   friend class el::base::LogDispatcher;
 
   template <typename Conf_T>
-  inline Conf_T getConfigByVal(Level level, const std::map<Level, Conf_T>* confMap, const char* confName) {
+  inline Conf_T getConfigByVal(Level level, const std::unordered_map<Level, Conf_T>* confMap, const char* confName) {
     base::threading::ScopedLock scopedLock(lock());
     return unsafeGetConfigByVal(level, confMap, confName);  // This is not unsafe anymore - mutex locked in scope
   }
 
   template <typename Conf_T>
-  inline Conf_T& getConfigByRef(Level level, std::map<Level, Conf_T>* confMap, const char* confName) {
+  inline Conf_T& getConfigByRef(Level level, std::unordered_map<Level, Conf_T>* confMap, const char* confName) {
     base::threading::ScopedLock scopedLock(lock());
     return unsafeGetConfigByRef(level, confMap, confName);  // This is not unsafe anymore - mutex locked in scope
   }
 
   template <typename Conf_T>
-  Conf_T unsafeGetConfigByVal(Level level, const std::map<Level, Conf_T>* confMap, const char* confName) {
+  Conf_T unsafeGetConfigByVal(Level level, const std::unordered_map<Level, Conf_T>* confMap, const char* confName) {
     ELPP_UNUSED(confName);
-    typename std::map<Level, Conf_T>::const_iterator it = confMap->find(level);
+    typename std::unordered_map<Level, Conf_T>::const_iterator it = confMap->find(level);
     if (it == confMap->end()) {
       try {
         return confMap->at(Level::Global);
@@ -2044,9 +1982,9 @@ class TypedConfigurations : public base::threading::ThreadSafe {
   }
 
   template <typename Conf_T>
-  Conf_T& unsafeGetConfigByRef(Level level, std::map<Level, Conf_T>* confMap, const char* confName) {
+  Conf_T& unsafeGetConfigByRef(Level level, std::unordered_map<Level, Conf_T>* confMap, const char* confName) {
     ELPP_UNUSED(confName);
-    typename std::map<Level, Conf_T>::iterator it = confMap->find(level);
+    typename std::unordered_map<Level, Conf_T>::iterator it = confMap->find(level);
     if (it == confMap->end()) {
       try {
         return confMap->at(Level::Global);
@@ -2060,14 +1998,15 @@ class TypedConfigurations : public base::threading::ThreadSafe {
   }
 
   template <typename Conf_T>
-  void setValue(Level level, const Conf_T& value, std::map<Level, Conf_T>* confMap, bool includeGlobalLevel = true) {
+  void setValue(Level level, const Conf_T& value, std::unordered_map<Level, Conf_T>* confMap,
+                bool includeGlobalLevel = true) {
     // If map is empty and we are allowed to add into generic level (Level::Global), do it!
     if (confMap->empty() && includeGlobalLevel) {
       confMap->insert(std::make_pair(Level::Global, value));
       return;
     }
     // If same value exist in generic level already, dont add it to explicit level
-    typename std::map<Level, Conf_T>::iterator it = confMap->find(Level::Global);
+    typename std::unordered_map<Level, Conf_T>::iterator it = confMap->find(Level::Global);
     if (it != confMap->end() && it->second == value) {
       return;
     }
@@ -2229,21 +2168,26 @@ class LogDispatchData {
   inline base::DispatchAction dispatchAction(void) const {
     return m_dispatchAction;
   }
- private:
-  LogMessage* m_logMessage;
-  base::DispatchAction m_dispatchAction;
-  friend class base::LogDispatcher;
-
   inline void setLogMessage(LogMessage* logMessage) {
     m_logMessage = logMessage;
   }
   inline void setDispatchAction(base::DispatchAction dispatchAction) {
     m_dispatchAction = dispatchAction;
   }
+ private:
+  LogMessage* m_logMessage;
+  base::DispatchAction m_dispatchAction;
+  friend class base::LogDispatcher;
+
 };
 class LogDispatchCallback : public Callback<LogDispatchData> {
+ protected:
+  virtual void handle(const LogDispatchData* data);
+  base::threading::Mutex& fileHandle(const LogDispatchData* data);
  private:
   friend class base::LogDispatcher;
+  std::unordered_map<std::string, std::unique_ptr<base::threading::Mutex>> m_fileLocks;
+  base::threading::Mutex m_fileLocksMapLock;
 };
 class PerformanceTrackingCallback : public Callback<PerformanceTrackingData> {
  private:
@@ -2361,7 +2305,7 @@ inline void FUNCTION_NAME(const T&);
   std::string m_parentApplicationName;
   bool m_isConfigured;
   Configurations m_configurations;
-  std::map<Level, unsigned int> m_unflushedCount;
+  std::unordered_map<Level, unsigned int> m_unflushedCount;
   base::LogStreamsReferenceMap* m_logStreamsReference;
   LogBuilderPtr m_logBuilder;
 
@@ -2467,7 +2411,7 @@ class RegisteredLoggers : public base::utils::Registry<Logger, std::string> {
   LogBuilderPtr m_defaultLogBuilder;
   Configurations m_defaultConfigurations;
   base::LogStreamsReferenceMap m_logStreamsReference;
-  std::map<std::string, base::type::LoggerRegistrationCallbackPtr> m_loggerRegistrationCallbacks;
+  std::unordered_map<std::string, base::type::LoggerRegistrationCallbackPtr> m_loggerRegistrationCallbacks;
   friend class el::base::Storage;
 
   void unsafeFlushAll(void);
@@ -2493,7 +2437,7 @@ class VRegistry : base::NoCopy, public base::threading::ThreadSafe {
 
   bool allowed(base::type::VerboseLevel vlevel, const char* file);
 
-  inline const std::map<std::string, base::type::VerboseLevel>& modules(void) const {
+  inline const std::unordered_map<std::string, base::type::VerboseLevel>& modules(void) const {
     return m_modules;
   }
 
@@ -2507,7 +2451,7 @@ class VRegistry : base::NoCopy, public base::threading::ThreadSafe {
  private:
   base::type::VerboseLevel m_level;
   base::type::EnumType* m_pFlags;
-  std::map<std::string, base::type::VerboseLevel> m_modules;
+  std::unordered_map<std::string, base::type::VerboseLevel> m_modules;
 };
 }  // namespace base
 class LogMessage {
@@ -2691,6 +2635,10 @@ class Storage : base::NoCopy, public base::threading::ThreadSafe {
     return &m_customFormatSpecifiers;
   }
 
+  base::threading::Mutex& customFormatSpecifiersLock() {
+    return m_customFormatSpecifiersLock;
+  }
+
   inline void setLoggingLevel(Level level) {
     m_loggingLevel = level;
   }
@@ -2731,12 +2679,13 @@ class Storage : base::NoCopy, public base::threading::ThreadSafe {
   /// @brief Sets thread name for current thread. Requires std::thread
   inline void setThreadName(const std::string& name) {
     if (name.empty()) return;
-    base::threading::ScopedLock scopedLock(lock());
+    base::threading::ScopedLock scopedLock(m_threadNamesLock);
     m_threadNames[base::threading::getCurrentThreadId()] = name;
   }
 
   inline std::string getThreadName(const std::string& threadId) {
-    std::map<std::string, std::string>::const_iterator it = m_threadNames.find(threadId);
+    base::threading::ScopedLock scopedLock(m_threadNamesLock);
+    std::unordered_map<std::string, std::string>::const_iterator it = m_threadNames.find(threadId);
     if (it == m_threadNames.end()) {
       return threadId;
     }
@@ -2753,10 +2702,12 @@ class Storage : base::NoCopy, public base::threading::ThreadSafe {
 #endif  // ELPP_ASYNC_LOGGING
   base::utils::CommandLineArgs m_commandLineArgs;
   PreRollOutCallback m_preRollOutCallback;
-  std::map<std::string, base::type::LogDispatchCallbackPtr> m_logDispatchCallbacks;
-  std::map<std::string, base::type::PerformanceTrackingCallbackPtr> m_performanceTrackingCallbacks;
-  std::map<std::string, std::string> m_threadNames;
+  std::unordered_map<std::string, base::type::LogDispatchCallbackPtr> m_logDispatchCallbacks;
+  std::unordered_map<std::string, base::type::PerformanceTrackingCallbackPtr> m_performanceTrackingCallbacks;
+  std::unordered_map<std::string, std::string> m_threadNames;
   std::vector<CustomFormatSpecifier> m_customFormatSpecifiers;
+  base::threading::Mutex m_customFormatSpecifiersLock;
+  base::threading::Mutex m_threadNamesLock;
   Level m_loggingLevel;
 
   friend class el::Helpers;
@@ -2799,7 +2750,7 @@ class AsyncDispatchWorker : public base::IWorker, public base::threading::Thread
   void run(void);
 
   void setContinueRunning(bool value) {
-    base::threading::ScopedLock scopedLock(m_continueRunningMutex);
+    base::threading::ScopedLock scopedLock(m_continueRunningLock);
     m_continueRunning = value;
   }
 
@@ -2809,7 +2760,7 @@ class AsyncDispatchWorker : public base::IWorker, public base::threading::Thread
  private:
   std::condition_variable cv;
   bool m_continueRunning;
-  base::threading::Mutex m_continueRunningMutex;
+  base::threading::Mutex m_continueRunningLock;
 };
 #endif  // ELPP_ASYNC_LOGGING
 }  // namespace base
@@ -2821,9 +2772,9 @@ class DefaultLogBuilder : public LogBuilder {
 /// @brief Dispatches log messages
 class LogDispatcher : base::NoCopy {
  public:
-  LogDispatcher(bool proceed, LogMessage&& logMessage, base::DispatchAction dispatchAction) :
+  LogDispatcher(bool proceed, LogMessage* logMessage, base::DispatchAction dispatchAction) :
     m_proceed(proceed),
-    m_logMessage(std::move(logMessage)),
+    m_logMessage(logMessage),
     m_dispatchAction(std::move(dispatchAction)) {
   }
 
@@ -2831,7 +2782,7 @@ class LogDispatcher : base::NoCopy {
 
  private:
   bool m_proceed;
-  LogMessage m_logMessage;
+  LogMessage* m_logMessage;
   base::DispatchAction m_dispatchAction;
 };
 #if defined(ELPP_STL_LOGGING)
@@ -3244,10 +3195,15 @@ class Writer : base::NoCopy {
   Writer(Level level, const char* file, base::type::LineNumber line,
          const char* func, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog,
          base::type::VerboseLevel verboseLevel = 0) :
-    m_level(level), m_file(file), m_line(line), m_func(func), m_verboseLevel(verboseLevel),
+    m_msg(nullptr), m_level(level), m_file(file), m_line(line), m_func(func), m_verboseLevel(verboseLevel),
     m_logger(nullptr), m_proceed(false), m_dispatchAction(dispatchAction) {
   }
 
+  Writer(LogMessage* msg, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog) :
+    m_msg(msg), m_level(msg != nullptr ? msg->level() : Level::Unknown),
+    m_line(0), m_logger(nullptr), m_proceed(false), m_dispatchAction(dispatchAction) {
+  }
+
   virtual ~Writer(void) {
     processDispatch();
   }
@@ -3278,6 +3234,7 @@ class Writer : base::NoCopy {
   Writer& construct(Logger* logger, bool needLock = true);
   Writer& construct(int count, const char* loggerIds, ...);
  protected:
+  LogMessage* m_msg;
   Level m_level;
   const char* m_file;
   const base::type::LineNumber m_line;
@@ -3615,8 +3572,9 @@ class StackTrace : base::NoCopy {
   static const unsigned int kStackStart = 2;  // We want to skip c'tor and StackTrace::generateNew()
   class StackTraceEntry {
    public:
-    StackTraceEntry(std::size_t index, const char* loc, const char* demang, const char* hex, const char* addr);
-    StackTraceEntry(std::size_t index, char* loc) :
+    StackTraceEntry(std::size_t index, const std::string& loc, const std::string& demang, const std::string& hex,
+                    const std::string& addr);
+    StackTraceEntry(std::size_t index, const std::string& loc) :
       m_index(index),
       m_location(loc) {
     }
@@ -3801,6 +3759,11 @@ class Helpers : base::StaticClass {
   static inline const el::base::utils::CommandLineArgs* commandLineArgs(void) {
     return ELPP->commandLineArgs();
   }
+  /// @brief Reserve space for custom format specifiers for performance
+  /// @see std::vector::reserve
+  static inline void reserveCustomFormatSpecifiers(std::size_t size) {
+    ELPP->m_customFormatSpecifiers.reserve(size);
+  }
   /// @brief Installs user defined format specifier and handler
   static inline void installCustomFormatSpecifier(const CustomFormatSpecifier& customFormatSpecifier) {
     ELPP->installCustomFormatSpecifier(customFormatSpecifier);
@@ -3814,7 +3777,7 @@ class Helpers : base::StaticClass {
     return ELPP->hasCustomFormatSpecifier(formatSpecifier);
   }
   static inline void validateFileRolling(Logger* logger, Level level) {
-    if (logger == nullptr) return;
+    if (ELPP == nullptr || logger == nullptr) return;
     logger->m_typedConfigurations->validateFileRolling(level, ELPP->preRollOutCallback());
   }
 };

+ 7 - 4
src/DatFile.cpp

@@ -29,7 +29,8 @@ namespace LOTRO_DAT {
         el::Loggers::addFlag(el::LoggingFlag::LogDetailedCrashReason);
         el::Loggers::addFlag(el::LoggingFlag::ImmediateFlush);
         el::Loggers::addFlag(el::LoggingFlag::StrictLogFileSizeCheck);
-
+        el::Loggers::addFlag(el::LoggingFlag::LogDetailedCrashReason);
+        
         defaultConf.setToDefault();
         defaultConf.setGlobally(el::ConfigurationType::Format, "%datetime %level : %msg (function: %func)");
 
@@ -38,11 +39,13 @@ namespace LOTRO_DAT {
         defaultConf.setGlobally(el::ConfigurationType::Filename, "dat_library.log");
         defaultConf.setGlobally(el::ConfigurationType::ToStandardOutput, "false");
         defaultConf.setGlobally(el::ConfigurationType::PerformanceTracking, "true");
-        defaultConf.setGlobally(el::ConfigurationType::MaxLogFileSize, "5242880"); // 5MB
+        defaultConf.setGlobally(el::ConfigurationType::MaxLogFileSize, "‭20971520‬"); // 20MB
 
-        defaultConf.set(el::Level::Debug, el::ConfigurationType::Enabled, "false");
+        #ifndef NDEBUG
+        defaultConf.set(el::Level::Debug, el::ConfigurationType::Enabled, "true");
         defaultConf.set(el::Level::Debug, el::ConfigurationType::Filename, "dat_library_debug.log");
-
+        #endif
+        
         el::Loggers::reconfigureAllLoggers(defaultConf);
 
         LOG(INFO) << "==================================================================";