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

Linux 之 【日志】(实现一个打印日志的类)

目录

1.日志的简介

1.1日志的概念

1.2日志的常见格式

2.实现日志类

包含所需头文件,定义所需宏

类成员

levelToString

operator()

printLog

printOneFile&printClassFile

完整呈现


1.日志的简介

1.1日志的概念

日志是软件运行过程中产生的带时间戳的、结构化的诊断记录,是调试的重要助手

1.2日志的常见格式

一条日志信息常包括默认部分与自定义部分

默认部分常包括:日志等级与日志时间

自定义部分则包括用户自定义的日志消息

常见的日志等级为:

(1)Info:常规消息(2)Warning:报警信息(3)Error:比较严重了,可能需要立即出来(4)Fatal:致命的(5)Debug:调试

2.实现日志类

使用下述类时,注意确保./log/目录存在

  • 包含所需头文件,定义所需宏

#pragma once #include <fcntl.h> #include <iostream> #include <stdarg.h> #include <string> #include <sys/stat.h> #include <sys/types.h> #include <time.h> #include <unistd.h> #define SIZE 1024 #define Info 0 #define Debug 1 #define Warning 2 #define Error 3 #define Fatal 4 #define Screen 1 #define Onefile 2 #define Classfile 3 #define LOGFILE "log.txt"
  • 类成员

class Log { public: //构造函数:初始化打印方法与路径 Log() : printMethod(Screen) , path("./log/"){ } //用户自定义打印方法 void Enable(int method) { printMethod = method; } //将日志等级转化为字符串 std::string levelToString(int level) { } //运算符重载以记录日志消息 void operator()(int level, const char *format, ...) { } //打印函数 void printLog(int level, const std::string &logtxt) { } //向一个文件打印日志消息 void printOneFile(const std::string &logname, const std::string &logtxt) { } //分类打印日志消息 void printClassFile(int level, const std::string &logtxt) { } //无实际意义,让类看着更完整 ~Log() { } private: int printMethod;//打印方法:显示器;一个文件;多个文件 std::string path;//日志文件存放的路径 };
  • levelToString

std::string levelToString(int level) { switch (level) { case Info: return "Info"; case Debug: return "Debug"; case Warning: return "Warning"; case Error: return "Error"; case Fatal: return "Fatal"; default: return "NONE"; } }

根据宏定义直接转化

  • operator()

void operator()(int level, const char *format, ...) { // 默认部分:【日志等级】【年-月-日 时:分:秒】 time_t t = time(nullptr); struct tm *ctime = localtime(&t); char leftbuffer[SIZE]; snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(), ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday, ctime->tm_hour, ctime->tm_min, ctime->tm_sec); // 自定义部分 va_list s; va_start(s, format); char rightbuffer[SIZE]; vsnprintf(rightbuffer, sizeof(rightbuffer), format, s); va_end(s); // 整合 char logtxt[SIZE * 2 + 1]; snprintf(logtxt, sizeof(logtxt), "%s %s\n", leftbuffer, rightbuffer); // 存储或者打印 printLog(level, logtxt); }

(1)重载 operator(),使得写日志像函数调用一样自然

Log log; log(Info, "Server started on port %d", 8080); // 输出:[Info][2024-...] Server started on port 8080

(2)默认部分包含日志等级和日志时间:将时间戳改造为年月日时分秒的格式。指的注意的是年是从1900开始的,月的范围是0-11,打印时需注意

(3)对于自定义部分日志信息,需要处理可变参数:

void Log(int level, const char *format, ...) // 1. 函数声明接受可变参数 { // 2. 定义遍历指针 va_list args_ptr; // char* 指针,用于逐个“指向”内存中的可变参数 // 3. 初始化指针,定位到第一个可变参数 va_start(args_ptr, format); // 关键:编译器知道‘format’是最后一个固定参数, // 通过它的地址计算出第一个可变参数在内存中的位置, // 让 args_ptr 指向那里。 // 4. 使用指针进行格式化 char buffer[256]; vsnprintf(buffer, sizeof(buffer), format, args_ptr); // vsnprintf 内部会: // a) 解析 format 字符串中的占位符(如 %d, %s) // b) 根据占位符类型,从 args_ptr 指向的内存位置“取出”相应大小的数据 // c) 每取一个参数,自动将 args_ptr 向内存高位移动相应距离,指向下一个参数 // d) 循环直到所有占位符处理完毕 // 5. 清理指针(防止野指针) va_end(args_ptr); // 通常将 args_ptr 置为 NULL }

(4)将默认部分与自定义部分整合后调用日志打印函数

  • printLog

void printLog(int level, const std::string &logtxt) { switch (printMethod) { case Screen: std::cout << logtxt << std::endl; break; case Onefile: printOneFile(LOGFILE, logtxt); break; case Classfile: printClassFile(level, logtxt); break; default: break; } }

日志打印函数通过打印方法,调用对应打印方法的函数

  • printOneFile&printClassFile

void printOneFile(const std::string &logname, const std::string &logtxt) { std::string filename = path + logname; int fd = open(filename.c_str(), O_CREAT | O_WRONLY | O_APPEND, 0666); // log.txt if (fd < 0) return; write(fd, logtxt.c_str(), logtxt.size()); close(fd); } void printClassFile(int level, const std::string &logtxt) { std::string filename = LOGFILE; filename += "."; filename += levelToString(level); // log.txt./Info/Debug....... printOneFile(filename, logtxt); }

(1)向一个文件打印所有日志信息时,首先为默认文件名添加路径(让日志信息处于新建目录中),然后调用系统调用open打开文件并写入

(2)分类打印日志消息,只需要为每种日志定义好文件名,然后复用向一个文件打印日志信息的代码就可

  • 完整呈现

使用下述类时,注意确保./log/目录存在

#pragma once #include <fcntl.h> #include <iostream> #include <stdarg.h> #include <string> #include <sys/stat.h> #include <sys/types.h> #include <time.h> #include <unistd.h> #define SIZE 1024 #define Info 0 #define Debug 1 #define Warning 2 #define Error 3 #define Fatal 4 #define Screen 1 #define Onefile 2 #define Classfile 3 #define LOGFILE "log.txt" class Log { public: Log() : printMethod(Screen) , path("./log/"){ } void Enable(int method) { printMethod = method; } std::string levelToString(int level) { switch (level) { case Info: return "Info"; case Debug: return "Debug"; case Warning: return "Warning"; case Error: return "Error"; case Fatal: return "Fatal"; default: return "NONE"; } } void operator()(int level, const char *format, ...) { // 默认部分:【日志等级】【年-月-日 时:分:秒】 time_t t = time(nullptr); struct tm *ctime = localtime(&t); char leftbuffer[SIZE]; snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(), ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday, ctime->tm_hour, ctime->tm_min, ctime->tm_sec); // 自定义部分 va_list s; va_start(s, format); char rightbuffer[SIZE]; vsnprintf(rightbuffer, sizeof(rightbuffer), format, s); va_end(s); // 整合 char logtxt[SIZE * 2 + 1]; snprintf(logtxt, sizeof(logtxt), "%s %s\n", leftbuffer, rightbuffer); // 存储或者打印 printLog(level, logtxt); } void printLog(int level, const std::string &logtxt) { switch (printMethod) { case Screen: std::cout << logtxt << std::endl; break; case Onefile: printOneFile(LOGFILE, logtxt); break; case Classfile: printClassFile(level, logtxt); break; default: break; } } void printOneFile(const std::string &logname, const std::string &logtxt) { std::string filename = path + logname; int fd = open(filename.c_str(), O_CREAT | O_WRONLY | O_APPEND, 0666); // log.txt if (fd < 0) return; write(fd, logtxt.c_str(), logtxt.size()); close(fd); } void printClassFile(int level, const std::string &logtxt) { std::string filename = LOGFILE; filename += "."; filename += levelToString(level); // log.txt./Info/Debug....... printOneFile(filename, logtxt); } ~Log() { } private: int printMethod; std::string path; };
http://www.jsqmd.com/news/294318/

相关文章:

  • 2026英语雅思考试培训辅导机构排行榜+核心解析 家长择校实用指南 精准匹配孩子雅思备考全阶段需求
  • Mermaid简记
  • 学长亲荐10个AI论文软件,助你搞定研究生毕业论文!
  • 计算机Java毕设实战-基于springboot的生产安全监测系统的设计与实现智慧生产安全系统【完整源码+LW+部署说明+演示视频,全bao一条龙等】
  • 2025假日欺诈:利用购物季的礼品卡骗局
  • Java计算机毕设之基于springboot的智慧生产安全系统基于SpringBoot的智慧工厂安全生产监督管理系统(完整前后端代码+说明文档+LW,调试定制等)
  • 2026英语雅思考试培训辅导机构排行榜 核心解析+适配人群指南 助力考生高效备考
  • 2026英语雅思考试培训辅导机构排行榜 备考择机构核心维度全解析:附高适配决策自查清单
  • 上海品牌设计4A公司2026年排行,设计服务谁更贴心?可靠的设计公司排行技术实力与市场典范解析
  • NMN哪个牌子效果最好?2026抗衰十大尖端NMN品牌排行榜盘点
  • 2026龙港净化工程公司,为生物制药改造添砖加瓦,洁净厂房/洁净车间/洁净室/无尘室,净化工程公司施工公司哪家靠谱
  • 常用的css
  • 学长亲荐2026TOP9AI论文软件:专科生毕业论文必备测评
  • 2026年了,还不知道匠厂AI?再晚一步,你的行业就被霸屏了。
  • ONNX模型转换避坑技巧
  • 网站安全太复杂?雷池SafeLine+cpolar实现“躺平式”防护! - 教程
  • 1000星巴克星礼卡回收多少,2026年划算的价格表一览
  • 2025年市面上优秀的横梁货架产品推荐,重型货架/货架/仓库货架/中型货架/层板货架,横梁货架供应商推荐排行榜单
  • 【ST表+二分】codeforces 359 D. Pair of Numbers
  • Mac系统安装nvm
  • 2026年武汉螺纹钢/线材/板材/管材源头厂家选购推荐:湖北鑫永盛钢铁贸易有限公司
  • 香橙派安装ch340驱动
  • 冲刺Day3
  • 实用指南:四旋翼无人机PID控制仿真模型探索
  • 枚举中间
  • 2026网络空间安全专业就业前景(非常详细)零基础入门到精通,收藏这篇就够了
  • 高空作业机器人设计
  • 机械手机器人
  • 权威测评出炉!2026 雅思网课课程 TOP5 实战提分机构口碑排行推荐
  • AI写毕业论文工具推荐:7款神器10分钟生成万字问卷类论文+自动生成高信度数据,论文写作超高效!