Boost之log日志使用

news2024/12/28 5:31:02

不讲理论,直接上在程序中可用代码:
一、引入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");
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

18.springcloud_openfeign之扩展组件二

文章目录 一、前言二、子容器默认组件FeignClientsConfigurationDecoder的注入Contract约定 对注解的支持对类上注解的支持对方法上注解的支持对参数上注解的支持MatrixVariablePathVariableRequestParamRequestHeaderSpringQueryMapRequestPartCookieValue FormattingConversi…

7-8 N皇后问题

目录 题目描述 输入格式: 输出格式: 输入样例: 输出样例: 解题思路&#xff1a; 详细代码&#xff08;dfs&#xff09;&#xff1a; 简单代码&#xff08;打表&#xff09;&#xff1a; 题目描述 在NN格的国际象棋盘上摆放N个皇后&#xff0c;使其不能互相攻击&#xff0c;即任…

现代网络负载均衡与代理导论

大家觉得有有参考意义和帮助记得及时关注和点赞&#xff01;&#xff01;&#xff01; Service mesh 是近两年网络、容器编排和微服务领域最火热的话题之一。Envoy 是目前 service mesh 数据平面的首选组件。Matt Klein 是 Envoy 的设计者和核心开发。 文章循序渐进&#xff0…

Kubernetes Gateway API-2-跨命名空间路由

1 跨命名空间路由 Gateway API 具有跨命名空间路由的核心支持。当多个用户或团队共享底层网络基础设施时,这很有用,但必须对控制和配置进行分段,以尽量减少访问和容错域。 Gateway 和 Route(HTTPRoute,TCPRoute,GRPCRoute) 可以部署到不同的命名空间中,路由可以跨命名空间…

Wend看源码-Java-集合学习(List)

摘要 本篇文章深入探讨了基于JDK 21版本的Java.util包中提供的多样化集合类型。在Java中集合共分类为三种数据结构&#xff1a;List、Set和Queue。本文将详细阐述这些数据类型的各自实现&#xff0c;并按照线程安全性进行分类&#xff0c;分别介绍非线程安全与线程安全的实现方…

集成方案 | Docusign + 蓝凌 EKP,打造一站式合同管理平台,实现无缝协作!

本文将详细介绍 Docusign 与蓝凌 EKP 的集成步骤及其效果&#xff0c;并通过实际应用场景来展示 Docusign 的强大集成能力&#xff0c;以证明 Docusign 集成功能的高效性和实用性。 在当今数字化办公环境中&#xff0c;企业对于提高工作效率和提升用户体验的需求日益迫切。蓝凌…

突围边缘:OpenAI开源实时嵌入式API,AI触角延伸至微观世界

当OpenAI宣布开源其名为openai-realtime-embedded-sdk的实时嵌入式API时&#xff0c;整个科技界都为之震惊。这一举动意味着&#xff0c;曾经遥不可及的强大AI能力&#xff0c;如今可以被嵌入到像ESP32这样的微型控制器中&#xff0c;真正地将AI的触角延伸到了物联网和边缘计算…

webrtc-internals调试工具

Google 的 Chrome&#xff08;87 或更高版本&#xff09;WebRTC 内部工具是一套内置于 Chrome 浏览器中的调试工具; webrtc-internals 能够查看有关视频和音频轨道、使用的编解码器以及流的一般质量的详细信息。这些知识对于解决音频和视频质量差的问题非常有帮助。 webrtc-int…

使用Webpack构建微前端应用

英文社区对 Webpack Module Federation 的响应非常热烈&#xff0c;甚至被誉为“A game-changer in JavaScript architecture”&#xff0c;相对而言国内对此热度并不高&#xff0c;这一方面是因为 MF 强依赖于 Webpack5&#xff0c;升级成本有点高&#xff1b;另一方面是国内已…

[bug]java导出csv用Microsoft Office Excel打开乱码解决

[bug]java导出csv用Microsoft Office Excel打开乱码 ‍ 现象 首先这个csv文件用macbook自带的 "Numbers表格" 软件打开是不乱码的, 但是使用者是Windows系统,他的电脑没有"Numbers表格"工具, ​​ 他用Microsoft Office Excel打开之后出现乱码,如下图…

关于分布式数据库需要了解的相关知识!!!

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///计算机爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于关于分布式数据库方面的相关内容&a…

tortoisegit推送失败

tortoisegit推送失败 git.exe push --progress -- "origin" testLidar:testLidar /usr/bin/bash: gitgithub.com: No such file or directory fatal: Could not read from remote repository. Please make sure you have the correct access rights and the reposit…

moviepy将图片序列制作成视频并加载字幕 - python 实现

DataBall 助力快速掌握数据集的信息和使用方式&#xff0c;会员享有 百种数据集&#xff0c;持续增加中。 需要更多数据资源和技术解决方案&#xff0c;知识星球&#xff1a; “DataBall - X 数据球(free)” -------------------------------------------------------------…

清空DNS 缓存

如果遇到修改了host文件&#xff0c;但是IP和域名的映射有问题的情况&#xff0c;可以尝试刷新DNS缓存。 ipconfig/flushdns win建加R建&#xff0c;然后输入cmd&#xff0c;然后回车 然后回车&#xff0c;或者点击确定按钮。 出现如下所示标识清空DNS 缓存成功。

2024最新鸿蒙开发面试题合集(二)-HarmonyOS NEXT Release(API 12 Release)

上一篇面试题链接&#xff1a;https://mp.csdn.net/mp_blog/creation/editor/144685078 1. 鸿蒙简单介绍和发展历程 HarmonyOS 是新一代的智能终端操作系统&#xff0c;为不同设备的智能化、互联与协同提供了统一的语言。带来简洁&#xff0c;流畅&#xff0c;连续&#xff0…

Yocto 项目 - 共享状态缓存 (Shared State Cache) 机制

引言 在嵌入式开发中&#xff0c;构建效率直接影响项目的开发进度和质量。Yocto 项目通过其核心工具 BitBake 提供了灵活而强大的构建能力。然而&#xff0c;OpenEmbedded 构建系统的传统设计是从头开始构建所有内容&#xff08;Build from Scratch&#xff09;&#xff0c;这…

idea 8年使用整理

文章目录 前言idea 8年使用整理1. 覆盖application配置2. 启动的时候设置编辑空间大小&#xff0c;并忽略最大空间3. 查询类的关系4. 查看这个方法的引用关系5. 查看方法的调用关系5.1. 查看被调用关系5.2. 查看调用关系 6. 方法分隔线7. 选择快捷键类型8. 代码预览插件9. JReb…

04软件测试需求分析案例-用户登录

通读文档&#xff0c;提取信息&#xff0c;提出问题&#xff0c;整理为需求。 从需求规格说明、设计说明、配置说明等文档获取原始需求&#xff0c;通读原始需求&#xff0c;分析有哪些功能&#xff0c;每种功能要完成什么业务&#xff0c;业务该如何实现&#xff0c;业务逻辑…

【MySQL】踩坑笔记——保存带有换行符等特殊字符的数据,需要进行转义保存

问题描述 从DBeaver中导出了部分业务数据的 insert sql&#xff0c;明明在开发、测试环境都可以一把执行通过&#xff0c;却在预发环境执行前的语法检查失败了&#xff0c;提示有SQL语法错误。 这条SQL长这样&#xff0c;default_sql是要在odps上执行的sql语句&#xff0c;提…

windos挂载目录到linux

验证环境麒麟V10 1: 在windows任意目录设置共享文件夹 2&#xff1a;记住网络路径\LAPTOP-86JV6NT1\gantie13_sdk 在linux中替换为本机ip级相对路径 比如本级ip是192.168.23.23&#xff0c;linux环境需要ping通本地地址 3&#xff1a; sudo apt-get install cifs-utils sud…