Merge pull request #4713

2587aec1 easylogging++: update to latest upstream (v9.96.5) (moneromooo-monero)
This commit is contained in:
Riccardo Spagni 2018-11-06 21:34:07 +02:00
commit 2aabaea1d9
No known key found for this signature in database
GPG key ID: 55432DF31CCD4FCD
3 changed files with 349 additions and 240 deletions

View file

@ -6,6 +6,7 @@
#define ELPP_NO_CHECK_MACROS #define ELPP_NO_CHECK_MACROS
#define ELPP_WINSOCK2 #define ELPP_WINSOCK2
#define ELPP_NO_DEBUG_MACROS #define ELPP_NO_DEBUG_MACROS
#define ELPP_UTC_DATETIME
#ifdef EASYLOGGING_CC #ifdef EASYLOGGING_CC
#if !(!defined __GNUC__ || defined __MINGW32__ || defined __MINGW64__ || defined __ANDROID__) #if !(!defined __GNUC__ || defined __MINGW32__ || defined __MINGW64__ || defined __ANDROID__)

View file

@ -1,13 +1,14 @@
// //
// Bismillah ar-Rahmaan ar-Raheem // Bismillah ar-Rahmaan ar-Raheem
// //
// Easylogging++ v9.94.1 // Easylogging++ v9.96.5
// Cross-platform logging library for C++ applications // Cross-platform logging library for C++ applications
// //
// Copyright (c) 2017 muflihun.com // Copyright (c) 2012-2018 Muflihun Labs
// Copyright (c) 2012-2018 @abumusamq
// //
// This library is released under the MIT Licence. // This library is released under the MIT Licence.
// http://labs.muflihun.com/easyloggingpp/licence.php // https://github.com/muflihun/easyloggingpp/blob/master/LICENSE
// //
// https://github.com/muflihun/easyloggingpp // https://github.com/muflihun/easyloggingpp
// https://muflihun.github.io/easyloggingpp // https://muflihun.github.io/easyloggingpp
@ -25,8 +26,95 @@ INITIALIZE_EASYLOGGINGPP
namespace el { namespace el {
// el::base::utils // el::base
namespace 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 { namespace utils {
/// @brief Aborts application due with user-defined status /// @brief Aborts application due with user-defined status
@ -303,11 +391,7 @@ void Configurations::set(Configuration* conf) {
void Configurations::setToDefault(void) { void Configurations::setToDefault(void) {
setGlobally(ConfigurationType::Enabled, std::string("true"), true); setGlobally(ConfigurationType::Enabled, std::string("true"), true);
#if !defined(ELPP_NO_DEFAULT_LOG_FILE)
setGlobally(ConfigurationType::Filename, std::string(base::consts::kDefaultLogFile), true); 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) #if defined(ELPP_NO_LOG_TO_FILE)
setGlobally(ConfigurationType::ToFile, std::string("false"), true); setGlobally(ConfigurationType::ToFile, std::string("false"), true);
#else #else
@ -336,9 +420,7 @@ void Configurations::setRemainingToDefault(void) {
#else #else
unsafeSetIfNotExist(Level::Global, ConfigurationType::Enabled, std::string("true")); unsafeSetIfNotExist(Level::Global, ConfigurationType::Enabled, std::string("true"));
#endif // defined(ELPP_NO_LOG_TO_FILE) #endif // defined(ELPP_NO_LOG_TO_FILE)
#if !defined(ELPP_NO_DEFAULT_LOG_FILE)
unsafeSetIfNotExist(Level::Global, ConfigurationType::Filename, std::string(base::consts::kDefaultLogFile)); 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::ToStandardOutput, std::string("true"));
unsafeSetIfNotExist(Level::Global, ConfigurationType::SubsecondPrecision, std::string("3")); unsafeSetIfNotExist(Level::Global, ConfigurationType::SubsecondPrecision, std::string("3"));
unsafeSetIfNotExist(Level::Global, ConfigurationType::PerformanceTracking, std::string("true")); unsafeSetIfNotExist(Level::Global, ConfigurationType::PerformanceTracking, std::string("true"));
@ -596,7 +678,6 @@ void Logger::configure(const Configurations& configurations) {
if (m_typedConfigurations != nullptr) { if (m_typedConfigurations != nullptr) {
Configurations* c = const_cast<Configurations*>(m_typedConfigurations->configurations()); Configurations* c = const_cast<Configurations*>(m_typedConfigurations->configurations());
if (c->hasConfiguration(Level::Global, ConfigurationType::Filename)) { if (c->hasConfiguration(Level::Global, ConfigurationType::Filename)) {
// This check is definitely needed for cases like ELPP_NO_DEFAULT_LOG_FILE
flush(); flush();
} }
} }
@ -640,7 +721,11 @@ void Logger::flush(Level level, base::type::fstream_t* fs) {
} }
if (fs != nullptr) { if (fs != nullptr) {
fs->flush(); fs->flush();
m_unflushedCount.find(level)->second = 0; std::unordered_map<Level, unsigned int>::iterator iter = m_unflushedCount.find(level);
if (iter != m_unflushedCount.end()) {
iter->second = 0;
}
Helpers::validateFileRolling(this, level);
} }
} }
@ -699,10 +784,9 @@ std::size_t File::getSizeOfFile(base::type::fstream_t* fs) {
if (fs == nullptr) { if (fs == nullptr) {
return 0; return 0;
} }
std::streampos currPos = fs->tellg(); // Since the file stream is appended to or truncated, the current
fs->seekg(0, fs->end); // offset is the file size.
std::size_t size = static_cast<std::size_t>(fs->tellg()); std::size_t size = static_cast<std::size_t>(fs->tellg());
fs->seekg(currPos);
return size; return size;
} }
@ -894,7 +978,10 @@ void Str::replaceFirstWithEscape(base::type::string_t& str, const base::type::st
#endif // defined(ELPP_UNICODE) #endif // defined(ELPP_UNICODE)
std::string& Str::toUpper(std::string& str) { std::string& Str::toUpper(std::string& str) {
std::transform(str.begin(), str.end(), str.begin(), ::toupper); std::transform(str.begin(), str.end(), str.begin(),
[](char c) {
return static_cast<char>(::toupper(c));
});
return str; return str;
} }
@ -1022,11 +1109,13 @@ const std::string OS::getBashOutput(const char* command) {
char hBuff[4096]; char hBuff[4096];
if (fgets(hBuff, sizeof(hBuff), proc) != nullptr) { if (fgets(hBuff, sizeof(hBuff), proc) != nullptr) {
pclose(proc); pclose(proc);
const size_t len = strlen(hBuff); const std::size_t buffLen = strlen(hBuff);
if (len > 0 && hBuff[len - 1] == '\n') { if (buffLen > 0 && hBuff[buffLen - 1] == '\n') {
hBuff[len- 1] = '\0'; hBuff[buffLen- 1] = '\0';
} }
return std::string(hBuff); return std::string(hBuff);
} else {
pclose(proc);
} }
return std::string(); return std::string();
#else #else
@ -1172,19 +1261,23 @@ unsigned long long DateTime::getTimeDifference(const struct timeval& endTime, co
struct ::tm* DateTime::buildTimeInfo(struct timeval* currTime, struct ::tm* timeInfo) { struct ::tm* DateTime::buildTimeInfo(struct timeval* currTime, struct ::tm* timeInfo) {
#if ELPP_OS_UNIX #if ELPP_OS_UNIX
time_t rawTime = currTime->tv_sec; time_t rawTime = currTime->tv_sec;
::gmtime_r(&rawTime, timeInfo); ::elpptime_r(&rawTime, timeInfo);
return timeInfo; return timeInfo;
#else #else
# if ELPP_COMPILER_MSVC # if ELPP_COMPILER_MSVC
ELPP_UNUSED(currTime); ELPP_UNUSED(currTime);
time_t t; time_t t;
# if defined(_USE_32BIT_TIME_T)
_time32(&t);
# else
_time64(&t); _time64(&t);
gmtime_s(timeInfo, &t); # endif
elpptime_s(timeInfo, &t);
return timeInfo; return timeInfo;
# else # else
// For any other compilers that don't have CRT warnings issue e.g, MinGW or TDM GCC- we use different method // For any other compilers that don't have CRT warnings issue e.g, MinGW or TDM GCC- we use different method
time_t rawTime = currTime->tv_sec; time_t rawTime = currTime->tv_sec;
struct tm* tmInf = gmtime(&rawTime); struct tm* tmInf = elpptime(&rawTime);
*timeInfo = *tmInf; *timeInfo = *tmInf;
return timeInfo; return timeInfo;
# endif // ELPP_COMPILER_MSVC # endif // ELPP_COMPILER_MSVC
@ -1292,7 +1385,8 @@ bool CommandLineArgs::hasParamWithValue(const char* paramKey) const {
} }
const char* CommandLineArgs::getParamValue(const char* paramKey) const { const char* CommandLineArgs::getParamValue(const char* paramKey) const {
return m_paramsWithValue.find(std::string(paramKey))->second.c_str(); 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() : "";
} }
bool CommandLineArgs::hasParam(const char* paramKey) const { bool CommandLineArgs::hasParam(const char* paramKey) const {
@ -1641,10 +1735,11 @@ void TypedConfigurations::build(Configurations* configurations) {
} else if (conf->configurationType() == ConfigurationType::PerformanceTracking) { } else if (conf->configurationType() == ConfigurationType::PerformanceTracking) {
setValue(Level::Global, getBool(conf->value()), &m_performanceTrackingMap); setValue(Level::Global, getBool(conf->value()), &m_performanceTrackingMap);
} else if (conf->configurationType() == ConfigurationType::MaxLogFileSize) { } else if (conf->configurationType() == ConfigurationType::MaxLogFileSize) {
setValue(conf->level(), static_cast<std::size_t>(getULong(conf->value())), &m_maxLogFileSizeMap); auto v = getULong(conf->value());
#if !defined(ELPP_NO_DEFAULT_LOG_FILE) setValue(conf->level(), static_cast<std::size_t>(v), &m_maxLogFileSizeMap);
if (v != 0) {
withFileSizeLimit.push_back(conf); withFileSizeLimit.push_back(conf);
#endif // !defined(ELPP_NO_DEFAULT_LOG_FILE) }
} else if (conf->configurationType() == ConfigurationType::LogFlushThreshold) { } else if (conf->configurationType() == ConfigurationType::LogFlushThreshold) {
setValue(conf->level(), static_cast<std::size_t>(getULong(conf->value())), &m_logFlushThresholdMap); setValue(conf->level(), static_cast<std::size_t>(getULong(conf->value())), &m_logFlushThresholdMap);
} }
@ -1718,12 +1813,6 @@ std::string TypedConfigurations::resolveFilename(const std::string& filename) {
} }
void TypedConfigurations::insertFile(Level level, const std::string& fullFilename) { 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
if (fullFilename.empty()) if (fullFilename.empty())
return; return;
std::string resolvedFilename = resolveFilename(fullFilename); std::string resolvedFilename = resolveFilename(fullFilename);
@ -1861,8 +1950,10 @@ bool RegisteredLoggers::remove(const std::string& id) {
if (id == base::consts::kDefaultLoggerId) { if (id == base::consts::kDefaultLoggerId) {
return false; return false;
} }
// get has internal lock
Logger* logger = base::utils::Registry<Logger, std::string>::get(id); Logger* logger = base::utils::Registry<Logger, std::string>::get(id);
if (logger != nullptr) { if (logger != nullptr) {
// unregister has internal lock
unregister(logger); unregister(logger);
} }
return true; return true;
@ -2066,9 +2157,11 @@ bool VRegistry::allowed(base::type::VerboseLevel vlevel, const char* file) {
if (m_modules.empty() || file == nullptr) { if (m_modules.empty() || file == nullptr) {
return vlevel <= m_level; return vlevel <= m_level;
} else { } else {
std::map<std::string, base::type::VerboseLevel>::iterator it = m_modules.begin(); char baseFilename[base::consts::kSourceFilenameMaxLength] = "";
base::utils::File::buildBaseFilename(file, baseFilename);
std::unordered_map<std::string, base::type::VerboseLevel>::iterator it = m_modules.begin();
for (; it != m_modules.end(); ++it) { for (; it != m_modules.end(); ++it) {
if (base::utils::Str::wildCardMatch(file, it->first.c_str())) { if (base::utils::Str::wildCardMatch(baseFilename, it->first.c_str())) {
return vlevel <= it->second; return vlevel <= it->second;
} }
} }
@ -2176,7 +2269,7 @@ Storage::~Storage(void) {
} }
bool Storage::hasCustomFormatSpecifier(const char* formatSpecifier) { 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(), return std::find(m_customFormatSpecifiers.begin(), m_customFormatSpecifiers.end(),
formatSpecifier) != m_customFormatSpecifiers.end(); formatSpecifier) != m_customFormatSpecifiers.end();
} }
@ -2185,12 +2278,12 @@ void Storage::installCustomFormatSpecifier(const CustomFormatSpecifier& customFo
if (hasCustomFormatSpecifier(customFormatSpecifier.formatSpecifier())) { if (hasCustomFormatSpecifier(customFormatSpecifier.formatSpecifier())) {
return; return;
} }
base::threading::ScopedLock scopedLock(lock()); base::threading::ScopedLock scopedLock(customFormatSpecifiersLock());
m_customFormatSpecifiers.push_back(customFormatSpecifier); m_customFormatSpecifiers.push_back(customFormatSpecifier);
} }
bool Storage::uninstallCustomFormatSpecifier(const char* formatSpecifier) { 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(), std::vector<CustomFormatSpecifier>::iterator it = std::find(m_customFormatSpecifiers.begin(),
m_customFormatSpecifiers.end(), formatSpecifier); m_customFormatSpecifiers.end(), formatSpecifier);
if (it != m_customFormatSpecifiers.end() && strcmp(formatSpecifier, it->formatSpecifier()) == 0) { if (it != m_customFormatSpecifiers.end() && strcmp(formatSpecifier, it->formatSpecifier()) == 0) {
@ -2228,9 +2321,35 @@ void Storage::setApplicationArguments(int argc, char** argv) {
#endif // defined(ELPP_LOGGING_FLAGS_FROM_ARG) #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 // DefaultLogDispatchCallback
void DefaultLogDispatchCallback::handle(const LogDispatchData* data) { void DefaultLogDispatchCallback::handle(const LogDispatchData* data) {
#if defined(ELPP_THREAD_SAFE)
#if 0
LogDispatchCallback::handle(data);
base::threading::ScopedLock scopedLock(fileHandle(data));
#endif
#endif
m_data = data; m_data = data;
dispatch(m_data->logMessage()->logger()->logBuilder()->build(m_data->logMessage(), dispatch(m_data->logMessage()->logger()->logBuilder()->build(m_data->logMessage(),
m_data->dispatchAction() == base::DispatchAction::NormalLog || m_data->dispatchAction() == base::DispatchAction::FileOnlyLog)); m_data->dispatchAction() == base::DispatchAction::NormalLog || m_data->dispatchAction() == base::DispatchAction::FileOnlyLog));
@ -2481,6 +2600,8 @@ base::type::string_t DefaultLogBuilder::build(const LogMessage* logMessage, bool
base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kMessageFormatSpecifier, logMessage->message()); base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kMessageFormatSpecifier, logMessage->message());
} }
#if !defined(ELPP_DISABLE_CUSTOM_FORMAT_SPECIFIERS) #if !defined(ELPP_DISABLE_CUSTOM_FORMAT_SPECIFIERS)
el::base::threading::ScopedLock lock_(ELPP->customFormatSpecifiersLock());
ELPP_UNUSED(lock_);
for (std::vector<CustomFormatSpecifier>::const_iterator it = ELPP->customFormatSpecifiers()->begin(); for (std::vector<CustomFormatSpecifier>::const_iterator it = ELPP->customFormatSpecifiers()->begin();
it != ELPP->customFormatSpecifiers()->end(); ++it) { it != ELPP->customFormatSpecifiers()->end(); ++it) {
std::string fs(it->formatSpecifier()); std::string fs(it->formatSpecifier());
@ -2501,10 +2622,15 @@ void LogDispatcher::dispatch(void) {
if (!m_proceed) { if (!m_proceed) {
return; return;
} }
#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()); base::threading::ScopedLock scopedLock(ELPP->lock());
base::TypedConfigurations* tc = m_logMessage.logger()->m_typedConfigurations; #endif
base::TypedConfigurations* tc = m_logMessage->logger()->m_typedConfigurations;
if (ELPP->hasFlag(LoggingFlag::StrictLogFileSizeCheck)) { if (ELPP->hasFlag(LoggingFlag::StrictLogFileSizeCheck)) {
tc->validateFileRolling(m_logMessage.level(), ELPP->preRollOutCallback()); tc->validateFileRolling(m_logMessage->level(), ELPP->preRollOutCallback());
} }
LogDispatchCallback* callback = nullptr; LogDispatchCallback* callback = nullptr;
LogDispatchData data; LogDispatchData data;
@ -2512,7 +2638,7 @@ void LogDispatcher::dispatch(void) {
: ELPP->m_logDispatchCallbacks) { : ELPP->m_logDispatchCallbacks) {
callback = h.second.get(); callback = h.second.get();
if (callback != nullptr && callback->enabled()) { if (callback != nullptr && callback->enabled()) {
data.setLogMessage(&m_logMessage); data.setLogMessage(m_logMessage);
data.setDispatchAction(m_dispatchAction); data.setDispatchAction(m_dispatchAction);
callback->handle(&data); callback->handle(&data);
} }
@ -2559,6 +2685,7 @@ Writer& Writer::construct(int count, const char* loggerIds, ...) {
va_list loggersList; va_list loggersList;
va_start(loggersList, loggerIds); va_start(loggersList, loggerIds);
const char* id = loggerIds; const char* id = loggerIds;
m_loggerIds.reserve(count);
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
m_loggerIds.push_back(std::string(id)); m_loggerIds.push_back(std::string(id));
id = va_arg(loggersList, const char*); id = va_arg(loggersList, const char*);
@ -2577,12 +2704,12 @@ void Writer::initializeLogger(const std::string& loggerId, bool lookup, bool nee
m_logger = ELPP->registeredLoggers()->get(loggerId, ELPP->hasFlag(LoggingFlag::CreateLoggerAutomatically)); m_logger = ELPP->registeredLoggers()->get(loggerId, ELPP->hasFlag(LoggingFlag::CreateLoggerAutomatically));
} }
if (m_logger == nullptr) { if (m_logger == nullptr) {
ELPP->acquireLock(); {
if (!ELPP->registeredLoggers()->has(std::string(base::consts::kDefaultLoggerId))) { if (!ELPP->registeredLoggers()->has(std::string(base::consts::kDefaultLoggerId))) {
// Somehow default logger has been unregistered. Not good! Register again // Somehow default logger has been unregistered. Not good! Register again
ELPP->registeredLoggers()->get(std::string(base::consts::kDefaultLoggerId)); ELPP->registeredLoggers()->get(std::string(base::consts::kDefaultLoggerId));
} }
ELPP->releaseLock(); // Need to unlock it for next writer }
Writer(Level::Debug, m_file, m_line, m_func).construct(1, base::consts::kDefaultLoggerId) Writer(Level::Debug, m_file, m_line, m_func).construct(1, base::consts::kDefaultLoggerId)
<< "Logger [" << loggerId << "] is not registered yet!"; << "Logger [" << loggerId << "] is not registered yet!";
m_proceed = false; m_proceed = false;
@ -2643,8 +2770,13 @@ void Writer::processDispatch() {
void Writer::triggerDispatch(void) { void Writer::triggerDispatch(void) {
if (m_proceed) { if (m_proceed) {
base::LogDispatcher(m_proceed, LogMessage(m_level, m_file, m_line, m_func, m_verboseLevel, if (m_msg == nullptr) {
m_logger), m_dispatchAction).dispatch(); 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) { if (m_logger != nullptr) {
m_logger->stream().str(ELPP_LITERAL("")); m_logger->stream().str(ELPP_LITERAL(""));
@ -2657,7 +2789,7 @@ void Writer::triggerDispatch(void) {
std::stringstream reasonStream; std::stringstream reasonStream;
reasonStream << "Fatal log at [" << m_file << ":" << m_line << "]" reasonStream << "Fatal log at [" << m_file << ":" << m_line << "]"
<< " If you wish to disable 'abort on fatal log' please use " << " If you wish to disable 'abort on fatal log' please use "
<< "el::Helpers::addFlag(el::LoggingFlag::DisableApplicationAbortOnFatalLog)"; << "el::Loggers::addFlag(el::LoggingFlag::DisableApplicationAbortOnFatalLog)";
base::utils::abort(1, reasonStream.str()); base::utils::abort(1, reasonStream.str());
} }
m_proceed = false; m_proceed = false;
@ -2773,18 +2905,19 @@ namespace debug {
// StackTrace // StackTrace
StackTrace::StackTraceEntry::StackTraceEntry(std::size_t index, const char* loc, const char* demang, const char* hex, StackTrace::StackTraceEntry::StackTraceEntry(std::size_t index, const std::string& loc, const std::string& demang,
const char* addr) { const std::string& hex,
m_index = index; const std::string& addr) :
m_location = std::string(loc); m_index(index),
m_demangled = std::string(demang); m_location(loc),
m_hex = std::string(hex); m_demangled(demang),
m_addr = std::string(addr); m_hex(hex),
m_addr(addr) {
} }
std::ostream& operator<<(std::ostream& ss, const StackTrace::StackTraceEntry& si) { std::ostream& operator<<(std::ostream& ss, const StackTrace::StackTraceEntry& si) {
ss << "[" << si.m_index << "] " << si.m_location << (si.m_demangled.empty() ? "" : ":") << si.m_demangled ss << "[" << si.m_index << "] " << si.m_location << (si.m_hex.empty() ? "" : "+") << si.m_hex << " " << si.m_addr <<
<< (si.m_hex.empty() ? "" : "+") << si.m_hex << si.m_addr; (si.m_demangled.empty() ? "" : ":") << si.m_demangled;
return ss; return ss;
} }
@ -2804,44 +2937,40 @@ void StackTrace::generateNew(void) {
char** strings = backtrace_symbols(stack, size); char** strings = backtrace_symbols(stack, size);
if (size > kStackStart) { // Skip StackTrace c'tor and generateNew if (size > kStackStart) { // Skip StackTrace c'tor and generateNew
for (std::size_t i = kStackStart; i < size; ++i) { for (std::size_t i = kStackStart; i < size; ++i) {
char* mangName = nullptr; std::string mangName;
char* hex = nullptr; std::string location;
char* addr = nullptr; std::string hex;
for (char* c = strings[i]; *c; ++c) { std::string addr;
switch (*c) {
case '(': // entry: 2 crash.cpp.bin 0x0000000101552be5 _ZN2el4base5debug10StackTraceC1Ev + 21
mangName = c; const std::string line(strings[i]);
break; auto p = line.find("_");
case '+': if (p != std::string::npos) {
hex = c; mangName = line.substr(p);
break; mangName = mangName.substr(0, mangName.find(" +"));
case ')':
addr = c;
break;
default:
break;
} }
p = line.find("0x");
if (p != std::string::npos) {
addr = line.substr(p);
addr = addr.substr(0, addr.find("_"));
} }
// Perform demangling if parsed properly // Perform demangling if parsed properly
if (mangName != nullptr && hex != nullptr && addr != nullptr && mangName < hex) { if (!mangName.empty()) {
*mangName++ = '\0';
*hex++ = '\0';
*addr++ = '\0';
int status = 0; 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 demangling is successful, output the demangled function name
if (status == 0) { if (status == 0) {
// Success (see http://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html) // 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); m_stack.push_back(entry);
} else { } else {
// Not successful - we will use mangled name // 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); m_stack.push_back(entry);
} }
free(demangName); free(demangName);
} else { } else {
StackTraceEntry entry(i - 1, strings[i]); StackTraceEntry entry(i - 1, line);
m_stack.push_back(entry); m_stack.push_back(entry);
} }
} }
@ -2875,6 +3004,9 @@ static std::string crashReason(int sig) {
} }
/// @brief Logs reason of crash from sig /// @brief Logs reason of crash from sig
static void logCrashReason(int sig, bool stackTraceIfAvailable, Level level, const char* logger) { static void logCrashReason(int sig, bool stackTraceIfAvailable, Level level, const char* logger) {
if (sig == SIGINT && ELPP->hasFlag(el::LoggingFlag::IgnoreSigInt)) {
return;
}
std::stringstream ss; std::stringstream ss;
ss << "CRASH HANDLED; "; ss << "CRASH HANDLED; ";
ss << crashReason(sig); ss << crashReason(sig);
@ -2953,7 +3085,6 @@ void Helpers::logCrashReason(int sig, bool stackTraceIfAvailable, Level level, c
// Loggers // Loggers
Logger* Loggers::getLogger(const std::string& identity, bool registerIfNotAvailable) { Logger* Loggers::getLogger(const std::string& identity, bool registerIfNotAvailable) {
base::threading::ScopedLock scopedLock(ELPP->lock());
return ELPP->registeredLoggers()->get(identity, registerIfNotAvailable); return ELPP->registeredLoggers()->get(identity, registerIfNotAvailable);
} }
@ -2962,12 +3093,10 @@ void Loggers::setDefaultLogBuilder(el::LogBuilderPtr& logBuilderPtr) {
} }
bool Loggers::unregisterLogger(const std::string& identity) { bool Loggers::unregisterLogger(const std::string& identity) {
base::threading::ScopedLock scopedLock(ELPP->lock());
return ELPP->registeredLoggers()->remove(identity); return ELPP->registeredLoggers()->remove(identity);
} }
bool Loggers::hasLogger(const std::string& identity) { bool Loggers::hasLogger(const std::string& identity) {
base::threading::ScopedLock scopedLock(ELPP->lock());
return ELPP->registeredLoggers()->has(identity); return ELPP->registeredLoggers()->has(identity);
} }
@ -3137,11 +3266,11 @@ const std::string &Loggers::getFilenameCommonPrefix() {
// VersionInfo // VersionInfo
const std::string VersionInfo::version(void) { const std::string VersionInfo::version(void) {
return std::string("9.94.1"); return std::string("9.96.5");
} }
/// @brief Release date of current version /// @brief Release date of current version
const std::string VersionInfo::releaseDate(void) { const std::string VersionInfo::releaseDate(void) {
return std::string("25-02-2017 0813hrs"); return std::string("07-09-2018 0950hrs");
} }
} // namespace el } // namespace el

View file

@ -1,18 +1,20 @@
// //
// Bismillah ar-Rahmaan ar-Raheem // Bismillah ar-Rahmaan ar-Raheem
// //
// Easylogging++ v9.94.1 // Easylogging++ v9.96.5
// Single-header only, cross-platform logging library for C++ applications // Single-header only, cross-platform logging library for C++ applications
// //
// Copyright (c) 2017 muflihun.com // Copyright (c) 2012-2018 Muflihun Labs
// Copyright (c) 2012-2018 @abumusamq
// //
// This library is released under the MIT Licence. // This library is released under the MIT Licence.
// http://labs.muflihun.com/easyloggingpp/licence.php // https://github.com/muflihun/easyloggingpp/blob/master/LICENSE
// //
// https://github.com/muflihun/easyloggingpp // https://github.com/muflihun/easyloggingpp
// https://muflihun.github.io/easyloggingpp // https://muflihun.github.io/easyloggingpp
// http://muflihun.com // http://muflihun.com
// //
#ifndef EASYLOGGINGPP_H #ifndef EASYLOGGINGPP_H
#define EASYLOGGINGPP_H #define EASYLOGGINGPP_H
#include "ea_config.h" #include "ea_config.h"
@ -94,7 +96,7 @@
#else #else
# define ELPP_OS_MAC 0 # define ELPP_OS_MAC 0
#endif #endif
#if (defined(__FreeBSD__)) #if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__))
# define ELPP_OS_FREEBSD 1 # define ELPP_OS_FREEBSD 1
#else #else
# define ELPP_OS_FREEBSD 0 # define ELPP_OS_FREEBSD 0
@ -114,13 +116,23 @@
#else #else
# define ELPP_OS_SOLARIS 0 # define ELPP_OS_SOLARIS 0
#endif #endif
#if (defined(_AIX))
# define ELPP_OS_AIX 1
#else
# define ELPP_OS_AIX 0
#endif
#if (defined(__NetBSD__))
# define ELPP_OS_NETBSD 1
#else
# define ELPP_OS_NETBSD 0
#endif
#if (defined(__DragonFly__)) #if (defined(__DragonFly__))
# define ELPP_OS_DRAGONFLY 1 # define ELPP_OS_DRAGONFLY 1
#else #else
# define ELPP_OS_DRAGONFLY 0 # define ELPP_OS_DRAGONFLY 0
#endif #endif
// Unix // Unix
#if ((ELPP_OS_LINUX || ELPP_OS_MAC || ELPP_OS_FREEBSD || ELPP_OS_SOLARIS || ELPP_OS_DRAGONFLY || ELPP_OS_OPENBSD || ELPP_OS_NETBSD ) && (!ELPP_OS_WINDOWS)) #if ((ELPP_OS_LINUX || ELPP_OS_MAC || ELPP_OS_FREEBSD || ELPP_OS_NETBSD || ELPP_OS_SOLARIS || ELPP_OS_AIX || ELPP_OS_DRAGONFLY || ELPP_OS_OPENBSD) && (!ELPP_OS_WINDOWS))
# define ELPP_OS_UNIX 1 # define ELPP_OS_UNIX 1
#else #else
# define ELPP_OS_UNIX 0 # define ELPP_OS_UNIX 0
@ -205,7 +217,7 @@ ELPP_INTERNAL_DEBUGGING_OUT_INFO << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStre
# define ELPP_INTERNAL_INFO(lvl, msg) # define ELPP_INTERNAL_INFO(lvl, msg)
#endif // (defined(ELPP_DEBUG_INFO)) #endif // (defined(ELPP_DEBUG_INFO))
#if (defined(ELPP_FEATURE_ALL)) || (defined(ELPP_FEATURE_CRASH_LOG)) #if (defined(ELPP_FEATURE_ALL)) || (defined(ELPP_FEATURE_CRASH_LOG))
# if (ELPP_COMPILER_GCC && !ELPP_MINGW && !ELPP_OS_OPENBSD && !ELPP_OS_NETBSD) # if (ELPP_COMPILER_GCC && !ELPP_MINGW && !ELPP_OS_OPENBSD && !ELPP_OS_NETBSD && !ELPP_OS_ANDROID)
# define ELPP_STACKTRACE 1 # define ELPP_STACKTRACE 1
# else # else
# define ELPP_STACKTRACE 0 # define ELPP_STACKTRACE 0
@ -386,6 +398,7 @@ ELPP_INTERNAL_DEBUGGING_OUT_INFO << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStre
#include <string> #include <string>
#include <vector> #include <vector>
#include <map> #include <map>
#include <unordered_map>
#include <utility> #include <utility>
#include <functional> #include <functional>
#include <algorithm> #include <algorithm>
@ -423,9 +436,6 @@ ELPP_INTERNAL_DEBUGGING_OUT_INFO << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStre
# if defined(ELPP_LOG_STD_ARRAY) # if defined(ELPP_LOG_STD_ARRAY)
# include <array> # include <array>
# endif // defined(ELPP_LOG_STD_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) # if defined(ELPP_LOG_UNORDERED_SET)
# include <unordered_set> # include <unordered_set>
# endif // defined(ELPP_UNORDERED_SET) # endif // defined(ELPP_UNORDERED_SET)
@ -460,6 +470,15 @@ ELPP_INTERNAL_DEBUGGING_OUT_INFO << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStre
// For logging wxWidgets based classes & templates // For logging wxWidgets based classes & templates
# include <wx/vector.h> # include <wx/vector.h>
#endif // defined(ELPP_WXWIDGETS_LOGGING) #endif // defined(ELPP_WXWIDGETS_LOGGING)
#if defined(ELPP_UTC_DATETIME)
# define elpptime_r gmtime_r
# define elpptime_s gmtime_s
# define elpptime gmtime
#else
# define elpptime_r localtime_r
# define elpptime_s localtime_s
# define elpptime localtime
#endif // defined(ELPP_UTC_DATETIME)
// Forward declarations // Forward declarations
namespace el { namespace el {
class Logger; class Logger;
@ -584,6 +603,16 @@ enum class Level : base::type::EnumType {
/// @brief Represents unknown level /// @brief Represents unknown level
Unknown = 1010 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 /// @brief Static class that contains helper functions for el::Level
class LevelHelper : base::StaticClass { class LevelHelper : base::StaticClass {
public: public:
@ -710,113 +739,41 @@ enum class LoggingFlag : base::type::EnumType {
/// @brief Adds spaces b/w logs that separated by left-shift operator /// @brief Adds spaces b/w logs that separated by left-shift operator
AutoSpacing = 8192, AutoSpacing = 8192,
/// @brief Preserves time format and does not convert it to sec, hour etc (performance tracking only) /// @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 { namespace base {
/// @brief Namespace containing constants used internally. /// @brief Namespace containing constants used internally.
namespace consts { namespace consts {
#if defined(__GNUC__) && !defined(__clang__) static const char kFormatSpecifierCharValue = 'v';
#pragma GCC diagnostic push static const char kFormatSpecifierChar = '%';
#pragma GCC diagnostic ignored "-Wunused-variable" static const unsigned int kMaxLogPerCounter = 100000;
#endif static const unsigned int kMaxLogPerContainer = 100;
// Level log values - These are values that are replaced in place of %level format specifier static const unsigned int kDefaultSubsecondPrecision = 3;
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("WARN ");
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("VER");
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
#ifdef ELPP_DEFAULT_LOGGER #ifdef ELPP_DEFAULT_LOGGER
static const char* kDefaultLoggerId = ELPP_DEFAULT_LOGGER; static const char* kDefaultLoggerId = ELPP_DEFAULT_LOGGER;
#else #else
static const char* kDefaultLoggerId = "default"; static const char* kDefaultLoggerId = "default";
#endif #endif
#ifdef ELPP_DEFAULT_PERFORMANCE_LOGGER #ifdef ELPP_DEFAULT_PERFORMANCE_LOGGER
static const char* kPerformanceLoggerId = ELPP_DEFAULT_PERFORMANCE_LOGGER; static const char* kPerformanceLoggerId = ELPP_DEFAULT_PERFORMANCE_LOGGER;
#else #else
static const char* kPerformanceLoggerId = "performance"; static const char* kPerformanceLoggerId = "performance";
#endif #endif
#if defined(ELPP_SYSLOG) #if defined(ELPP_SYSLOG)
static const char* kSysLogLoggerId = "syslog"; static const char* kSysLogLoggerId = "syslog";
#endif // defined(ELPP_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 #if ELPP_OS_WINDOWS
static const char* kFilePathSeperator = "\\"; static const char* kFilePathSeperator = "\\";
#else #else
static const char* kFilePathSeperator = "/"; static const char* kFilePathSeperator = "/";
#endif // ELPP_OS_WINDOWS #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 kSourceFilenameMaxLength = 100;
static const std::size_t kSourceLineMaxLength = 10; static const std::size_t kSourceLineMaxLength = 10;
static const Level kPerformanceTrackerDefaultLevel = Level::Info; static const Level kPerformanceTrackerDefaultLevel = Level::Info;
@ -861,9 +818,6 @@ const struct {
}, },
}; };
static const int kCrashSignalsCount = sizeof(kCrashSignals) / sizeof(kCrashSignals[0]); static const int kCrashSignalsCount = sizeof(kCrashSignals) / sizeof(kCrashSignals[0]);
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
} // namespace consts } // namespace consts
} // namespace base } // namespace base
typedef std::function<void(const char*, std::size_t)> PreRollOutCallback; typedef std::function<void(const char*, std::size_t)> PreRollOutCallback;
@ -1270,8 +1224,8 @@ class DateTime : base::StaticClass {
base::TimestampUnit timestampUnit); base::TimestampUnit timestampUnit);
private:
static struct ::tm* buildTimeInfo(struct timeval* currTime, struct ::tm* timeInfo); 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, static char* parseFormat(char* buf, std::size_t bufSz, const char* format, const struct tm* tInfo,
std::size_t msec, const base::SubsecondPrecision* ssPrec); std::size_t msec, const base::SubsecondPrecision* ssPrec);
}; };
@ -1310,7 +1264,7 @@ class CommandLineArgs {
private: private:
int m_argc; int m_argc;
char** m_argv; 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; std::vector<std::string> m_params;
}; };
/// @brief Abstract registry (aka repository) that provides basic interface for pointer repository specified by T_Ptr type. /// @brief Abstract registry (aka repository) that provides basic interface for pointer repository specified by T_Ptr type.
@ -1435,7 +1389,7 @@ class AbstractRegistry : public base::threading::ThreadSafe {
/// of AbstractRegistry<T_Ptr, Container>. Any implementation of this class should be /// of AbstractRegistry<T_Ptr, Container>. Any implementation of this class should be
/// explicitly (by using lock functions) /// explicitly (by using lock functions)
template <typename T_Ptr, typename T_Key = const char*> 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: public:
typedef typename Registry<T_Ptr, T_Key>::iterator iterator; typedef typename Registry<T_Ptr, T_Key>::iterator iterator;
typedef typename Registry<T_Ptr, T_Key>::const_iterator const_iterator; typedef typename Registry<T_Ptr, T_Key>::const_iterator const_iterator;
@ -1485,8 +1439,8 @@ class Registry : public AbstractRegistry<T_Ptr, std::map<T_Key, T_Ptr*>> {
void unregister(const T_Key& uniqKey) { void unregister(const T_Key& uniqKey) {
T_Ptr* existing = get(uniqKey); T_Ptr* existing = get(uniqKey);
if (existing != nullptr) { if (existing != nullptr) {
base::utils::safeDelete(existing);
this->list().erase(uniqKey); this->list().erase(uniqKey);
base::utils::safeDelete(existing);
} }
} }
@ -1499,7 +1453,7 @@ class Registry : public AbstractRegistry<T_Ptr, std::map<T_Key, T_Ptr*>> {
} }
private: 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) { for (const_iterator it = sr.cbegin(); it != sr.cend(); ++it) {
registerNew(it->first, new T_Ptr(*it->second)); registerNew(it->first, new T_Ptr(*it->second));
} }
@ -1599,7 +1553,7 @@ class RegistryWithPred : public AbstractRegistry<T_Ptr, std::vector<T_Ptr*>> {
class Utils { class Utils {
public: public:
template <typename T, typename TPtr> 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()) { if (mapT->find(id) == mapT->end()) {
mapT->insert(std::make_pair(id, TPtr(new T()))); mapT->insert(std::make_pair(id, TPtr(new T())));
return true; return true;
@ -1608,15 +1562,15 @@ class Utils {
} }
template <typename T, typename TPtr> 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()) { if (mapT->find(id) != mapT->end()) {
mapT->erase(id); mapT->erase(id);
} }
} }
template <typename T, typename TPtr> template <typename T, typename TPtr>
static T* callback(const std::string& id, std::map<std::string, TPtr>* mapT) { static T* callback(const std::string& id, std::unordered_map<std::string, TPtr>* mapT) {
typename std::map<std::string, TPtr>::iterator iter = mapT->find(id); typename std::unordered_map<std::string, TPtr>::iterator iter = mapT->find(id);
if (iter != mapT->end()) { if (iter != mapT->end()) {
return static_cast<T*>(iter->second.get()); return static_cast<T*>(iter->second.get());
} }
@ -1961,7 +1915,7 @@ class Configurations : public base::utils::RegistryWithPred<Configuration, Confi
namespace base { namespace base {
typedef std::shared_ptr<base::type::fstream_t> FileStreamPtr; 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. /// @brief Configurations with data types.
/// ///
/// @detail el::Configurations have string based values. This is whats used internally in order to read correct configurations. /// @detail el::Configurations have string based values. This is whats used internally in order to read correct configurations.
@ -1998,16 +1952,16 @@ class TypedConfigurations : public base::threading::ThreadSafe {
private: private:
Configurations* m_configurations; Configurations* m_configurations;
std::map<Level, bool> m_enabledMap; std::unordered_map<Level, bool> m_enabledMap;
std::map<Level, bool> m_toFileMap; std::unordered_map<Level, bool> m_toFileMap;
std::map<Level, std::string> m_filenameMap; std::unordered_map<Level, std::string> m_filenameMap;
std::map<Level, bool> m_toStandardOutputMap; std::unordered_map<Level, bool> m_toStandardOutputMap;
std::map<Level, base::LogFormat> m_logFormatMap; std::unordered_map<Level, base::LogFormat> m_logFormatMap;
std::map<Level, base::SubsecondPrecision> m_subsecondPrecisionMap; std::unordered_map<Level, base::SubsecondPrecision> m_subsecondPrecisionMap;
std::map<Level, bool> m_performanceTrackingMap; std::unordered_map<Level, bool> m_performanceTrackingMap;
std::map<Level, base::FileStreamPtr> m_fileStreamMap; std::unordered_map<Level, base::FileStreamPtr> m_fileStreamMap;
std::map<Level, std::size_t> m_maxLogFileSizeMap; std::unordered_map<Level, std::size_t> m_maxLogFileSizeMap;
std::map<Level, std::size_t> m_logFlushThresholdMap; std::unordered_map<Level, std::size_t> m_logFlushThresholdMap;
base::LogStreamsReferenceMap* m_logStreamsReference; base::LogStreamsReferenceMap* m_logStreamsReference;
friend class el::Helpers; friend class el::Helpers;
@ -2017,21 +1971,21 @@ class TypedConfigurations : public base::threading::ThreadSafe {
friend class el::base::LogDispatcher; friend class el::base::LogDispatcher;
template <typename Conf_T> 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()); base::threading::ScopedLock scopedLock(lock());
return unsafeGetConfigByVal(level, confMap, confName); // This is not unsafe anymore - mutex locked in scope return unsafeGetConfigByVal(level, confMap, confName); // This is not unsafe anymore - mutex locked in scope
} }
template <typename Conf_T> 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()); base::threading::ScopedLock scopedLock(lock());
return unsafeGetConfigByRef(level, confMap, confName); // This is not unsafe anymore - mutex locked in scope return unsafeGetConfigByRef(level, confMap, confName); // This is not unsafe anymore - mutex locked in scope
} }
template <typename Conf_T> 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); 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()) { if (it == confMap->end()) {
try { try {
return confMap->at(Level::Global); return confMap->at(Level::Global);
@ -2046,9 +2000,9 @@ class TypedConfigurations : public base::threading::ThreadSafe {
} }
template <typename Conf_T> 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); 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()) { if (it == confMap->end()) {
try { try {
return confMap->at(Level::Global); return confMap->at(Level::Global);
@ -2062,14 +2016,15 @@ class TypedConfigurations : public base::threading::ThreadSafe {
} }
template <typename Conf_T> 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 map is empty and we are allowed to add into generic level (Level::Global), do it!
if (confMap->empty() && includeGlobalLevel) { if (confMap->empty() && includeGlobalLevel) {
confMap->insert(std::make_pair(Level::Global, value)); confMap->insert(std::make_pair(Level::Global, value));
return; return;
} }
// If same value exist in generic level already, dont add it to explicit level // 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) { if (it != confMap->end() && it->second == value) {
return; return;
} }
@ -2231,21 +2186,26 @@ class LogDispatchData {
inline base::DispatchAction dispatchAction(void) const { inline base::DispatchAction dispatchAction(void) const {
return m_dispatchAction; return m_dispatchAction;
} }
private:
LogMessage* m_logMessage;
base::DispatchAction m_dispatchAction;
friend class base::LogDispatcher;
inline void setLogMessage(LogMessage* logMessage) { inline void setLogMessage(LogMessage* logMessage) {
m_logMessage = logMessage; m_logMessage = logMessage;
} }
inline void setDispatchAction(base::DispatchAction dispatchAction) { inline void setDispatchAction(base::DispatchAction dispatchAction) {
m_dispatchAction = dispatchAction; m_dispatchAction = dispatchAction;
} }
private:
LogMessage* m_logMessage;
base::DispatchAction m_dispatchAction;
friend class base::LogDispatcher;
}; };
class LogDispatchCallback : public Callback<LogDispatchData> { class LogDispatchCallback : public Callback<LogDispatchData> {
protected:
virtual void handle(const LogDispatchData* data);
base::threading::Mutex& fileHandle(const LogDispatchData* data);
private: private:
friend class base::LogDispatcher; 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> { class PerformanceTrackingCallback : public Callback<PerformanceTrackingData> {
private: private:
@ -2363,7 +2323,7 @@ inline void FUNCTION_NAME(const T&);
std::string m_parentApplicationName; std::string m_parentApplicationName;
bool m_isConfigured; bool m_isConfigured;
Configurations m_configurations; Configurations m_configurations;
std::map<Level, unsigned int> m_unflushedCount; std::unordered_map<Level, unsigned int> m_unflushedCount;
base::LogStreamsReferenceMap* m_logStreamsReference; base::LogStreamsReferenceMap* m_logStreamsReference;
LogBuilderPtr m_logBuilder; LogBuilderPtr m_logBuilder;
@ -2469,7 +2429,7 @@ class RegisteredLoggers : public base::utils::Registry<Logger, std::string> {
LogBuilderPtr m_defaultLogBuilder; LogBuilderPtr m_defaultLogBuilder;
Configurations m_defaultConfigurations; Configurations m_defaultConfigurations;
base::LogStreamsReferenceMap m_logStreamsReference; 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; friend class el::base::Storage;
void unsafeFlushAll(void); void unsafeFlushAll(void);
@ -2507,7 +2467,7 @@ class VRegistry : base::NoCopy, public base::threading::ThreadSafe {
bool allowed(base::type::VerboseLevel vlevel, const char* file); 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; return m_modules;
} }
@ -2529,7 +2489,7 @@ class VRegistry : base::NoCopy, public base::threading::ThreadSafe {
private: private:
base::type::VerboseLevel m_level; base::type::VerboseLevel m_level;
base::type::EnumType* m_pFlags; base::type::EnumType* m_pFlags;
std::map<std::string, base::type::VerboseLevel> m_modules; std::unordered_map<std::string, base::type::VerboseLevel> m_modules;
std::vector<std::pair<std::string, Level>> m_categories; std::vector<std::pair<std::string, Level>> m_categories;
std::map<std::string, int> m_cached_allowed_categories; std::map<std::string, int> m_cached_allowed_categories;
std::string m_categoriesString; std::string m_categoriesString;
@ -2717,6 +2677,10 @@ class Storage : base::NoCopy, public base::threading::ThreadSafe {
return &m_customFormatSpecifiers; return &m_customFormatSpecifiers;
} }
base::threading::Mutex& customFormatSpecifiersLock() {
return m_customFormatSpecifiersLock;
}
inline void setLoggingLevel(Level level) { inline void setLoggingLevel(Level level) {
m_loggingLevel = level; m_loggingLevel = level;
} }
@ -2757,13 +2721,13 @@ class Storage : base::NoCopy, public base::threading::ThreadSafe {
/// @brief Sets thread name for current thread. Requires std::thread /// @brief Sets thread name for current thread. Requires std::thread
inline void setThreadName(const std::string& name) { inline void setThreadName(const std::string& name) {
if (name.empty()) return; if (name.empty()) return;
base::threading::ScopedLock scopedLock(lock()); base::threading::ScopedLock scopedLock(m_threadNamesLock);
m_threadNames[base::threading::getCurrentThreadId()] = name; m_threadNames[base::threading::getCurrentThreadId()] = name;
} }
inline std::string getThreadName(const std::string& threadId) { inline std::string getThreadName(const std::string& threadId) {
base::threading::ScopedLock scopedLock(lock()); base::threading::ScopedLock scopedLock(m_threadNamesLock);
std::map<std::string, std::string>::const_iterator it = m_threadNames.find(threadId); std::unordered_map<std::string, std::string>::const_iterator it = m_threadNames.find(threadId);
if (it == m_threadNames.end()) { if (it == m_threadNames.end()) {
return threadId; return threadId;
} }
@ -2783,10 +2747,12 @@ class Storage : base::NoCopy, public base::threading::ThreadSafe {
#endif // ELPP_ASYNC_LOGGING #endif // ELPP_ASYNC_LOGGING
base::utils::CommandLineArgs m_commandLineArgs; base::utils::CommandLineArgs m_commandLineArgs;
PreRollOutCallback m_preRollOutCallback; PreRollOutCallback m_preRollOutCallback;
std::map<std::string, base::type::LogDispatchCallbackPtr> m_logDispatchCallbacks; std::unordered_map<std::string, base::type::LogDispatchCallbackPtr> m_logDispatchCallbacks;
std::map<std::string, base::type::PerformanceTrackingCallbackPtr> m_performanceTrackingCallbacks; std::unordered_map<std::string, base::type::PerformanceTrackingCallbackPtr> m_performanceTrackingCallbacks;
std::map<std::string, std::string> m_threadNames; std::unordered_map<std::string, std::string> m_threadNames;
std::vector<CustomFormatSpecifier> m_customFormatSpecifiers; std::vector<CustomFormatSpecifier> m_customFormatSpecifiers;
base::threading::Mutex m_customFormatSpecifiersLock;
base::threading::Mutex m_threadNamesLock;
Level m_loggingLevel; Level m_loggingLevel;
friend class el::Helpers; friend class el::Helpers;
@ -2829,7 +2795,7 @@ class AsyncDispatchWorker : public base::IWorker, public base::threading::Thread
void run(void); void run(void);
void setContinueRunning(bool value) { void setContinueRunning(bool value) {
base::threading::ScopedLock scopedLock(m_continueRunningMutex); base::threading::ScopedLock scopedLock(m_continueRunningLock);
m_continueRunning = value; m_continueRunning = value;
} }
@ -2839,7 +2805,7 @@ class AsyncDispatchWorker : public base::IWorker, public base::threading::Thread
private: private:
std::condition_variable cv; std::condition_variable cv;
bool m_continueRunning; bool m_continueRunning;
base::threading::Mutex m_continueRunningMutex; base::threading::Mutex m_continueRunningLock;
}; };
#endif // ELPP_ASYNC_LOGGING #endif // ELPP_ASYNC_LOGGING
} // namespace base } // namespace base
@ -2851,9 +2817,9 @@ class DefaultLogBuilder : public LogBuilder {
/// @brief Dispatches log messages /// @brief Dispatches log messages
class LogDispatcher : base::NoCopy { class LogDispatcher : base::NoCopy {
public: public:
LogDispatcher(bool proceed, LogMessage&& logMessage, base::DispatchAction dispatchAction) : LogDispatcher(bool proceed, LogMessage* logMessage, base::DispatchAction dispatchAction) :
m_proceed(proceed), m_proceed(proceed),
m_logMessage(std::move(logMessage)), m_logMessage(logMessage),
m_dispatchAction(std::move(dispatchAction)) { m_dispatchAction(std::move(dispatchAction)) {
} }
@ -2861,7 +2827,7 @@ class LogDispatcher : base::NoCopy {
private: private:
bool m_proceed; bool m_proceed;
LogMessage m_logMessage; LogMessage* m_logMessage;
base::DispatchAction m_dispatchAction; base::DispatchAction m_dispatchAction;
}; };
#if defined(ELPP_STL_LOGGING) #if defined(ELPP_STL_LOGGING)
@ -3274,10 +3240,15 @@ class Writer : base::NoCopy {
Writer(Level level, const char* file, base::type::LineNumber line, Writer(Level level, const char* file, base::type::LineNumber line,
const char* func, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog, const char* func, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog,
base::type::VerboseLevel verboseLevel = 0) : 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) { 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) { virtual ~Writer(void) {
processDispatch(); processDispatch();
} }
@ -3320,6 +3291,7 @@ class Writer : base::NoCopy {
Writer& construct(Logger* logger, bool needLock = true); Writer& construct(Logger* logger, bool needLock = true);
Writer& construct(int count, const char* loggerIds, ...); Writer& construct(int count, const char* loggerIds, ...);
protected: protected:
LogMessage* m_msg;
Level m_level; Level m_level;
const char* m_file; const char* m_file;
const base::type::LineNumber m_line; const base::type::LineNumber m_line;
@ -3378,6 +3350,7 @@ void Logger::log_(Level level, int vlevel, const T& log) {
base::DispatchAction::NormalLog, vlevel).construct(this, false) << log; base::DispatchAction::NormalLog, vlevel).construct(this, false) << log;
} else { } else {
stream().str(ELPP_LITERAL("")); stream().str(ELPP_LITERAL(""));
releaseLock();
} }
} else { } else {
base::Writer(level, "FILE", 0, "FUNCTION").construct(this, false) << log; base::Writer(level, "FILE", 0, "FUNCTION").construct(this, false) << log;
@ -3385,23 +3358,23 @@ void Logger::log_(Level level, int vlevel, const T& log) {
} }
template <typename T, typename... Args> template <typename T, typename... Args>
inline void Logger::log(Level level, const char* s, const T& value, const Args&... args) { inline void Logger::log(Level level, const char* s, const T& value, const Args&... args) {
base::threading::ScopedLock scopedLock(lock()); acquireLock(); // released in Writer!
log_(level, 0, s, value, args...); log_(level, 0, s, value, args...);
} }
template <typename T> template <typename T>
inline void Logger::log(Level level, const T& log) { inline void Logger::log(Level level, const T& log) {
base::threading::ScopedLock scopedLock(lock()); acquireLock(); // released in Writer!
log_(level, 0, log); log_(level, 0, log);
} }
# if ELPP_VERBOSE_LOG # if ELPP_VERBOSE_LOG
template <typename T, typename... Args> template <typename T, typename... Args>
inline void Logger::verbose(int vlevel, const char* s, const T& value, const Args&... args) { inline void Logger::verbose(int vlevel, const char* s, const T& value, const Args&... args) {
base::threading::ScopedLock scopedLock(lock()); acquireLock(); // released in Writer!
log_(el::Level::Verbose, vlevel, s, value, args...); log_(el::Level::Verbose, vlevel, s, value, args...);
} }
template <typename T> template <typename T>
inline void Logger::verbose(int vlevel, const T& log) { inline void Logger::verbose(int vlevel, const T& log) {
base::threading::ScopedLock scopedLock(lock()); acquireLock(); // released in Writer!
log_(el::Level::Verbose, vlevel, log); log_(el::Level::Verbose, vlevel, log);
} }
# else # else
@ -3656,8 +3629,9 @@ class StackTrace : base::NoCopy {
static const unsigned int kStackStart = 2; // We want to skip c'tor and StackTrace::generateNew() static const unsigned int kStackStart = 2; // We want to skip c'tor and StackTrace::generateNew()
class StackTraceEntry { class StackTraceEntry {
public: public:
StackTraceEntry(std::size_t index, const char* loc, const char* demang, const char* hex, const char* addr); StackTraceEntry(std::size_t index, const std::string& loc, const std::string& demang, const std::string& hex,
StackTraceEntry(std::size_t index, char* loc) : const std::string& addr);
StackTraceEntry(std::size_t index, const std::string& loc) :
m_index(index), m_index(index),
m_location(loc) { m_location(loc) {
} }
@ -3842,6 +3816,11 @@ class Helpers : base::StaticClass {
static inline const el::base::utils::CommandLineArgs* commandLineArgs(void) { static inline const el::base::utils::CommandLineArgs* commandLineArgs(void) {
return ELPP->commandLineArgs(); 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 /// @brief Installs user defined format specifier and handler
static inline void installCustomFormatSpecifier(const CustomFormatSpecifier& customFormatSpecifier) { static inline void installCustomFormatSpecifier(const CustomFormatSpecifier& customFormatSpecifier) {
ELPP->installCustomFormatSpecifier(customFormatSpecifier); ELPP->installCustomFormatSpecifier(customFormatSpecifier);