第四部分:Spdlog日志库的核心组件分析-logger
Spdlog是一个快速且可扩展的C++日志库,它支持多线程和异步日志记录。在本文中,我们将分析Spdlog日志库的核心代码,探究其实现原理和代码结构。
Spdlog的基本架构
上一篇文章介绍了spdlog的五个主要组件,其中最重要是Logger、Sink和Formatter其中,Logger负责日志的记录和管理,Sink负责将日志输出到不同的目标(比如控制台、文件、网络等),Formatter负责将日志格式化为字符串。我们会在下面详细的介绍下它们。
Logger
Logger是Spdlog日志库的核心组件,它负责记录和管理日志。Logger的定义如下:
class logger {
public:
explicit logger(std::string logger_name, sinks_init_list sinks);
template<typename T>
void log(level::level_enum lvl, const T &msg);
template<typename... Args>
void log(source_loc loc, level::level_enum lvl, format_string_t<Args...> fmt, Args &&... args);
template<typename... Args>
void log(level::level_enum lvl, format_string_t<Args...> fmt, Args &&... args);
// ...
template<typename... Args>
void trace(format_string_t<Args...> fmt, Args &&... args);
template<typename... Args>
void debug(format_string_t<Args...> fmt, Args &&... args);
template<typename... Args>
void info(format_string_t<Args...> fmt, Args &&... args);
// ....
private:
std::string name_;
std::vector<sink_ptr> sinks_;
// ...
};
Logger主要包含一个名称和一组Sink,它还提供了log()方法用于记录日志。当调用log()方法时,Logger会将日志消息传递给每个Sink,并由Sink将日志输出到目标。Logger还提供了其他一些方法,比如设置日志级别、添加和删除Sink等。
Logger 是个日志包装器,包含了日志名称和一组Sink,它提供了输出不同级别日志的方法,通过不同Sink的组合可以输出到一个或多个不同输出路径(文件,控制台,网络等)。
日志名全局唯一
每个 logger 都有一个名称,并且是全局唯一的,通过上一篇提到的 register 组件注册到全局的 map里,代码如下, registry 的 loggers_ 字段通过名字记录了所有的 logger 实例。
class registry
{
public:
// .....
// 注册日志
void register_logger(std::shared_ptr<logger> new_logger);
private:
// ....
std::unordered_map<std::string, std::shared_ptr<logger>> loggers_;
}
registry 提供 register_logger 接口注册日志。这里值得注意点是:注册时候如果发现已经存在则会抛异常, throw_if_exists_ 会检查是否已经存在同名日志实例,存在则通过 throw_spdlog_ex 抛出异常。
SPDLOG_INLINE void registry::throw_if_exists_(const std::string &logger_name)
{
if (loggers_.find(logger_name) != loggers_.end())
{
throw_spdlog_ex("logger with name '" + logger_name + "' already exists");
}
}
SPDLOG_INLINE void registry::register_logger_(std::shared_ptr<logger> new_logger)
{
auto logger_name = new_logger->name();
throw_if_exists_(logger_name);
loggers_[logger_name] = std::move(new_logger);
}
日志输出控制
- 提供不同级别日志的输出接口
在 logger 类中,Spdlog 提供了不同级别日志的输出接口,包括 trace()、debug()、info()、warn()、error() 和 critical() 等。下面是 logger 类中提供的不同级别日志输出接口的代码示例:
template<typename... Args>
void trace(format_string_t<Args...> fmt, Args &&... args);
template<typename... Args>
void debug(format_string_t<Args...> fmt, Args &&... args);
template<typename... Args>
void info(format_string_t<Args...> fmt, Args &&... args);
template<typename... Args>
void warn(format_string_t<Args...> fmt, Args &&... args);
template<typename... Args>
void error(format_string_t<Args...> fmt, Args &&... args);
template<typename... Args>
void critical(format_string_t<Args...> fmt, Args &&... args);
使用这些接口,可以根据不同的日志级别输出不同的日志信息,比如 logger.info("This is an info message."); 将输出一条信息级别为 info 的日志。
- 日志输出级别控制
logger 提供了 set_level 接口来设置日志级别,这个级别可以是枚举类型 level 中的任何一个,比如 spdlog::set_level(spdlog::level::trace); 将设置日志级别为 trace,这样所有级别的日志都会被记录下来。如果想要只记录 info 级别及以上的日志,则可以使用 spdlog::set_level(spdlog::level::info);。
如果想要在运行时动态地设置日志级别,可以使用 set_level() 方法,例如 logger->set_level(spdlog::level::trace); 将设置当前 logger 的日志级别为 trace。
注意:如果想要关闭日志,则可以将日志级别设置为 off,例如 spdlog::set_level(spdlog::level::off);。
enum class level
{
trace,
debug,
info,
warn,
err,
critical,
off
};
- 日志刷新控制
logger提供了一些控制日志刷新的方法,最重要的方法是flush()。当调用flush()方法时,Logger会将所有挂起的日志消息刷新到Sink中。Logger还提供了set_pattern()方法,用于设置日志格式化模式。这个方法可以用于修改日志的输出格式,例如添加时间戳、线程ID等信息。
void flush();
- 日志格式设置
logger 提供了设置日志格式的方法 set_pattern 通过此方法可以设置包含的 skin的日志格式,具体的格式信息可以参考上一篇。
// 日志格式设置
void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local);
通过格式字符串 pattern,会生成 formatter 实例,调用 skin的set_formatter 接口设置日志格式。
SPDLOG_INLINE void logger::set_pattern(std::string pattern, pattern_time_type time_type)
{
auto new_formatter = details::make_unique<pattern_formatter>(std::move(pattern), time_type);
set_formatter(std::move(new_formatter));
}
// set formatting for the sinks in this logger.
// each sink will get a separate instance of the formatter object.
SPDLOG_INLINE void logger::set_formatter(std::unique_ptr<formatter> f)
{
for (auto it = sinks_.begin(); it != sinks_.end(); ++it)
{
if (std::next(it) == sinks_.end())
{
// last element - we can be move it.
(*it)->set_formatter(std::move(f));
break; // to prevent clang-tidy warning
}
else
{
(*it)->set_formatter(f->clone());
}
}
}
第四部分:Spdlog日志库的核心组件分析-logger的更多相关文章
- 字节开源RPC框架Kitex的日志库klog源码解读
前言 这篇文章将着重于分析字节跳动开源的RPC框架Kitex的日志库klog的源码,通过对比Go原生日志库log的实现,探究其作出的改进. 为了平滑学习曲线,我写下了这篇分析Go原生log库的文章,希 ...
- 开源日志库log4cplus+VS2008使用
一.简介 log4cplus是C++编写的开源的日志系统,功能非常全面.本文介绍如何在Windows+VS2008中使用该日志库. 二.下载 可从网站[url]http://log ...
- C/C++log日志库比较
事实上,在C的世界里面没有特别好的日志函数库(就像Java里面的的log4j,或者C++的log4cxx).C程序员都喜欢用自己的轮子.printf就是个挺好的轮子,但没办法通过配置改变日志的格式或者 ...
- C++的开源跨平台日志库glog学习研究(二)--宏的使用
上一篇从整个工程上简单分析了glog,请看C++的开源跨平台日志库glog学习研究(一),这一篇对glog的实现代码入手,比如在其源码中以宏的使用最为广泛,接下来就先对各种宏的使用做一简单分析. 1. ...
- C++的开源跨平台日志库glog学习研究(一)
作为C++领域中为数不多的好用.高效的.跨平台的日志工具,Google的开源日志库glog也算是凤毛麟角了.glog 是一个C++实现的应用级日志记录框架,提供了C++风格的流操作. 恰巧趁着五一我也 ...
- Logan:美团点评的开源移动端基础日志库
前言 Logan是美团点评集团移动端基础日志组件,这个名称是Log和An的组合,代表个体日志服务.同时Logan也是“金刚狼”大叔的名号,当然我们更希望这个产品能像金刚狼大叔一样犀利. Logan已经 ...
- [转]开源日志库<log4cplus+VS2008使用>整理
转 开源日志库<log4cplus+VS2008使用>整理 转http://pyhcx.blog.51cto.com/713166/143549 一.简介 log4cplus是C+ ...
- c++ 高性能日志库(muduo_AsyncLogging)
c++ 高性能日志库(muduo_AsyncLogging) 实现一个高效的网络日志库要解决那些问题? 首先明确一下问题的模型,这是一个典型的多生产者 单消费者问题,对于前端的日志库使用者来说,应该做 ...
- C++第三方日志库Pantheios
C++第三方日志库Pantheios Kagula 2012-1-11 简介 在项目实践中发现一个好的日志记录非常重要,你需要借助Logging才能跟踪软件中的错误.所以这里研究下第三方C++库Pan ...
- Go第三方日志库logrus
日志是程序中必不可少的一个环节,由于Go语言内置的日志库功能比较简洁,我们在实际开发中通常会选择使用第三方的日志库来进行开发.本文介绍了logrus这个日志库的基本使用. logrus介绍 Logru ...
随机推荐
- Windows 10 ~ Jenkins 安装
首先: jenkins是由java写的,所以在使用之前请安装好JDK(最好安装JDK1.8) 下载jenkins.war包并放到一个自己创建的目录D:\jenkins下:https://mirrors ...
- QT搭建Ffmpeg开发环境gcc版本
1 先安装qt 解压ffmpeg包 2打开qt创建工程 3 导入头文件和库文件 这里一定要注意gcc版本和库的版本一定要一致 4 添加一下简单的源代码 1 #include <libavcode ...
- impdp,depdp 常用参数
转载于:https://www.cnblogs.com/halberd-lee/p/7807032.html 1 导数据注意事项 检查数据库版本(用于决定导出时生成为哪个版本的dmp头文件) sele ...
- PHP、Navicat安装
一.PHPStudy小皮面板:https://public.xp.cn/upgrades/phpStudy_64.zip 下载完成后解压后双击 点击立即安装 安装完成 启动MySQL,Nginx(my ...
- Java 中的内存分配
Java 中的内存分配 Java 程序运行时,需要在内存中分配空间.为了提高运算效率,就对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式. 一.栈:储存局部变量 局部变量 ...
- 2月27日Android开发学习
App工程目录结构 App工程分为两个层次,第一个层次是项目,另一个层次是模块. 模块依附于项目,每个项目至少有一个模块.一般而言的"编译运行App",指的是运行某一模块,而非运行 ...
- Context,多个组件公用的数据传导方法
三个组件:输入A组件 输出B组件 TestContext组件,数据x. 方法: 输入端(A): import TestContext from "TestContext组件路径&qu ...
- vs 2015 默认管理员启动
方法一: 找到 VS快捷方式 所在位置,并对其高级属性中的"用管理员身份运行"进行勾选,然后进行确定. 此方法 如果是通过sln文件的快捷方式打开的,不是管理员 方法二: 1.打开 ...
- RS485总线常用拓扑结构
RS485总线拓扑结构一般可分为以下4种,分别是:总线型拓扑结构.星型拓扑结构.树形拓扑结构.环形拓扑结构.根据RS485总线布线规范,只能按照总线拓扑结构布线,但是由于现场环境复杂多变,为了能够使整 ...
- tornado cgi wsgi uwsgi之间的关系
Tornado可以当作HTTP server,直接TCP开始实现HTTP服务,这也就是为啥说Tornado可以不经过WSGI.实际上它也不是CGI. CGI是指通过stdin和stdout进行HTTP ...