diff options
Diffstat (limited to 'third_party/easyloggingpp/easylogging++.cc')
-rw-r--r-- | third_party/easyloggingpp/easylogging++.cc | 3526 |
1 files changed, 0 insertions, 3526 deletions
diff --git a/third_party/easyloggingpp/easylogging++.cc b/third_party/easyloggingpp/easylogging++.cc deleted file mode 100644 index 7451a3c1..00000000 --- a/third_party/easyloggingpp/easylogging++.cc +++ /dev/null @@ -1,3526 +0,0 @@ -// -// Bismillah ar-Rahmaan ar-Raheem -// -// Easylogging++ v9.96.7 -// Cross-platform logging library for C++ applications -// -// Copyright (c) 2012-2018 Amrayn Web Services -// Copyright (c) 2012-2018 @abumusamq -// -// This library is released under the MIT Licence. -// https://github.com/amrayn/easyloggingpp/blob/master/LICENSE -// -// https://amrayn.com -// http://muflihun.com -// - -#include "easylogging++.h" - -#if defined(AUTO_INITIALIZE_EASYLOGGINGPP) -INITIALIZE_EASYLOGGINGPP -#endif - -namespace el { - -// 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", "April", "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 = "unknown-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 = "--"; -} // namespace consts -// el::base::utils -namespace utils { - -/// @brief Aborts application due with user-defined status -static void abort(int status, const std::string &reason) { - // Both status and reason params are there for debugging with tools like gdb - // etc - ELPP_UNUSED(status); - ELPP_UNUSED(reason); -#if defined(ELPP_COMPILER_MSVC) && defined(_M_IX86) && defined(_DEBUG) - // Ignore msvc critical error dialog - break instead (on debug mode) - _asm int 3 -#else - ::abort(); -#endif // defined(ELPP_COMPILER_MSVC) && defined(_M_IX86) && defined(_DEBUG) -} - -} // namespace utils -} // namespace base - -// el - -// LevelHelper - -const char *LevelHelper::convertToString(Level level) { - // Do not use switch over strongly typed enums because Intel C++ compilers - // dont support them yet. - if (level == Level::Global) - return "GLOBAL"; - if (level == Level::Debug) - return "DEBUG"; - if (level == Level::Info) - return "INFO"; - if (level == Level::Warning) - return "WARNING"; - if (level == Level::Error) - return "ERROR"; - if (level == Level::Fatal) - return "FATAL"; - if (level == Level::Verbose) - return "VERBOSE"; - if (level == Level::Trace) - return "TRACE"; - return "UNKNOWN"; -} - -struct StringToLevelItem { - const char *levelString; - Level level; -}; - -static struct StringToLevelItem stringToLevelMap[] = { - {"global", Level::Global}, {"debug", Level::Debug}, - {"info", Level::Info}, {"warning", Level::Warning}, - {"error", Level::Error}, {"fatal", Level::Fatal}, - {"verbose", Level::Verbose}, {"trace", Level::Trace}}; - -Level LevelHelper::convertFromString(const char *levelStr) { - for (auto &item : stringToLevelMap) { - if (base::utils::Str::cStringCaseEq(levelStr, item.levelString)) { - return item.level; - } - } - return Level::Unknown; -} - -void LevelHelper::forEachLevel(base::type::EnumType *startIndex, - const std::function<bool(void)> &fn) { - base::type::EnumType lIndexMax = LevelHelper::kMaxValid; - do { - if (fn()) { - break; - } - *startIndex = static_cast<base::type::EnumType>(*startIndex << 1); - } while (*startIndex <= lIndexMax); -} - -// ConfigurationTypeHelper - -const char * -ConfigurationTypeHelper::convertToString(ConfigurationType configurationType) { - // Do not use switch over strongly typed enums because Intel C++ compilers - // dont support them yet. - if (configurationType == ConfigurationType::Enabled) - return "ENABLED"; - if (configurationType == ConfigurationType::Filename) - return "FILENAME"; - if (configurationType == ConfigurationType::Format) - return "FORMAT"; - if (configurationType == ConfigurationType::ToFile) - return "TO_FILE"; - if (configurationType == ConfigurationType::ToStandardOutput) - return "TO_STANDARD_OUTPUT"; - if (configurationType == ConfigurationType::SubsecondPrecision) - return "SUBSECOND_PRECISION"; - if (configurationType == ConfigurationType::PerformanceTracking) - return "PERFORMANCE_TRACKING"; - if (configurationType == ConfigurationType::MaxLogFileSize) - return "MAX_LOG_FILE_SIZE"; - if (configurationType == ConfigurationType::LogFlushThreshold) - return "LOG_FLUSH_THRESHOLD"; - return "UNKNOWN"; -} - -struct ConfigurationStringToTypeItem { - const char *configString; - ConfigurationType configType; -}; - -static struct ConfigurationStringToTypeItem configStringToTypeMap[] = { - {"enabled", ConfigurationType::Enabled}, - {"to_file", ConfigurationType::ToFile}, - {"to_standard_output", ConfigurationType::ToStandardOutput}, - {"format", ConfigurationType::Format}, - {"filename", ConfigurationType::Filename}, - {"subsecond_precision", ConfigurationType::SubsecondPrecision}, - {"milliseconds_width", ConfigurationType::MillisecondsWidth}, - {"performance_tracking", ConfigurationType::PerformanceTracking}, - {"max_log_file_size", ConfigurationType::MaxLogFileSize}, - {"log_flush_threshold", ConfigurationType::LogFlushThreshold}, -}; - -ConfigurationType -ConfigurationTypeHelper::convertFromString(const char *configStr) { - for (auto &item : configStringToTypeMap) { - if (base::utils::Str::cStringCaseEq(configStr, item.configString)) { - return item.configType; - } - } - return ConfigurationType::Unknown; -} - -void ConfigurationTypeHelper::forEachConfigType( - base::type::EnumType *startIndex, const std::function<bool(void)> &fn) { - base::type::EnumType cIndexMax = ConfigurationTypeHelper::kMaxValid; - do { - if (fn()) { - break; - } - *startIndex = static_cast<base::type::EnumType>(*startIndex << 1); - } while (*startIndex <= cIndexMax); -} - -// Configuration - -Configuration::Configuration(const Configuration &c) - : m_level(c.m_level), m_configurationType(c.m_configurationType), - m_value(c.m_value) {} - -Configuration &Configuration::operator=(const Configuration &c) { - if (&c != this) { - m_level = c.m_level; - m_configurationType = c.m_configurationType; - m_value = c.m_value; - } - return *this; -} - -/// @brief Full constructor used to sets value of configuration -Configuration::Configuration(Level level, ConfigurationType configurationType, - const std::string &value) - : m_level(level), m_configurationType(configurationType), m_value(value) {} - -void Configuration::log(el::base::type::ostream_t &os) const { - os << LevelHelper::convertToString(m_level) << ELPP_LITERAL(" ") - << ConfigurationTypeHelper::convertToString(m_configurationType) - << ELPP_LITERAL(" = ") << m_value.c_str(); -} - -/// @brief Used to find configuration from configuration (pointers) repository. -/// Avoid using it. -Configuration::Predicate::Predicate(Level level, - ConfigurationType configurationType) - : m_level(level), m_configurationType(configurationType) {} - -bool Configuration::Predicate::operator()(const Configuration *conf) const { - return ((conf != nullptr) && (conf->level() == m_level) && - (conf->configurationType() == m_configurationType)); -} - -// Configurations - -Configurations::Configurations(void) - : m_configurationFile(std::string()), m_isFromFile(false) {} - -Configurations::Configurations(const std::string &configurationFile, - bool useDefaultsForRemaining, - Configurations *base) - : m_configurationFile(configurationFile), m_isFromFile(false) { - parseFromFile(configurationFile, base); - if (useDefaultsForRemaining) { - setRemainingToDefault(); - } -} - -bool Configurations::parseFromFile(const std::string &configurationFile, - Configurations *base) { - // We initial assertion with true because if we have assertion disabled, we - // want to pass this check and if assertion is enabled we will have values - // re-assigned any way. - bool assertionPassed = true; - ELPP_ASSERT((assertionPassed = base::utils::File::pathExists( - configurationFile.c_str(), true)) == true, - "Configuration file [" << configurationFile - << "] does not exist!"); - if (!assertionPassed) { - return false; - } - bool success = Parser::parseFromFile(configurationFile, this, base); - m_isFromFile = success; - return success; -} - -bool Configurations::parseFromText(const std::string &configurationsString, - Configurations *base) { - bool success = Parser::parseFromText(configurationsString, this, base); - if (success) { - m_isFromFile = false; - } - return success; -} - -void Configurations::setFromBase(Configurations *base) { - if (base == nullptr || base == this) { - return; - } - base::threading::ScopedLock scopedLock(base->lock()); - for (Configuration *&conf : base->list()) { - set(conf); - } -} - -bool Configurations::hasConfiguration(ConfigurationType configurationType) { - base::type::EnumType lIndex = LevelHelper::kMinValid; - bool result = false; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - if (hasConfiguration(LevelHelper::castFromInt(lIndex), configurationType)) { - result = true; - } - return result; - }); - return result; -} - -bool Configurations::hasConfiguration(Level level, - ConfigurationType configurationType) { - base::threading::ScopedLock scopedLock(lock()); -#if ELPP_COMPILER_INTEL - // We cant specify template types here, Intel C++ throws compilation error - // "error: type name is not allowed" - return RegistryWithPred::get(level, configurationType) != nullptr; -#else - return RegistryWithPred<Configuration, Configuration::Predicate>::get( - level, configurationType) != nullptr; -#endif // ELPP_COMPILER_INTEL -} - -void Configurations::set(Level level, ConfigurationType configurationType, - const std::string &value) { - base::threading::ScopedLock scopedLock(lock()); - unsafeSet(level, configurationType, - value); // This is not unsafe anymore as we have locked mutex - if (level == Level::Global) { - unsafeSetGlobally(configurationType, value, - false); // Again this is not unsafe either - } -} - -void Configurations::set(Configuration *conf) { - if (conf == nullptr) { - return; - } - set(conf->level(), conf->configurationType(), conf->value()); -} - -void Configurations::setToDefault(void) { - setGlobally(ConfigurationType::Enabled, std::string("true"), true); - setGlobally(ConfigurationType::Filename, - std::string(base::consts::kDefaultLogFile), true); -#if defined(ELPP_NO_LOG_TO_FILE) - setGlobally(ConfigurationType::ToFile, std::string("false"), true); -#else - setGlobally(ConfigurationType::ToFile, std::string("true"), true); -#endif // defined(ELPP_NO_LOG_TO_FILE) - setGlobally(ConfigurationType::ToStandardOutput, std::string("true"), true); - setGlobally(ConfigurationType::SubsecondPrecision, std::string("3"), true); - setGlobally(ConfigurationType::PerformanceTracking, std::string("true"), - true); - setGlobally(ConfigurationType::MaxLogFileSize, std::string("0"), true); - setGlobally(ConfigurationType::LogFlushThreshold, std::string("0"), true); - - setGlobally(ConfigurationType::Format, - std::string("%datetime %level [%logger] %msg"), true); - set(Level::Debug, ConfigurationType::Format, - std::string( - "%datetime %level [%logger] [%user@%host] [%func] [%loc] %msg")); - // INFO and WARNING are set to default by Level::Global - set(Level::Error, ConfigurationType::Format, - std::string("%datetime %level [%logger] %msg")); - set(Level::Fatal, ConfigurationType::Format, - std::string("%datetime %level [%logger] %msg")); - set(Level::Verbose, ConfigurationType::Format, - std::string("%datetime %level-%vlevel [%logger] %msg")); - set(Level::Trace, ConfigurationType::Format, - std::string("%datetime %level [%logger] [%func] [%loc] %msg")); -} - -void Configurations::setRemainingToDefault(void) { - base::threading::ScopedLock scopedLock(lock()); -#if defined(ELPP_NO_LOG_TO_FILE) - unsafeSetIfNotExist(Level::Global, ConfigurationType::Enabled, - std::string("false")); -#else - unsafeSetIfNotExist(Level::Global, ConfigurationType::Enabled, - std::string("true")); -#endif // defined(ELPP_NO_LOG_TO_FILE) - unsafeSetIfNotExist(Level::Global, ConfigurationType::Filename, - std::string(base::consts::kDefaultLogFile)); - unsafeSetIfNotExist(Level::Global, ConfigurationType::ToStandardOutput, - std::string("true")); - unsafeSetIfNotExist(Level::Global, ConfigurationType::SubsecondPrecision, - std::string("3")); - unsafeSetIfNotExist(Level::Global, ConfigurationType::PerformanceTracking, - std::string("true")); - unsafeSetIfNotExist(Level::Global, ConfigurationType::MaxLogFileSize, - std::string("0")); - unsafeSetIfNotExist(Level::Global, ConfigurationType::Format, - std::string("%datetime %level [%logger] %msg")); - unsafeSetIfNotExist( - Level::Debug, ConfigurationType::Format, - std::string( - "%datetime %level [%logger] [%user@%host] [%func] [%loc] %msg")); - // INFO and WARNING are set to default by Level::Global - unsafeSetIfNotExist(Level::Error, ConfigurationType::Format, - std::string("%datetime %level [%logger] %msg")); - unsafeSetIfNotExist(Level::Fatal, ConfigurationType::Format, - std::string("%datetime %level [%logger] %msg")); - unsafeSetIfNotExist(Level::Verbose, ConfigurationType::Format, - std::string("%datetime %level-%vlevel [%logger] %msg")); - unsafeSetIfNotExist( - Level::Trace, ConfigurationType::Format, - std::string("%datetime %level [%logger] [%func] [%loc] %msg")); -} - -bool Configurations::Parser::parseFromFile(const std::string &configurationFile, - Configurations *sender, - Configurations *base) { - sender->setFromBase(base); - std::ifstream fileStream_(configurationFile.c_str(), std::ifstream::in); - ELPP_ASSERT(fileStream_.is_open(), "Unable to open configuration file [" - << configurationFile - << "] for parsing."); - bool parsedSuccessfully = false; - std::string line = std::string(); - Level currLevel = Level::Unknown; - std::string currConfigStr = std::string(); - std::string currLevelStr = std::string(); - while (fileStream_.good()) { - std::getline(fileStream_, line); - parsedSuccessfully = - parseLine(&line, &currConfigStr, &currLevelStr, &currLevel, sender); - ELPP_ASSERT(parsedSuccessfully, - "Unable to parse configuration line: " << line); - } - return parsedSuccessfully; -} - -bool Configurations::Parser::parseFromText( - const std::string &configurationsString, Configurations *sender, - Configurations *base) { - sender->setFromBase(base); - bool parsedSuccessfully = false; - std::stringstream ss(configurationsString); - std::string line = std::string(); - Level currLevel = Level::Unknown; - std::string currConfigStr = std::string(); - std::string currLevelStr = std::string(); - while (std::getline(ss, line)) { - parsedSuccessfully = - parseLine(&line, &currConfigStr, &currLevelStr, &currLevel, sender); - ELPP_ASSERT(parsedSuccessfully, - "Unable to parse configuration line: " << line); - } - return parsedSuccessfully; -} - -void Configurations::Parser::ignoreComments(std::string *line) { - std::size_t foundAt = 0; - std::size_t quotesStart = line->find("\""); - std::size_t quotesEnd = std::string::npos; - if (quotesStart != std::string::npos) { - quotesEnd = line->find("\"", quotesStart + 1); - while (quotesEnd != std::string::npos && line->at(quotesEnd - 1) == '\\') { - // Do not erase slash yet - we will erase it in parseLine(..) while loop - quotesEnd = line->find("\"", quotesEnd + 2); - } - } - if ((foundAt = line->find(base::consts::kConfigurationComment)) != - std::string::npos) { - if (foundAt < quotesEnd) { - foundAt = line->find(base::consts::kConfigurationComment, quotesEnd + 1); - } - *line = line->substr(0, foundAt); - } -} - -bool Configurations::Parser::isLevel(const std::string &line) { - return base::utils::Str::startsWith( - line, std::string(base::consts::kConfigurationLevel)); -} - -bool Configurations::Parser::isComment(const std::string &line) { - return base::utils::Str::startsWith( - line, std::string(base::consts::kConfigurationComment)); -} - -bool Configurations::Parser::isConfig(const std::string &line) { - std::size_t assignment = line.find('='); - return line != "" && - ((line[0] >= 'A' && line[0] <= 'Z') || - (line[0] >= 'a' && line[0] <= 'z')) && - (assignment != std::string::npos) && (line.size() > assignment); -} - -bool Configurations::Parser::parseLine(std::string *line, - std::string *currConfigStr, - std::string *currLevelStr, - Level *currLevel, Configurations *conf) { - ConfigurationType currConfig = ConfigurationType::Unknown; - std::string currValue = std::string(); - *line = base::utils::Str::trim(*line); - if (isComment(*line)) - return true; - ignoreComments(line); - *line = base::utils::Str::trim(*line); - if (line->empty()) { - // Comment ignored - return true; - } - if (isLevel(*line)) { - if (line->size() <= 2) { - return true; - } - *currLevelStr = line->substr(1, line->size() - 2); - *currLevelStr = base::utils::Str::toUpper(*currLevelStr); - *currLevelStr = base::utils::Str::trim(*currLevelStr); - *currLevel = LevelHelper::convertFromString(currLevelStr->c_str()); - return true; - } - if (isConfig(*line)) { - std::size_t assignment = line->find('='); - *currConfigStr = line->substr(0, assignment); - *currConfigStr = base::utils::Str::toUpper(*currConfigStr); - *currConfigStr = base::utils::Str::trim(*currConfigStr); - currConfig = - ConfigurationTypeHelper::convertFromString(currConfigStr->c_str()); - currValue = line->substr(assignment + 1); - currValue = base::utils::Str::trim(currValue); - std::size_t quotesStart = currValue.find("\"", 0); - std::size_t quotesEnd = std::string::npos; - if (quotesStart != std::string::npos) { - quotesEnd = currValue.find("\"", quotesStart + 1); - while (quotesEnd != std::string::npos && - currValue.at(quotesEnd - 1) == '\\') { - currValue = currValue.erase(quotesEnd - 1, 1); - quotesEnd = currValue.find("\"", quotesEnd + 2); - } - } - if (quotesStart != std::string::npos && quotesEnd != std::string::npos) { - // Quote provided - check and strip if valid - ELPP_ASSERT((quotesStart < quotesEnd), - "Configuration error - No ending quote found in [" - << currConfigStr << "]"); - ELPP_ASSERT((quotesStart + 1 != quotesEnd), - "Empty configuration value for [" << currConfigStr << "]"); - if ((quotesStart != quotesEnd) && (quotesStart + 1 != quotesEnd)) { - // Explicit check in case if assertion is disabled - currValue = currValue.substr(quotesStart + 1, quotesEnd - 1); - } - } - } - ELPP_ASSERT(*currLevel != Level::Unknown, - "Unrecognized severity level [" << *currLevelStr << "]"); - ELPP_ASSERT(currConfig != ConfigurationType::Unknown, - "Unrecognized configuration [" << *currConfigStr << "]"); - if (*currLevel == Level::Unknown || - currConfig == ConfigurationType::Unknown) { - return false; // unrecognizable level or config - } - conf->set(*currLevel, currConfig, currValue); - return true; -} - -void Configurations::unsafeSetIfNotExist(Level level, - ConfigurationType configurationType, - const std::string &value) { - Configuration *conf = - RegistryWithPred<Configuration, Configuration::Predicate>::get( - level, configurationType); - if (conf == nullptr) { - unsafeSet(level, configurationType, value); - } -} - -void Configurations::unsafeSet(Level level, ConfigurationType configurationType, - const std::string &value) { - Configuration *conf = - RegistryWithPred<Configuration, Configuration::Predicate>::get( - level, configurationType); - if (conf == nullptr) { - registerNew(new Configuration(level, configurationType, value)); - } else { - conf->setValue(value); - } - if (level == Level::Global) { - unsafeSetGlobally(configurationType, value, false); - } -} - -void Configurations::setGlobally(ConfigurationType configurationType, - const std::string &value, - bool includeGlobalLevel) { - if (includeGlobalLevel) { - set(Level::Global, configurationType, value); - } - base::type::EnumType lIndex = LevelHelper::kMinValid; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - set(LevelHelper::castFromInt(lIndex), configurationType, value); - return false; // Do not break lambda function yet as we need to set all - // levels regardless - }); -} - -void Configurations::unsafeSetGlobally(ConfigurationType configurationType, - const std::string &value, - bool includeGlobalLevel) { - if (includeGlobalLevel) { - unsafeSet(Level::Global, configurationType, value); - } - base::type::EnumType lIndex = LevelHelper::kMinValid; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - unsafeSet(LevelHelper::castFromInt(lIndex), configurationType, value); - return false; // Do not break lambda function yet as we need to set all - // levels regardless - }); -} - -// LogBuilder - -void LogBuilder::convertToColoredOutput(base::type::string_t *logLine, - Level level) { - if (!m_termSupportsColor) - return; - const base::type::char_t *resetColor = ELPP_LITERAL("\x1b[0m"); - if (level == Level::Error || level == Level::Fatal) - *logLine = ELPP_LITERAL("\x1b[31m") + *logLine + resetColor; - else if (level == Level::Warning) - *logLine = ELPP_LITERAL("\x1b[33m") + *logLine + resetColor; - else if (level == Level::Debug) - *logLine = ELPP_LITERAL("\x1b[32m") + *logLine + resetColor; - else if (level == Level::Info) - *logLine = ELPP_LITERAL("\x1b[36m") + *logLine + resetColor; - else if (level == Level::Trace) - *logLine = ELPP_LITERAL("\x1b[35m") + *logLine + resetColor; -} - -// Logger - -Logger::Logger(const std::string &id, - base::LogStreamsReferenceMapPtr logStreamsReference) - : m_id(id), m_typedConfigurations(nullptr), - m_parentApplicationName(std::string()), m_isConfigured(false), - m_logStreamsReference(logStreamsReference) { - initUnflushedCount(); -} - -Logger::Logger(const std::string &id, const Configurations &configurations, - base::LogStreamsReferenceMapPtr logStreamsReference) - : m_id(id), m_typedConfigurations(nullptr), - m_parentApplicationName(std::string()), m_isConfigured(false), - m_logStreamsReference(logStreamsReference) { - initUnflushedCount(); - configure(configurations); -} - -Logger::Logger(const Logger &logger) { - base::utils::safeDelete(m_typedConfigurations); - m_id = logger.m_id; - m_typedConfigurations = logger.m_typedConfigurations; - m_parentApplicationName = logger.m_parentApplicationName; - m_isConfigured = logger.m_isConfigured; - m_configurations = logger.m_configurations; - m_unflushedCount = logger.m_unflushedCount; - m_logStreamsReference = logger.m_logStreamsReference; -} - -Logger &Logger::operator=(const Logger &logger) { - if (&logger != this) { - base::utils::safeDelete(m_typedConfigurations); - m_id = logger.m_id; - m_typedConfigurations = logger.m_typedConfigurations; - m_parentApplicationName = logger.m_parentApplicationName; - m_isConfigured = logger.m_isConfigured; - m_configurations = logger.m_configurations; - m_unflushedCount = logger.m_unflushedCount; - m_logStreamsReference = logger.m_logStreamsReference; - } - return *this; -} - -void Logger::configure(const Configurations &configurations) { - m_isConfigured = false; // we set it to false in case if we fail - initUnflushedCount(); - if (m_typedConfigurations != nullptr) { - Configurations *c = - const_cast<Configurations *>(m_typedConfigurations->configurations()); - if (c->hasConfiguration(Level::Global, ConfigurationType::Filename)) { - flush(); - } - } - base::threading::ScopedLock scopedLock(lock()); - if (m_configurations != configurations) { - m_configurations.setFromBase(const_cast<Configurations *>(&configurations)); - } - base::utils::safeDelete(m_typedConfigurations); - m_typedConfigurations = - new base::TypedConfigurations(&m_configurations, m_logStreamsReference); - resolveLoggerFormatSpec(); - m_isConfigured = true; -} - -void Logger::reconfigure(void) { - ELPP_INTERNAL_INFO(1, "Reconfiguring logger [" << m_id << "]"); - configure(m_configurations); -} - -bool Logger::isValidId(const std::string &id) { - for (std::string::const_iterator it = id.begin(); it != id.end(); ++it) { - if (!base::utils::Str::contains(base::consts::kValidLoggerIdSymbols, *it)) { - return false; - } - } - return true; -} - -void Logger::flush(void) { - ELPP_INTERNAL_INFO(3, "Flushing logger [" << m_id << "] all levels"); - base::threading::ScopedLock scopedLock(lock()); - base::type::EnumType lIndex = LevelHelper::kMinValid; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - flush(LevelHelper::castFromInt(lIndex), nullptr); - return false; - }); -} - -void Logger::flush(Level level, base::type::fstream_t *fs) { - if (fs == nullptr && m_typedConfigurations->toFile(level)) { - fs = m_typedConfigurations->fileStream(level); - } - if (fs != nullptr) { - fs->flush(); - std::unordered_map<Level, unsigned int>::iterator iter = - m_unflushedCount.find(level); - if (iter != m_unflushedCount.end()) { - iter->second = 0; - } - Helpers::validateFileRolling(this, level); - } -} - -void Logger::initUnflushedCount(void) { - m_unflushedCount.clear(); - base::type::EnumType lIndex = LevelHelper::kMinValid; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - m_unflushedCount.insert( - std::make_pair(LevelHelper::castFromInt(lIndex), 0)); - return false; - }); -} - -void Logger::resolveLoggerFormatSpec(void) const { - base::type::EnumType lIndex = LevelHelper::kMinValid; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - base::LogFormat *logFormat = const_cast<base::LogFormat *>( - &m_typedConfigurations->logFormat(LevelHelper::castFromInt(lIndex))); - base::utils::Str::replaceFirstWithEscape( - logFormat->m_format, base::consts::kLoggerIdFormatSpecifier, m_id); - return false; - }); -} - -// el::base -namespace base { - -// el::base::utils -namespace utils { - -// File - -base::type::fstream_t *File::newFileStream(const std::string &filename) { - base::type::fstream_t *fs = new base::type::fstream_t( - filename.c_str(), base::type::fstream_t::out -#if !defined(ELPP_FRESH_LOG_FILE) - | base::type::fstream_t::app -#endif - ); -#if defined(ELPP_UNICODE) - std::locale elppUnicodeLocale(""); -#if ELPP_OS_WINDOWS - std::locale elppUnicodeLocaleWindows(elppUnicodeLocale, - new std::codecvt_utf8_utf16<wchar_t>); - elppUnicodeLocale = elppUnicodeLocaleWindows; -#endif // ELPP_OS_WINDOWS - fs->imbue(elppUnicodeLocale); -#endif // defined(ELPP_UNICODE) - if (fs->is_open()) { - fs->flush(); - } else { - base::utils::safeDelete(fs); - ELPP_INTERNAL_ERROR("Bad file [" << filename << "]", true); - } - return fs; -} - -std::size_t File::getSizeOfFile(base::type::fstream_t *fs) { - if (fs == nullptr) { - return 0; - } - // 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()); - return size; -} - -bool File::pathExists(const char *path, bool considerFile) { - if (path == nullptr) { - return false; - } -#if ELPP_OS_UNIX - ELPP_UNUSED(considerFile); - struct stat st; - return (stat(path, &st) == 0); -#elif ELPP_OS_WINDOWS - DWORD fileType = GetFileAttributesA(path); - if (fileType == INVALID_FILE_ATTRIBUTES) { - return false; - } - return considerFile - ? true - : ((fileType & FILE_ATTRIBUTE_DIRECTORY) == 0 ? false : true); -#endif // ELPP_OS_UNIX -} - -bool File::createPath(const std::string &path) { - if (path.empty()) { - return false; - } - if (base::utils::File::pathExists(path.c_str())) { - return true; - } - int status = -1; - - char *currPath = const_cast<char *>(path.c_str()); - std::string builtPath = std::string(); -#if ELPP_OS_UNIX - if (path[0] == '/') { - builtPath = "/"; - } - currPath = STRTOK(currPath, base::consts::kFilePathSeparator, 0); -#elif ELPP_OS_WINDOWS - // Use secure functions API - char *nextTok_ = nullptr; - currPath = STRTOK(currPath, base::consts::kFilePathSeparator, &nextTok_); - ELPP_UNUSED(nextTok_); -#endif // ELPP_OS_UNIX - while (currPath != nullptr) { - builtPath.append(currPath); - builtPath.append(base::consts::kFilePathSeparator); -#if ELPP_OS_UNIX - status = mkdir(builtPath.c_str(), ELPP_LOG_PERMS); - currPath = STRTOK(nullptr, base::consts::kFilePathSeparator, 0); -#elif ELPP_OS_WINDOWS - status = _mkdir(builtPath.c_str()); - currPath = STRTOK(nullptr, base::consts::kFilePathSeparator, &nextTok_); -#endif // ELPP_OS_UNIX - } - if (status == -1) { - ELPP_INTERNAL_ERROR("Error while creating path [" << path << "]", true); - return false; - } - return true; -} - -std::string File::extractPathFromFilename(const std::string &fullPath, - const char *separator) { - if ((fullPath == "") || (fullPath.find(separator) == std::string::npos)) { - return fullPath; - } - std::size_t lastSlashAt = fullPath.find_last_of(separator); - if (lastSlashAt == 0) { - return std::string(separator); - } - return fullPath.substr(0, lastSlashAt + 1); -} - -void File::buildStrippedFilename(const char *filename, char buff[], - std::size_t limit) { - std::size_t sizeOfFilename = strlen(filename); - if (sizeOfFilename >= limit) { - filename += (sizeOfFilename - limit); - if (filename[0] != '.' && filename[1] != '.') { // prepend if not already - filename += 3; // 3 = '..' - STRCAT(buff, "..", limit); - } - } - STRCAT(buff, filename, limit); -} - -void File::buildBaseFilename(const std::string &fullPath, char buff[], - std::size_t limit, const char *separator) { - const char *filename = fullPath.c_str(); - std::size_t lastSlashAt = fullPath.find_last_of(separator); - filename += lastSlashAt ? lastSlashAt + 1 : 0; - std::size_t sizeOfFilename = strlen(filename); - if (sizeOfFilename >= limit) { - filename += (sizeOfFilename - limit); - if (filename[0] != '.' && filename[1] != '.') { // prepend if not already - filename += 3; // 3 = '..' - STRCAT(buff, "..", limit); - } - } - STRCAT(buff, filename, limit); -} - -// Str - -bool Str::wildCardMatch(const char *str, const char *pattern) { - while (*pattern) { - switch (*pattern) { - case '?': - if (!*str) - return false; - ++str; - ++pattern; - break; - case '*': - if (wildCardMatch(str, pattern + 1)) - return true; - if (*str && wildCardMatch(str + 1, pattern)) - return true; - return false; - default: - if (*str++ != *pattern++) - return false; - break; - } - } - return !*str && !*pattern; -} - -std::string &Str::ltrim(std::string &str) { - str.erase(str.begin(), std::find_if(str.begin(), str.end(), - [](char c) { return !std::isspace(c); })); - return str; -} - -std::string &Str::rtrim(std::string &str) { - str.erase(std::find_if(str.rbegin(), str.rend(), - [](char c) { return !std::isspace(c); }) - .base(), - str.end()); - return str; -} - -std::string &Str::trim(std::string &str) { return ltrim(rtrim(str)); } - -bool Str::startsWith(const std::string &str, const std::string &start) { - return (str.length() >= start.length()) && - (str.compare(0, start.length(), start) == 0); -} - -bool Str::endsWith(const std::string &str, const std::string &end) { - return (str.length() >= end.length()) && - (str.compare(str.length() - end.length(), end.length(), end) == 0); -} - -std::string &Str::replaceAll(std::string &str, char replaceWhat, - char replaceWith) { - std::replace(str.begin(), str.end(), replaceWhat, replaceWith); - return str; -} - -std::string &Str::replaceAll(std::string &str, const std::string &replaceWhat, - const std::string &replaceWith) { - if (replaceWhat == replaceWith) - return str; - std::size_t foundAt = std::string::npos; - while ((foundAt = str.find(replaceWhat, foundAt + 1)) != std::string::npos) { - str.replace(foundAt, replaceWhat.length(), replaceWith); - } - return str; -} - -void Str::replaceFirstWithEscape(base::type::string_t &str, - const base::type::string_t &replaceWhat, - const base::type::string_t &replaceWith) { - 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 - 1, 1); - ++foundAt; - } else { - str.replace(foundAt, replaceWhat.length(), replaceWith); - return; - } - } -} -#if defined(ELPP_UNICODE) -void Str::replaceFirstWithEscape(base::type::string_t &str, - const base::type::string_t &replaceWhat, - const std::string &replaceWith) { - replaceFirstWithEscape( - str, replaceWhat, - base::type::string_t(replaceWith.begin(), replaceWith.end())); -} -#endif // defined(ELPP_UNICODE) - -std::string &Str::toUpper(std::string &str) { - std::transform(str.begin(), str.end(), str.begin(), - [](char c) { return static_cast<char>(::toupper(c)); }); - return str; -} - -bool Str::cStringEq(const char *s1, const char *s2) { - if (s1 == nullptr && s2 == nullptr) - return true; - if (s1 == nullptr || s2 == nullptr) - return false; - return strcmp(s1, s2) == 0; -} - -bool Str::cStringCaseEq(const char *s1, const char *s2) { - if (s1 == nullptr && s2 == nullptr) - return true; - if (s1 == nullptr || s2 == nullptr) - return false; - - // With thanks to cygwin for this code - int d = 0; - - while (true) { - const int c1 = toupper(*s1++); - const int c2 = toupper(*s2++); - - if (((d = c1 - c2) != 0) || (c2 == '\0')) { - break; - } - } - - return d == 0; -} - -bool Str::contains(const char *str, char c) { - for (; *str; ++str) { - if (*str == c) - return true; - } - return false; -} - -char *Str::convertAndAddToBuff(std::size_t n, int len, char *buf, - const char *bufLim, bool zeroPadded) { - char localBuff[10] = ""; - char *p = localBuff + sizeof(localBuff) - 2; - if (n > 0) { - for (; n > 0 && p > localBuff && len > 0; n /= 10, --len) - *--p = static_cast<char>(n % 10 + '0'); - } else { - *--p = '0'; - --len; - } - if (zeroPadded) - while (p > localBuff && len-- > 0) - *--p = static_cast<char>('0'); - return addToBuff(p, buf, bufLim); -} - -char *Str::addToBuff(const char *str, char *buf, const char *bufLim) { - while ((buf < bufLim) && ((*buf = *str++) != '\0')) - ++buf; - return buf; -} - -char *Str::clearBuff(char buff[], std::size_t lim) { - STRCPY(buff, "", lim); - ELPP_UNUSED( - lim); // For *nix we dont have anything using lim in above STRCPY macro - return buff; -} - -/// @brief Converts wchar* to char* -/// NOTE: Need to free return value after use! -char *Str::wcharPtrToCharPtr(const wchar_t *line) { - std::size_t len_ = wcslen(line) + 1; - char *buff_ = static_cast<char *>(malloc(len_ + 1)); -#if ELPP_OS_UNIX || (ELPP_OS_WINDOWS && !ELPP_CRT_DBG_WARNINGS) - std::wcstombs(buff_, line, len_); -#elif ELPP_OS_WINDOWS - std::size_t convCount_ = 0; - mbstate_t mbState_; - ::memset(static_cast<void *>(&mbState_), 0, sizeof(mbState_)); - wcsrtombs_s(&convCount_, buff_, len_, &line, len_, &mbState_); -#endif // ELPP_OS_UNIX || (ELPP_OS_WINDOWS && !ELPP_CRT_DBG_WARNINGS) - return buff_; -} - -// OS - -#if ELPP_OS_WINDOWS -/// @brief Gets environment variables for Windows based OS. -/// We are not using <code>getenv(const char*)</code> because of CRT -/// deprecation -/// @param varname Variable name to get environment variable value for -/// @return If variable exist the value of it otherwise nullptr -const char *OS::getWindowsEnvironmentVariable(const char *varname) { - const DWORD bufferLen = 50; - static char buffer[bufferLen]; - if (GetEnvironmentVariableA(varname, buffer, bufferLen)) { - return buffer; - } - return nullptr; -} -#endif // ELPP_OS_WINDOWS -#if ELPP_OS_ANDROID -std::string OS::getProperty(const char *prop) { - char propVal[PROP_VALUE_MAX + 1]; - int ret = __system_property_get(prop, propVal); - return ret == 0 ? std::string() : std::string(propVal); -} - -std::string OS::getDeviceName(void) { - std::stringstream ss; - std::string manufacturer = getProperty("ro.product.manufacturer"); - std::string model = getProperty("ro.product.model"); - if (manufacturer.empty() || model.empty()) { - return std::string(); - } - ss << manufacturer << "-" << model; - return ss.str(); -} -#endif // ELPP_OS_ANDROID - -const std::string OS::getBashOutput(const char *command) { -#if (ELPP_OS_UNIX && !ELPP_OS_ANDROID && !ELPP_CYGWIN) - if (command == nullptr) { - return std::string(); - } - FILE *proc = nullptr; - if ((proc = popen(command, "r")) == nullptr) { - ELPP_INTERNAL_ERROR("\nUnable to run command [" << command << "]", true); - return std::string(); - } - char hBuff[4096]; - if (fgets(hBuff, sizeof(hBuff), proc) != nullptr) { - pclose(proc); - const std::size_t buffLen = strlen(hBuff); - if (buffLen > 0 && hBuff[buffLen - 1] == '\n') { - hBuff[buffLen - 1] = '\0'; - } - return std::string(hBuff); - } else { - pclose(proc); - } - return std::string(); -#else - ELPP_UNUSED(command); - return std::string(); -#endif // (ELPP_OS_UNIX && !ELPP_OS_ANDROID && !ELPP_CYGWIN) -} - -std::string OS::getEnvironmentVariable(const char *variableName, - const char *defaultVal, - const char *alternativeBashCommand) { -#if ELPP_OS_UNIX - const char *val = getenv(variableName); -#elif ELPP_OS_WINDOWS - const char *val = getWindowsEnvironmentVariable(variableName); -#endif // ELPP_OS_UNIX - if ((val == nullptr) || ((strcmp(val, "") == 0))) { -#if ELPP_OS_UNIX && defined(ELPP_FORCE_ENV_VAR_FROM_BASH) - // Try harder on unix-based systems - std::string valBash = - base::utils::OS::getBashOutput(alternativeBashCommand); - if (valBash.empty()) { - return std::string(defaultVal); - } else { - return valBash; - } -#elif ELPP_OS_WINDOWS || ELPP_OS_UNIX - ELPP_UNUSED(alternativeBashCommand); - return std::string(defaultVal); -#endif // ELPP_OS_UNIX && defined(ELPP_FORCE_ENV_VAR_FROM_BASH) - } - return std::string(val); -} - -std::string OS::currentUser(void) { -#if ELPP_OS_UNIX && !ELPP_OS_ANDROID - return getEnvironmentVariable("USER", base::consts::kUnknownUser, "whoami"); -#elif ELPP_OS_WINDOWS - return getEnvironmentVariable("USERNAME", base::consts::kUnknownUser); -#elif ELPP_OS_ANDROID - ELPP_UNUSED(base::consts::kUnknownUser); - return std::string("android"); -#else - return std::string(); -#endif // ELPP_OS_UNIX && !ELPP_OS_ANDROID -} - -std::string OS::currentHost(void) { -#if ELPP_OS_UNIX && !ELPP_OS_ANDROID - return getEnvironmentVariable("HOSTNAME", base::consts::kUnknownHost, - "hostname"); -#elif ELPP_OS_WINDOWS - return getEnvironmentVariable("COMPUTERNAME", base::consts::kUnknownHost); -#elif ELPP_OS_ANDROID - ELPP_UNUSED(base::consts::kUnknownHost); - return getDeviceName(); -#else - return std::string(); -#endif // ELPP_OS_UNIX && !ELPP_OS_ANDROID -} - -bool OS::termSupportsColor(void) { - std::string term = getEnvironmentVariable("TERM", ""); - return term == "xterm" || term == "xterm-color" || term == "xterm-256color" || - term == "screen" || term == "linux" || term == "cygwin" || - term == "screen-256color"; -} - -// DateTime - -void DateTime::gettimeofday(struct timeval *tv) { -#if ELPP_OS_WINDOWS - if (tv != nullptr) { -#if ELPP_COMPILER_MSVC || defined(_MSC_EXTENSIONS) - const unsigned __int64 delta_ = 11644473600000000Ui64; -#else - const unsigned __int64 delta_ = 11644473600000000ULL; -#endif // ELPP_COMPILER_MSVC || defined(_MSC_EXTENSIONS) - const double secOffSet = 0.000001; - const unsigned long usecOffSet = 1000000; - FILETIME fileTime; - GetSystemTimeAsFileTime(&fileTime); - unsigned __int64 present = 0; - present |= fileTime.dwHighDateTime; - present = present << 32; - present |= fileTime.dwLowDateTime; - present /= 10; // mic-sec - // Subtract the difference - present -= delta_; - tv->tv_sec = static_cast<long>(present * secOffSet); - tv->tv_usec = static_cast<long>(present % usecOffSet); - } -#else - ::gettimeofday(tv, nullptr); -#endif // ELPP_OS_WINDOWS -} - -std::string DateTime::getDateTime(const char *format, - const base::SubsecondPrecision *ssPrec) { - struct timeval currTime; - gettimeofday(&currTime); - return timevalToString(currTime, format, ssPrec); -} - -std::string -DateTime::timevalToString(struct timeval tval, const char *format, - const el::base::SubsecondPrecision *ssPrec) { - struct ::tm timeInfo; - buildTimeInfo(&tval, &timeInfo); - const int kBuffSize = 30; - char buff_[kBuffSize] = ""; - parseFormat(buff_, kBuffSize, format, &timeInfo, - static_cast<std::size_t>(tval.tv_usec / ssPrec->m_offset), - ssPrec); - return std::string(buff_); -} - -base::type::string_t DateTime::formatTime(unsigned long long time, - base::TimestampUnit timestampUnit) { - base::type::EnumType start = static_cast<base::type::EnumType>(timestampUnit); - const base::type::char_t *unit = base::consts::kTimeFormats[start].unit; - for (base::type::EnumType i = start; i < base::consts::kTimeFormatsCount - 1; - ++i) { - if (time <= base::consts::kTimeFormats[i].value) { - break; - } - if (base::consts::kTimeFormats[i].value == 1000.0f && - time / 1000.0f < 1.9f) { - break; - } - time /= static_cast<decltype(time)>(base::consts::kTimeFormats[i].value); - unit = base::consts::kTimeFormats[i + 1].unit; - } - base::type::stringstream_t ss; - ss << time << " " << unit; - return ss.str(); -} - -unsigned long long -DateTime::getTimeDifference(const struct timeval &endTime, - const struct timeval &startTime, - base::TimestampUnit timestampUnit) { - if (timestampUnit == base::TimestampUnit::Microsecond) { - return static_cast<unsigned long long>( - static_cast<unsigned long long>(1000000 * endTime.tv_sec + - endTime.tv_usec) - - static_cast<unsigned long long>(1000000 * startTime.tv_sec + - startTime.tv_usec)); - } - // milliseconds - auto conv = [](const struct timeval &tim) { - return static_cast<unsigned long long>((tim.tv_sec * 1000) + - (tim.tv_usec / 1000)); - }; - return static_cast<unsigned long long>(conv(endTime) - conv(startTime)); -} - -struct ::tm *DateTime::buildTimeInfo(struct timeval *currTime, - struct ::tm *timeInfo) { -#if ELPP_OS_UNIX - time_t rawTime = currTime->tv_sec; - ::elpptime_r(&rawTime, timeInfo); - return timeInfo; -#else -#if ELPP_COMPILER_MSVC - ELPP_UNUSED(currTime); - time_t t; -#if defined(_USE_32BIT_TIME_T) - _time32(&t); -#else - _time64(&t); -#endif - elpptime_s(timeInfo, &t); - return timeInfo; -#else - // 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; - struct tm *tmInf = elpptime(&rawTime); - *timeInfo = *tmInf; - return timeInfo; -#endif // ELPP_COMPILER_MSVC -#endif // ELPP_OS_UNIX -} - -char *DateTime::parseFormat(char *buf, std::size_t bufSz, const char *format, - const struct tm *tInfo, std::size_t msec, - const base::SubsecondPrecision *ssPrec) { - const char *bufLim = buf + bufSz; - for (; *format; ++format) { - if (*format == base::consts::kFormatSpecifierChar) { - switch (*++format) { - case base::consts::kFormatSpecifierChar: // Escape - break; - case '\0': // End - --format; - break; - case 'd': // Day - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_mday, 2, buf, - bufLim); - continue; - case 'a': // Day of week (short) - buf = base::utils::Str::addToBuff( - base::consts::kDaysAbbrev[tInfo->tm_wday], buf, bufLim); - continue; - case 'A': // Day of week (long) - buf = base::utils::Str::addToBuff(base::consts::kDays[tInfo->tm_wday], - buf, bufLim); - continue; - case 'M': // month - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_mon + 1, 2, buf, - bufLim); - continue; - case 'b': // month (short) - buf = base::utils::Str::addToBuff( - base::consts::kMonthsAbbrev[tInfo->tm_mon], buf, bufLim); - continue; - case 'B': // month (long) - buf = base::utils::Str::addToBuff(base::consts::kMonths[tInfo->tm_mon], - buf, bufLim); - continue; - case 'y': // year (two digits) - buf = base::utils::Str::convertAndAddToBuff( - tInfo->tm_year + base::consts::kYearBase, 2, buf, bufLim); - continue; - case 'Y': // year (four digits) - buf = base::utils::Str::convertAndAddToBuff( - tInfo->tm_year + base::consts::kYearBase, 4, buf, bufLim); - continue; - case 'h': // hour (12-hour) - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_hour % 12, 2, buf, - bufLim); - continue; - case 'H': // hour (24-hour) - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_hour, 2, buf, - bufLim); - continue; - case 'm': // minute - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_min, 2, buf, - bufLim); - continue; - case 's': // second - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_sec, 2, buf, - bufLim); - continue; - case 'z': // subsecond part - case 'g': - buf = base::utils::Str::convertAndAddToBuff(msec, ssPrec->m_width, buf, - bufLim); - continue; - case 'F': // AM/PM - buf = base::utils::Str::addToBuff( - (tInfo->tm_hour >= 12) ? base::consts::kPm : base::consts::kAm, buf, - bufLim); - continue; - default: - continue; - } - } - if (buf == bufLim) - break; - *buf++ = *format; - } - return buf; -} - -// CommandLineArgs - -void CommandLineArgs::setArgs(int argc, char **argv) { - m_params.clear(); - m_paramsWithValue.clear(); - if (argc == 0 || argv == nullptr) { - return; - } - m_argc = argc; - m_argv = argv; - for (int i = 1; i < m_argc; ++i) { - const char *v = (strstr(m_argv[i], "=")); - if (v != nullptr && strlen(v) > 0) { - std::string key = std::string(m_argv[i]); - key = key.substr(0, key.find_first_of('=')); - if (hasParamWithValue(key.c_str())) { - ELPP_INTERNAL_INFO(1, "Skipping [" - << key << "] arg since it already has value [" - << getParamValue(key.c_str()) << "]"); - } else { - m_paramsWithValue.insert(std::make_pair(key, std::string(v + 1))); - } - } - if (v == nullptr) { - if (hasParam(m_argv[i])) { - ELPP_INTERNAL_INFO(1, "Skipping [" << m_argv[i] - << "] arg since it already exists"); - } else { - m_params.push_back(std::string(m_argv[i])); - } - } - } -} - -bool CommandLineArgs::hasParamWithValue(const char *paramKey) const { - return m_paramsWithValue.find(std::string(paramKey)) != - m_paramsWithValue.end(); -} - -const char *CommandLineArgs::getParamValue(const char *paramKey) const { - 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 { - return std::find(m_params.begin(), m_params.end(), std::string(paramKey)) != - m_params.end(); -} - -bool CommandLineArgs::empty(void) const { - return m_params.empty() && m_paramsWithValue.empty(); -} - -std::size_t CommandLineArgs::size(void) const { - return m_params.size() + m_paramsWithValue.size(); -} - -base::type::ostream_t &operator<<(base::type::ostream_t &os, - const CommandLineArgs &c) { - for (int i = 1; i < c.m_argc; ++i) { - os << ELPP_LITERAL("[") << c.m_argv[i] << ELPP_LITERAL("]"); - if (i < c.m_argc - 1) { - os << ELPP_LITERAL(" "); - } - } - return os; -} - -} // namespace utils - -// el::base::threading -namespace threading { - -#if ELPP_THREADING_ENABLED -#if ELPP_USE_STD_THREADING -#if ELPP_ASYNC_LOGGING -static void msleep(int ms) { - // Only when async logging enabled - this is because async is strict on - // compiler -#if defined(ELPP_NO_SLEEP_FOR) - usleep(ms * 1000); -#else - std::this_thread::sleep_for(std::chrono::milliseconds(ms)); -#endif // defined(ELPP_NO_SLEEP_FOR) -} -#endif // ELPP_ASYNC_LOGGING -#endif // !ELPP_USE_STD_THREADING -#endif // ELPP_THREADING_ENABLED - -} // namespace threading - -// el::base - -// SubsecondPrecision - -void SubsecondPrecision::init(int width) { - if (width < 1 || width > 6) { - width = base::consts::kDefaultSubsecondPrecision; - } - m_width = width; - switch (m_width) { - case 3: - m_offset = 1000; - break; - case 4: - m_offset = 100; - break; - case 5: - m_offset = 10; - break; - case 6: - m_offset = 1; - break; - default: - m_offset = 1000; - break; - } -} - -// LogFormat - -LogFormat::LogFormat(void) - : m_level(Level::Unknown), m_userFormat(base::type::string_t()), - m_format(base::type::string_t()), m_dateTimeFormat(std::string()), - m_flags(0x0), m_currentUser(base::utils::OS::currentUser()), - m_currentHost(base::utils::OS::currentHost()) {} - -LogFormat::LogFormat(Level level, const base::type::string_t &format) - : m_level(level), m_userFormat(format), - m_currentUser(base::utils::OS::currentUser()), - m_currentHost(base::utils::OS::currentHost()) { - parseFromFormat(m_userFormat); -} - -LogFormat::LogFormat(const LogFormat &logFormat) - : m_level(logFormat.m_level), m_userFormat(logFormat.m_userFormat), - m_format(logFormat.m_format), - m_dateTimeFormat(logFormat.m_dateTimeFormat), m_flags(logFormat.m_flags), - m_currentUser(logFormat.m_currentUser), - m_currentHost(logFormat.m_currentHost) {} - -LogFormat::LogFormat(LogFormat &&logFormat) { - m_level = std::move(logFormat.m_level); - m_userFormat = std::move(logFormat.m_userFormat); - m_format = std::move(logFormat.m_format); - m_dateTimeFormat = std::move(logFormat.m_dateTimeFormat); - m_flags = std::move(logFormat.m_flags); - m_currentUser = std::move(logFormat.m_currentUser); - m_currentHost = std::move(logFormat.m_currentHost); -} - -LogFormat &LogFormat::operator=(const LogFormat &logFormat) { - if (&logFormat != this) { - m_level = logFormat.m_level; - m_userFormat = logFormat.m_userFormat; - m_dateTimeFormat = logFormat.m_dateTimeFormat; - m_flags = logFormat.m_flags; - m_currentUser = logFormat.m_currentUser; - m_currentHost = logFormat.m_currentHost; - } - return *this; -} - -bool LogFormat::operator==(const LogFormat &other) { - return m_level == other.m_level && m_userFormat == other.m_userFormat && - m_format == other.m_format && - m_dateTimeFormat == other.m_dateTimeFormat && m_flags == other.m_flags; -} - -/// @brief Updates format to be used while logging. -/// @param userFormat User provided format -void LogFormat::parseFromFormat(const base::type::string_t &userFormat) { - // We make copy because we will be changing the format - // i.e, removing user provided date format from original format - // and then storing it. - base::type::string_t formatCopy = userFormat; - m_flags = 0x0; - auto conditionalAddFlag = [&](const base::type::char_t *specifier, - base::FormatFlags flag) { - std::size_t foundAt = base::type::string_t::npos; - while ((foundAt = formatCopy.find(specifier, foundAt + 1)) != - base::type::string_t::npos) { - if (foundAt > 0 && - formatCopy[foundAt - 1] == base::consts::kFormatSpecifierChar) { - 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 - 1, 1); - ++foundAt; - } - } else { - if (!hasFlag(flag)) - addFlag(flag); - } - } - }; - conditionalAddFlag(base::consts::kAppNameFormatSpecifier, - base::FormatFlags::AppName); - conditionalAddFlag(base::consts::kSeverityLevelFormatSpecifier, - base::FormatFlags::Level); - conditionalAddFlag(base::consts::kSeverityLevelShortFormatSpecifier, - base::FormatFlags::LevelShort); - conditionalAddFlag(base::consts::kLoggerIdFormatSpecifier, - base::FormatFlags::LoggerId); - conditionalAddFlag(base::consts::kThreadIdFormatSpecifier, - base::FormatFlags::ThreadId); - conditionalAddFlag(base::consts::kLogFileFormatSpecifier, - base::FormatFlags::File); - conditionalAddFlag(base::consts::kLogFileBaseFormatSpecifier, - base::FormatFlags::FileBase); - conditionalAddFlag(base::consts::kLogLineFormatSpecifier, - base::FormatFlags::Line); - conditionalAddFlag(base::consts::kLogLocationFormatSpecifier, - base::FormatFlags::Location); - conditionalAddFlag(base::consts::kLogFunctionFormatSpecifier, - base::FormatFlags::Function); - conditionalAddFlag(base::consts::kCurrentUserFormatSpecifier, - base::FormatFlags::User); - conditionalAddFlag(base::consts::kCurrentHostFormatSpecifier, - base::FormatFlags::Host); - conditionalAddFlag(base::consts::kMessageFormatSpecifier, - base::FormatFlags::LogMessage); - conditionalAddFlag(base::consts::kVerboseLevelFormatSpecifier, - base::FormatFlags::VerboseLevel); - // For date/time we need to extract user's date format first - std::size_t dateIndex = std::string::npos; - if ((dateIndex = formatCopy.find(base::consts::kDateTimeFormatSpecifier)) != - std::string::npos) { - while (dateIndex != std::string::npos && dateIndex > 0 && - formatCopy[dateIndex - 1] == base::consts::kFormatSpecifierChar) { - dateIndex = formatCopy.find(base::consts::kDateTimeFormatSpecifier, - dateIndex + 1); - } - if (dateIndex != std::string::npos) { - addFlag(base::FormatFlags::DateTime); - updateDateFormat(dateIndex, formatCopy); - } - } - m_format = formatCopy; - updateFormatSpec(); -} - -void LogFormat::updateDateFormat(std::size_t index, - base::type::string_t &currFormat) { - if (hasFlag(base::FormatFlags::DateTime)) { - index += ELPP_STRLEN(base::consts::kDateTimeFormatSpecifier); - } - const base::type::char_t *ptr = currFormat.c_str() + index; - if ((currFormat.size() > index) && (ptr[0] == '{')) { - // User has provided format for date/time - ++ptr; - int count = 1; // Start by 1 in order to remove starting brace - std::stringstream ss; - for (; *ptr; ++ptr, ++count) { - if (*ptr == '}') { - ++count; // In order to remove ending brace - break; - } - ss << static_cast<char>(*ptr); - } - currFormat.erase(index, count); - m_dateTimeFormat = ss.str(); - } else { - // No format provided, use default - if (hasFlag(base::FormatFlags::DateTime)) { - m_dateTimeFormat = std::string(base::consts::kDefaultDateTimeFormat); - } - } -} - -void LogFormat::updateFormatSpec(void) { - // Do not use switch over strongly typed enums because Intel C++ compilers - // dont support them yet. - if (m_level == Level::Debug) { - base::utils::Str::replaceFirstWithEscape( - m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kDebugLevelLogValue); - base::utils::Str::replaceFirstWithEscape( - m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kDebugLevelShortLogValue); - } else if (m_level == Level::Info) { - base::utils::Str::replaceFirstWithEscape( - m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kInfoLevelLogValue); - base::utils::Str::replaceFirstWithEscape( - m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kInfoLevelShortLogValue); - } else if (m_level == Level::Warning) { - base::utils::Str::replaceFirstWithEscape( - m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kWarningLevelLogValue); - base::utils::Str::replaceFirstWithEscape( - m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kWarningLevelShortLogValue); - } else if (m_level == Level::Error) { - base::utils::Str::replaceFirstWithEscape( - m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kErrorLevelLogValue); - base::utils::Str::replaceFirstWithEscape( - m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kErrorLevelShortLogValue); - } else if (m_level == Level::Fatal) { - base::utils::Str::replaceFirstWithEscape( - m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kFatalLevelLogValue); - base::utils::Str::replaceFirstWithEscape( - m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kFatalLevelShortLogValue); - } else if (m_level == Level::Verbose) { - base::utils::Str::replaceFirstWithEscape( - m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kVerboseLevelLogValue); - base::utils::Str::replaceFirstWithEscape( - m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kVerboseLevelShortLogValue); - } else if (m_level == Level::Trace) { - base::utils::Str::replaceFirstWithEscape( - m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kTraceLevelLogValue); - base::utils::Str::replaceFirstWithEscape( - m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kTraceLevelShortLogValue); - } - if (hasFlag(base::FormatFlags::User)) { - base::utils::Str::replaceFirstWithEscape( - m_format, base::consts::kCurrentUserFormatSpecifier, m_currentUser); - } - if (hasFlag(base::FormatFlags::Host)) { - base::utils::Str::replaceFirstWithEscape( - m_format, base::consts::kCurrentHostFormatSpecifier, m_currentHost); - } - // Ignore Level::Global and Level::Unknown -} - -// TypedConfigurations - -TypedConfigurations::TypedConfigurations( - Configurations *configurations, - LogStreamsReferenceMapPtr logStreamsReference) { - m_configurations = configurations; - m_logStreamsReference = logStreamsReference; - build(m_configurations); -} - -TypedConfigurations::TypedConfigurations(const TypedConfigurations &other) { - this->m_configurations = other.m_configurations; - this->m_logStreamsReference = other.m_logStreamsReference; - build(m_configurations); -} - -bool TypedConfigurations::enabled(Level level) { - return getConfigByVal<bool>(level, &m_enabledMap, "enabled"); -} - -bool TypedConfigurations::toFile(Level level) { - return getConfigByVal<bool>(level, &m_toFileMap, "toFile"); -} - -const std::string &TypedConfigurations::filename(Level level) { - return getConfigByRef<std::string>(level, &m_filenameMap, "filename"); -} - -bool TypedConfigurations::toStandardOutput(Level level) { - return getConfigByVal<bool>(level, &m_toStandardOutputMap, - "toStandardOutput"); -} - -const base::LogFormat &TypedConfigurations::logFormat(Level level) { - return getConfigByRef<base::LogFormat>(level, &m_logFormatMap, "logFormat"); -} - -const base::SubsecondPrecision & -TypedConfigurations::subsecondPrecision(Level level) { - return getConfigByRef<base::SubsecondPrecision>( - level, &m_subsecondPrecisionMap, "subsecondPrecision"); -} - -const base::MillisecondsWidth & -TypedConfigurations::millisecondsWidth(Level level) { - return getConfigByRef<base::MillisecondsWidth>( - level, &m_subsecondPrecisionMap, "millisecondsWidth"); -} - -bool TypedConfigurations::performanceTracking(Level level) { - return getConfigByVal<bool>(level, &m_performanceTrackingMap, - "performanceTracking"); -} - -base::type::fstream_t *TypedConfigurations::fileStream(Level level) { - return getConfigByRef<base::FileStreamPtr>(level, &m_fileStreamMap, - "fileStream") - .get(); -} - -std::size_t TypedConfigurations::maxLogFileSize(Level level) { - return getConfigByVal<std::size_t>(level, &m_maxLogFileSizeMap, - "maxLogFileSize"); -} - -std::size_t TypedConfigurations::logFlushThreshold(Level level) { - return getConfigByVal<std::size_t>(level, &m_logFlushThresholdMap, - "logFlushThreshold"); -} - -void TypedConfigurations::build(Configurations *configurations) { - base::threading::ScopedLock scopedLock(lock()); - auto getBool = [](std::string boolStr) -> bool { // Pass by value for trimming - base::utils::Str::trim(boolStr); - return (boolStr == "TRUE" || boolStr == "true" || boolStr == "1"); - }; - std::vector<Configuration *> withFileSizeLimit; - for (Configurations::const_iterator it = configurations->begin(); - it != configurations->end(); ++it) { - Configuration *conf = *it; - // We cannot use switch on strong enums because Intel C++ dont support them - // yet - if (conf->configurationType() == ConfigurationType::Enabled) { - setValue(conf->level(), getBool(conf->value()), &m_enabledMap); - } else if (conf->configurationType() == ConfigurationType::ToFile) { - setValue(conf->level(), getBool(conf->value()), &m_toFileMap); - } else if (conf->configurationType() == - ConfigurationType::ToStandardOutput) { - setValue(conf->level(), getBool(conf->value()), &m_toStandardOutputMap); - } else if (conf->configurationType() == ConfigurationType::Filename) { - // We do not yet configure filename but we will configure in another - // loop. This is because if file cannot be created, we will force ToFile - // to be false. Because configuring logger is not necessarily performance - // sensitive operation, we can live with another loop; (by the way this - // loop is not very heavy either) - } else if (conf->configurationType() == ConfigurationType::Format) { - setValue(conf->level(), - base::LogFormat(conf->level(), - base::type::string_t(conf->value().begin(), - conf->value().end())), - &m_logFormatMap); - } else if (conf->configurationType() == - ConfigurationType::SubsecondPrecision) { - setValue( - Level::Global, - base::SubsecondPrecision(static_cast<int>(getULong(conf->value()))), - &m_subsecondPrecisionMap); - } else if (conf->configurationType() == - ConfigurationType::PerformanceTracking) { - setValue(Level::Global, getBool(conf->value()), - &m_performanceTrackingMap); - } else if (conf->configurationType() == ConfigurationType::MaxLogFileSize) { - 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); - } - } - // As mentioned earlier, we will now set filename configuration in separate - // loop to deal with non-existent files - for (Configurations::const_iterator it = configurations->begin(); - it != configurations->end(); ++it) { - Configuration *conf = *it; - if (conf->configurationType() == ConfigurationType::Filename) { - insertFile(conf->level(), conf->value()); - } - } - for (std::vector<Configuration *>::iterator conf = withFileSizeLimit.begin(); - conf != withFileSizeLimit.end(); ++conf) { - // This is not unsafe as mutex is locked in currect scope - unsafeValidateFileRolling((*conf)->level(), - base::defaultPreRollOutCallback); - } -} - -unsigned long TypedConfigurations::getULong(std::string confVal) { - bool valid = true; - base::utils::Str::trim(confVal); - valid = !confVal.empty() && - std::find_if(confVal.begin(), confVal.end(), [](char c) { - return !base::utils::Str::isDigit(c); - }) == confVal.end(); - if (!valid) { - valid = false; - ELPP_ASSERT(valid, - "Configuration value not a valid integer [" << confVal << "]"); - return 0; - } - return atol(confVal.c_str()); -} - -std::string TypedConfigurations::resolveFilename(const std::string &filename) { - std::string resultingFilename = filename; - std::size_t dateIndex = std::string::npos; - std::string dateTimeFormatSpecifierStr = - std::string(base::consts::kDateTimeFormatSpecifierForFilename); - if ((dateIndex = resultingFilename.find( - dateTimeFormatSpecifierStr.c_str())) != std::string::npos) { - while (dateIndex > 0 && resultingFilename[dateIndex - 1] == - base::consts::kFormatSpecifierChar) { - dateIndex = resultingFilename.find(dateTimeFormatSpecifierStr.c_str(), - dateIndex + 1); - } - if (dateIndex != std::string::npos) { - const char *ptr = resultingFilename.c_str() + dateIndex; - // Goto end of specifier - ptr += dateTimeFormatSpecifierStr.size(); - std::string fmt; - if ((resultingFilename.size() > dateIndex) && (ptr[0] == '{')) { - // User has provided format for date/time - ++ptr; - int count = 1; // Start by 1 in order to remove starting brace - std::stringstream ss; - for (; *ptr; ++ptr, ++count) { - if (*ptr == '}') { - ++count; // In order to remove ending brace - break; - } - ss << *ptr; - } - resultingFilename.erase(dateIndex + dateTimeFormatSpecifierStr.size(), - count); - fmt = ss.str(); - } else { - fmt = std::string(base::consts::kDefaultDateTimeFormatInFilename); - } - base::SubsecondPrecision ssPrec(3); - std::string now = - base::utils::DateTime::getDateTime(fmt.c_str(), &ssPrec); - base::utils::Str::replaceAll( - now, '/', - '-'); // Replace path element since we are dealing with filename - base::utils::Str::replaceAll(resultingFilename, - dateTimeFormatSpecifierStr, now); - } - } - return resultingFilename; -} - -void TypedConfigurations::insertFile(Level level, - const std::string &fullFilename) { - std::string resolvedFilename = resolveFilename(fullFilename); - if (resolvedFilename.empty()) { - std::cerr << "Could not load empty file for logging, please re-check your " - "configurations for level [" - << LevelHelper::convertToString(level) << "]"; - } - std::string filePath = base::utils::File::extractPathFromFilename( - resolvedFilename, base::consts::kFilePathSeparator); - if (filePath.size() < resolvedFilename.size()) { - base::utils::File::createPath(filePath); - } - auto create = [&](Level level) { - base::LogStreamsReferenceMap::iterator filestreamIter = - m_logStreamsReference->find(resolvedFilename); - base::type::fstream_t *fs = nullptr; - if (filestreamIter == m_logStreamsReference->end()) { - // We need a completely new stream, nothing to share with - fs = base::utils::File::newFileStream(resolvedFilename); - m_filenameMap.insert(std::make_pair(level, resolvedFilename)); - m_fileStreamMap.insert(std::make_pair(level, base::FileStreamPtr(fs))); - m_logStreamsReference->insert(std::make_pair( - resolvedFilename, base::FileStreamPtr(m_fileStreamMap.at(level)))); - } else { - // Woops! we have an existing one, share it! - m_filenameMap.insert(std::make_pair(level, filestreamIter->first)); - m_fileStreamMap.insert( - std::make_pair(level, base::FileStreamPtr(filestreamIter->second))); - fs = filestreamIter->second.get(); - } - if (fs == nullptr) { - // We display bad file error from newFileStream() - ELPP_INTERNAL_ERROR("Setting [TO_FILE] of [" - << LevelHelper::convertToString(level) - << "] to FALSE", - false); - setValue(level, false, &m_toFileMap); - } - }; - // If we dont have file conf for any level, create it for Level::Global first - // otherwise create for specified level - create(m_filenameMap.empty() && m_fileStreamMap.empty() ? Level::Global - : level); -} - -bool TypedConfigurations::unsafeValidateFileRolling( - Level level, const PreRollOutCallback &preRollOutCallback) { - base::type::fstream_t *fs = - unsafeGetConfigByRef(level, &m_fileStreamMap, "fileStream").get(); - if (fs == nullptr) { - return true; - } - std::size_t maxLogFileSize = - unsafeGetConfigByVal(level, &m_maxLogFileSizeMap, "maxLogFileSize"); - std::size_t currFileSize = base::utils::File::getSizeOfFile(fs); - if (maxLogFileSize != 0 && currFileSize >= maxLogFileSize) { - std::string fname = unsafeGetConfigByRef(level, &m_filenameMap, "filename"); - ELPP_INTERNAL_INFO(1, "Truncating log file [" - << fname - << "] as a result of configurations for level [" - << LevelHelper::convertToString(level) << "]"); - fs->close(); - preRollOutCallback(fname.c_str(), currFileSize); - fs->open(fname, std::fstream::out | std::fstream::trunc); - return true; - } - return false; -} - -// RegisteredHitCounters - -bool RegisteredHitCounters::validateEveryN(const char *filename, - base::type::LineNumber lineNumber, - std::size_t n) { - base::threading::ScopedLock scopedLock(lock()); - base::HitCounter *counter = get(filename, lineNumber); - if (counter == nullptr) { - registerNew(counter = new base::HitCounter(filename, lineNumber)); - } - counter->validateHitCounts(n); - bool result = - (n >= 1 && counter->hitCounts() != 0 && counter->hitCounts() % n == 0); - return result; -} - -/// @brief Validates counter for hits >= N, i.e, registers new if does not exist -/// otherwise updates original one -/// @return True if validation resulted in triggering hit. Meaning logs should -/// be written everytime true is returned -bool RegisteredHitCounters::validateAfterN(const char *filename, - base::type::LineNumber lineNumber, - std::size_t n) { - base::threading::ScopedLock scopedLock(lock()); - base::HitCounter *counter = get(filename, lineNumber); - if (counter == nullptr) { - registerNew(counter = new base::HitCounter(filename, lineNumber)); - } - // Do not use validateHitCounts here since we do not want to reset counter - // here Note the >= instead of > because we are incrementing after this check - if (counter->hitCounts() >= n) - return true; - counter->increment(); - return false; -} - -/// @brief Validates counter for hits are <= n, i.e, registers new if does not -/// exist otherwise updates original one -/// @return True if validation resulted in triggering hit. Meaning logs should -/// be written everytime true is returned -bool RegisteredHitCounters::validateNTimes(const char *filename, - base::type::LineNumber lineNumber, - std::size_t n) { - base::threading::ScopedLock scopedLock(lock()); - base::HitCounter *counter = get(filename, lineNumber); - if (counter == nullptr) { - registerNew(counter = new base::HitCounter(filename, lineNumber)); - } - counter->increment(); - // Do not use validateHitCounts here since we do not want to reset counter - // here - if (counter->hitCounts() <= n) - return true; - return false; -} - -// RegisteredLoggers - -RegisteredLoggers::RegisteredLoggers(const LogBuilderPtr &defaultLogBuilder) - : m_defaultLogBuilder(defaultLogBuilder) { - m_defaultConfigurations.setToDefault(); - m_logStreamsReference = std::make_shared<base::LogStreamsReferenceMap>(); -} - -Logger *RegisteredLoggers::get(const std::string &id, bool forceCreation) { - base::threading::ScopedLock scopedLock(lock()); - Logger *logger_ = base::utils::Registry<Logger, std::string>::get(id); - if (logger_ == nullptr && forceCreation) { - bool validId = Logger::isValidId(id); - if (!validId) { - ELPP_ASSERT(validId, "Invalid logger ID [" - << id << "]. Not registering this logger."); - return nullptr; - } - logger_ = new Logger(id, m_defaultConfigurations, m_logStreamsReference); - logger_->m_logBuilder = m_defaultLogBuilder; - registerNew(id, logger_); - LoggerRegistrationCallback *callback = nullptr; - for (const std::pair<std::string, base::type::LoggerRegistrationCallbackPtr> - h : m_loggerRegistrationCallbacks) { - callback = h.second.get(); - if (callback != nullptr && callback->enabled()) { - callback->handle(logger_); - } - } - } - return logger_; -} - -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; -} - -void RegisteredLoggers::unsafeFlushAll(void) { - ELPP_INTERNAL_INFO(1, "Flushing all log files"); - for (base::LogStreamsReferenceMap::iterator it = - m_logStreamsReference->begin(); - it != m_logStreamsReference->end(); ++it) { - if (it->second.get() == nullptr) - continue; - it->second->flush(); - } -} - -// VRegistry - -VRegistry::VRegistry(base::type::VerboseLevel level, - base::type::EnumType *pFlags) - : m_level(level), m_pFlags(pFlags) {} - -/// @brief Sets verbose level. Accepted range is 0-9 -void VRegistry::setLevel(base::type::VerboseLevel level) { - base::threading::ScopedLock scopedLock(lock()); - if (level > 9) - m_level = base::consts::kMaxVerboseLevel; - else - m_level = level; -} - -void VRegistry::setModules(const char *modules) { - base::threading::ScopedLock scopedLock(lock()); - auto addSuffix = [](std::stringstream &ss, const char *sfx, - const char *prev) { - if (prev != nullptr && - base::utils::Str::endsWith(ss.str(), std::string(prev))) { - std::string chr(ss.str().substr(0, ss.str().size() - strlen(prev))); - ss.str(std::string("")); - ss << chr; - } - if (base::utils::Str::endsWith(ss.str(), std::string(sfx))) { - std::string chr(ss.str().substr(0, ss.str().size() - strlen(sfx))); - ss.str(std::string("")); - ss << chr; - } - ss << sfx; - }; - auto insert = [&](std::stringstream &ss, base::type::VerboseLevel level) { - if (!base::utils::hasFlag(LoggingFlag::DisableVModulesExtensions, - *m_pFlags)) { - addSuffix(ss, ".h", nullptr); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".c", ".h"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".cpp", ".c"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".cc", ".cpp"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".cxx", ".cc"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".-inl.h", ".cxx"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".hxx", ".-inl.h"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".hpp", ".hxx"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".hh", ".hpp"); - } - m_modules.insert(std::make_pair(ss.str(), level)); - }; - bool isMod = true; - bool isLevel = false; - std::stringstream ss; - int level = -1; - for (; *modules; ++modules) { - switch (*modules) { - case '=': - isLevel = true; - isMod = false; - break; - case ',': - isLevel = false; - isMod = true; - if (!ss.str().empty() && level != -1) { - insert(ss, static_cast<base::type::VerboseLevel>(level)); - ss.str(std::string("")); - level = -1; - } - break; - default: - if (isMod) { - ss << *modules; - } else if (isLevel) { - if (isdigit(*modules)) { - level = static_cast<base::type::VerboseLevel>(*modules) - 48; - } - } - break; - } - } - if (!ss.str().empty() && level != -1) { - insert(ss, static_cast<base::type::VerboseLevel>(level)); - } -} - -bool VRegistry::allowed(base::type::VerboseLevel vlevel, const char *file) { - base::threading::ScopedLock scopedLock(lock()); - if (m_modules.empty() || file == nullptr) { - return vlevel <= m_level; - } else { - 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) { - if (base::utils::Str::wildCardMatch(baseFilename, it->first.c_str())) { - return vlevel <= it->second; - } - } - if (base::utils::hasFlag(LoggingFlag::AllowVerboseIfModuleNotSpecified, - *m_pFlags)) { - return true; - } - return false; - } -} - -void VRegistry::setFromArgs( - const base::utils::CommandLineArgs *commandLineArgs) { - if (commandLineArgs->hasParam("-v") || - commandLineArgs->hasParam("--verbose") || - commandLineArgs->hasParam("-V") || - commandLineArgs->hasParam("--VERBOSE")) { - setLevel(base::consts::kMaxVerboseLevel); - } else if (commandLineArgs->hasParamWithValue("--v")) { - setLevel(static_cast<base::type::VerboseLevel>( - atoi(commandLineArgs->getParamValue("--v")))); - } else if (commandLineArgs->hasParamWithValue("--V")) { - setLevel(static_cast<base::type::VerboseLevel>( - atoi(commandLineArgs->getParamValue("--V")))); - } else if ((commandLineArgs->hasParamWithValue("-vmodule")) && - vModulesEnabled()) { - setModules(commandLineArgs->getParamValue("-vmodule")); - } else if (commandLineArgs->hasParamWithValue("-VMODULE") && - vModulesEnabled()) { - setModules(commandLineArgs->getParamValue("-VMODULE")); - } -} - -#if !defined(ELPP_DEFAULT_LOGGING_FLAGS) -#define ELPP_DEFAULT_LOGGING_FLAGS 0x0 -#endif // !defined(ELPP_DEFAULT_LOGGING_FLAGS) -// Storage -#if ELPP_ASYNC_LOGGING -Storage::Storage(const LogBuilderPtr &defaultLogBuilder, - base::IWorker *asyncDispatchWorker) - : -#else -Storage::Storage(const LogBuilderPtr &defaultLogBuilder) - : -#endif // ELPP_ASYNC_LOGGING - m_registeredHitCounters(new base::RegisteredHitCounters()), - 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)); - sysLogLogger->configurations()->setGlobally(ConfigurationType::Format, - std::string("%level: %msg")); - sysLogLogger->reconfigure(); -#endif // defined(ELPP_SYSLOG) - addFlag(LoggingFlag::AllowVerboseIfModuleNotSpecified); -#if ELPP_ASYNC_LOGGING - installLogDispatchCallback<base::AsyncLogDispatchCallback>( - std::string("AsyncLogDispatchCallback")); -#else - installLogDispatchCallback<base::DefaultLogDispatchCallback>( - std::string("DefaultLogDispatchCallback")); -#endif // ELPP_ASYNC_LOGGING -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) - installPerformanceTrackingCallback<base::DefaultPerformanceTrackingCallback>( - std::string("DefaultPerformanceTrackingCallback")); -#endif // defined(ELPP_FEATURE_ALL) || - // defined(ELPP_FEATURE_PERFORMANCE_TRACKING) - ELPP_INTERNAL_INFO(1, "Easylogging++ has been initialized"); -#if ELPP_ASYNC_LOGGING - m_asyncDispatchWorker->start(); -#endif // ELPP_ASYNC_LOGGING -} - -Storage::~Storage(void) { - ELPP_INTERNAL_INFO(4, "Destroying storage"); -#if ELPP_ASYNC_LOGGING - ELPP_INTERNAL_INFO(5, "Replacing log dispatch callback to synchronous"); - uninstallLogDispatchCallback<base::AsyncLogDispatchCallback>( - std::string("AsyncLogDispatchCallback")); - installLogDispatchCallback<base::DefaultLogDispatchCallback>( - std::string("DefaultLogDispatchCallback")); - ELPP_INTERNAL_INFO(5, "Destroying asyncDispatchWorker"); - base::utils::safeDelete(m_asyncDispatchWorker); - ELPP_INTERNAL_INFO(5, "Destroying asyncLogQueue"); - base::utils::safeDelete(m_asyncLogQueue); -#endif // ELPP_ASYNC_LOGGING - ELPP_INTERNAL_INFO(5, "Destroying registeredHitCounters"); - base::utils::safeDelete(m_registeredHitCounters); - ELPP_INTERNAL_INFO(5, "Destroying registeredLoggers"); - base::utils::safeDelete(m_registeredLoggers); - ELPP_INTERNAL_INFO(5, "Destroying vRegistry"); - base::utils::safeDelete(m_vRegistry); -} - -bool Storage::hasCustomFormatSpecifier(const char *formatSpecifier) { - base::threading::ScopedLock scopedLock(customFormatSpecifiersLock()); - return std::find(m_customFormatSpecifiers.begin(), - m_customFormatSpecifiers.end(), - formatSpecifier) != m_customFormatSpecifiers.end(); -} - -void Storage::installCustomFormatSpecifier( - const CustomFormatSpecifier &customFormatSpecifier) { - if (hasCustomFormatSpecifier(customFormatSpecifier.formatSpecifier())) { - return; - } - base::threading::ScopedLock scopedLock(customFormatSpecifiersLock()); - m_customFormatSpecifiers.push_back(customFormatSpecifier); -} - -bool Storage::uninstallCustomFormatSpecifier(const char *formatSpecifier) { - 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) { - m_customFormatSpecifiers.erase(it); - return true; - } - return false; -} - -void Storage::setApplicationArguments(int argc, char **argv) { - m_commandLineArgs.setArgs(argc, argv); - m_vRegistry->setFromArgs(commandLineArgs()); - // default log file -#if !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG) - if (m_commandLineArgs.hasParamWithValue(base::consts::kDefaultLogFileParam)) { - Configurations c; - c.setGlobally(ConfigurationType::Filename, - std::string(m_commandLineArgs.getParamValue( - base::consts::kDefaultLogFileParam))); - registeredLoggers()->setDefaultConfigurations(c); - for (base::RegisteredLoggers::iterator it = registeredLoggers()->begin(); - it != registeredLoggers()->end(); ++it) { - it->second->configure(c); - } - } -#endif // !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG) -#if defined(ELPP_LOGGING_FLAGS_FROM_ARG) - if (m_commandLineArgs.hasParamWithValue(base::consts::kLoggingFlagsParam)) { - int userInput = - atoi(m_commandLineArgs.getParamValue(base::consts::kLoggingFlagsParam)); - if (ELPP_DEFAULT_LOGGING_FLAGS == 0x0) { - m_flags = userInput; - } else { - base::utils::addFlag<base::type::EnumType>(userInput, &m_flags); - } - } -#endif // defined(ELPP_LOGGING_FLAGS_FROM_ARG) -} - -} // namespace base - -// LogDispatchCallback -#if defined(ELPP_THREAD_SAFE) -void LogDispatchCallback::handle(const LogDispatchData *data) { - 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))); - } -} -#else -void LogDispatchCallback::handle(const LogDispatchData * /*data*/) {} -#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)); -} - -void DefaultLogDispatchCallback::dispatch(base::type::string_t &&logLine) { - if (m_data->dispatchAction() == base::DispatchAction::NormalLog) { - if (m_data->logMessage()->logger()->m_typedConfigurations->toFile( - m_data->logMessage()->level())) { - base::type::fstream_t *fs = - m_data->logMessage()->logger()->m_typedConfigurations->fileStream( - m_data->logMessage()->level()); - if (fs != nullptr) { - fs->write(logLine.c_str(), logLine.size()); - if (fs->fail()) { - ELPP_INTERNAL_ERROR( - "Unable to write log to file [" - << m_data->logMessage() - ->logger() - ->m_typedConfigurations->filename( - m_data->logMessage()->level()) - << "].\n" - << "Few possible reasons (could be something else):\n" - << " * Permission denied\n" - << " * Disk full\n" - << " * Disk is not writable", - true); - } else { - if (ELPP->hasFlag(LoggingFlag::ImmediateFlush) || - (m_data->logMessage()->logger()->isFlushNeeded( - m_data->logMessage()->level()))) { - m_data->logMessage()->logger()->flush(m_data->logMessage()->level(), - fs); - } - } - } else { - ELPP_INTERNAL_ERROR( - "Log file for [" - << LevelHelper::convertToString(m_data->logMessage()->level()) - << "] " - << "has not been configured but [TO_FILE] is configured to " - "TRUE. [Logger ID: " - << m_data->logMessage()->logger()->id() << "]", - false); - } - } - if (m_data->logMessage()->logger()->m_typedConfigurations->toStandardOutput( - m_data->logMessage()->level())) { - if (ELPP->hasFlag(LoggingFlag::ColoredTerminalOutput)) - m_data->logMessage()->logger()->logBuilder()->convertToColoredOutput( - &logLine, m_data->logMessage()->level()); - ELPP_COUT << ELPP_COUT_LINE(logLine); - } - } -#if defined(ELPP_SYSLOG) - else if (m_data->dispatchAction() == base::DispatchAction::SysLog) { - // Determine syslog priority - int sysLogPriority = 0; - if (m_data->logMessage()->level() == Level::Fatal) - sysLogPriority = LOG_EMERG; - else if (m_data->logMessage()->level() == Level::Error) - sysLogPriority = LOG_ERR; - else if (m_data->logMessage()->level() == Level::Warning) - sysLogPriority = LOG_WARNING; - else if (m_data->logMessage()->level() == Level::Info) - sysLogPriority = LOG_INFO; - else if (m_data->logMessage()->level() == Level::Debug) - sysLogPriority = LOG_DEBUG; - else - sysLogPriority = LOG_NOTICE; -#if defined(ELPP_UNICODE) - char *line = base::utils::Str::wcharPtrToCharPtr(logLine.c_str()); - syslog(sysLogPriority, "%s", line); - free(line); -#else - syslog(sysLogPriority, "%s", logLine.c_str()); -#endif - } -#endif // defined(ELPP_SYSLOG) -} - -#if ELPP_ASYNC_LOGGING - -// AsyncLogDispatchCallback - -void AsyncLogDispatchCallback::handle(const LogDispatchData *data) { - base::type::string_t logLine = - data->logMessage()->logger()->logBuilder()->build( - data->logMessage(), - data->dispatchAction() == base::DispatchAction::NormalLog); - if (data->dispatchAction() == base::DispatchAction::NormalLog && - data->logMessage()->logger()->typedConfigurations()->toStandardOutput( - data->logMessage()->level())) { - if (ELPP->hasFlag(LoggingFlag::ColoredTerminalOutput)) - data->logMessage()->logger()->logBuilder()->convertToColoredOutput( - &logLine, data->logMessage()->level()); - ELPP_COUT << ELPP_COUT_LINE(logLine); - } - // Save resources and only queue if we want to write to file otherwise just - // ignore handler - if (data->logMessage()->logger()->typedConfigurations()->toFile( - data->logMessage()->level())) { - ELPP->asyncLogQueue()->push( - AsyncLogItem(*(data->logMessage()), *data, logLine)); - } -} - -// AsyncDispatchWorker -AsyncDispatchWorker::AsyncDispatchWorker() { setContinueRunning(false); } - -AsyncDispatchWorker::~AsyncDispatchWorker() { - setContinueRunning(false); - ELPP_INTERNAL_INFO(6, "Stopping dispatch worker - Cleaning log queue"); - clean(); - ELPP_INTERNAL_INFO(6, "Log queue cleaned"); -} - -bool AsyncDispatchWorker::clean(void) { - std::mutex m; - std::unique_lock<std::mutex> lk(m); - cv.wait(lk, [] { return !ELPP->asyncLogQueue()->empty(); }); - emptyQueue(); - lk.unlock(); - cv.notify_one(); - return ELPP->asyncLogQueue()->empty(); -} - -void AsyncDispatchWorker::emptyQueue(void) { - while (!ELPP->asyncLogQueue()->empty()) { - AsyncLogItem data = ELPP->asyncLogQueue()->next(); - handle(&data); - base::threading::msleep(100); - } -} - -void AsyncDispatchWorker::start(void) { - base::threading::msleep(5000); // 5s (why?) - setContinueRunning(true); - std::thread t1(&AsyncDispatchWorker::run, this); - t1.join(); -} - -void AsyncDispatchWorker::handle(AsyncLogItem *logItem) { - LogDispatchData *data = logItem->data(); - LogMessage *logMessage = logItem->logMessage(); - Logger *logger = logMessage->logger(); - base::TypedConfigurations *conf = logger->typedConfigurations(); - base::type::string_t logLine = logItem->logLine(); - if (data->dispatchAction() == base::DispatchAction::NormalLog) { - if (conf->toFile(logMessage->level())) { - base::type::fstream_t *fs = conf->fileStream(logMessage->level()); - if (fs != nullptr) { - fs->write(logLine.c_str(), logLine.size()); - if (fs->fail()) { - ELPP_INTERNAL_ERROR( - "Unable to write log to file [" - << conf->filename(logMessage->level()) << "].\n" - << "Few possible reasons (could be something else):\n" - << " * Permission denied\n" - << " * Disk full\n" - << " * Disk is not writable", - true); - } else { - if (ELPP->hasFlag(LoggingFlag::ImmediateFlush) || - (logger->isFlushNeeded(logMessage->level()))) { - logger->flush(logMessage->level(), fs); - } - } - } else { - ELPP_INTERNAL_ERROR( - "Log file for [" - << LevelHelper::convertToString(logMessage->level()) << "] " - << "has not been configured but [TO_FILE] is configured to " - "TRUE. [Logger ID: " - << logger->id() << "]", - false); - } - } - } -#if defined(ELPP_SYSLOG) - else if (data->dispatchAction() == base::DispatchAction::SysLog) { - // Determine syslog priority - int sysLogPriority = 0; - if (logMessage->level() == Level::Fatal) - sysLogPriority = LOG_EMERG; - else if (logMessage->level() == Level::Error) - sysLogPriority = LOG_ERR; - else if (logMessage->level() == Level::Warning) - sysLogPriority = LOG_WARNING; - else if (logMessage->level() == Level::Info) - sysLogPriority = LOG_INFO; - else if (logMessage->level() == Level::Debug) - sysLogPriority = LOG_DEBUG; - else - sysLogPriority = LOG_NOTICE; -#if defined(ELPP_UNICODE) - char *line = base::utils::Str::wcharPtrToCharPtr(logLine.c_str()); - syslog(sysLogPriority, "%s", line); - free(line); -#else - syslog(sysLogPriority, "%s", logLine.c_str()); -#endif - } -#endif // defined(ELPP_SYSLOG) -} - -void AsyncDispatchWorker::run(void) { - while (continueRunning()) { - emptyQueue(); - base::threading::msleep(10); // 10ms - } -} -#endif // ELPP_ASYNC_LOGGING - -// DefaultLogBuilder - -base::type::string_t DefaultLogBuilder::build(const LogMessage *logMessage, - bool appendNewLine) const { - base::TypedConfigurations *tc = logMessage->logger()->typedConfigurations(); - const base::LogFormat *logFormat = &tc->logFormat(logMessage->level()); - base::type::string_t logLine = logFormat->format(); - char buff[base::consts::kSourceFilenameMaxLength + - base::consts::kSourceLineMaxLength] = ""; - const char *bufLim = buff + sizeof(buff); - if (logFormat->hasFlag(base::FormatFlags::AppName)) { - // App name - base::utils::Str::replaceFirstWithEscape( - logLine, base::consts::kAppNameFormatSpecifier, - logMessage->logger()->parentApplicationName()); - } - if (logFormat->hasFlag(base::FormatFlags::ThreadId)) { - // Thread ID - base::utils::Str::replaceFirstWithEscape( - logLine, base::consts::kThreadIdFormatSpecifier, - ELPP->getThreadName(base::threading::getCurrentThreadId())); - } - if (logFormat->hasFlag(base::FormatFlags::DateTime)) { - // DateTime - base::utils::Str::replaceFirstWithEscape( - logLine, base::consts::kDateTimeFormatSpecifier, - base::utils::DateTime::getDateTime( - logFormat->dateTimeFormat().c_str(), - &tc->subsecondPrecision(logMessage->level()))); - } - if (logFormat->hasFlag(base::FormatFlags::Function)) { - // Function - base::utils::Str::replaceFirstWithEscape( - logLine, base::consts::kLogFunctionFormatSpecifier, logMessage->func()); - } - if (logFormat->hasFlag(base::FormatFlags::File)) { - // File - base::utils::Str::clearBuff(buff, base::consts::kSourceFilenameMaxLength); - base::utils::File::buildStrippedFilename(logMessage->file().c_str(), buff); - base::utils::Str::replaceFirstWithEscape( - logLine, base::consts::kLogFileFormatSpecifier, std::string(buff)); - } - if (logFormat->hasFlag(base::FormatFlags::FileBase)) { - // FileBase - base::utils::Str::clearBuff(buff, base::consts::kSourceFilenameMaxLength); - base::utils::File::buildBaseFilename(logMessage->file(), buff); - base::utils::Str::replaceFirstWithEscape( - logLine, base::consts::kLogFileBaseFormatSpecifier, std::string(buff)); - } - if (logFormat->hasFlag(base::FormatFlags::Line)) { - // Line - char *buf = - base::utils::Str::clearBuff(buff, base::consts::kSourceLineMaxLength); - buf = base::utils::Str::convertAndAddToBuff( - logMessage->line(), base::consts::kSourceLineMaxLength, buf, bufLim, - false); - base::utils::Str::replaceFirstWithEscape( - logLine, base::consts::kLogLineFormatSpecifier, std::string(buff)); - } - if (logFormat->hasFlag(base::FormatFlags::Location)) { - // Location - char *buf = base::utils::Str::clearBuff( - buff, base::consts::kSourceFilenameMaxLength + - base::consts::kSourceLineMaxLength); - base::utils::File::buildStrippedFilename(logMessage->file().c_str(), buff); - buf = base::utils::Str::addToBuff(buff, buf, bufLim); - buf = base::utils::Str::addToBuff(":", buf, bufLim); - buf = base::utils::Str::convertAndAddToBuff( - logMessage->line(), base::consts::kSourceLineMaxLength, buf, bufLim, - false); - base::utils::Str::replaceFirstWithEscape( - logLine, base::consts::kLogLocationFormatSpecifier, std::string(buff)); - } - if (logMessage->level() == Level::Verbose && - logFormat->hasFlag(base::FormatFlags::VerboseLevel)) { - // Verbose level - char *buf = base::utils::Str::clearBuff(buff, 1); - buf = base::utils::Str::convertAndAddToBuff(logMessage->verboseLevel(), 1, - buf, bufLim, false); - base::utils::Str::replaceFirstWithEscape( - logLine, base::consts::kVerboseLevelFormatSpecifier, std::string(buff)); - } - if (logFormat->hasFlag(base::FormatFlags::LogMessage)) { - // Log message - base::utils::Str::replaceFirstWithEscape( - logLine, base::consts::kMessageFormatSpecifier, logMessage->message()); - } -#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(); - it != ELPP->customFormatSpecifiers()->end(); ++it) { - std::string fs(it->formatSpecifier()); - base::type::string_t wcsFormatSpecifier(fs.begin(), fs.end()); - base::utils::Str::replaceFirstWithEscape(logLine, wcsFormatSpecifier, - it->resolver()(logMessage)); - } -#endif // !defined(ELPP_DISABLE_CUSTOM_FORMAT_SPECIFIERS) - if (appendNewLine) - logLine += ELPP_LITERAL("\n"); - return logLine; -} - -// LogDispatcher - -void LogDispatcher::dispatch(void) { - if (m_proceed && m_dispatchAction == base::DispatchAction::None) { - m_proceed = false; - } - if (!m_proceed) { - return; - } -#ifndef ELPP_NO_GLOBAL_LOCK - // see https://github.com/muflihun/easyloggingpp/issues/580 - // global lock is turned on 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()); - } - LogDispatchCallback *callback = nullptr; - LogDispatchData data; - for (const std::pair<std::string, base::type::LogDispatchCallbackPtr> h : - ELPP->m_logDispatchCallbacks) { - callback = h.second.get(); - if (callback != nullptr && callback->enabled()) { - data.setLogMessage(m_logMessage); - data.setDispatchAction(m_dispatchAction); - callback->handle(&data); - } - } -} - -// MessageBuilder - -void MessageBuilder::initialize(Logger *logger) { - m_logger = logger; - m_containerLogSeparator = ELPP->hasFlag(LoggingFlag::NewLineForContainer) - ? ELPP_LITERAL("\n ") - : ELPP_LITERAL(", "); -} - -MessageBuilder &MessageBuilder::operator<<(const wchar_t *msg) { - if (msg == nullptr) { - m_logger->stream() << base::consts::kNullPointer; - return *this; - } -#if defined(ELPP_UNICODE) - m_logger->stream() << msg; -#else - char *buff_ = base::utils::Str::wcharPtrToCharPtr(msg); - m_logger->stream() << buff_; - free(buff_); -#endif - if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) { - m_logger->stream() << " "; - } - return *this; -} - -// Writer - -Writer &Writer::construct(Logger *logger, bool needLock) { - m_logger = logger; - initializeLogger(logger->id(), false, needLock); - m_messageBuilder.initialize(m_logger); - return *this; -} - -Writer &Writer::construct(int count, const char *loggerIds, ...) { - if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) { - 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 *); - } - va_end(loggersList); - initializeLogger(m_loggerIds.at(0)); - } else { - initializeLogger(std::string(loggerIds)); - } - m_messageBuilder.initialize(m_logger); - return *this; -} - -void Writer::initializeLogger(const std::string &loggerId, bool lookup, - bool needLock) { - if (lookup) { - m_logger = ELPP->registeredLoggers()->get( - loggerId, ELPP->hasFlag(LoggingFlag::CreateLoggerAutomatically)); - } - if (m_logger == nullptr) { - { - 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)); - } - } - Writer(Level::Debug, m_file, m_line, m_func) - .construct(1, base::consts::kDefaultLoggerId) - << "Logger [" << loggerId << "] is not registered yet!"; - m_proceed = false; - } else { - if (needLock) { - m_logger->acquireLock(); // This should not be unlocked by checking - // m_proceed because - // m_proceed can be changed by lines below - } - if (ELPP->hasFlag(LoggingFlag::HierarchicalLogging)) { - m_proceed = m_level == Level::Verbose - ? m_logger->enabled(m_level) - : LevelHelper::castToInt(m_level) >= - LevelHelper::castToInt(ELPP->m_loggingLevel); - } else { - m_proceed = m_logger->enabled(m_level); - } - } -} - -void Writer::processDispatch() { -#if ELPP_LOGGING_ENABLED - if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) { - bool firstDispatched = false; - base::type::string_t logMessage; - std::size_t i = 0; - do { - if (m_proceed) { - if (firstDispatched) { - m_logger->stream() << logMessage; - } else { - firstDispatched = true; - if (m_loggerIds.size() > 1) { - logMessage = m_logger->stream().str(); - } - } - triggerDispatch(); - } else if (m_logger != nullptr) { - m_logger->stream().str(ELPP_LITERAL("")); - m_logger->releaseLock(); - } - if (i + 1 < m_loggerIds.size()) { - initializeLogger(m_loggerIds.at(i + 1)); - } - } while (++i < m_loggerIds.size()); - } else { - if (m_proceed) { - triggerDispatch(); - } else if (m_logger != nullptr) { - m_logger->stream().str(ELPP_LITERAL("")); - m_logger->releaseLock(); - } - } -#else - if (m_logger != nullptr) { - m_logger->stream().str(ELPP_LITERAL("")); - m_logger->releaseLock(); - } -#endif // ELPP_LOGGING_ENABLED -} - -void Writer::triggerDispatch(void) { - try { - if (m_proceed) { - 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("")); - m_logger->releaseLock(); - } - if (m_proceed && m_level == Level::Fatal && - !ELPP->hasFlag(LoggingFlag::DisableApplicationAbortOnFatalLog)) { - base::Writer(Level::Warning, m_file, m_line, m_func) - .construct(1, base::consts::kDefaultLoggerId) - << "Aborting application. Reason: Fatal log at [" << m_file << ":" - << m_line << "]"; - std::stringstream reasonStream; - reasonStream << "Fatal log at [" << m_file << ":" << m_line << "]" - << " If you wish to disable 'abort on fatal log' please use " - << "el::Loggers::addFlag(el::LoggingFlag::" - "DisableApplicationAbortOnFatalLog)"; - base::utils::abort(1, reasonStream.str()); - } - m_proceed = false; - } catch (std::exception &ex) { - // Extremely low memory situation; don't let exception be unhandled. - } -} - -// PErrorWriter - -PErrorWriter::~PErrorWriter(void) { - if (m_proceed) { -#if ELPP_COMPILER_MSVC - char buff[256]; - strerror_s(buff, 256, errno); - m_logger->stream() << ": " << buff << " [" << errno << "]"; -#else - m_logger->stream() << ": " << strerror(errno) << " [" << errno << "]"; -#endif - } -} - -// PerformanceTracker - -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) - -PerformanceTracker::PerformanceTracker(const std::string &blockName, - base::TimestampUnit timestampUnit, - const std::string &loggerId, - bool scopedLog, Level level) - : m_blockName(blockName), m_timestampUnit(timestampUnit), - m_loggerId(loggerId), m_scopedLog(scopedLog), m_level(level), - m_hasChecked(false), m_lastCheckpointId(std::string()), m_enabled(false) { -#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED - // We store it locally so that if user happen to change configuration by the - // end of scope or before calling checkpoint, we still depend on state of - // configuration at time of construction - el::Logger *loggerPtr = ELPP->registeredLoggers()->get(loggerId, false); - m_enabled = loggerPtr != nullptr && - loggerPtr->m_typedConfigurations->performanceTracking(m_level); - if (m_enabled) { - base::utils::DateTime::gettimeofday(&m_startTime); - } -#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED -} - -PerformanceTracker::~PerformanceTracker(void) { -#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED - if (m_enabled) { - base::threading::ScopedLock scopedLock(lock()); - if (m_scopedLog) { - base::utils::DateTime::gettimeofday(&m_endTime); - base::type::string_t formattedTime = getFormattedTimeTaken(); - PerformanceTrackingData data(PerformanceTrackingData::DataType::Complete); - data.init(this); - data.m_formattedTimeTaken = formattedTime; - PerformanceTrackingCallback *callback = nullptr; - for (const std::pair<std::string, - base::type::PerformanceTrackingCallbackPtr> &h : - ELPP->m_performanceTrackingCallbacks) { - callback = h.second.get(); - if (callback != nullptr && callback->enabled()) { - callback->handle(&data); - } - } - } - } -#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) -} - -void PerformanceTracker::checkpoint(const std::string &id, const char *file, - base::type::LineNumber line, - const char *func) { -#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED - if (m_enabled) { - base::threading::ScopedLock scopedLock(lock()); - base::utils::DateTime::gettimeofday(&m_endTime); - base::type::string_t formattedTime = - m_hasChecked ? getFormattedTimeTaken(m_lastCheckpointTime) - : ELPP_LITERAL(""); - PerformanceTrackingData data(PerformanceTrackingData::DataType::Checkpoint); - data.init(this); - data.m_checkpointId = id; - data.m_file = file; - data.m_line = line; - data.m_func = func; - data.m_formattedTimeTaken = formattedTime; - PerformanceTrackingCallback *callback = nullptr; - for (const std::pair<std::string, - base::type::PerformanceTrackingCallbackPtr> &h : - ELPP->m_performanceTrackingCallbacks) { - callback = h.second.get(); - if (callback != nullptr && callback->enabled()) { - callback->handle(&data); - } - } - base::utils::DateTime::gettimeofday(&m_lastCheckpointTime); - m_hasChecked = true; - m_lastCheckpointId = id; - } -#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED - ELPP_UNUSED(id); - ELPP_UNUSED(file); - ELPP_UNUSED(line); - ELPP_UNUSED(func); -} - -const base::type::string_t -PerformanceTracker::getFormattedTimeTaken(struct timeval startTime) const { - if (ELPP->hasFlag(LoggingFlag::FixedTimeFormat)) { - base::type::stringstream_t ss; - ss << base::utils::DateTime::getTimeDifference(m_endTime, startTime, - m_timestampUnit) - << " " - << base::consts::kTimeFormats[static_cast<base::type::EnumType>( - m_timestampUnit)] - .unit; - return ss.str(); - } - return base::utils::DateTime::formatTime( - base::utils::DateTime::getTimeDifference(m_endTime, startTime, - m_timestampUnit), - m_timestampUnit); -} - -#endif // defined(ELPP_FEATURE_ALL) || - // defined(ELPP_FEATURE_PERFORMANCE_TRACKING) - -namespace debug { -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) - -// StackTrace - -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_hex.empty() ? "" : "+") << si.m_hex << " " << si.m_addr - << (si.m_demangled.empty() ? "" : ":") << si.m_demangled; - return ss; -} - -std::ostream &operator<<(std::ostream &os, const StackTrace &st) { - std::vector<StackTrace::StackTraceEntry>::const_iterator it = - st.m_stack.begin(); - while (it != st.m_stack.end()) { - os << " " << *it++ << "\n"; - } - return os; -} - -void StackTrace::generateNew(void) { -#ifdef HAVE_EXECINFO - m_stack.clear(); - void *stack[kMaxStack]; - unsigned int size = backtrace(stack, kMaxStack); - char **strings = backtrace_symbols(stack, size); - if (size > kStackStart) { // Skip StackTrace c'tor and generateNew - for (std::size_t i = kStackStart; i < size; ++i) { - 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.empty()) { - int status = 0; - 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, location, demangName, hex, addr); - m_stack.push_back(entry); - } else { - // Not successful - we will use mangled name - StackTraceEntry entry(i - 1, location, mangName, hex, addr); - m_stack.push_back(entry); - } - free(demangName); - } else { - StackTraceEntry entry(i - 1, line); - m_stack.push_back(entry); - } - } - } - free(strings); -#else - ELPP_INTERNAL_INFO( - 1, "Stacktrace generation not supported for selected compiler"); -#endif // ELPP_STACKTRACE -} - -// Static helper functions - -static std::string crashReason(int sig) { - std::stringstream ss; - bool foundReason = false; - for (int i = 0; i < base::consts::kCrashSignalsCount; ++i) { - if (base::consts::kCrashSignals[i].numb == sig) { - ss << "Application has crashed due to [" - << base::consts::kCrashSignals[i].name << "] signal"; - if (ELPP->hasFlag(el::LoggingFlag::LogDetailedCrashReason)) { - ss << std::endl - << " " << base::consts::kCrashSignals[i].brief << std::endl - << " " << base::consts::kCrashSignals[i].detail; - } - foundReason = true; - } - } - if (!foundReason) { - ss << "Application has crashed due to unknown signal [" << sig << "]"; - } - return ss.str(); -} -/// @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); -#if ELPP_STACKTRACE - if (stackTraceIfAvailable) { - ss << std::endl - << " ======= Backtrace: =========" << std::endl - << base::debug::StackTrace(); - } -#else - ELPP_UNUSED(stackTraceIfAvailable); -#endif // ELPP_STACKTRACE - ELPP_WRITE_LOG(el::base::Writer, level, base::DispatchAction::NormalLog, - logger) - << ss.str(); -} - -static inline void crashAbort(int sig) { - base::utils::abort(sig, std::string()); -} - -/// @brief Default application crash handler -/// -/// @detail This function writes log using 'default' logger, prints stack trace -/// for GCC based compilers and aborts program. -static inline void defaultCrashHandler(int sig) { - base::debug::logCrashReason(sig, true, Level::Fatal, - base::consts::kDefaultLoggerId); - base::debug::crashAbort(sig); -} - -// CrashHandler - -CrashHandler::CrashHandler(bool useDefault) { - if (useDefault) { - setHandler(defaultCrashHandler); - } -} - -void CrashHandler::setHandler(const Handler &cHandler) { - m_handler = cHandler; -#if defined(ELPP_HANDLE_SIGABRT) - int i = 0; // SIGABRT is at base::consts::kCrashSignals[0] -#else - int i = 1; -#endif // defined(ELPP_HANDLE_SIGABRT) - for (; i < base::consts::kCrashSignalsCount; ++i) { - m_handler = signal(base::consts::kCrashSignals[i].numb, cHandler); - } -} - -#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) -} // namespace debug -} // namespace base - -// el - -// Helpers - -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) - -void Helpers::crashAbort(int sig, const char *sourceFile, - unsigned int long line) { - std::stringstream ss; - ss << base::debug::crashReason(sig).c_str(); - ss << " - [Called el::Helpers::crashAbort(" << sig << ")]"; - if (sourceFile != nullptr && strlen(sourceFile) > 0) { - ss << " - Source: " << sourceFile; - if (line > 0) - ss << ":" << line; - else - ss << " (line number not specified)"; - } - base::utils::abort(sig, ss.str()); -} - -void Helpers::logCrashReason(int sig, bool stackTraceIfAvailable, Level level, - const char *logger) { - el::base::debug::logCrashReason(sig, stackTraceIfAvailable, level, logger); -} - -#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) - -// Loggers - -Logger *Loggers::getLogger(const std::string &identity, - bool registerIfNotAvailable) { - return ELPP->registeredLoggers()->get(identity, registerIfNotAvailable); -} - -void Loggers::setDefaultLogBuilder(el::LogBuilderPtr &logBuilderPtr) { - ELPP->registeredLoggers()->setDefaultLogBuilder(logBuilderPtr); -} - -bool Loggers::unregisterLogger(const std::string &identity) { - return ELPP->registeredLoggers()->remove(identity); -} - -bool Loggers::hasLogger(const std::string &identity) { - return ELPP->registeredLoggers()->has(identity); -} - -Logger *Loggers::reconfigureLogger(Logger *logger, - const Configurations &configurations) { - if (!logger) - return nullptr; - logger->configure(configurations); - return logger; -} - -Logger *Loggers::reconfigureLogger(const std::string &identity, - const Configurations &configurations) { - return Loggers::reconfigureLogger(Loggers::getLogger(identity), - configurations); -} - -Logger *Loggers::reconfigureLogger(const std::string &identity, - ConfigurationType configurationType, - const std::string &value) { - Logger *logger = Loggers::getLogger(identity); - if (logger == nullptr) { - return nullptr; - } - logger->configurations()->set(Level::Global, configurationType, value); - logger->reconfigure(); - return logger; -} - -void Loggers::reconfigureAllLoggers(const Configurations &configurations) { - for (base::RegisteredLoggers::iterator it = - ELPP->registeredLoggers()->begin(); - it != ELPP->registeredLoggers()->end(); ++it) { - Loggers::reconfigureLogger(it->second, configurations); - } -} - -void Loggers::reconfigureAllLoggers(Level level, - ConfigurationType configurationType, - const std::string &value) { - for (base::RegisteredLoggers::iterator it = - ELPP->registeredLoggers()->begin(); - it != ELPP->registeredLoggers()->end(); ++it) { - Logger *logger = it->second; - logger->configurations()->set(level, configurationType, value); - logger->reconfigure(); - } -} - -void Loggers::setDefaultConfigurations(const Configurations &configurations, - bool reconfigureExistingLoggers) { - ELPP->registeredLoggers()->setDefaultConfigurations(configurations); - if (reconfigureExistingLoggers) { - Loggers::reconfigureAllLoggers(configurations); - } -} - -const Configurations *Loggers::defaultConfigurations(void) { - return ELPP->registeredLoggers()->defaultConfigurations(); -} - -const base::LogStreamsReferenceMapPtr Loggers::logStreamsReference(void) { - return ELPP->registeredLoggers()->logStreamsReference(); -} - -base::TypedConfigurations Loggers::defaultTypedConfigurations(void) { - return base::TypedConfigurations( - ELPP->registeredLoggers()->defaultConfigurations(), - ELPP->registeredLoggers()->logStreamsReference()); -} - -std::vector<std::string> * -Loggers::populateAllLoggerIds(std::vector<std::string> *targetList) { - targetList->clear(); - for (base::RegisteredLoggers::iterator it = - ELPP->registeredLoggers()->list().begin(); - it != ELPP->registeredLoggers()->list().end(); ++it) { - targetList->push_back(it->first); - } - return targetList; -} - -void Loggers::configureFromGlobal(const char *globalConfigurationFilePath) { - std::ifstream gcfStream(globalConfigurationFilePath, std::ifstream::in); - ELPP_ASSERT(gcfStream.is_open(), "Unable to open global configuration file [" - << globalConfigurationFilePath - << "] for parsing."); - std::string line = std::string(); - std::stringstream ss; - Logger *logger = nullptr; - auto configure = [&](void) { - ELPP_INTERNAL_INFO(8, "Configuring logger: '" - << logger->id() << "' with configurations \n" - << ss.str() << "\n--------------"); - Configurations c; - c.parseFromText(ss.str()); - logger->configure(c); - }; - while (gcfStream.good()) { - std::getline(gcfStream, line); - ELPP_INTERNAL_INFO(1, "Parsing line: " << line); - base::utils::Str::trim(line); - if (Configurations::Parser::isComment(line)) - continue; - Configurations::Parser::ignoreComments(&line); - base::utils::Str::trim(line); - if (line.size() > 2 && - base::utils::Str::startsWith( - line, std::string(base::consts::kConfigurationLoggerId))) { - if (!ss.str().empty() && logger != nullptr) { - configure(); - } - ss.str(std::string("")); - line = line.substr(2); - base::utils::Str::trim(line); - if (line.size() > 1) { - ELPP_INTERNAL_INFO(1, "Getting logger: '" << line << "'"); - logger = getLogger(line); - } - } else { - ss << line << "\n"; - } - } - if (!ss.str().empty() && logger != nullptr) { - configure(); - } -} - -bool Loggers::configureFromArg(const char *argKey) { -#if defined(ELPP_DISABLE_CONFIGURATION_FROM_PROGRAM_ARGS) - ELPP_UNUSED(argKey); -#else - if (!Helpers::commandLineArgs()->hasParamWithValue(argKey)) { - return false; - } - configureFromGlobal(Helpers::commandLineArgs()->getParamValue(argKey)); -#endif // defined(ELPP_DISABLE_CONFIGURATION_FROM_PROGRAM_ARGS) - return true; -} - -void Loggers::flushAll(void) { ELPP->registeredLoggers()->flushAll(); } - -void Loggers::setVerboseLevel(base::type::VerboseLevel level) { - ELPP->vRegistry()->setLevel(level); -} - -base::type::VerboseLevel Loggers::verboseLevel(void) { - return ELPP->vRegistry()->level(); -} - -void Loggers::setVModules(const char *modules) { - if (ELPP->vRegistry()->vModulesEnabled()) { - ELPP->vRegistry()->setModules(modules); - } -} - -void Loggers::clearVModules(void) { ELPP->vRegistry()->clearModules(); } - -// VersionInfo - -const std::string VersionInfo::version(void) { return std::string("9.96.7"); } -/// @brief Release date of current version -const std::string VersionInfo::releaseDate(void) { - return std::string("24-11-2018 0728hrs"); -} - -} // namespace el |