diff --git a/external/easylogging++/easylogging++.h b/external/easylogging++/easylogging++.h index 33f26ceb..e2d96983 100644 --- a/external/easylogging++/easylogging++.h +++ b/external/easylogging++/easylogging++.h @@ -356,6 +356,7 @@ ELPP_INTERNAL_DEBUGGING_OUT_INFO << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStre #include #include #include +#include #include #include #include @@ -601,6 +602,28 @@ namespace el { return Level::Trace; return Level::Unknown; } + /// @brief Converts from prefix of levelStr to Level + /// @param levelStr Upper case string based level. + /// Lower case is also valid but providing upper case is recommended. + static Level convertFromStringPrefix(const char* levelStr) { + if ((strncmp(levelStr, "GLOBAL", 6) == 0) || (strncmp(levelStr, "global", 6) == 0)) + return Level::Global; + if ((strncmp(levelStr, "DEBUG", 5) == 0) || (strncmp(levelStr, "debug", 5) == 0)) + return Level::Debug; + if ((strncmp(levelStr, "INFO", 4) == 0) || (strncmp(levelStr, "info", 4) == 0)) + return Level::Info; + if ((strncmp(levelStr, "WARNING", 7) == 0) || (strncmp(levelStr, "warning", 7) == 0)) + return Level::Warning; + if ((strncmp(levelStr, "ERROR", 5) == 0) || (strncmp(levelStr, "error", 5) == 0)) + return Level::Error; + if ((strncmp(levelStr, "FATAL", 5) == 0) || (strncmp(levelStr, "fatal", 5) == 0)) + return Level::Fatal; + if ((strncmp(levelStr, "VERBOSE", 7) == 0) || (strncmp(levelStr, "verbose", 7) == 0)) + return Level::Verbose; + if ((strncmp(levelStr, "TRACE", 5) == 0) || (strncmp(levelStr, "trace", 5) == 0)) + return Level::Trace; + return Level::Unknown; + } /// @brief Applies specified function to each level starting from startIndex /// @param startIndex initial value to start the iteration from. This is passed as pointer and /// is left-shifted so this can be used inside function (fn) to represent current level. @@ -3755,6 +3778,11 @@ inline void FUNCTION_NAME(const T&); m_modules.clear(); } + inline void clearCategories(void) { + base::threading::ScopedLock scopedLock(lock()); + m_categories.clear(); + } + void setModules(const char* modules) { base::threading::ScopedLock scopedLock(lock()); auto addSuffix = [](std::stringstream& ss, const char* sfx, const char* prev) { @@ -3827,6 +3855,52 @@ inline void FUNCTION_NAME(const T&); } } + void setCategories(const char* categories, bool clear = true) { + base::threading::ScopedLock scopedLock(lock()); + auto insert = [&](std::stringstream& ss, Level level) { + m_categories.push_back(std::make_pair(ss.str(), level)); + }; + + if (clear) + m_categories.clear(); + if (!categories) + return; + + bool isCat = true; + bool isLevel = false; + std::stringstream ss; + Level level = Level::Unknown; + for (; *categories; ++categories) { + switch (*categories) { + case ':': + isLevel = true; + isCat = false; + break; + case ',': + isLevel = false; + isCat = true; + if (!ss.str().empty() && level != Level::Unknown) { + insert(ss, level); + ss.str(std::string("")); + level = Level::Unknown; + } + break; + default: + if (isCat) { + ss << *categories; + } else if (isLevel) { + level = LevelHelper::convertFromStringPrefix(categories); + if (level != Level::Unknown) + categories += strlen(LevelHelper::convertToString(level)) - 1; + } + break; + } + } + if (!ss.str().empty() && level != Level::Unknown) { + insert(ss, level); + } + } + bool allowed(base::type::VerboseLevel vlevel, const char* file) { base::threading::ScopedLock scopedLock(lock()); if (m_modules.empty() || file == nullptr) { @@ -3845,6 +3919,33 @@ inline void FUNCTION_NAME(const T&); } } + // Log levels are sorted in a weird way... + int priority(Level level) { + if (level == Level::Fatal) return 0; + if (level == Level::Error) return 1; + if (level == Level::Warning) return 2; + if (level == Level::Info) return 3; + if (level == Level::Debug) return 4; + if (level == Level::Verbose) return 5; + if (level == Level::Trace) return 6; + return 7; + } + + bool allowed(Level level, const char* category) { + base::threading::ScopedLock scopedLock(lock()); + if (m_categories.empty() || category == nullptr) { + return false; + } else { + std::deque>::const_reverse_iterator it = m_categories.rbegin(); + for (; it != m_categories.rend(); ++it) { + if (base::utils::Str::wildCardMatch(category, it->first.c_str())) { + return priority(level) <= priority(it->second); + } + } + return false; + } + } + inline const std::map& modules(void) const { return m_modules; } @@ -3873,6 +3974,7 @@ inline void FUNCTION_NAME(const T&); base::type::VerboseLevel m_level; base::type::EnumType* m_pFlags; std::map m_modules; + std::deque> m_categories; }; } // namespace base class LogMessage { @@ -5036,7 +5138,7 @@ ELPP_LITERAL("(") << elem->first << ELPP_LITERAL(", ") << elem->second << ELPP_L } 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); + ELPP->vRegistry()->allowed(m_level, loggerId.c_str()); } else { m_proceed = m_logger->enabled(m_level); } @@ -6014,10 +6116,18 @@ el::base::type::ostream_t& operator<<(el::base::type::ostream_t& OutputStreamIns ELPP->vRegistry()->setModules(modules); } } + /// @brief Sets categories as specified (on the fly) + static inline void setCategories(const char* categories, bool clear = true) { + ELPP->vRegistry()->setCategories(categories, clear); + } /// @brief Clears vmodules static inline void clearVModules(void) { ELPP->vRegistry()->clearModules(); } + /// @brief Clears categories + static inline void clearCategories(void) { + ELPP->vRegistry()->clearCategories(); + } }; class VersionInfo : base::StaticClass { public: