自定义日志打印功能--C++
一、介绍
日志是计算机程序中用于记录运行时事件和状态的重要工具。通过记录关键信息和错误情况,日志可以帮助程序开发人员和维护人员追踪程序的执行过程,排查问题和改进性能。 在软件开发中,日志通常记录如下类型的信息:
- 事件信息:记录程序执行过程中的重要事件,如启动和关闭,特定操作完成等。
- 错误信息:记录发生的错误和异常情况,包括错误类型、位置和可能的原因。
- 警告信息:记录潜在问题或需要注意的情况,但不是严重到导致程序崩溃的程度。
- 调试信息:记录用于调试程序的详细信息,方便追踪程序状态和流程。 日志的记录一般包括时间戳、事件类型、事件描述等信息。这些记录可以写入文件、数据库或发送至远程服务器,以供后续分析和监控。
通过分析日志,开发人员可以了解程序的运行情况,发现潜在问题并优化程序性能。因此,良好的日志记录和管理对于确保软件运行稳定、故障排除和改进具有重要意义。
二、日志级别
#define DEBUG 0
#define NORMAL 1
#define WARNING 2
#define ERROR 3
#define FATAL 4const char* gLevelMap[]={"DEBUG","NORMAL","WARNING","ERROR","FATAL"
};
日志级别是一种对日志信息进行分类和标记的方法,用于帮助程序员和系统管理员更好地理解和处理日志信息。日志级别包括DEBUG(调试)、NORMAL(正常)、WARNING(警告)、ERROR(错误)和FATAL(严重错误)五种级别。通过宏定义将这五种级别编号化,可以在程序中方便地使用对应的编号来表示不同的日志级别。同时,通过使用一个数组 gLevelMap[],可以将编号与日志级别名对应起来,从而方便地在程序中根据编号找到对应的级别名,并进行相应的处理。这种分类和标记的方法有助于开发人员根据日志级别进行精细化的调试、监控和错误处理。
三、日志函数logMessage
// 日志打印 文件名
#define LOGFILE "./LOG.log"void logMessage(int level, const char* format, ...)
{char timebuffer[1024];// 日志时间time_t timestamp = time(nullptr);tm* ltm = localtime(×tamp);int year = ltm->tm_year+1900;int month = ltm->tm_mon+1;int day = ltm->tm_mday;int hour = ltm->tm_hour;int min = ltm->tm_min;int second = ltm->tm_sec;snprintf(timebuffer, sizeof timebuffer, "[%s][%04d-%02d-%02d %02d:%02d:%02d]",gLevelMap[level], year, month, day, hour, min, second);// 日志内容char logBuffer[1024];va_list args; // 初始化参数信息va_start(args, format); // 初始化参数列表vsnprintf(logBuffer, sizeof logBuffer, format, args); //日志内容存入logBuffe中va_end(args);// 显示器打印日志信息printf("%s %s\n", timebuffer, logBuffer);// //往文件打印// FILE *fp = fopen(LOGFILE, "a");// fprintf(fp, "%s %s\n", timebuffer, logBuffer);// fclose(fp);
}
logMessage(int level, const char* format, ...)该日志函数level代表日志等级、format表示日志内容、...是可变参数列表。这样使日志的使用跟printf()使用方法类似。
timebuffer:用于存储日志的等级和时间信息。
logBuffer:用于存储日志的内容。

内部解析
#define LOGFILE "./LOG.log"定义的一个日志文件,可以设置把打印的日志显示到这个文件里面。
// 日志时间time_t timestamp = time(nullptr);tm* ltm = localtime(×tamp);int year = ltm->tm_year+1900;int month = ltm->tm_mon+1;int day = ltm->tm_mday;int hour = ltm->tm_hour;int min = ltm->tm_min;int second = ltm->tm_sec;
time_t timestamp = time(nullptr);获取系统当前的时间戳。
tm* ltm = localtime(×tamp);将时间戳转为用本地时区表示,比如Thu Aug 23 09:12:05 2012
localtime():原型(struct tm *localtime(const time_t *timer))localtime的函数声明。返回的是tm结构体,其结构如下:
struct tm {int tm_sec; /* 秒,范围从 0 到 59*/int tm_min; /* 分,范围从 0 到 59*/int tm_hour; /* 小时,范围从 0 到 23*/int tm_mday; /* 一月中的第几天,范围从 1 到 31 */int tm_mon; /* 月份,范围从 0 到 11*/int tm_year; /* 自 1900 起的年数 */int tm_wday; /* 一周中的第几天,范围从 0 到 6 */int tm_yday; /* 一年中的第几天,范围从 0 到 365 */int tm_isdst; /* 夏令时*/
};
所以通过调用ltm对象的内部变量,就可以获取想要的时间格式。例如int year = ltm->tm_year+1900;可以获取当前时间的年份(+1900是因为获取的年份是从1900年至今的)。
snprintf(timebuffer, sizeof timebuffer, "[%s][%04d-%02d-%02d %02d:%02d:%02d]",gLevelMap[level], year, month, day, hour, min, second);
使用格式化输出字符串snprintf函数,我们可以将当前的日志级别、时间,按指定的格式输入到缓冲区timebuffer中。这样,timebuffer中的内容就如同这个样子:([日志级别][时间])
![]()
// 日志内容char logBuffer[1024];va_list args; // 初始化参数信息va_start(args, format); // 初始化参数列表vsnprintf(logBuffer, sizeof logBuffer, format, args); //日志内容存入logBuffe中va_end(args);
format是传进来的日志内容,因为logMessge()有一个可变的参数列表...。所以需要va_list args;va_start(args, format);
va_list是C语言中的一个宏定义,用于表示一个变长参数列表。它是一个指向变长参数列表的指针,可以通过宏va_start、va_arg和va_end对变长参数列表进行访问和操作。在函数中需要接收不定数量的参数时,可以使用va_list来处理这些参数。
va_start:它的作用是初始化一个va_list类型的变量,使其指向可变参数列表的第一个参数。
vsnprintf()用于向一个字符串缓冲区打印格式化字符串,且可以限定打印的格式化字符串的最大长度。用它把日志的内容输入到logBuffer中。
va_end:是一个宏,用于结束使用 va_start 和 va_arg 宏定义的可变参数列表。它的作用是清理 va_list 类型变量,以便该变量可以被再次使用。
// 打印日志信息printf("%s %s\n", timebuffer, logBuffer);// //往文件打印FILE *fp = fopen(LOGFILE, "a");fprintf(fp, "%s %s\n", timebuffer, logBuffer);fclose(fp);
打印日志内容有两种方式,一种是向显示器上打,一种是往文件里写。通过将timebuffer和logBuffer把时间和内容组合到一起,就是一条完整的日志信息了。
测试
简单的测试,将日志信息打印在显示器上:
#include "log.hpp"int main()
{printf("ssd\n");int n=1;logMessage(DEBUG, "测试日志信息输出%d", n);return 0;
}

四、完整代码
#pragma once
#include <iostream>
#include <cstring>
#include <time.h>
#include <stdarg.h>
#include <cstdio>//日志级别
#define DEBUG 0
#define NORMAL 1
#define WARNING 2
#define ERROR 3
#define FATAL 4const char* gLevelMap[]={"DEBUG","NORMAL","WARNING","ERROR","FATAL"
};// 日志打印 文件名
#define LOGFILE "./LOG.log"void logMessage(int level, const char* format, ...)
{char timebuffer[1024];// 日志时间time_t timestamp = time(nullptr);tm* ltm = localtime(×tamp);int year = ltm->tm_year+1900;int month = ltm->tm_mon+1;int day = ltm->tm_mday;int hour = ltm->tm_hour;int min = ltm->tm_min;int second = ltm->tm_sec;snprintf(timebuffer, sizeof timebuffer, "[%s][%04d-%02d-%02d %02d:%02d:%02d]",gLevelMap[level], year, month, day, hour, min, second);// 日志内容char logBuffer[1024];va_list args; // 初始化参数信息va_start(args, format); // 初始化参数列表vsnprintf(logBuffer, sizeof logBuffer, format, args); //日志内容存入logBuffe中va_end(args);// 打印日志信息printf("%s %s\n", timebuffer, logBuffer);// //往文件打印// FILE *fp = fopen(LOGFILE, "a");// fprintf(fp, "%s %s\n", timebuffer, logBuffer);// fclose(fp);
}
相关文章:
自定义日志打印功能--C++
一、介绍 日志是计算机程序中用于记录运行时事件和状态的重要工具。通过记录关键信息和错误情况,日志可以帮助程序开发人员和维护人员追踪程序的执行过程,排查问题和改进性能。 在软件开发中,日志通常记录如下类型的信息: 事件信…...
gitlab注册无中国区电话验证问题
众所周知gitlab对中国区不友好,无法直接注册,页面无法选择86的手机号进行验证码发送。 Google上众多的方案是修改dom,而且时间大约是21年以前。 修改dom,对于现在的VUE、React框架来说是没有用的,所以不用尝试。 直接看…...
【JAVA基础题目练习】----第二天
JAVA基础题目练习 1. 键盘录入数据,比较大小2. 代码重构(简化代码,少做判断)3. 键盘录入月份的值,输出对应的季节4. 获取三个数据中的最大值使用IF语句5. 用switch语句实现键盘录入月份,输出对应的季节6. 求…...
node.js和npm的安装与环境配置(2023最新版)
目录 安装node.js测试是否安装成功测试npm环境配置更改环境变量新建系统变量 安装node.js 1、进入官网下载:node.js官网 我选择的是windows64位的,你可以根据自己的实际情况选择对应的版本。 2、下载完成,安装。 打开安装程序 接受协议 选…...
ke14--10章-1数据库JDBC介绍
注册数据库(两种方式),获取连接,通过Connection对象获取Statement对象,使用Statement执行SQL语句。操作ResultSet结果集 ,回收数据库资源. 需要语句: 1Class.forName("DriverName");2Connection conn DriverManager.getConnection(String url, String user, String…...
【IC验证】perl脚本——分析前/后仿用例回归情况
目录 1 脚本名称 2 脚本使用说明 3 nocare_list文件示例 4 脚本执行方法 5 postsim_result.log文件示例 6 脚本代码 1 脚本名称 post_analysis 2 脚本使用说明 help:打印脚本说明信息 命令:post_analysis help 前/后仿结束后,首先填…...
Ansible适合的场景是什么?
Ansible将编排与配置管理、供应和应用程序部署结合并统一在一个易于使用的平台上。Ansible的一些主要场景包括: 配置管理:集中配置文件管理和部署是Ansible的一个常见场景。 应用程序部署:当使用Ansible定义应用程序,并使用Ansible Tower管…...
Flink 读写 HBase 总结
前言 总结 Flink 读写 HBase 版本 Flink 1.15.4HBase 2.0.2Hudi 0.13.0官方文档 https://nightlies.apache.org/flink/flink-docs-release-1.17/zh/docs/connectors/table/hbase/ Jar包 https://repo1.maven.org/maven2/org/apache/flink/flink-sql-connector-hbase-2.2/1…...
记录一次chatGPT人机协同实战辅助科研——根据词库自动进行情感分析
有一个Excel中的一列,读取文本判断文本包含积极情感词.txt和消极情感词.txt的个数,分别生成两列统计数据 请将 ‘your_file.xlsx’ 替换为你的Excel文件名,Your Text Column’替换为包含文本的列名。 这个程序首先读取了积极和消极情感词&…...
Java_LinkedList链表详解
目录 前言 ArrayList的缺陷 链表 链表的概念及结构 链表的种类 1.单向或双向 2.带头或不带头 3.循环或不循环 LinkedList的使用 什么是LinkedList LinkedList的使用 LinkedList的构造 LinkedList的其他常用方法介绍 LinkedList的遍历 ArrayList和LinkedList的…...
MacOS 12 开放指定端口 指定ip访问
MacOS 12 开放指定端口 指定ip访问 在 macOS 上开放一个端口,并指定只能特定的 IP 访问,你可以使用 macOS 内置的 pfctl(Packet Filter)工具来实现。 以下是一些基本的步骤: 1、 编辑 pf 配置文件: 打开 /…...
LeedCode刷题---滑动窗口问题
顾得泉:个人主页 个人专栏:《Linux操作系统》 《C/C》 《LeedCode刷题》 键盘敲烂,年薪百万! 一、长度最小的子数组 题目链接:长度最小的子数组 题目描述 给定一个含有 n 个正整数的数组和一个正整数 target 。…...
leetcode24. 两两交换链表中的节点
题目描述 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。 示例 1: 输入:head [1,2,3,4] 输出&#…...
TCP传输层详解(计算机网络复习)
介绍:TCP/IP包含了一系列的协议,也叫TCP/IP协议族,简称TCP/IP。该协议族提供了点对点的连接机制,并将传输数据帧的封装、寻址、传输、路由以及接收方式都予以标准化 TCP/IP的分层模型 在讲TCP/IP协议之前,首先介绍一…...
【LuatOS】简单案例网页点灯
材料 硬件:合宙ESP32C3简约版,BH1750光照度模块,0.96寸OLED(4P_IIC),杜邦线若干 接线: ESP32C3.GND — OLED.GND — BH1750.GND ESP32C3.3.3V — OLED.VCC — BH1750.VCC ESP32C3.GPIO5 — OLED.SCL — BH1750.SCL E…...
百度APP iOS端包体积50M优化实践(七)编译器优化
一. 前言 百度APP iOS端包体积优化系列文章的前六篇重点介绍了包体积优化整体方案、图片优化、资源优化、代码优化、无用类优化、HEIC图片优化实践和无用方法清理,图片优化是从无用图片、Asset Catalog和HEIC格式三个角度做深度优化;资源优化包括大资源…...
STM32-新建工程(标准库)
目录 STM32F10x新建工程(标准库) 移植文件夹 新建工程 添加启动文件和必需文件 在工程中加载新添加的文件 在工程中添加文件路径 在工程中添加main函数 添加lib库 添加必需文件 添加宏定义 点亮LED(标准库) STM32F10x新…...
Android集成科大讯飞语音识别与语音唤醒简易封装
目录 一、语音唤醒部分 1、首先在科大讯飞官网注册开发者账号 2、配置唤醒词然后下载sdk 3、选择对应功能下载 4、语音唤醒lib包全部复制到工程目录下 5、把语音唤醒词文件复制到工程的assets目录 6、复制对应权限到AndroidManifest.xml中 7、唤醒工具类封装 二、语音识…...
【Linux】telnet命令使用
telnet命令 telnet命令用于使用telnet协议与另一台主机进行通信。如果在没有主机参数的情况下调用telnet,它将进入命令模式,由其提示(telnet>)指示。在这种模式下,它接受并执行下面列出的命令。如果使用参数调用它…...
VCG 标记使用(BitFlags)
文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 对于网格的每个单形,我们都有一个称为BitFlags的组件,该组件存储固定大小的32位向量,用于各种需求。管理这些标志的相关类:vcg::tri::UpdateFlags与vcg::tri::UpdateSelection。主要的标记有:删除标记、边界标记…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...
