首页 > 其他分享 >一个简单的spdlog使用示例

一个简单的spdlog使用示例

时间:2023-08-26 14:46:40浏览次数:51  
标签:__ std log 示例 spdlog 简单 logger 日志

目录
spdlog是一个开源、跨平台、无依赖、只有头文件的C++11日志库,网上介绍的文章有很多这里就不过多的介绍了,GitHub链接:https://github.com/gabime/spdlog

引用源码

先下载spdlog的源码,将源码的include文件夹复制到自己的项目文件夹下:
image

然后在项目属性中包含include目录,如下图所示:
image

封装Log头文件

一般的项目对日志要求都不高,主要是要求日志线程安全、异步写入文件、每天生成新日志、支持日志回调显示,spdlog稍微配置一下即可。
把spdlog相关的配置全放到Log.h文件中,封装成Log头文件有两个好处:

  • 可以随时替换后台日志实现
  • 对外只用暴露一个头文件

Log头文件的代码如下:

#pragma once

#include "spdlog/spdlog.h"
#include "spdlog/async.h"
#include "spdlog/sinks/daily_file_sink.h"
#include "spdlog/stopwatch.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/callback_sink.h"
#include <iostream>

void init_spdlog()
{
    //异步日志,具有8k个项目和1个后台线程的队列
    spdlog::init_thread_pool(8192, 1);
    //标准控制台输出
    auto stdout_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt >();
    stdout_sink->set_level(spdlog::level::debug);
    //日志文件输出,0点0分创建新日志
    auto file_sink = std::make_shared<spdlog::sinks::daily_file_sink_mt>("logs/log.txt", 0, 0);
    file_sink->set_level(spdlog::level::info);
    //日志回调
    auto callback_sink = std::make_shared<spdlog::sinks::callback_sink_mt>([](const spdlog::details::log_msg& msg)
        {
            //日志记录器名称
            std::string name(msg.logger_name.data(), 0, msg.logger_name.size());
            //日志消息
            std::string str(msg.payload.data(), 0, msg.payload.size());
            //日志时间
            std::time_t now_c = std::chrono::system_clock::to_time_t(msg.time);

            //回调的处理逻辑自己根据项目情况定义,比如实时显示到UI、保存到数据库等等
            
            //.... 回调处理逻辑的示例
            //std::tm localTime;
            //localtime_s(&localTime, &now_c);
            //char timeStr[50];
            //std::strftime(timeStr, sizeof(timeStr), "%Y-%m-%d %H:%M:%S", &localTime);
            //// 获取毫秒数
            //auto duration = msg.time.time_since_epoch();
            //auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() % 1000;
            //std::cout << timeStr << "." << std::setfill('0') << std::setw(3) << milliseconds << " " ;
            //std::cout << to_string_view(msg.level).data() << " " << str << std::endl << std::endl << std::flush;

        });
    callback_sink->set_level(spdlog::level::info);

    std::vector<spdlog::sink_ptr> sinks{ stdout_sink, file_sink,callback_sink };
    auto log = std::make_shared<spdlog::async_logger>("logger", sinks.begin(), sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block);

    //设置日志记录级别,您需要用 %^ 和 %$  括上想要彩色的部分
    log->set_level(spdlog::level::trace);
    //设置格式
    //参考 https://github.com/gabime/spdlog/wiki/3.-Custom-formatting
    //[%Y-%m-%d %H:%M:%S.%e] 时间
    //[%l] 日志级别
    //[%t] 线程
    //[%s] 文件
    //[%#] 行号
    //[%!] 函数
    //[%v] 实际文本
    log->set_pattern("[%Y-%m-%d %H:%M:%S.%e] %^[%l]%$ [%t] [%s %!:%#] %v");
    //设置当出发 err 或更严重的错误时立刻刷新日志到  disk
    log->flush_on(spdlog::level::err);
    //3秒刷新一次队列
    spdlog::flush_every(std::chrono::seconds(3));
    spdlog::set_default_logger(log);
}

//单个日志记录器
std::shared_ptr<spdlog::logger>  get_async_file_logger(std::string name)
{
    auto log = spdlog::get(name);
    if (!log)
    {
        //指针为空,则创建日志记录器,
        log = spdlog::daily_logger_mt<spdlog::async_factory>(name, "logs/" + name + "/log.txt");
        log->set_level(spdlog::level::trace);
        log->flush_on(spdlog::level::err);
        log->set_pattern("[%Y-%m-%d %H:%M:%S.%e] %^[%l]%$ [%t] [%s %!:%#] %v");
        //记录器是自动注册的,不需要手动注册  spdlog::register_logger(name);
    }
    return log;
}

#define INITLOG()     init_spdlog()


#define TRACE(...)     SPDLOG_TRACE(__VA_ARGS__)
#define DEBUG(...)     SPDLOG_DEBUG(__VA_ARGS__)
#define INFO(...)      SPDLOG_INFO(__VA_ARGS__)
#define WARN(...)      SPDLOG_WARN(__VA_ARGS__)
#define ERROR(...)     SPDLOG_ERROR(__VA_ARGS__)
#define CRITICAL(...)  SPDLOG_CRITICAL(__VA_ARGS__)

//单个日志文件
#define GETLOG(LOG_NAME) get_async_file_logger(LOG_NAME)

#define LOGGER_TRACE(logger,...)     SPDLOG_LOGGER_TRACE(logger,__VA_ARGS__)
#define LOGGER_DEBUG(logger,...)     SPDLOG_LOGGER_DEBUG(logger,__VA_ARGS__)
#define LOGGER_INFO(logger,...)      SPDLOG_LOGGER_INFO(logger,__VA_ARGS__)
#define LOGGER_WARN(logger,...)      SPDLOG_LOGGER_WARN(logger,__VA_ARGS__)
#define LOGGER_ERROR(logger,...)     SPDLOG_LOGGER_ERROR(logger,__VA_ARGS__)
#define LOGGER_CRITICAL(logger,...)  SPDLOG_LOGGER_CRITICAL(logger,__VA_ARGS__)

//时间统计宏
#define LOGSW() spdlog::stopwatch()

上面的代码是用于初始化和配置spdlog库的日志记录器的代码。主要包括以下几个部分:

  • init_spdlog()函数用于初始化spdlog库的配置。该函数创建了一个包含控制台、文件和回调三种sink的日志记录器,并设置将其设置为默认记录器。
  • get_async_file_logger()函数获取一个单独的异步文件日志记录器,主要用于记录多线程日志,一般情况下用的比较少。
  • 用于简化日志记录的操作一些宏,spdlog自带的有日志宏,这里只是简化一下并做隔离,实际上是对spdlog库的相应函数进行了封装。
  • 定义了一个LOGSW()宏,用于方便地创建一个时间统计器,使用时不需要过多的关注统计类本身。

使用方法

使用方法如下:

#include "Log.h"
#include <thread>
#include <chrono>
#include <iostream>

int main()
{
    INITLOG("path");

    //单个日志
    auto log1= GETLOG("Test1");
    auto log2= GETLOG("Test1");
    //原始调用方式
    //SPDLOG_LOGGER_INFO(log1, "123");
    LOGGER_INFO(log2, "123");

    auto sw = LOGSW();
    // 延时2秒
    std::this_thread::sleep_for(std::chrono::seconds(2)); 
    INFO("Elapsed {0} {1}","时间", sw);
    WARN("Elapsed {0} {1}", "时间", sw);
    //原始调用方式
    //SPDLOG_INFO("TEST");
    INFO("TEST");
}

最后生成的日志文件如下:
image
image

标签:__,std,log,示例,spdlog,简单,logger,日志
From: https://www.cnblogs.com/timefiles/p/17658766.html

相关文章

  • 【算法-二分查找】实现过程、C++代码示例以及实际应用
    二分查找简介:也称为折半查找,是一个在已排序数组中查找特定元素的搜索算法。它的工作原理是将有序数组分成两半,然后检查目标值是在左半部分还是右半部分,然后在所选择的那部分中继续查找。这一过程将不断地重复,直到找到目标值或确定目标值不在数组中。实现过程:1.初始化两个指针:lo......
  • Arthas简单入门
    简介Arthas是一款线上监控诊断产品,通过全局视角实时查看应用load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率。当你遇到以下类似问题而束手无策时,Arthas......
  • 8.Acwing基础课第795题-简单-前缀和
    8.Acwing基础课第795题-简单-前缀和题目描述输入一个长度为n的整数序列。接下来再输入m个询问,每个询问输入一对l,r。对于每个询问,输出原序列中从第l个数到第r个数的和。输入格式第一行包含两个整数n和m。第二行包含n个整数,表示整数数列。接下来m行,每行包含......
  • 11.Acwing基础课第795题-简单-前缀和
    11.Acwing基础课第795题-简单-前缀和题目描述输入一个n行m列的整数矩阵,再输入q个操作,每个操作包含五个整数,,,,c,其中(,)和(,)表示一个子矩阵的左上角坐标和右下角坐标。每个操作都要将选中的子矩阵中的每个元素的值加上c。请你将进行完所有操作后的矩阵输出。输......
  • 10.Acwing基础课第797题-简单-差分
    10.Acwing基础课第797题-简单-差分题目描述输入一个长度为n的整数序列。接下来输入m个操作,每个操作包含三个整数l,r,c,表示将序列中[l,r]之间的每个数加上c。请你输出进行完所有操作后的序列。输入格式第一行包含两个整数n和m。第二行包含n个整数,表示整数序列......
  • 9.Acwing基础课第796题-简单-子矩阵的和
    9.Acwing基础课第796题-简单-子矩阵的和题目描述输入一个n行m列的整数矩阵,再输入q个询问,每个询问包含四个整数,,,,表示一个子矩阵的左上角坐标和右下角坐标。对于每个询问输出子矩阵中所有数的和。输入格式第一行包含三个整数n,m,q。接下来n行,每行包含m个整数,表示......
  • 12.Acwing基础课第799题-简单-最长连续不重复子序列
    12.Acwing基础课第799题-简单-最长连续不重复子序列题目描述给定一个长度为n的整数序列,请找出最长的不包含重复的数的连续区间,输出它的长度。输入格式第一行包含整数n。第二行包含n个整数(均在0∼1050∼105范围内),表示整数序列。输出格式共一行,包含一个整数,表示最长的不......
  • 教你写出高质量函数,简单又实用
    在编写函数时,程序员通常需要遵循以下步骤进行:1、确定最佳的设计逻辑是编写函数时应该考虑的重要因素。这些因素包括设计合理的数据结构、算法和逻辑封装,并且还要考虑到用户的安全因素。挑战在于确保所设计的方案既满足客户需求,又能得到客户的认可,并且要在项目的时间范围内完成。2......
  • 一、【ChatGLM-6B学习】-搭建一个简单的大模型
    最近业务上需要用到大模型相关的知识,所以准备简单的搭建一个环境,详细的细节后面慢慢研究,现记录下搭建过程。至于为什么选择ChatGLM-6B,主要原因是它支持中英双语,同时支持离线部署,可以方便的构建本地化的问答知识库。由于ChatGLM-6B对python版本有一定要求,目前要求3.7+版本,为了减......
  • docker-compose的简单使用并搭建zookeeper集群
    简介DockerCompose是一个用于定义和运行多容器Docker应用程序的工具。它能够简化在单个主机上使用多个容器的部署过程。使用DockerCompose,您可以使用简单的YAML文件来定义应用程序的服务、网络和卷,并通过单个命令一键启动、停止和重建整个应用程序。DockerCompose允许......