easylogging++的那些事(四)源码分析(十四)其他工具类(一)
在上一篇文章中我们介绍完了 LogFormat 类,今天我们来看看还剩下的一些工具类当中的一部分。
Helpers 类
Helpers
类为库的使用者提供的一些方便的接口。其实现如下:/// @brief Static helpers for developers class Helpers : base::StaticClass { public: // 设置全局管理对象 /// @brief Shares logging repository (base::Storage) static inline void setStorage(base::type::StoragePointer storage) { ELPP = storage; } // 获取全局管理对象 /// @return Main storage repository static inline base::type::StoragePointer storage() { return ELPP; } // 通过设置命令行参数来加载相关配置,如设置详细日志模块规则,加载LoggingFlag,全局配置默认日志文件名等 /// @brief Sets application arguments and figures out whats active for logging and whats not. static inline void setArgs(int argc, char **argv) { ELPP->setApplicationArguments(argc, argv); } /// @copydoc setArgs(int argc, char** argv) static inline void setArgs(int argc, const char **argv) { ELPP->setApplicationArguments(argc, const_cast<char **>(argv)); } /// @brief Sets thread name for current thread. Requires std::thread static inline void setThreadName(const std::string &name) { ELPP->setThreadName(name); } static inline std::string getThreadName() { return ELPP->getThreadName(base::threading::getCurrentThreadId()); } #if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) // 设置崩溃信号处理器 /// @brief Overrides default crash handler and installs custom handler. /// @param crashHandler A functor with no return type that takes single int argument. /// Handler is a typedef with specification: void (*Handler)(int) static inline void setCrashHandler(const el::base::debug::CrashHandler::Handler &crashHandler) { el::elCrashHandler.setHandler(crashHandler); } // 记录程序崩溃原因 // 记录崩溃相关信息让后程序退出 /// @brief Abort due to crash with signal in parameter /// @param sig Crash signal static void crashAbort(int sig, const char *sourceFile = "", unsigned int long line = 0); /// @brief Logs reason of crash as per sig /// @param sig Crash signal /// @param stackTraceIfAvailable Includes stack trace if available /// @param level Logging level /// @param logger Logger to use for logging static void logCrashReason(int sig, bool stackTraceIfAvailable = false, Level level = Level::Fatal, const char *logger = base::consts::kDefaultLoggerId); #endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) // 安装日志回旋回调(源码当中仅能用于备份,和实际项目需求有差异) /// @brief Installs pre rollout callback, this callback is triggered when log file is about to be rolled out /// (can be useful for backing up) static inline void installPreRollOutCallback(const PreRollOutCallback &callback) { ELPP->setPreRollOutCallback(callback); } // 卸载日志回旋回调(恢复为默认的日志回旋回调) /// @brief Uninstalls pre rollout callback static inline void uninstallPreRollOutCallback(void) { ELPP->unsetPreRollOutCallback(); } // 安装日志派发回调 /// @brief Installs post log dispatch callback, this callback is triggered when log is dispatched template <typename T> static inline bool installLogDispatchCallback(const std::string &id) { return ELPP->installLogDispatchCallback<T>(id); } // 卸载日志派发回调 /// @brief Uninstalls log dispatch callback template <typename T> static inline void uninstallLogDispatchCallback(const std::string &id) { ELPP->uninstallLogDispatchCallback<T>(id); } // 获取指定的日志派发回调对象指针 template <typename T> static inline T *logDispatchCallback(const std::string &id) { return ELPP->logDispatchCallback<T>(id); } #if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) // 安装性能跟踪回调 /// @brief Installs post performance tracking callback, this callback is triggered when performance tracking is finished template <typename T> static inline bool installPerformanceTrackingCallback(const std::string &id) { return ELPP->installPerformanceTrackingCallback<T>(id); } // 卸载性能跟踪回调 /// @brief Uninstalls post performance tracking handler template <typename T> static inline void uninstallPerformanceTrackingCallback(const std::string &id) { ELPP->uninstallPerformanceTrackingCallback<T>(id); } // 获取指定的性能跟踪回调对象指针 template <typename T> static inline T *performanceTrackingCallback(const std::string &id) { return ELPP->performanceTrackingCallback<T>(id); } // 将指定类型的对象转化为string #endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) /// @brief Converts template to std::string - useful for loggable classes to log containers within log(std::ostream&) const template <typename T> static std::string convertTemplateToStdString(const T &templ) { el::Logger *logger = ELPP->registeredLoggers()->get(el::base::consts::kDefaultLoggerId); if (logger == nullptr) { return std::string(); } base::MessageBuilder b; b.initialize(logger); logger->acquireLock(); b << templ; #if defined(ELPP_UNICODE) std::string s = std::string(logger->stream().str().begin(), logger->stream().str().end()); #else std::string s = logger->stream().str(); #endif // defined(ELPP_UNICODE) logger->stream().str(ELPP_LITERAL("")); logger->releaseLock(); return s; } // 获取全局命令行参数解析器 /// @brief Returns command line arguments (pointer) provided to easylogging++ static inline const el::base::utils::CommandLineArgs *commandLineArgs(void) { return ELPP->commandLineArgs(); } // 自定义日志格式解析器相关接口 // 调整全局自定义日志格式解析器容器的大小 /// @brief Reserve space for custom format specifiers for performance /// @see std::vector::reserve static inline void reserveCustomFormatSpecifiers(std::size_t size) { ELPP->m_customFormatSpecifiers.reserve(size); } // 安装自定义自定义日志格式解析器 /// @brief Installs user defined format specifier and handler static inline void installCustomFormatSpecifier(const CustomFormatSpecifier &customFormatSpecifier) { ELPP->installCustomFormatSpecifier(customFormatSpecifier); } // 卸载自定义日志格式的解析器 /// @brief Uninstalls user defined format specifier and handler static inline bool uninstallCustomFormatSpecifier(const char *formatSpecifier) { return ELPP->uninstallCustomFormatSpecifier(formatSpecifier); } // 查询是否含有自定义日志格式的解析器 /// @brief Returns true if custom format specifier is installed static inline bool hasCustomFormatSpecifier(const char *formatSpecifier) { return ELPP->hasCustomFormatSpecifier(formatSpecifier); } // 执行日志回旋 static inline void validateFileRolling(Logger *logger, Level level) { if (ELPP == nullptr || logger == nullptr) return; logger->m_typedConfigurations->validateFileRolling(level, ELPP->preRollOutCallback()); } }; // 记录崩溃相关信息让后程序退出 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); }
Helpers
工具类仅仅是其他相关接口的简单包装而已,没什么好多说的。
Loggers 类
Loggers
类是处理日志记录器和对应配置的工具类已经介绍的接口
在 日志格式配置方式 中我们介绍了日志配置相关的接口。相关接口声明如下:
Logger *reconfigureLogger(Logger *logger, const Configurations &configurations); Logger *reconfigureLogger(const std::string &identity, const Configurations &configurations); // 配置某个日志记录器的某个配置项 Logger *reconfigureLogger(const std::string &identity, ConfigurationType configurationType, const std::string &value); // 配置所有日志记录器的某个配置项 void reconfigureAllLoggers(ConfigurationType configurationType, const std::string &value); // 配置所有日志记录器的某个日志级别的某个配置项 void reconfigureAllLoggers(Level level, ConfigurationType configurationType, const std::string &value); // 所有日志记录器的默认配置 void setDefaultConfigurations(const Configurations &configurations, bool reconfigureExistingLoggers = false); const Configurations *defaultConfigurations(void); base::TypedConfigurations defaultTypedConfigurations(void); // 从全局配置文件中加载配置(仅仅支持带记录器ID这种形式的配置文件 如--default) // 主要就是解析配置文件,一些文件流和字符串的操作比较多,这里就不一一解析每行代码干嘛用的了,整个代码可读性较好。 void configureFromGlobal(const char *globalConfigurationFilePath); // 通过命令行参数配置 bool Loggers::configureFromArg(const char *argKey);
在 VERBOSE 日志信息管理 中我们介绍了
VERBOSE
日志信息管理相关的接口。相关接口声明如下:void Loggers::setVerboseLevel(base::type::VerboseLevel level); base::type::VerboseLevel Loggers::verboseLevel(void); void Loggers::setVModules(const char *modules); void Loggers::clearVModules(void);
日志记录器注册事件回调相关接口
// 安装回调日志记录器注册事件回调 /// @brief Installs logger registration callback, this callback is triggered when new logger is registered template <typename T> static inline bool installLoggerRegistrationCallback(const std::string &id) { return ELPP->registeredLoggers()->installLoggerRegistrationCallback<T>(id); } // 卸载日志记录器注册事件回调 /// @brief Uninstalls log dispatch callback template <typename T> static inline void uninstallLoggerRegistrationCallback(const std::string &id) { ELPP->registeredLoggers()->uninstallLoggerRegistrationCallback<T>(id); } // 获取日志记录器注册事件回调 template <typename T> static inline T *loggerRegistrationCallback(const std::string &id) { return ELPP->registeredLoggers()->loggerRegistrationCallback<T>(id); }
获取日志记录器
Logger *Loggers::getLogger(const std::string &identity, bool registerIfNotAvailable) { return ELPP->registeredLoggers()->get(identity, registerIfNotAvailable); }
查询日志记录器是否存在
bool Loggers::hasLogger(const std::string &identity) { return ELPP->registeredLoggers()->has(identity); }
删除日志记录器
bool Loggers::unregisterLogger(const std::string &identity) { return ELPP->registeredLoggers()->remove(identity); }
统计所有的日志记录器的 ID
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::setDefaultLogBuilder(el::LogBuilderPtr &logBuilderPtr) { ELPP->registeredLoggers()->setDefaultLogBuilder(logBuilderPtr); }
获取所有正在使用的日志文件对应的文件流容器
const base::LogStreamsReferenceMapPtr Loggers::logStreamsReference(void) { return ELPP->registeredLoggers()->logStreamsReference(); } // 刷新全部的日志文件 void Loggers::flushAll(void) { ELPP->registeredLoggers()->flushAll(); }
LoggingFlag 相关接口
// 向全局LoggingFlag中追加指定LoggingFlag /// @brief Adds logging flag used internally. static inline void addFlag(LoggingFlag flag) { ELPP->addFlag(flag); } // 向全局LoggingFlag中删除指定LoggingFlag /// @brief Removes logging flag used internally. static inline void removeFlag(LoggingFlag flag) { ELPP->removeFlag(flag); } // 检测是全局LoggingFlag中否存在指定的LoggingFlag /// @brief Determines whether or not certain flag is active static inline bool hasFlag(LoggingFlag flag) { return ELPP->hasFlag(flag); } // 提供的内部warpper类管理LoggingFlag // 向LoggingFlag中临时添加LoggingFlag,离开ScopedAddFlag作用域时删除添加的LoggingFlag /// @brief Adds flag and removes it when scope goes out class ScopedAddFlag { public: ScopedAddFlag(LoggingFlag flag) : m_flag(flag) { Loggers::addFlag(m_flag); } ~ScopedAddFlag(void) { Loggers::removeFlag(m_flag); } private: LoggingFlag m_flag; }; // 从LoggingFlag中临时删除LoggingFlag,离开ScopedRemoveFlag作用域时添加删除的LoggingFlag /// @brief Removes flag and add it when scope goes out class ScopedRemoveFlag { public: ScopedRemoveFlag(LoggingFlag flag) : m_flag(flag) { Loggers::removeFlag(m_flag); } ~ScopedRemoveFlag(void) { Loggers::addFlag(m_flag); } private: LoggingFlag m_flag; };
设置全局分层日志级别的基准级别
// 全局分层日志级别的基准级别用于确定是否处理日志 /// @brief Sets hierarchy for logging. Needs to enable logging flag (HierarchicalLogging) static void setLoggingLevel(Level level) { ELPP->setLoggingLevel(level); }
Loggers
工具类仅仅是其他相关接口的简单包装而已,没什么好多说的。
回调相关函数模板接口
下面三个函数模板被其他类型的回调使用,如:日志记录器注册事件回调、性能跟踪回调和日志派发回调的相关对应接口使用。
// 安装回调 template <typename T, typename TPtr> static bool installCallback(const std::string &id, std::unordered_map<std::string, TPtr> *mapT) { if (mapT->find(id) == mapT->end()) { mapT->insert(std::make_pair(id, TPtr(new T()))); return true; } return false; } // 卸载回调 template <typename T, typename TPtr> static void uninstallCallback(const std::string &id, std::unordered_map<std::string, TPtr> *mapT) { if (mapT->find(id) != mapT->end()) { mapT->erase(id); } } // 获取回调对象指针 template <typename T, typename TPtr> static T *callback(const std::string &id, std::unordered_map<std::string, TPtr> *mapT) { typename std::unordered_map<std::string, TPtr>::iterator iter = mapT->find(id); if (iter != mapT->end()) { return static_cast<T *>(iter->second.get()); } return nullptr; }
Loggable 类
自定义第三方类型可通过继承这个类,实现
log
接口来让 easylogging++支持直接日志记录这个类型的对象。class Loggable { public: virtual ~Loggable(void) {} virtual void log(el::base::type::ostream_t &) const = 0; private: friend inline el::base::type::ostream_t &operator<<(el::base::type::ostream_t &os, const Loggable &loggable) { // 内部通过调用实际类型的log接口来实现将指定Loggable的实例直接写日志 loggable.log(os); return os; } };
HitCounter 类
HitCounter
类是指定文件的指定行的统计类/// @brief Class that keeps record of current line hit for occasional logging class HitCounter { public: HitCounter(void) : m_filename(""), m_lineNumber(0), m_hitCounts(0) { } HitCounter(const char *filename, base::type::LineNumber lineNumber) : m_filename(filename), m_lineNumber(lineNumber), m_hitCounts(0) { } HitCounter(const HitCounter &hitCounter) : m_filename(hitCounter.m_filename), m_lineNumber(hitCounter.m_lineNumber), m_hitCounts(hitCounter.m_hitCounts) { } HitCounter &operator=(const HitCounter &hitCounter) { if (&hitCounter != this) { m_filename = hitCounter.m_filename; m_lineNumber = hitCounter.m_lineNumber; m_hitCounts = hitCounter.m_hitCounts; } return *this; } virtual ~HitCounter(void) { } /// @brief Resets location of current hit counter inline void resetLocation(const char *filename, base::type::LineNumber lineNumber) { m_filename = filename; m_lineNumber = lineNumber; } /// @brief Validates hit counts and resets it if necessary inline void validateHitCounts(std::size_t n) { if (m_hitCounts >= base::consts::kMaxLogPerCounter) { m_hitCounts = (n >= 1 ? base::consts::kMaxLogPerCounter % n : 0); } ++m_hitCounts; } inline const char *filename(void) const { return m_filename; } inline base::type::LineNumber lineNumber(void) const { return m_lineNumber; } inline std::size_t hitCounts(void) const { return m_hitCounts; } inline void increment(void) { ++m_hitCounts; } // 内部类用作谓词 class Predicate { public: Predicate(const char *filename, base::type::LineNumber lineNumber) : m_filename(filename), m_lineNumber(lineNumber) { } inline bool operator()(const HitCounter *counter) { return ((counter != nullptr) && (strcmp(counter->m_filename, m_filename) == 0) && (counter->m_lineNumber == m_lineNumber)); } private: const char *m_filename; base::type::LineNumber m_lineNumber; }; private: const char *m_filename; // 源文件名称 base::type::LineNumber m_lineNumber; // 行号 std::size_t m_hitCounts; // 指定文件的指定行的统计次数 };
RegisteredHitCounters 类
RegisteredHitCounters
类是HitCounter
的管理类。
公有继承自base::utils::RegistryWithPred <base::HitCounter, base::HitCounter::Predicate>
。
底层容器为std::vector <base::HitCounter*>
。
迭代器类型:// 实际iterator就是std::vector<base::HitCounter*>::iterator typedef typename RegistryWithPred<base::HitCounter, base::HitCounter::Predicate>::iterator iterator; // 实际const_iterator就是std::vector<base::HitCounter*>::const_iterator typedef typename RegistryWithPred<base::HitCounter, base::HitCounter::Predicate>::const_iterator const_iterator;
base::utils::RegistryWithPred
这个类模板后面介绍 easylogging++的设计理念时会详细分析,这里就不多说了。已经介绍的接口
在 偶尔日志宏 中我们已经介绍了偶尔写日志的相关接口。相关接口声明如下:
// 统计次数是n的整数倍时返回true /// @brief Validates counter for every 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 validateEveryN(const char *filename, base::type::LineNumber lineNumber, std::size_t n); // 统计次数大于n时返回true /// @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 validateAfterN(const char *filename, base::type::LineNumber lineNumber, std::size_t n); // 统计次数小于等于n次时返回true /// @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 validateNTimes(const char *filename, base::type::LineNumber lineNumber, std::size_t n);
获取指定文件和指定行对应的 HitCounter
inline const base::HitCounter *getCounter(const char *filename, base::type::LineNumber lineNumber) { base::threading::ScopedLock scopedLock(lock()); return get(filename, lineNumber); }
LogDispatchCallback 类
LogDispatchCallback
类是日志派发回调的基类,每次记录日志后会触发。子类可以重写handle
接口,以定制记录日志后会触发的动作。class LogDispatchCallback : public Callback<LogDispatchData> { protected: virtual void handle(const LogDispatchData *data); base::threading::Mutex &fileHandle(const LogDispatchData *data); private: friend class base::LogDispatcher; // 保存文件名和文件锁的unique_ptr对象的映射关系 std::unordered_map<std::string, std::unique_ptr<base::threading::Mutex>> m_fileLocks; base::threading::Mutex m_fileLocksMapLock; }; // ELPP_THREAD_SAFE宏:启用线程安全 #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()); }
SysLogInitializer 类
/// @brief Initializes syslog with process ID, options and facility. calls closelog() on d'tor class SysLogInitializer { public: SysLogInitializer(const char *processIdent, int options = 0, int facility = 0) { #if defined(ELPP_SYSLOG) (void)base::consts::kSysLogLoggerId; openlog(processIdent, options, facility); #else ELPP_UNUSED(processIdent); ELPP_UNUSED(options); ELPP_UNUSED(facility); #endif // defined(ELPP_SYSLOG) } virtual ~SysLogInitializer(void) { #if defined(ELPP_SYSLOG) closelog(); #endif // defined(ELPP_SYSLOG) } };
基于
RAII
方式对于syslog
日志系统 API 的封装,也不复杂,就不多说了。
用于ELPP_INITIALIZE_SYSLOG
宏中:#define ELPP_INITIALIZE_SYSLOG(id, opt, fac) el::SysLogInitializer elSyslogInit(id, opt, fac)
至此,相关工具类的介绍今天就到这里为止,下一篇我们继续介绍其他工具类。
本文来自博客园,作者:节奏自由,转载请注明原文链接:https://www.cnblogs.com/DesignLife/p/16968630.html