项目中需要快速写入巨量日志,一开始用的是boost::log,但遇到崩溃问题,程序负载大了,滚动日志时偶尔会崩溃,总是报:
boost::filesystem_errorbad_year, bad_month 一些问题。在boost官网,和github上的 boostlog 项目 issue中窥见些端倪,说是boost::filesystem存在问题blabla
枉我还一直很信任 boost ,还是换个日志库吧。

github 上 spdlog 星星比 boost::log 多多了,boost::log 好像用的人挺少。

这一换发现:相比boost::log,spdlog 速度又快,占内存又小(取决于队列长度)

使用 spdlog1.10.0 封装的 dll

  • 使用这个dll,你的项目不用再依赖 spdlog 头文件
  • C 风格的字符串格式化语法
  • 同步/异步、滚动日志
  • 程序退出前需要调用静态方法 shutdown()
  • VS2019 编译通过
// log_spd.h
#pragma once
#include <string>
#ifndef LOG_LIB_H
#define LOG_LIB_H#ifdef _MSC_VER
#define LOG_API _declspec(dllexport)
#else
#define LOG_API
#endifclass SpdlogWrapper;enum class lv {trace,debug,info,warn,error,fatal
};class LOG_API Logger
{public:Logger();Logger(const std::string& file, lv level=lv::trace, int rotateFileSize=100 /* MB */, int rotateFileCount=5);Logger(const Logger&);Logger& operator=(const Logger&);~Logger();// 返回一个日志对象static Logger createLogger(const std::string& filename, lv level=lv::trace, int rotateFileSize=100 /* MB */, int rotateFileCount=5);// 全局设置。定时写日志到文件。0 秒则不启用static void setFlushEverySec(int sec);// 设置日志文件void setFileName(const std::string&);// 设置日志前缀格式;default: [%Y-%m-%d %H:%M:%S.%e][%t][%l] %vvoid setFormat(const std::string&);// 设置日志等级,大于此等级才写入文件void setLevel(lv);// 设置滚动日志文件void setRotateFile(int size /* MB */, int count);// 设置立即写到文件的日志等级void setFlushOnLevel(lv);// 是否异步日志,default: truevoid setAsyncMode(bool);// 设置异步日志队列长度。默认 256。经测试,队列更长,占用内存更大,未见性能明显提升void setAsyncQueueSize(int);// 在调用 setXX 类函数之后,最后调用 init(); 赋值操作后,被赋值的对象需要重新 init()void init();void init(const std::string& file, lv level=lv::trace, int rotateFileSize=100 /* MB */, int rotateFileCount=5);// 格式化后的字符串最大长度: 1024void trace(const char* fmt, ...);void info(const char* fmt, ...);void debug(const char* fmt, ...);void warn(const char* fmt, ...);void error(const char* fmt, ...);void fatal(const char* fmt, ...);// 异步模式:通知缓冲, 要求写入日志文件;// 同步模式:立即写入日志文件void flush();// EXE 主程序退出前需要调用。因为 spdlog 在 windows 上存在问题关不掉程序// 如果是在 dll 中使用此日志库,你的 dll 需要提供接口来让 EXE 程序在退出前主动调用到此函数static void shutdown();private:SpdlogWrapper* m_logWrapper;
};#endif // LOG_LIB_H
// log_spd.cpp
#pragma once
#include "log_spd.h"
#include "log_wrapper.h"Logger::Logger() : m_logWrapper(nullptr)
{m_logWrapper = new SpdlogWrapper(DEFAULT_FILE, lv::trace, 100, 5);
}Logger::Logger(const std::string& file,lv level,int rotateFileSize, // MBint rotateFileCount) : m_logWrapper(nullptr)
{m_logWrapper = new SpdlogWrapper(file, level, rotateFileSize, rotateFileCount);
}Logger::Logger(const Logger& logger)
{m_logWrapper = new SpdlogWrapper(*logger.m_logWrapper);
}Logger& Logger::operator=(const Logger& logger)
{delete m_logWrapper;m_logWrapper = new SpdlogWrapper(*logger.m_logWrapper);return *this;
}Logger::~Logger()
{delete m_logWrapper;
}void Logger::init()
{m_logWrapper->init();
}void Logger::init(const std::string& file, lv level, int rotateFileSize, int rotateFileCount)
{m_logWrapper->m_fileName = file;m_logWrapper->m_logLevel = level;m_logWrapper->m_fileSize = rotateFileSize;m_logWrapper->m_fileCount = rotateFileCount;m_logWrapper->init();
}Logger Logger::createLogger(const std::string& filename, lv level, int rotateFileSize, int rotateFileCount)
{return Logger(filename, level, rotateFileSize, rotateFileCount);
}
void Logger::setAsyncMode(bool enabled)
{m_logWrapper->m_async = enabled;
}void Logger::flush()
{m_logWrapper->flush();
}void Logger::setFileName(const std::string& file)
{m_logWrapper->m_fileName = file;
}void Logger::setFormat(const std::string& fmt)
{m_logWrapper->m_fmt = fmt;
}void Logger::setLevel(lv level)
{m_logWrapper->m_logLevel = level;
}void Logger::setFlushOnLevel(lv level)
{m_logWrapper->m_flushOnLevel = (int)level;
}void Logger::setFlushEverySec(int sec)
{SpdlogWrapper::FlushEverySec = sec;
}void Logger::setAsyncQueueSize(int size)
{m_logWrapper->m_queueSize = size;
}void Logger::setRotateFile(int rotateFileSize, int rotateFileCount)
{m_logWrapper->m_fileSize = rotateFileSize;m_logWrapper->m_fileCount = rotateFileCount;
}void Logger::shutdown()
{SpdlogWrapper::shutdown();
}void Logger::trace(const char* fmt, ...)
{if (m_logWrapper->m_logLevel > lv::trace)return;char buff[BUFF_SIZE];va_list ap;va_start(ap, fmt);vsnprintf_s(buff, BUFF_SIZE, fmt, ap);va_end(ap);m_logWrapper->write(buff, lv::trace);
}void Logger::info(const char* fmt, ...)
{if (m_logWrapper->m_logLevel > lv::info)return;char buff[BUFF_SIZE];va_list ap;va_start(ap, fmt);vsnprintf_s(buff, BUFF_SIZE, fmt, ap);va_end(ap);m_logWrapper->write(buff, lv::info);
}void Logger::debug(const char* fmt, ...)
{if (m_logWrapper->m_logLevel > lv::debug)return;char buff[BUFF_SIZE];va_list ap;va_start(ap, fmt);vsnprintf_s(buff, BUFF_SIZE, fmt, ap);va_end(ap);m_logWrapper->write(buff, lv::debug);
}void Logger::warn(const char* fmt, ...)
{if (m_logWrapper->m_logLevel > lv::warn)return;char buff[BUFF_SIZE];va_list ap;va_start(ap, fmt);vsnprintf_s(buff, BUFF_SIZE, fmt, ap);va_end(ap);m_logWrapper->write(buff, lv::warn);
}void Logger::error(const char* fmt, ...)
{if (m_logWrapper->m_logLevel > lv::error)return;char buff[BUFF_SIZE];va_list ap;va_start(ap, fmt);vsnprintf_s(buff, BUFF_SIZE, fmt, ap);va_end(ap);m_logWrapper->write(buff, lv::error);
}void Logger::fatal(const char* fmt, ...)
{if (m_logWrapper->m_logLevel > lv::fatal)return;char buff[BUFF_SIZE];va_list ap;va_start(ap, fmt);vsnprintf_s(buff, BUFF_SIZE, fmt, ap);va_end(ap);m_logWrapper->write(buff, lv::fatal);
}
// log_wrapper.h
#pragma once
#ifndef LOG_API_H
#define LOG_API_H
#include <string>
#include "spdlog/spdlog.h"
#include "spdlog/async.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/details/thread_pool.h"static const int BUFF_SIZE = 1024;
const std::string DEFAULT_FILE = "log.log";
const std::string DEFAULT_FMT = "[%Y-%m-%d %H:%M:%S.%e][%t][%l] %v";class SpdlogWrapper
{public:SpdlogWrapper(const std::string& file, lv level, int rotateFileSize, int rotateFileCount);SpdlogWrapper(const SpdlogWrapper&);~SpdlogWrapper();void init();void write(const char* msg, lv level);void flush();static void shutdown();static int FlushEverySec;static int Id;static bool GlobalAttr;bool m_async;int m_queueSize;lv m_logLevel;int m_flushOnLevel;int m_fileCount;int m_fileSize;std::string m_fileName;std::string m_fmt;private:std::string m_logName;std::shared_ptr<spdlog::logger> m_spdLogger;std::shared_ptr<spdlog::details::thread_pool> m_tp;std::shared_ptr<spdlog::sinks::rotating_file_sink_mt> m_sink;void initGlobalAttr();
};
#endif //LOG_API_H
// log_wrapper.cpp
#pragma once
#include "log_spd.h"
#include "log_wrapper.h"int SpdlogWrapper::Id = 0;
int SpdlogWrapper::FlushEverySec = 3;
bool SpdlogWrapper::GlobalAttr = false;
SpdlogWrapper::SpdlogWrapper(const std::string& file, lv level, int rotateFileSize, int rotateFileCount): m_fileCount(rotateFileCount), m_fileSize(rotateFileSize), m_logLevel(level), m_fileName(file), m_flushOnLevel(-1),m_fmt(DEFAULT_FMT), m_logName(""), m_queueSize(256),m_async(true)
{}SpdlogWrapper::SpdlogWrapper(const SpdlogWrapper& log)
{m_fileCount = log.m_fileCount;m_fileSize = log.m_fileSize;m_logLevel = log.m_logLevel;m_fileName = log.m_fileName;m_flushOnLevel = log.m_flushOnLevel;m_fmt = log.m_fmt;m_logName = "";m_queueSize = log.m_queueSize;m_async = log.m_async;m_spdLogger = nullptr;m_tp = nullptr;m_sink = nullptr;
}void SpdlogWrapper::init()
{if (m_spdLogger)spdlog::drop(m_logName);initGlobalAttr();m_logName = "__log__" + std::to_string(SpdlogWrapper::Id++);if (m_async) {m_tp = std::make_shared<spdlog::details::thread_pool>(m_queueSize, 1U);m_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(m_fileName, m_fileSize * 1024 * 1024, m_fileCount);m_spdLogger = std::make_shared<spdlog::async_logger>(m_logName, m_sink, m_tp, spdlog::async_overflow_policy::block);spdlog::register_logger(m_spdLogger);}else m_spdLogger = spdlog::rotating_logger_mt(m_logName, m_fileName, (size_t)m_fileSize * 1024 * 1024, m_fileCount);m_spdLogger->set_pattern(m_fmt);m_spdLogger->set_level((spdlog::level::level_enum)m_logLevel);if (m_flushOnLevel >= 0)m_spdLogger->flush_on((spdlog::level::level_enum)m_flushOnLevel);
}void SpdlogWrapper::initGlobalAttr()
{if (!SpdlogWrapper::GlobalAttr) {spdlog::flush_every(std::chrono::seconds(SpdlogWrapper::FlushEverySec));SpdlogWrapper::GlobalAttr = true;}
}void SpdlogWrapper::write(const char* msg, lv level)
{SPDLOG_LOGGER_CALL(m_spdLogger, (spdlog::level::level_enum)level, msg);
}void SpdlogWrapper::flush()
{if (m_spdLogger)m_spdLogger->flush();
}void SpdlogWrapper::shutdown()
{spdlog::drop_all();spdlog::shutdown();
}SpdlogWrapper::~SpdlogWrapper()
{if (m_spdLogger)spdlog::drop(m_logName);
}

使用

// main.cpp#include "log_spd.h"int main(int argc, char  *argv[])
{Logger logger, logger2;// Logger logger = Logger::createLogger("mylog.log", lv::trace, 100, 5);logger.setAsyncMode(false); logger.init();logger.trace("Hello %s, you are the %dth visitor.", "Tony", 1);logger.flush();logger2 = logger;logger2.setAsyncMode(true);logger2.setFormat("%+");logger2.init("mylog.log");logger2.info("blasa bad w");logger2.flush();Logger::shutdown();return 0;
}

log.log

[2022-09-30 14:32:25.065][9532][trace] Hello Tony, you are the 1th visitor.

mylog.log

[2022-09-30 14:32:25.069] [__log__1] [info] [log_wrapper.cpp:75] blasa bad woa

缺点

  • 输出日志所在的代码文件、行号不是调用封装接口的行。比如上面的 [log_wrapper.cpp:75]

编译好的库

spdlog 封装为 DLL相关推荐

  1. 【转】将QT开发的界面程序封装成DLL,在VC中成功调用

    最近手头的一个项目需要做一个QT界面,并且封装成DLL,然后再动态调用DLL给出的接口函数,使封装在DLL内部的QT界面跑起来,在网上查了很多资料,今天终于成功了,经验不敢独享,因为CSDN给了我很多 ...

  2. 将MFC Grid Control封装为DLL的做法及其在DLL中的使用方法

    将MFC Grid Control封装为DLL的做法及其在DLL中的使用方法 MFCGrid control是一款非常优秀的网格控件,支持非常丰富的界面元素,如下图: 因而在数据库程序及报表程序应用较 ...

  3. wasm转c调用与封装至dll案例

    wasm转c调用与封装至dll案例 准备工作 初级 猿人学练习题 中级 崔大网习题 高级 某视频网站 准备工作 相关文档: 1.某德地图矢量瓦片逆向(快速wasm逆向),执行wasm2c翻译出来的c代 ...

  4. Matlab函数封装为DLL供Cpp调用

    Matlab函数封装为DLL供Cpp调用 文章目录 Matlab函数封装为DLL供Cpp调用 Ⅰ目标 Ⅱ 学习 Ⅲ 实现 1. Matlab 函数封装为DLL 2. vs2015中C++调用Matla ...

  5. VisionPro——在脚本中调用自己封装的DLL

    VisionPro--在脚本中调用自己封装的DLL 前言 一.具体配置与代码 前言 做硬件测试时,用到了vp的c#脚本,由于偷懒导出数据表想直接用以前封装好的函数库,在测试时遇到些问题,在此做些记录. ...

  6. 把WinMain封装到dll里

    把WinMain封装到dll里 例子如下: 1.dll项目文件testDll.cpp,代码: #include "stdafx.h" int WINAPI WinMain(HINS ...

  7. 【C++】QT调用VS封装的dll(以科大讯飞离线命令词识别SDK为例)

    QT调用VS封装的dll(以科大讯飞离线命令词识别SDK为例) 1.说明: 跨平台调用dll出现各种坑,谨以此文避坑. 参考博文:https://www.cnblogs.com/seer/p/4789 ...

  8. 把你的unity 工程中的cs文件封装成 dll

    文章目录 1.打开Visual Studio 新建一个类库(.NET Framework) 项目 2.unity的dll引用:UnityEngine.dll 和 UnityEditor.dll 3.. ...

  9. VS如何将核心函数封装成dll、lib,并供给第三方调用?

    本文首发于微信公众号[3D视觉工坊],作者原创. 文章目录 前言 一 先封装核心函数,实现功能 二 将核心函数生成dll.lib(此处以debug模式下为例,release模式下相类似) 三 调用dl ...

最新文章

  1. 和远程ip_漏洞Microsoft Windows TCP/IP 远程执行代码漏洞威胁通告
  2. linux怎样服务,如何在linux添加服务
  3. diy计算机组装注意事项,自己组装电脑要注意什么?DIY老司机教你装机注意事项...
  4. Bailian2915 字符串排序【排序】
  5. 基于JAVA个人饮食营养管理信息系统计算机毕业设计源码+系统+mysql数据库+lw文档+部署
  6. PCS7专用台式计算机,PCS7.V7.0.深入浅出.pdf
  7. VMWARE 之 分布式网络交换机
  8. stm32+ESP8266实现最简单的手机控制LED灯
  9. java upperbound_scala类型系统:11) upper bounds lower bounds
  10. idou老师教你学Istio 16:如何用 Istio 实现微服务间的访问控制
  11. Android OTA升级后更新APN参数的实现
  12. 照片放大工具Topaz Gigapixel AI for Mac
  13. Skiplist跳表详解及其模拟实现
  14. 阿里云国际站:阿里云架构变革背后:刺破宁静 激活新增长
  15. C语言 系统调用操作内核信号集
  16. SQL 语句的类型和 用法
  17. Win10笔记本电脑突然不能自动关闭屏幕的可能原因之一
  18. layui 数据表格的搜索分页功能的实现
  19. C4996 ‘strlwr’:The POSIX name for this item is deprecated.Instead,use the ISO C and C++ comformant
  20. 第4章 数据可视化答案

热门文章

  1. 文件上传 华为云服务器,文件上传云服务器
  2. 关于个人开发者上线Android-App步骤浅谈
  3. http状态码304缓存机制(强缓存和协商缓存-304)
  4. Java包装类(封装类)详解
  5. 基于光流场的运动分析
  6. Medical Image Analyse
  7. Linux常用命令08 - curl
  8. RFID软件:简介、功能和应用范围
  9. 指纹锁的安全性及其未来发展
  10. 独立院校中计算机专业,计算机专业最热门的“实力派”十大院校