Boost之log日志使用

不讲理论,直接上在程序中可用代码:
一、引入Boost模块

开发环境:Visual Studio 2017
Boost库版本:1.68.0
安装方式:Nuget
安装命令:

#只安装下面几个即可
Install-package boost -version 1.68.0
Install-package boost_filesystem-vc141 -version 1.68.0
Install-package boost_log_setup-vc141 -version 1.68.0
Install-package boost_log-vc141 -version 1.68.0

#这里是其他模块,可不安装
Install-package boost_atomic-vc141 -version 1.68.0
Install-package boost_chrono-vc141 -version 1.68.0
Install-package boost_date_time-vc141 -version 1.68.0
Install-package boost_system-vc141 -version 1.68.0
Install-package boost_thread-vc141 -version 1.68.0
Install-package boost_locale-vc141 -version 1.68.0

调用Nuget控制台:

 

二、引入下面两个hpp文件
boost_logger.hpp

#pragma once

#include <string>
#include <fstream>
#include <iostream>
#include <boost/filesystem.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <boost/core/null_deleter.hpp>
#include <boost/log/core.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sinks/async_frontend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/attributes/current_thread_id.hpp>
#include <boost/log/attributes/current_process_name.hpp>
#include <boost/log/attributes/attribute.hpp>
#include <boost/log/attributes/attribute_cast.hpp>
#include <boost/log/attributes/attribute_value.hpp>
#include <boost/log/sinks/async_frontend.hpp>

// Related headersQDebug
#include <boost/log/sinks/unbounded_fifo_queue.hpp>
#include <boost/log/sinks/unbounded_ordering_queue.hpp>
#include <boost/log/sinks/bounded_fifo_queue.hpp>
#include <boost/log/sinks/bounded_ordering_queue.hpp>
#include <boost/log/sinks/drop_on_overflow.hpp>
#include <boost/log/sinks/block_on_overflow.hpp>

//这里是logger的头文件,后面根据实际路径引入
#include "logger.hpp"

//引入各种命名空间
namespace logging = boost::log;
namespace src = boost::log::sources;
namespace expr = boost::log::expressions;
namespace sinks = boost::log::sinks;
namespace keywords = boost::log::keywords;
namespace attrs = boost::log::attributes;
//建立日志源,支持严重属性
thread_local static boost::log::sources::severity_logger<log_level> lg;

#define BOOST_LOG_Q_SIZE 1000

//创建输出槽:synchronous_sink是同步前端,允许多个线程同时写日志,后端无需考虑多线程问题
typedef sinks::asynchronous_sink<sinks::text_file_backend, sinks::bounded_fifo_queue<BOOST_LOG_Q_SIZE, sinks::block_on_overflow>> sink_t;
static std::ostream &operator<<(std::ostream &strm, log_level level)
{
  static const char *strings[] =
    {
      "debug",
      "info",
      "warn",
      "error",
      "critical"};

  if (static_cast<std::size_t>(level) < sizeof(strings) / sizeof(*strings))
    strm << strings[level];
  else
    strm << static_cast<int>(level);

  return strm;
}
class boost_logger : public logger_iface
{
public:
  boost_logger(const std::string& dir) : m_level(log_level::error_level), dir(dir)
  {
  }
  ~boost_logger()
  {
  }
  /**
   * 日志初始化
   */
  void init() override
  {
    //判断日志文件所在路径是否存在
    if (boost::filesystem::exists(dir) == false)
    {
      boost::filesystem::create_directories(dir);
    }
    //添加公共属性
    logging::add_common_attributes();
    //获取日志库核心
    core = logging::core::get();
    //创建后端,并设值日志文件相关控制属性
    boost::shared_ptr<sinks::text_file_backend> backend = boost::make_shared<sinks::text_file_backend>(
      keywords::open_mode = std::ios::app, // 采用追加模式
      keywords::file_name = dir + "/%Y%m%d_%N.log", //归档日志文件名
      keywords::rotation_size = 10 * 1024 * 1024, //超过此大小自动建立新文件
      keywords::time_based_rotation = sinks::file::rotation_at_time_point(0, 0, 0), //每隔指定时间重建新文件
      keywords::min_free_space = 100 * 1024 * 1024  //最低磁盘空间限制
      );
    if (!_sink)
    {
      _sink.reset(new sink_t(backend));
      //向日志源添加槽
      core->add_sink(_sink);
    }
    //添加线程ID公共属性
    core->add_global_attribute("ThreadID", attrs::current_thread_id());
    //添加进程公共属性
    core->add_global_attribute("Process", attrs::current_process_name());
    //设置过滤器
    _sink->set_filter(expr::attr<log_level>("Severity") >= m_level);
    // 如果不写这个,它不会实时的把日志写下去,而是等待缓冲区满了,或者程序正常退出时写下
    // 这样做的好处是减少IO操作,提高效率
    _sink->locked_backend()->auto_flush(true); // 使日志实时更新
    //这些都可在配置文件中配置
    _sink->set_formatter(
      expr::stream
      << "["
      << expr::attr<std::string>("Process") << ":" << expr::attr<attrs::current_thread_id::value_type>("ThreadID") << ":"
      << expr::attr<unsigned int>("LineID") << "]["
      << expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y-%m-%d %H:%M:%S.%f") << "]["
      << expr::attr<log_level>("Severity") << "] "
      << expr::smessage);
  }
  /**
   * 停止记录日志
   */
  void stop() override
  {
    warn_log("boost logger stopping");
    _sink->flush();
    _sink->stop();
    core->remove_sink(_sink);
  }
  /**
   * 设置日志级别
   */
  void set_log_level(log_level level) override
  {
    m_level = level;

    if (_sink)
    {
      _sink->set_filter(expr::attr<log_level>("Severity") >= m_level);
    }
  }

  log_level get_log_level() override
  {
    return m_level;
  }

  void debug_log(const std::string &msg) override
  {
    BOOST_LOG_SEV(lg, debug_level) << msg << std::endl;
  }
  void info_log(const std::string &msg) override
  {
    BOOST_LOG_SEV(lg, info_level) << blue << msg << normal << std::endl;
  }
  void warn_log(const std::string &msg) override
  {
    BOOST_LOG_SEV(lg, warn_level) << yellow << msg << normal << std::endl;
  }
  void error_log(const std::string &msg) override
  {
    BOOST_LOG_SEV(lg, error_level) << red << msg << normal << std::endl;
  }
  void critical_log(const std::string &msg) override
  {
    BOOST_LOG_SEV(lg, critical_level) << red << msg << normal << std::endl;
  }

private:
  log_level m_level;
  boost::shared_ptr<logging::core> core;
  boost::shared_ptr<sink_t> _sink;
  //日志文件路径
  const std::string& dir;
};

logger.hpp

#pragma once
#define BOOST_ALL_DYN_LINK

#include <string>   // std::string
#include <iostream> // std::cout
#include <fstream>
#include <sstream> // std::ostringstream
#include <memory>

typedef std::basic_ostringstream<char> tostringstream;
static const char black[] = {0x1b, '[', '1', ';', '3', '0', 'm', 0};
static const char red[] = {0x1b, '[', '1', ';', '3', '1', 'm', 0};
static const char yellow[] = {0x1b, '[', '1', ';', '3', '3', 'm', 0};
static const char blue[] = {0x1b, '[', '1', ';', '3', '4', 'm', 0};
static const char normal[] = {0x1b, '[', '0', ';', '3', '9', 'm', 0};
#define ACTIVE_LOGGER_INSTANCE (*activeLogger::getLoggerAddr())
// note: this will replace the logger instace. If this is not the first time to set the logger instance.
// Please make sure to delete/free the old instance.
#define INIT_LOGGER(loggerImpPtr)              \
  {                                           \
    ACTIVE_LOGGER_INSTANCE = loggerImpPtr;    \
    ACTIVE_LOGGER_INSTANCE->init();           \
  }
#define CHECK_LOG_LEVEL(logLevel) (ACTIVE_LOGGER_INSTANCE ? ((ACTIVE_LOGGER_INSTANCE->get_log_level() <= log_level::logLevel##_level) ? true : false) : false)
#define SET_LOG_LEVEL(logLevel)                                                   \
  {                                                                              \
    if (ACTIVE_LOGGER_INSTANCE)                                                  \
      (ACTIVE_LOGGER_INSTANCE->set_log_level(log_level::logLevel##_level));      \
  }
#define DESTROY_LOGGER                      \
  {                                        \
    if (ACTIVE_LOGGER_INSTANCE)            \
    {                                      \
      ACTIVE_LOGGER_INSTANCE->stop();      \
      delete ACTIVE_LOGGER_INSTANCE;       \
    }                                      \
  }

enum log_level
{
  debug_level = 0,
  info_level,
  warn_level,
  error_level,
  critical_level
};

class logger_iface
{
public:
  logger_iface(void) = default;
  virtual ~logger_iface(void) = default;
  logger_iface(const logger_iface &) = default;
  logger_iface &operator=(const logger_iface &) = default;

public:
  virtual void init() = 0;
  virtual void stop() = 0;
  virtual void set_log_level(log_level level) = 0;
  virtual log_level get_log_level() = 0;
  virtual void debug_log(const std::string &msg) = 0;
  virtual void info_log(const std::string &msg) = 0;
  virtual void warn_log(const std::string &msg) = 0;
  virtual void error_log(const std::string &msg) = 0;
  virtual void critical_log(const std::string &msg) = 0;
};

class activeLogger
{
public:
  static logger_iface **getLoggerAddr()
  {
    static logger_iface *activeLogger;
    return &activeLogger;
  }
};

#define __LOGGING_ENABLED

#ifdef __LOGGING_ENABLED
#define __LOG(level, msg)                                                       \
                                                                               \
  {                                                                            \
    tostringstream var;                                                        \
    var << "[" << __FILE__ << ":" << __LINE__ << ":" << __func__ << "] \n"     \
      << msg;                                                                  \
    if (ACTIVE_LOGGER_INSTANCE)                                                \
      ACTIVE_LOGGER_INSTANCE->level##_log(var.str());                          \
  }
#else
#define __LOG(level, msg)
#endif /* __LOGGING_ENABLED */

三、使用样例

#include "logger/boost_logger.hpp"
#include "logger/simpleLogger.hpp"

void testCustomLogger() {
  //初始化日志对象:日志路径后期从配置文件读取
  const std::string logDir = "E:\\log";
  INIT_LOGGER(new boost_logger(logDir));
  //设置过滤级别(可以读取配置文件)
  SET_LOG_LEVEL(debug);
  //输出各级别日志,(void *)ACTIVE_LOGGER_INSTANCE:代表激活的日志实例(可不写)
  __LOG(critical, "hello logger!"
    << "this is critical log" << (void *)ACTIVE_LOGGER_INSTANCE);

  __LOG(debug, "hello logger!!!!!!!!!!!!!!!"
    << "this is debug log");
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/943971.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C语言初阶习题【17】求N的阶乘( 递归和非递归实现)

1.题目 2.分析 非递归 需要用到循环&#xff0c;n个数就是循环n次&#xff0c;每次和之前的乘起来 例如 5的阶乘 就是 5*4 *3 *2 *1 循环1到5 。需要一个变量来接收每次的结果 注意这个地方是乘&#xff0c;所以要从1 开始&#xff0c;sum 也需要是1而不是0 for(i 1&#xf…

云效流水线自动化部署web静态网站

云效流水线部署静态网站 背景新建流水线配置流水线运行流水线总结 背景 配置流水线以前&#xff0c;每次更新导航网站都要登进去宝塔后台&#xff0c;删掉旧的目录和文件&#xff0c;再上传最新的文件&#xff0c;太麻烦啦 网上的博客基本都是分享vue项目&#xff0c;这一篇是…

【开源项目】数字孪生化工厂—开源工程及源码

飞渡科技数字孪生化工厂管理平台&#xff0c;基于自研孪生引擎&#xff0c;将物联网IOT、人工智能、大数据、云计算等技术应用于化工厂&#xff0c;为化工厂提供实时数据分析、工艺优化、设备运维等功能&#xff0c;助力提高生产效率以及提供安全保障。 通过可视化点位标注各厂…

SpringCloud整合skywalking实现链路追踪和日志采集

1.部署skywalking https://blog.csdn.net/qq_40942490/article/details/144701194 2.添加依赖 <!-- 日志采集 --><dependency><groupId>org.apache.skywalking</groupId><artifactId>apm-toolkit-logback-1.x</artifactId><version&g…

Linux下Nvidia显卡GPU开启驱动持久化

GPU开启驱动持久化的原因 GPU 驱动一直处于加载状态&#xff0c; 减少运行程序时驱动加载的延迟。不开启该模式时&#xff0c;在程序每次调用完 GPU 后&#xff0c; GPU 驱动都会被卸载&#xff0c;下次调用时再重新加载&#xff0c; 驱动频繁卸载加载&#xff0c; GPU 频繁被…

图像处理-Ch4-频率域处理

Ch4 频率域处理(Image Enhancement in Frequency Domain) FT &#xff1a;将信号表示成各种频率的正弦信号的线性组合。 频谱&#xff1a; ∣ F ( u , v ) ∣ [ R 2 ( u , v ) I 2 ( u , v ) ] 1 2 |F(u, v)| \left[ R^2(u, v) I^2(u, v) \right]^{\frac{1}{2}} ∣F(u,v)…

虚拟化 | Proxmox VE 8.x 开源的虚拟化平台快速上手指南

[ 知识是人生的灯塔,只有不断学习,才能照亮前行的道路 ] 0x00 简介说明 前言简述 描述:作为一个爱折腾的IT打工佬,时刻以学习各类新技术新知识为目标,这不正好有一台部署了VMware vSphere ESXi 虚拟化环境的服务器,由于正好安装其系统的磁盘有坏道,经常导致使用 ESXi 异…

rocketmq-push模式-消费侧重平衡-类流程图分析

1、观察consumer线程 使用arthas分析 MQClientFactoryScheduledThread 定时任务线程 定时任务线程&#xff0c;包含如下任务&#xff1a; 每2分钟更新nameServer列表 每30秒更新topic的路由信息 每30秒检查broker的存活&#xff0c;发送心跳请求 每5秒持久化消费队列的offset…

使用亚马逊针对 PyTorch 和 MinIO 的 S3 连接器实现可迭代式数据集

2023 年 11 月&#xff0c;Amazon 宣布推出适用于 PyTorch 的 S3 连接器。适用于 PyTorch 的 Amazon S3 连接器提供了专为 S3 对象存储构建的 PyTorch 数据集基元&#xff08;数据集和数据加载器&#xff09;的实现。它支持用于随机数据访问模式的地图样式数据集和用于流式处理…

[2003].第2-01节:关系型数据库表及SQL简介

所有博客大纲 后端学习大纲 MySQL学习大纲 1.数据库表介绍&#xff1a; 1.1.表、记录、字段 1.E-R&#xff08;entity-relationship&#xff0c;实体-联系&#xff09;模型中有三个主要概念是&#xff1a; 实体集 、 属性 、 联系集2.一个实体集&#xff08;class&#xff09…

wps透视数据表

1、操作 首先选中你要的行字段表格 -> 插入 -> 透视数据表 -> 拖动行值&#xff08;部门&#xff09;到下方&#xff0c;拖动值&#xff08;包裹数量、运费&#xff09;到下方 2、删除 选中整个透视数据表 -> delete 如图&#xff1a;

Python-流量分析常用工具脚本(Tshark,pyshark,scapy)

免责声明&#xff1a;本文仅作分享~ 目录 wireshark scapy 例&#xff1a;分析DNS流量 检查数据包是否包含特定协议层&#xff08;过滤&#xff09; 获取域名 例&#xff1a;提取 HTTP 请求中的 Host 信息 pyshark 例&#xff1a;解析 HTTP 请求和响应 例&#xff1a;分…

开发场景中Java 集合的最佳选择

在 Java 开发中&#xff0c;集合类是处理数据的核心工具。合理选择集合&#xff0c;不仅可以提高代码效率&#xff0c;还能让代码更简洁。本篇文章将重点探讨 List、Set 和 Map 的适用场景及优缺点&#xff0c;帮助你在实际开发中找到最佳解决方案。 一、List&#xff1a;有序存…

[2029].第6-06节:MyISAM引擎中的索引与 InnoDB引擎中的索引对比

所有博客大纲 后端学习大纲 MySQL学习大纲 1.MyISAM索引&#xff1a; 1.1.B树索引适用存储引擎&#xff1a; 1.B树索引适用存储引擎如下表所示&#xff1a; 2.即使多个存储引擎都支持同一种类型的B树索引&#xff0c;但它们的实现原理也是不同的 Innodb和MyISAM默认的索引是B…

DS的使用

使用DS和[address]实现字的传送 要解决的问题:CPU从内存单元中要读取数据 要求&#xff1a;CPU要读取一个内存单元的时候&#xff0c;必须先给出这个内存单元的地址。 原理&#xff1a;在8086PC中&#xff0c;内存地址段地址和偏移地址组成(段地址:偏移地址) 解决方案 :DS和[a…

使用RKNN进行YOLOv8人体姿态估计的实战教程:yolov8-pose.onnx转yolov8-pose.rknn+推理全流程

之前文章有提到“YOLOv8的原生模型包含了后处理步骤,其中一些形状超出了RK3588的矩阵计算限制,因此需要对输出层进行一些裁剪”,通过裁剪后得到的onnx能够顺利的进行rknn转换,本文将对转rnkk过程,以及相应的后处理进行阐述。并在文末附上全部源码、数据、模型的百度云盘链…

短视频矩阵系统后端源码搭建实战与技术详解,支持OEM

一、引言 随着短视频行业的蓬勃发展&#xff0c;短视频矩阵系统成为了众多企业和创作者进行多平台内容运营的有力工具。后端作为整个系统的核心支撑&#xff0c;负责处理复杂的业务逻辑、数据存储与交互&#xff0c;其搭建的质量直接影响着系统的性能、稳定性和可扩展性。本文将…

JS 设置按钮的loading效果

本文是在其他博主的博客JS学习笔记 | 遮罩层Loading实现_jsp loading-CSDN博客基础上&#xff0c;进行实践的。 目录 一、需求 二、Jspcss实现代码 一、需求 在springboot项目中的原始html5页面中&#xff0c;原本的功能是页面加载时&#xff0c;使用ajax向后端发送请求&…

用VBA将word文档处理成支持弹出式注释的epub文档可用的html内容

有一种epub文件&#xff0c;其中的注释以弹窗形式显示&#xff0c;如下图&#xff1a; 点击注释引用后&#xff0c;对应的注释内容会弹出在页面中显示&#xff0c;再次点击弹窗外的任意位置该弹窗即关闭&#xff0c;关闭后点击任意注释引用&#xff0c;对应的注释内容会弹窗显示…

实践KDTS-WEB从mysql迁移到kingbasev9

数据库国产化替代数据迁移是一个复杂且关键的过程。这涉及到将原有数据库中的数据准确、完整地迁移到新的国产数据库中&#xff0c;同时确保数据的完整性和一致性。人大金仓提供了强大的数据库迁移工具&#xff08;KDTS&#xff09;对同构、异构数据库数据迁移&#xff1b; 数…