当前位置: 首页 > news >正文

日志Log程序(C++)

        本篇将使用 C/C++ 代码实现一个日志程序,便于我们在调试程序的时候,打印出对应的日志信息,同时也可以重定向然后记录我们的日志信息。

        日志:软件运行的记录信息,可以向显示器打印,也可以向文件中打印。

        本篇中设置出的日志特定格式:

        [日志等级][pid][filename][filenumber][time] 日志内容(支持可变参数)

        其中日志等级分为:DEBUG(调试信息)、INFO(正常信息)、WARNING(存在问题,但不影响正常运行)、ERROR(存在错误,但还是希望尽量不要退出程序)、FATAL(致命错误,直接退出)。

        实现的日志程序如下:

        Log.hpp:

#pragma once
#include <iostream>
#include <string>
#include <cstdarg>
#include <cstring>
#include <fstream>
#include <sys/types.h>
#include <pthread.h>
#include <unistd.h>namespace log_ns {enum { DEBUG = 1, INFO, WARNING, ERROR, FATAL };// 定义日子真正需要记录的信息struct LogMessage {std::string _level;int _id;std::string _filename;int _filenumber;std::string _curtime;std::string _log_message;};#define SCREEN_TYPE 1#define FILE_TYPE   2const std::string defaultlogfile = "./log.txt";pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER;class Log {private:std::string LevelToString(int level) {switch(level) {case DEBUG:return "DEBUG";case INFO:return "INFO";case WARNING:return "WARNING";case ERROR:return "ERROR";case FATAL:return "FATAL";default:return "UNKNOWN";}}std::string CurTime() {// 获取当前的时间戳time_t curtime = time(nullptr);// 将当前时间戳转换成结构体struct tm* now = localtime(&curtime);char buff[128];snprintf(buff, sizeof(buff), "%d-%02d-%02d %02d:%02d:%02d", now->tm_year + 1900,now->tm_mon + 1,now->tm_mday,now->tm_hour,now->tm_min,now->tm_sec);return buff;}void Flush(const LogMessage& lg) {// 打印日志的时候可能存在线程安全,使用锁lock住pthread_mutex_lock(&log_lock);switch(_type) {case SCREEN_TYPE:FlushToScreen(lg);break;case FILE_TYPE:FlushToFile(lg);break;}pthread_mutex_unlock(&log_lock);}void FlushToFile(const LogMessage& lg) {std::ofstream out;out.open(_logfile, std::ios::app); // 文件的操作使用追加if (!out.is_open()) return;char buff[2024];snprintf(buff ,sizeof(buff), "[%s][%d][%s][%d][%s] %s",lg._level.c_str(),lg._id,lg._filename.c_str(),lg._filenumber,lg._curtime.c_str(),lg._log_message.c_str());            out.write(buff, strlen(buff));out.close();}void FlushToScreen(const LogMessage& lg) {printf("[%s][%d][%s][%d][%s] %s",lg._level.c_str(),lg._id,lg._filename.c_str(),lg._filenumber,lg._curtime.c_str(),lg._log_message.c_str());}public:Log(std::string logfile = defaultlogfile): _type(SCREEN_TYPE),_logfile(logfile){}void Enable(int type) {_type = type;}void LoadMessage(std::string filename, int filenumber, int level, const char* format, ...) {LogMessage lg;lg._level = LevelToString(level);lg._filename = filename;lg._filenumber = filenumber;// 获取当前时间lg._curtime = CurTime();// std::cout << lg._curtime << std::endl;lg._id = getpid();// 获取可变参数va_list ap;va_start(ap, format);char buff[2048];vsnprintf(buff, sizeof(buff), format, ap);va_end(ap);lg._log_message = buff;// std::cout << lg._log_message;Flush(lg);}void ClearOurFile() {std::ofstream out;out.open(_logfile);out.close();}~Log() {}private:int _type;std::string _logfile;};Log lg;// LOG 宏
#define LOG(level, format, ...)                                           \do                                                                    \{                                                                     \lg.LoadMessage(__FILE__, __LINE__, level, format, ##__VA_ARGS__); \} while (0)#define EnableToScreen()        \do                          \{                           \lg.Enable(SCREEN_TYPE); \} while (0)#define EnableToFile()        \do                        \{                         \lg.Enable(FILE_TYPE); \} while (0)// 清理文件
#define ClearFile()        \do                     \{                      \lg.ClearOurFile(); \} while (0)
}

        实现如上代码之后,我们只需要将在需要进行日志打印出直接使用宏 LOG 就可以进行日志打印了(同时该 LOG 支持类似与 printf 函数的可变参数打印),同时宏 EnableToFile 和 EnableToScreen 可以选择是在屏幕上打印还是在文件中打印(文件打印可以指定文件位置,不指定则是默认的当前路径下的文件)。

        以后想要打印 debug 程序完全就可以使用 LOG 宏代替我们的打印语句,测试如下:

        可以自动的记录当前打印的 LOG 宏在哪个文件,哪一行,以及当前进程的 pid。

        将其放入到我们的线程池程序中进行测试,如下:

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 深度学习每周学习总结N6:使用Word2vec实现文本分类
  • Spring Cloud全解析:注册中心之zookeeper注册中心
  • 4.MySQL数据类型
  • 2023华为od机试C卷【围棋的气】python实现
  • 哈萨克语驾考学习软件求推荐?
  • Springboot项目基础开发模式+注解
  • 【香橙派系列教程】(十三) 香橙派的摄像头接入
  • 【Pyspark-驯化】一文搞懂Pyspark修改hive表描述以及增加列使用技巧
  • 简单的射箭小游戏网页源码
  • 表字段显示tip
  • 【数据结构题目】循环队列,以及队列实现栈的模拟
  • C语言 | Leetcode C语言题解之第332题重新安排行程
  • Android 下载安装配置
  • 探索Python模块搜索路径的奥秘
  • Python中的责任链模式:构建灵活的请求处理机制
  • 【402天】跃迁之路——程序员高效学习方法论探索系列(实验阶段159-2018.03.14)...
  • GDB 调试 Mysql 实战(三)优先队列排序算法中的行记录长度统计是怎么来的(上)...
  • Java多线程(4):使用线程池执行定时任务
  • Python学习之路13-记分
  • Swift 中的尾递归和蹦床
  • vue-cli3搭建项目
  • vue脚手架vue-cli
  • 电商搜索引擎的架构设计和性能优化
  • 分享一个自己写的基于canvas的原生js图片爆炸插件
  • 湖南卫视:中国白领因网络偷菜成当代最寂寞的人?
  • 缓存与缓冲
  • 面试遇到的一些题
  • 前端路由实现-history
  • 由插件封装引出的一丢丢思考
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • 阿里云IoT边缘计算助力企业零改造实现远程运维 ...
  • ​字​节​一​面​
  • # 利刃出鞘_Tomcat 核心原理解析(八)-- Tomcat 集群
  • #define与typedef区别
  • (pojstep1.1.1)poj 1298(直叙式模拟)
  • (PySpark)RDD实验实战——取最大数出现的次数
  • (二)WCF的Binding模型
  • (附源码)ssm经济信息门户网站 毕业设计 141634
  • (十七)devops持续集成开发——使用jenkins流水线pipeline方式发布一个微服务项目
  • (五)IO流之ByteArrayInput/OutputStream
  • (一)基于IDEA的JAVA基础1
  • (轉貼) 蒼井そら挑戰筋肉擂台 (Misc)
  • .gitignore文件_Git:.gitignore
  • .net core MVC 通过 Filters 过滤器拦截请求及响应内容
  • .NET Core 和 .NET Framework 中的 MEF2
  • .NET LINQ 通常分 Syntax Query 和Syntax Method
  • .NET NPOI导出Excel详解
  • .NET 表达式计算:Expression Evaluator
  • .NET 反射 Reflect
  • .net 中viewstate的原理和使用
  • .net访问oracle数据库性能问题
  • /etc/fstab和/etc/mtab的区别
  • [ vulhub漏洞复现篇 ] Django SQL注入漏洞复现 CVE-2021-35042
  • [AHK] WinHttpRequest.5.1报错 0x80092004 找不到对象或属性
  • [Angular] 笔记 21:@ViewChild