← 返回主页

spdlog 使用指南

spdlog 是一个快速、仅头文件的 C++ 日志库,提供了丰富的日志功能,包括多线程安全、异步日志记录、多种输出格式和自定义格式化。它被广泛应用于各种 C++ 项目中。

📦 安装

通过 vcpkg 安装(推荐)

vcpkg install spdlog

通过 Conan 安装

conan install spdlog/1.12.0@

从源码编译

git clone https://github.com/gabime/spdlog.git
cd spdlog
mkdir build && cd build
cmake .. -DSPDLOG_BUILD_EXAMPLE=ON
cmake --build . --parallel

头文件方式使用

#include <spdlog/spdlog.h>
#include <spdlog/sinks/basic_file_sink.h>

🚀 基础使用

Hello World

#include <spdlog/spdlog.h>

int main() {
    // 控制台输出
    spdlog::info("Hello, spdlog!");
    spdlog::warn("Warning message");
    spdlog::error("Error message");
    spdlog::critical("Critical error");

    return 0;
}

不同级别的日志

#include <spdlog/spdlog.h>

int main() {
    // 设置日志级别
    spdlog::set_level(spdlog::level::debug);

    spdlog::trace("Trace message");
    spdlog::debug("Debug message");
    spdlog::info("Info message");
    spdlog::warn("Warning message");
    spdlog::error("Error message");
    spdlog::critical("Critical message");

    return 0;
}

格式化输出

#include <spdlog/spdlog.h>
#include <string>

int main() {
    // 使用占位符格式化
    int count = 42;
    std::string name = "spdlog";

    spdlog::info("Count: {}", count);
    spdlog::info("Library: {}", name);
    spdlog::info("Hello, {}! You have {} messages.", name, count);

    // 多参数格式化
    spdlog::info("User: {}, Age: {}, Score: {}", "Alice", 25, 95.5);

    return 0;
}

📝 输出到文件

创建文件日志器

#include <spdlog/spdlog.h>
#include <spdlog/sinks/basic_file_sink.h>

int main() {
    try {
        // 创建一个文件日志器
        auto logger = spdlog::basic_logger_mt("basic_logger", "logs/basic.txt");
        
        // 设置日志级别
        logger->set_level(spdlog::level::debug);
        
        // 记录日志
        logger->info("Log to file: {}", "Hello");
        logger->warn("This is a warning");
        logger->error("This is an error");

        // 刷新所有日志器
        spdlog::shutdown();
    }
    catch (const spdlog::spdlog_ex& ex) {
        spdlog::error("Log init failed: {}", ex.what());
    }

    return 0;
}

每日滚动文件

#include <spdlog/spdlog.h>
#include <spdlog/sinks/daily_file_sink.h>

int main() {
    try {
        // 创建每日滚动文件日志器
        auto logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
        
        logger->info("Daily log entry");
        logger->warn("Warning in daily log");

        spdlog::shutdown();
    }
    catch (const spdlog::spdlog_ex& ex) {
        spdlog::error("Log init failed: {}", ex.what());
    }

    return 0;
}

按大小滚动文件

#include <spdlog/spdlog.h>
#include <spdlog/sinks/rotating_file_sink.h>

int main() {
    try {
        // 创建按大小滚动文件日志器(5MB,保留3个文件)
        auto logger = spdlog::rotating_logger_mt("rotating_logger", "logs/rotating.txt", 1024 * 1024 * 5, 3);
        
        logger->info("Rotating log entry");
        logger->warn("Warning in rotating log");

        spdlog::shutdown();
    }
    catch (const spdlog::spdlog_ex& ex) {
        spdlog::error("Log init failed: {}", ex.what());
    }

    return 0;
}

🔄 多输出目标

同时输出到控制台和文件

#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/basic_file_sink.h>

int main() {
    try {
        // 创建控制台和文件 sink
        auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
        auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/multisink.txt");

        // 创建多 sink 日志器
        spdlog::sinks_init_list sink_list = {console_sink, file_sink};
        auto logger = std::make_shared<spdlog::logger>("multi_sink", sink_list);
        
        // 注册日志器
        spdlog::register_logger(logger);
        
        // 输出日志(同时到控制台和文件)
        logger->info("This goes to both console and file");
        logger->warn("Warning message");

        spdlog::shutdown();
    }
    catch (const spdlog::spdlog_ex& ex) {
        spdlog::error("Log init failed: {}", ex.what());
    }

    return 0;
}

⚡ 异步日志

使用异步日志器

#include <spdlog/spdlog.h>
#include <spdlog/async.h>
#include <spdlog/sinks/basic_file_sink.h>

int main() {
    try {
        // 创建异步日志器(队列大小8192)
        auto async_logger = spdlog::basic_logger_mt<spdlog::async_factory>(
            "async_logger", 
            "logs/async.txt"
        );
        
        async_logger->info("Async log message");
        async_logger->warn("Async warning");
        async_logger->error("Async error");

        spdlog::shutdown();
    }
    catch (const spdlog::spdlog_ex& ex) {
        spdlog::error("Log init failed: {}", ex.what());
    }

    return 0;
}

异步日志配置

#include <spdlog/spdlog.h>
#include <spdlog/async.h>

int main() {
    try {
        // 配置异步日志器
        spdlog::init_thread_pool(8192, 1);  // 队列大小8192,1个线程

        auto sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/async_config.txt");
        auto logger = std::make_shared<spdlog::async_logger>(
            "async_config", 
            sink, 
            spdlog::thread_pool()
        );
        
        spdlog::register_logger(logger);
        logger->info("Async configured log");

        spdlog::shutdown();
    }
    catch (const spdlog::spdlog_ex& ex) {
        spdlog::error("Log init failed: {}", ex.what());
    }

    return 0;
}

🎨 自定义格式

自定义日志格式

#include <spdlog/spdlog.h>
#include <spdlog/pattern_formatter.h>

int main() {
    // 设置全局格式
    spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%n] [%^%l%$] [thread %t] %v");

    spdlog::info("Formatted log message");
    spdlog::warn("Warning with custom format");

    // 为特定日志器设置格式
    auto logger = spdlog::basic_logger_mt("custom", "logs/custom.txt");
    logger->set_pattern("[%Y-%m-%d] [%l] %v");
    logger->info("Custom format");

    spdlog::shutdown();
    return 0;
}

常用格式标识符

标识符 说明
%v 实际的消息文本
%t 线程ID
%P 进程ID
%n 日志器名称
%l 日志级别(文本)
%L 日志级别(简写)
%Y-%m-%d %H:%M:%S 日期时间
%e 毫秒
%f 微秒
%s 源文件名
%# 源代码行号
%! 函数名

💼 实际应用示例

多模块日志系统

#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/basic_file_sink.h>

class LoggerFactory {
public:
    static std::shared_ptr<spdlog::logger> getLogger(const std::string& name) {
        // 如果日志器已存在,直接返回
        if (auto logger = spdlog::get(name)) {
            return logger;
        }

        // 创建新的日志器
        auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
        auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(
            "logs/" + name + ".log"
        );

        auto logger = std::make_shared<spdlog::logger>(
            name,
            spdlog::sinks_init_list{console_sink, file_sink}
        );

        logger->set_level(spdlog::level::debug);
        logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%n] [%^%l%$] %v");
        spdlog::register_logger(logger);

        return logger;
    }
};

int main() {
    try {
        // 获取不同模块的日志器
        auto db_logger = LoggerFactory::getLogger("database");
        auto network_logger = LoggerFactory::getLogger("network");
        auto app_logger = LoggerFactory::getLogger("application");

        db_logger->info("Database connection established");
        network_logger->info("Network initialized on port 8080");
        app_logger->info("Application started");

        db_logger->warn("Slow query detected");
        network_logger->error("Connection timeout");

        spdlog::shutdown();
    }
    catch (const spdlog::spdlog_ex& ex) {
        spdlog::error("Log init failed: {}", ex.what());
    }

    return 0;
}

📋 日志级别速查

级别 数值 说明
trace 0 最详细的跟踪信息
debug 1 调试信息
info 2 一般信息
warn 3 警告信息
error 4 错误信息
critical 5 严重错误
off 6 关闭日志
💡 提示: spdlog 是线程安全的,可以在多线程环境中安全使用。异步日志模式可以显著提高性能,特别是在高并发场景下。
⚠️ 注意:

🔗 参考资料