C++简易日志
文章目录
- main.cpp
- Log.h
- Log.cpp
- ClassAuxMacro.h
- Singleton.h
main.cpp
#include "Log.h"int main()
{LogInfo << "main start";int i = 1;double d = 3.14;LogInfo << "i = " << i << ", d = " << d;getchar();
}
Log.h
#pragma once
#include <sstream>
#include <string>
#include <chrono>
#include "Singleton.h"template <typename T, size_t N>
inline constexpr size_t GetFileNameOffset(const T(&str)[N], size_t i = N - 1)
{return (str[i] == '/' || str[i] == '\\' ? i + 1 : i > 0 ? GetFileNameOffset(str, i - 1) : 0);
}
template <typename T>
inline constexpr size_t GetFileNameOffset(const T(&str)[1])
{return 0;
}
#define SRC_FILE_NAME(FilePath) (&FilePath[GetFileNameOffset(FilePath)])enum class ELevel {_FATAL,_ERROR,_WARN,_INFO,_DEBUF,
};class LogStream {
public:LogStream();LogStream(const std::string& name);~LogStream();
public:std::ostringstream& Process(ELevel level, const char* fileName, int lineNum, const char* funcName);
private:std::ostringstream osstream_;std::string logName_;
};class Log {SINGLE_INSTANCE_CLASS(Log);DEF_MEMBER_VAR_DEFAULT_VALUE(ELevel, m_globalLogLevel, GlobalLogLevel, ELevel::_INFO);DEF_MEMBER_VAR_DEFAULT_VALUE(std::string, m_logDir, LogDir, "./");DEF_MEMBER_VAR_DEFAULT_VALUE(bool, m_stop, Stop, false);
public:void StartAsyncLog();
};
#define GLogInst Log::GetInstance()#define LogInfo if (GLogInst->GetGlobalLogLevel()>=ELevel::_INFO && !GLogInst->GetStop()) LogStream().Process(ELevel::_INFO, SRC_FILE_NAME(__FILE__), __LINE__, __func__)
#define LogWarn if (GLogInst->GetGlobalLogLevel()>=ELevel::_WARN && !GLogInst->GetStop()) LogStream().Process(ELevel::_WARN, SRC_FILE_NAME(__FILE__), __LINE__, __func__)
#define LogError if (GLogInst->GetGlobalLogLevel()>=ELevel::_ERROR && !GLogInst->GetStop()) LogStream().Process(ELevel::_ERROR, SRC_FILE_NAME(__FILE__), __LINE__, __func__)
#define LogFatal if (GLogInst->GetGlobalLogLevel()>=ELevel::_FATAL && !GLogInst->GetStop()) LogStream().Process(ELevel::_FATAL, SRC_FILE_NAME(__FILE__), __LINE__, __func__)
#define LogDebug if (GLogInst->GetGlobalLogLevel()>=ELevel::_DEBUF && !GLogInst->GetStop()) LogStream().Process(ELevel::_DEBUF, SRC_FILE_NAME(__FILE__), __LINE__, __func__)
#define LogInfoF(logPath) if (GLogInst->GetGlobalLogLevel()>=ELevel::_INFO && !GLogInst->GetStop()) LogStream(logPath).Process(ELevel::_INFO, SRC_FILE_NAME(__FILE__), __LINE__, __func__)
#define LogWarnF(logPath) if (GLogInst->GetGlobalLogLevel()>=ELevel::_WARN && !GLogInst->GetStop()) LogStream(logPath).Process(ELevel::_WARN, SRC_FILE_NAME(__FILE__), __LINE__, __func__)
#define LogErrorF(logPath) if (GLogInst->GetGlobalLogLevel()>=ELevel::_ERROR && !GLogInst->GetStop()) LogStream(logPath).Process(ELevel::_ERROR, SRC_FILE_NAME(__FILE__), __LINE__, __func__)
#define LogFatalF(logPath) if (GLogInst->GetGlobalLogLevel()>=ELevel::_FATAL && !GLogInst->GetStop()) LogStream(logPath).Process(ELevel::_FATAL, SRC_FILE_NAME(__FILE__), __LINE__, __func__)
#define LogDebugF(logPath) if (GLogInst->GetGlobalLogLevel()>=ELevel::_DEBUF && !GLogInst->GetStop()) LogStream(logPath).Process(ELevel::_DEBUF, SRC_FILE_NAME(__FILE__), __LINE__, __func__)struct BeginEndLog {BeginEndLog(const char* name) :name_(name) {LogInfo << "begin " << name_;}~BeginEndLog() {LogInfo << "end " << name_;}const char* name_;
};struct CostTimeLog {CostTimeLog(const char* name) :name_(name) {start_ = std::chrono::system_clock::now();}~CostTimeLog() {auto end = std::chrono::system_clock::now();double duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start_).count();LogInfo << "call " << name_ << " cost time " << duration << "ms";}decltype(std::chrono::system_clock::now()) start_;const char* name_;
};#define ENABLE_CALL_LOG 1
#define ENABLE_CALL_COST_TIME_LOG 1#if ENABLE_CALL_LOG
#define RECORD_FUNC_CALL_LOG BeginEndLog BeginEndLog___(__FUNCTION__)
#else
#define RECORD_FUNC_CALL_LOG
#endif#if ENABLE_CALL_COST_TIME_LOG
#define RECORD_FUNC_CALL_COST_TIME_LOG CostTimeLog CostTimeLog___(__FUNCTION__)
#else
#define RECORD_FUNC_CALL_COST_TIME_LOG
#endif
Log.cpp
#include "Log.h"
#include <fstream>
#include <iomanip>
#include "BlockingQueue.h"namespace {
std::mutex mtx;
void SaveLogToFile(std::string path, std::string content)
{std::unique_lock<std::mutex> lock(mtx);std::ofstream out(path, std::ios::app);if (out.rdstate() == std::ofstream::goodbit) {out << content << std::endl;out.close();}
}
const char* loglevelStr[] = { "Fatal", "Error", "Warn", "Info", "Debug" };
std::thread asyncThread;
std::unique_ptr<BlockingQueue<std::pair<std::string, std::string>>> blockingQueue;
std::function<void(std::string, std::string)> logProcess;void AsyncLogProcess(std::string path, std::string content)
{blockingQueue->Push({ path,content });
}
std::string GetFormatDateTime()
{std::stringstream ss;auto curTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());struct tm t;localtime_s(&t, &curTime);ss << std::put_time(&t, "%Y-%m-%d %H:%M:%S");auto tNow = std::chrono::system_clock::now();auto tMilli = std::chrono::duration_cast<std::chrono::milliseconds>(tNow.time_since_epoch());auto tSeconds = std::chrono::duration_cast<std::chrono::seconds>(tNow.time_since_epoch());auto ms = tMilli - tSeconds;ss << "." << std::setfill('0') << std::setw(3) << ms.count();return ss.str();
}
std::string GetTodayDate()
{auto curTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());struct tm t;localtime_s(&t, &curTime);std::ostringstream os;os << std::put_time(&t, "%Y-%m-%d") << ".log";return os.str();
}
}LogStream::LogStream() : logName_(GLogInst->GetLogDir() + GetTodayDate()){}
LogStream::LogStream(const std::string & name) : logName_(name){}
LogStream::~LogStream()
{if (!logProcess) {logProcess = SaveLogToFile;}logProcess(logName_, osstream_.str());
}
std::ostringstream& LogStream::Process(ELevel level, const char* fileName, int lineNum, const char* funcName)
{osstream_ << loglevelStr[static_cast<int>(level)] << ";"<< GetFormatDateTime() << ";"<< fileName << ";"<< std::setfill('0') << std::setw(4) << lineNum << ";"<< "tid:" << std::this_thread::get_id() << ";";return osstream_;
}void Log::StartAsyncLog()
{blockingQueue = std::make_unique<BlockingQueue<std::pair<std::string, std::string>>>();blockingQueue->SetMaxSize(INT_MAX);logProcess = AsyncLogProcess;std::thread t([this] {while (true) {std::pair<std::string, std::string> pair;bool res = blockingQueue->Pop(pair);if (res)SaveLogToFile(pair.first, pair.second);}});t.detach();
}
ClassAuxMacro.h
#pragma once#define DEF_MEMBER_VAR(type, name, opName)\
public:\type Get##opName() { return name; }\void Set##opName(const type& val) { name = val; }\
private:\type name#define DEF_MEMBER_VAR_DEFAULT_VALUE(type, name, opName, value)\
public:\type Get##opName() { return name; }\void Set##opName(const type& val) { name = val; }\
private:\type name = value#define DEF_MEMBER_VAR_READONLY(type, name, opName, value)\
public:\const type& Get##opName() { return name; }\
private:\const type name = value#define DEF_MEMBER_VAR_PTR(type, name, opName)\
public:\type* Get##opName() { return name; }\void Set##opName(type* val) { name = val; }\
private:\type* name#define DEF_MEMBER_VAR_LOW_LIMIT(type, name, opName, value)\
public:\type Get##opName() { return name; }\void Set##opName(const type& val) { \name = val;\if (name < value) {\name = value;\}\}\
private:\type name = value
Singleton.h
#pragma once#include "ClassAuxMacro.h"#define SINGLE_INSTANCE_CLASS(type)\
public:\static type* GetInstance() {\static type i;\return &i;\}\
private:\type() = default#define SINGLE_INSTANCE_CLASS_CUSTOM(type)\
public:\static type* GetInstance() {\static type i;\return &i;\}\
private:\type()
相关文章:
C++简易日志
文章目录 main.cppLog.hLog.cppClassAuxMacro.hSingleton.h main.cpp #include "Log.h"int main() {LogInfo << "main start";int i 1;double d 3.14;LogInfo << "i " << i << ", d " << d;getcha…...
kotlin音乐之自定义唱片组件(简单版本)
代码地址 import android.animation.ObjectAnimator import android.animation.ValueAnimator import android.content.Context import android.os.Binder import android.util.AttributeSet import android.view.animation.LinearInterpolator import androidx.appcompat.widg…...
Redis 版本变更的变化
Redis 版本变更的变化 以下是 Redis 主要版本的清单及其核心功能变化的梳理,按时间顺序整理关键版本演进 8版本没有整理: Redis 1.0 (2009) 初始版本:发布首个稳定版本,支持基本键值存储。 核心特性: 支持字符串&…...
flink扫盲-调整checkpoint的时间会影响原来的state数据吗
一、核心结论 原 State 数据仍可用 只要作业的 拓扑结构(DAG) 和 状态类型(StateDescriptor) 未发生变更,旧的 Checkpoint 依然有效。Checkpoint 间隔调整仅影响 新生成的 Checkpoint…...
文本纠错WPS插件:提升文档质量的利器
文本纠错WPS插件:提升文档质量的利器 引言 在数字化办公日益普及的今天,文档的质量直接影响到我们的工作效率和形象。一个错别字或标点错误,可能就会让我们的专业形象大打折扣。今天,我要向大家介绍一款强大的WPS插件——文本纠…...
多光谱相机与高光谱相机的区别
多光谱相机与高光谱相机均属于光谱成像设备,但两者在光谱分辨率、波段数量、数据维度及应用场景上存在显著差异。以下是详细的对比分析: 一、核心差异对比 二、工作原理差异 多光谱相机 波段选择:根据目标物特性预设特定…...
MVCC详细介绍及面试题
目录 1.什么是mvcc? 2.问题引入 3. MVCC实现原理? 3.1 隐藏字段 3.2 undo log 日志 3.2.1 undo log版本链 3.3 readview 3.3.1 当前读 编辑 3.3.2 快照读 3.3.3 ReadView中4个核心字段 3.3.4 版本数据链访问的规则(了解&#x…...
电商企业如何实现流程精细化?日事清「标准化+可视化+自动化」全流程管理实战解析
电商企业在业务快速发展中,往往会遇到如下问题: 1、店铺多款产品需要上新维护,但工作重点往往不清晰,员工经常忘记,没做也不当回事; 2、员工做事经常错漏细节,犯低级错误; 3、人员…...
威锋VL822-Q7T10GHUB芯片适用于扩展坞显示器
一、概述 VL822-Q7T是VIA Lab(威盛电子旗下专注于USB相关技术研发的子公司)精心打造的一款高性能USB 3.1 Gen2集线器控制器芯片。在当今数字化时代,USB接口作为设备连接与数据传输的核心通道,其性能与稳定性至关重要。VL822-Q7T凭…...
交换机与路由器的默契配合:它们的联系与区别
交换机与路由器的默契配合:它们的联系与区别 一. 交换机与路由器的基本功能1.1 交换机的功能1.2 路由器的功能 二. 交换机和路由器的区别三. 交换机和路由器的联系3.1 数据转发的协作3.2 网络分段与分隔3.3 协同工作提供互联网接入 四. 交换机和路由器的联合应用场景…...
Git提交规范及最佳实践
Git 提交规范通常是为了提高代码提交的可读性、可维护性和自动化效率(如生成 ChangeLog)。以下是常见的 Conventional Commits 规范,结合社区最佳实践总结而成: 1. 提交格式 每次提交的 commit message 应包含三部分:…...
Ubuntu 常用命令行指令
1. 文件与目录操作 命令作用示例ls列出目录内容ls -l(详细列表)cd切换目录cd ~/Documentspwd显示当前目录路径pwdmkdir创建目录mkdir new_folderrm删除文件rm file.txtrm -r递归删除目录rm -r old_dircp复制文件cp file.txt backup/mv移动/重命名文件mv…...
Redis 分布式锁+秒杀异步优化
文章目录 问题思路setnx实现锁误删问题和解决方案Redis Lua脚本问题引出解决方案 setnx实现的问题Redission快速入门redission可重入锁原理 秒杀优化(异步优化)异步秒杀思路秒杀资格判断Redis消息队列 问题 比如我们两个机器都部署了我们项目,这里nginx使用轮询的方…...
Git_获取GitLab的token方法(访问令牌)
一、操作步骤 GitLab-获取token(访问令牌)主要步骤:以及相关截图 登录 GitLab 打开 GitLab 网站并登录你的账号。 进入用户设置 点击右上角头像 → Edit profile → 左侧菜单选择 Access Tokens。 创建 Token Token name: 输入名称&#…...
【生活相关-日语-日本-东京-留学生-搬家后或新入驻-水道局申请饮用水(1)-办理手续】
【生活相关-日语-日本-东京-搬家后-水道局申请饮用水-办理手续】 1、前言2、情况说明(1)他人代办(2)打电话(3)网络申请(4)你将会面临什么,主要步骤(5…...
【C语言】--- 预处理详解
预处理详解 1. 预定义符号2. define定义常量2. define 定义宏4. 带有副作用的宏参数5.宏替换的规则6. 宏和函数的对比7. # 和 \##7.1#运算符 7.2 \##运算符8. 命名约定9.#undef10.命令行定义11.条件编译12. 头文件的包含12.1 头文件被包含的方式12.1.1 头文件的本地包含12.1.2 …...
【Axure视频教程】标准金额格式转换
今天教大家在Axure制作标准金额格式转换的原型模板,具体效果可以参考下方视频,该教程从0开始制作,手把手教学,无论是新手小白还是有一定基础的同学,都可以学习的哦。 【视频教程——试看版】 【Axure教程】标准金额格…...
每日算法(双指针算法)(Day 1)
双指针算法 1.算法题目(移动零)2.讲解算法原理3.编写代码 1.算法题目(移动零) 2.讲解算法原理 数组划分,数组分块(快排里面最核心的一步)只需把0改为tmp 双指针算法:利用数组下标来…...
微服务多模块构建feign项目过程与一些报错(2025详细版)
目录 1.eureka-server的注意事项 2.eureka-feign的注意事项 3.多模块构建feign项目过程 3.1创建父项目 3.2创建子项目eureka-server 3.3创建子项目eureka-provider 3.4创建子项目eureka-feign 3.5运行 给个点赞谢谢 1.eureka-server的注意事项 eureka-server的yml文件…...
性能测试-tomcat连接数
Tomcat 处理请求时,是需要 Connector 进行调度和控制的,Connector是Tomcat 处理请求的主干。 Connector 中有一个 accepf队列,当客户端向服务器发送http请求时,如果客户端与操作系统完成三次握手建立了连接,就将该连接放入accept队列,poller从队列中获取到链接后,从链接…...
【Django】框架-路由系统核心概念解析
1. 最基本路由关系 路由是URL地址与处理逻辑(视图函数)的对应关系。 本质:将用户请求的URL路径映射到具体的处理程序(如Django视图函数)。 示例: # urls.py urlpatterns [ path(home/, views.home_…...
C# 运行web项目
1、web项目直接点击顶部运行...
C++ 创龙UDP通讯demo
C 创龙UDP通讯demo #include <iostream> #include <vector> #include <string>static uint8_t checksum(uint8_t *buff,int size) {uint8_t ldr 0;for(int i 0;i<size;i){ldr ^ buff[i];}return ldr; }bool decode(uint8_t *inbuff,int inbuffsize,uin…...
深入讲解 CSS 选择器权重及实战
1. 权重计算规则详解 CSS 选择器的优先级由 三元组 (x, y, z) 决定,比较规则如下: 选择器类型权重值 (x, y, z)示例ID 选择器x 1#header → (1,0,0)类/伪类/属性y 1.active, :hover元素/伪元素z 1div, ::before 比较规则:从左到右逐级比…...
全网通emotn ui桌面免费吗?如何开机自启动
在智能设备的使用中,一款优秀的桌面系统能带来截然不同的体验。全网通Emotn UI桌面便是其中的佼佼者,它以完全免费的特性与卓越性能,成为众多用户的心头好。 其简洁美观的界面设计如同为设备换上"清新外衣",常用功能一…...
【AI模型学习】MAE——CV界的无监督预训练
文章目录 一、诞生背景1.1 自监督学习的趋势2.2 ViT 的出现 二、模型2.1 模型架构2.1.1 数据shape变化2.1.2 模型架构流程图2.1.3 PyTorch 代码示例(核心部分) 2.2 位置信息2.3 非对称的编码器-解码器结构2.4图片重构 三、实验3.1 主实验3.2 消融实验3.3…...
远方游子的归家记:模仿美食网页的制作与实现
前言 2023年的夏天,闲得无聊学了一个礼拜前端知识点。并根据所学知识点模仿制作了一篇网络上公开发布的关于家乡美食的文章。今天才想到有这个不错的案例可以分享出来,以供大家学习参考。 知识点简介 运用的知识点比较简单,常规的div盒子&…...
【消息队列kafka_中间件】三、Kafka 打造极致高效的消息处理系统
在当今数字化时代,数据量呈爆炸式增长,实时数据处理的需求变得愈发迫切。Kafka 作为一款高性能、分布式的消息队列系统,在众多企业级应用中得到了广泛应用。然而,要充分发挥 Kafka 的潜力,实现极致高效的消息处理&…...
element-ui colorPicker 组件源码分享
简单分享 colorPicker 颜色选择器组件源码,主要从以下三个方面: 1、colorPicker 组件页面结构。 2、colorPicker 组件属性。 3、colorPicker 组件事件。 一、组件页面结构。 二、组件属性。 2.1 value/v-model 绑定值属性,类型为 string…...
Git 学习笔记
这篇笔记记录了我在git学习中常常用到的指令,方便在未来进行查阅。此篇文章也会根据笔者的学习进度持续更新。 网站分享 Git 常用命令大全 Learn Git Branching 基础 $ git init //在当前位置配置一个git版本库 $ git add <file> //将文件添加至…...
