简介

核心概念

  • logger: 日志对象,每个日志内包含一个sink组成的vector,每个sink可以分别设置优先级,logger本身也可设置优先级。
  • sink: 直译是水槽,实际上是引流的对象或者可以认为是输出目标,spdlog库内置了多种不同类型的logger可供选择
  • formatter: 格式化对象,绝大部分情况下spdlog默认的格式就足够用了,但是如果有个性化需求,可以进行自定义格式
  • level: 日志级别,不同的日志库可能会有不同的设置,但是基本情况下都会有debug,info,warn,error等级别划分来处理不同的情况,具体各个级别的情况可以根据自己的实际情况选取

  • 逻辑关系
    • 每个logger包含一个vector,该vector由一个或者多个 std::shared_ptr 组成,logger的每条日志都会调用sink对象,由sink对象按照formatter的格式输出到指定的地方(有可能是控制台,文件等)

formatter

  • formatter也即是格式化对象,用于控制日志的输出格式,spdlog自带了默认的formatter,一般情况下,我们无需任何修改,直接使用即可。需要注意的是,每个sink会有一个formatter
  • 默认formatter的格式为: [日期时间][logger名][log级别]log内容
    [2022-10-13 17:00:55.795] [service] [debug] found env XXXXXXX : true
    [2022-10-13 17:00:55.795] [func_config] [debug] kafka_brokers : localhost:9092
    [2022-10-13 17:00:55.795] [func_config] [debug] kafka_main_topic : kafka_test
    [2022-10-13 17:00:55.795] [func_config] [debug] kafka_partition_value : -1
    [2022-10-13 17:00:55.795] [service] [info] initialized
    

sink

  • 每个sink对应着一个输出目标和输出格式,它内部包含一个formatter,输出目标可以是控制台,文件等地方。
  • 所有的sink都在命名空间spdlog::sinks下,可以自行探索

  • spdlog中创建控制台sink非常简单,该方式创建的sink会输出到命令行终端,且是彩色的。后缀的 _mt 代表多线程, _st 代表单线程
    1
    
    auto sink1 = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    
  • 文件sink的类型有很多,这里展示几种经典类型 ```cpp auto sink1 = std::make_shared<spdlog::sinks::basic_file_sink_mt>(log_file_name);//最简单的文件sink,只需要指定文件名

auto sink2 = std::make_shared<spdlog::sinks::daily_file_sink_mt>(log_file_name, path, 14, 22);//每天的14点22分在path下创建新的文件

auto sink3 = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(log_file_name, 1024 * 1024 * 10, 100, false);//轮转文件,一个文件满了会写到下一个文件,第二个参数是单文件大小上限,第三个参数是文件数量最大值

1
2
3
4
5
6
7
8
9
10
11

+ 其他sink
  + ostream_sink
  + syslog_sink

+ sink的flush问题
  + 创建好sink后建议设置flush方式,否则可能无法立刻在文件中看到logger的内容
  + 以下为两种重要的flush方式设置(直接设置全局)
```cpp
spdlog::flush_every(std::chrono::seconds(1));
spdlog::flush_on(spdlog::level::debug);

logger

  • 日志对象,每个logger内容包含了一个vector用于存放sink,每个sink都是互相独立
  • 因此一个日志对象在输出日志时可以同时输出到控制台和文件等位置

  • 如果整个项目中只需要一个logger,spdlog提供了最为便捷的logger,注意,该logger在全局公用,输出到控制台,多线程,彩色。
    1
    2
    
    //Use the default logger (stdout, multi-threaded, colored)
    spdlog::info("Hello, {}!", "World");
    
  • 创建特定的logger
    • 大部分情况下默认logger是不够用的,因为我们可能需要做不同模块各自的logger,可能需要logger输出到文件进行持久化,所以创建logger是很很重要的一件事。
  • 直接创建
    • 与创建sink类似,我们可以非常便捷的创建logger。
    • 由于大部分时候一个logger只会有一个sink,所以spdlog提供了创建logger的接口并封装了创建sink的过程
      1
      2
      
      auto console = spdlog::stdout_color_mt("some_unique_name");//一个输出到控制台的彩色多线程logger,可以指定名字
      auto file_logger = spdlog::rotating_logger_mt("file_logger", "logs/mylogfile", 1048576 * 5, 3);//一个输出到指定文件的轮转文件logger,后面的参数指定了文件的信息
      
  • 组合sinks方式创建
    • 有时候,单sink的logger不够用,那么可以先创建sink的vector,然后使用sinks_vector创建vector
    • 以下示例中,首先创建了sink的vector,然后创建了两个sink并放入vector,最后使用该vector创建了logger,其中 set_level 的过程不是必须的, register_logger 一般是必须的,否则只能在创建logger的地方使用该logger
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      
      std::vector<spdlog::sink_ptr> sinks;
      
      auto sink1 = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
      sink1->set_level(MyLoggers::getGlobalLevel());
      sinks.push_back(sink1);
      
      auto sink2 = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(log_file_name, 1024 * 1024 * 10, 100, false);
      sink2->set_level(spdlog::level::debug);
      sinks.push_back(sink2);
          
      auto logger = std::make_shared<spdlog::logger>("logger_name", begin(sinks), end(sinks));
      logger->set_level(spdlog::level::debug);
      spdlog::register_logger(logger);
      
  • logger的注册与获取
    • 在一个地方创建了logger却智能在该处使用肯定是不好的,所以spdlog提供了全局注册和获取logger,我们只需要在某处先创建logger并注册,那么后面再其他地方使用时直接获取就可以了
    • 注册: spdlog::register_logger()
    • 获取: spdlog::get()
      1
      2
      
      //上面的代码中我们注册了一个logger,名字是logger_name,接下来尝试获取
      auto logger = MyLoggers::getLogger("logger_name");
      

logger的使用

  • logger的默认level是info,如果处于开发换进给或者生产环境,绘制需要debug级别以上,可以设置logger的级别
    1
    
    logger->set_level(spdlog::level::debug);
    
  • 可以设置全局logger级别
    1
    
    spdlog::set_level(spdlog::level::warn);
    
  • 可以设置sink级别的logger
    1
    
    sink1->set_level(spdlog::level::info);
    
  • 注意: 一个logger假如有多个sink,那么这些sink分别设置level是可以不同的,但是由于logger本身也有level,所以真正使用时,logger的level如果高于某个sink,会覆盖该sink的level,所以建议此时把logger的level手动设置为debug(默认为info)

1.1 概述

  • 使用方法一:
    • 下载好项目源代码,使用cmake编译,命令:cmake -S . -B build,然后进入build进行make,会获取到一个静态库 libspdlog.a
    • 之后通过包含include下的头文件和链接生成的静态库,使用spdlog
  • 使用方法二:
    • 将头文件和源文件分别添加到相应工程中的头文件和源文件
    • 然后再CMakeLists.txt中添加头文件目录和源文件目录,并且添加一条命令用来编译指定文件:target_compile_definitions(${PROJECT_NAME} PUBLIC SPDLOG_COMPILED_LIB)

1.2 基本用法

  • 输出日志信息到标准输出
    • spdlog::info("This is a log message.{0} {1}", "hello", "world")
    • spdlog::warn("This is a warn message");
    • spdlog::debug("This message should not be displayed");
    • spdlog::set_level(spdlog::level::trace); // set specifice logger's log level
    • spdlog::debug("This message should be displayed, because the level is setted trace");
  • 日志信息输出到文件
    • 创建基础日志文件:
      • #include "spdlog/sinks/basic_file_sink.h"
      • auto my_logger = spdlog::basic_logger_mt("file_logger", "logs/basic-log.txt", true);
      • 创建一个文件为logs/basic-log.txt,并设置输出的消息标识为file_logger的日志文件,通过使用my_logger来操作该日志文件
    • 将日志输出到日志文件中:
      • my_logger->info("Helo Info");
  • 输出行号:
    • SPDLOG_DEBUG("some debug message about program: {}", "robot");

spdlog spdlog::get()函数 详解

spdlog 是一个快速的 C++ 日志库,广泛用于高效日志记录。spdlog::get() 函数用于获取已经创建的日志记录器(logger)的共享指针。如果指定名称的日志记录器不存在,它会返回 nullptr

1. 函数定义

1
std::shared_ptr<spdlog::logger> spdlog::get(const std::string &name);

2. 参数说明

  • name: 一个 std::string 类型的参数,表示需要获取的日志记录器的名称。

3. 返回值

  • std::shared_ptr<spdlog::logger>: 返回一个指向指定名称的日志记录器的共享指针。如果指定名称的日志记录器未找到,则返回 nullptr

4. 使用场景

spdlog::get() 通常用于在应用程序的不同模块中共享同一个日志记录器。比如,你在主模块中创建了一个名为 “my_logger” 的日志记录器,之后可以在其他模块中通过 spdlog::get("my_logger") 获取同一个记录器,而无需重新创建。

5. 示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <spdlog/spdlog.h>
#include <spdlog/sinks/basic_file_sink.h>

int main() {
    // 创建一个名为 "file_logger" 的日志记录器
    auto logger = spdlog::basic_logger_mt("file_logger", "logs.txt");

    // 使用记录器进行日志记录
    logger->info("This is an info message");

    // 在其他地方获取并使用相同的记录器
    auto same_logger = spdlog::get("file_logger");
    if (same_logger) {
        same_logger->warn("This is a warning message from the same logger");
    } else {
        spdlog::error("Logger not found");
    }

    return 0;
}

6. 注意事项

  • spdlog::get() 只返回已经通过 spdlog::register_logger() 或者 spdlog::basic_logger_mt() 等方法注册过的日志记录器。如果未注册过,返回的会是 nullptr
  • spdlog::get() 函数是线程安全的,因此可以在多线程环境中安全使用。

通过 spdlog::get(),你可以在不同模块中灵活地获取和使用日志记录器,确保日志管理的一致性。