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

引用源码

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

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

封装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");
}

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



一个简单的spdlog使用示例的更多相关文章

  1. 一个简单的JSP程序示例

    <%@ page language="java" import="java.util.*" pageEncoding="utf-8"% ...

  2. 使用TensorFlow v2张量的一个简单的“hello world”示例

    使用TensorFlow v2张量的一个简单的"hello world"示例 import tensorflow as tf # 创建一个张量 hello = tf.constan ...

  3. 一个简单的Java死锁示例(转)

    在实际编程中,要尽量避免出现死锁的情况,但是让你故意写一个死锁的程序时似乎也不太简单(有公司会出这样的面试题),以下是一个简单的死锁例子,程序说明都写着类的注释里了,有点罗嗦,但是应该也还是表述清楚了 ...

  4. 一个简单的Javascript闭包示例

    //=====用闭包实现函数的Curry化===== //数字求和函数的函数生成器 function addGenerator( num ){ //返回一个简单的匿名函数,求两个数的和,其中第一个数字 ...

  5. 一个简单IOC与DI示例

    1.通过bean工厂实现读取xml文件,并实例化对象,实现自动注入. package com.pri.test; import com.pri.factory.BeanFactory; import ...

  6. 一个简单的 ValueTask 的示例

    Task 确实有潜在的缺点,特别是对于实例创建很多  并且高吞吐量和性能是关键问题的场景  :  Task 是一个类.作为一个类,这意味着任何需要创建一个对象的操作都需要分配一个对象,分配的对象越多, ...

  7. [deviceone开发]-一个简单的表单示例

    一.简介 这个例子我们用do_ScrollView+do_LinearLayout来实现,当没有输入相关的值而去保存的时候,则把隐藏的几个提示Label显示出来,然后调用do_LinearLayout ...

  8. 从一个简单的Java单例示例谈谈并发

    一个简单的单例示例 单例模式可能是大家经常接触和使用的一个设计模式,你可能会这么写 public class UnsafeLazyInitiallization { private static Un ...

  9. 从一个简单的Java单例示例谈谈并发 JMM JUC

    原文: http://www.open-open.com/lib/view/open1462871898428.html 一个简单的单例示例 单例模式可能是大家经常接触和使用的一个设计模式,你可能会这 ...

  10. 简单的Spring Batch示例

    使用Spring Batch做为批处理框架,可以完成常规的数据量不是特别大的离线计算. 现在写一个简单的入门版示例. 这里默认大家已经掌握了Spring Batch的基本知识,示例只是为了快速上手实践 ...

随机推荐

  1. 7.5 Windows驱动开发:监控Register注册表回调

    在笔者前一篇文章<内核枚举Registry注册表回调>中实现了对注册表的枚举,本章将实现对注册表的监控,不同于32位系统在64位系统中,微软为我们提供了两个针对注册表的专用内核监控函数,通 ...

  2. C# 中类与继承等概念

    C#是一种现代的.面向对象的编程语言,其中类和继承是面向对象编程语言中非常重要的概念,类和继承是C#中面向对象编程的基本概念,可以用于创建复杂的应用程序和模块,而多态和接口可以使程序更加灵活和可扩展. ...

  3. WPF性能优化:形状(Shape)、几何图形(Geometry)和图画(Drawing)的使用

    在用户界面技术中,绘图是一个绕不开的话题.WPF提供了多种可根据应用程序要求进行优化的2D图形和图像的处理功能,包括画刷(Brush).形状(Shape).几何图形(Geometry).图画(Draw ...

  4. 【Python】一篇拿下类属性与类方法详解【超详细的注释和解释】

    文章目录 前言 类的实例化 类的非静态属性或方法(实例属性和方法) 类的静态属性和方法 静态属性(静态成员变量) 静态方法 类方法(静态成员函数) 总结 属性的访问权限 尾声 前言 先赞后看好习惯 打 ...

  5. P4093 [HEOI2016/TJOI2016] 序列 题解

    题目链接:序列 对于 LIS 问题,很显而易见的有 dp方程为: \[dp_i=\max{dp_j}+1 \ (j<i,a_j \le a_i) \text{ dp表示以某个位置结尾的最长 LI ...

  6. 求助:Docker怎么连接mongoDB?

    首先 在playwithDocker中通过docker pull mongo引入mongo 然后创建容器 docker run -it --name mymongo -p 27017:27017 -v ...

  7. 【Flink入门修炼】1-1 为什么要学习 Flink?

    流处理和批处理是什么? 什么是 Flink?为什么要学习 Flink? Flink 有什么特点,能做什么? 本文将为你解答以上问题. 一.批处理和流处理 早些年,大数据处理还主要为批处理,一般按天或小 ...

  8. 使用VNC在Windows上远程访问Ubuntu服务器

    Step 0:事前准备 一台安装了ghome桌面的Ubuntu服务器(用作server) 一台Windows机器(用作client) Step 1:Linux服务器 在Ubuntu上安装一个VNC服务 ...

  9. VMware 虚拟机一键去虚拟化工具

    前言: 如果你想在 VMware 虚拟机里面多开玩游戏的话,但是现在大多数网游都会检测是否虚拟机,进入游戏被检测到在虚拟机中运行,游戏可能直接闪退.所以就得对 VMware 虚拟机进行去除虚拟化. 原 ...

  10. Python 中isinstance的用法

    isinstance()函数用来判断一个对象是否是一个已知的类型.isinstance(object, classinfo) 类似 type().isinstance() 与 type() 区别: t ...