日志的介绍及简单实现

个人主页:Lei宝啊 

愿所有美好如期而遇


目录

日志是什么?

为什么需要日志?

实现一个简单日志

时间戳

clock_gettime

time & localtime

可变模板参数(使用C语言),va_start & va_end &  vsprintf

宏  __LINE__ & __FILE__ & ##__VA_ARGS__

小技巧

代码实现


日志是什么?

日志(Log) 是记录系统、应用或设备在运行过程中产生的各种事件、状态、错误等信息的文件或数据流。这些日志信息对于了解系统的运行状况、排查问题、优化性能以及安全审计等方面都非常重要。

为什么需要日志?

  1. 问题排查:当系统或应用出现故障时,通过查看日志可以快速定位问题发生的原因和位置,从而加快故障解决的速度。
  2. 性能监控:通过分析日志,可以了解系统的运行状况,包括请求量、响应时间、资源使用情况等,从而发现性能瓶颈并进行优化。
  3. 安全审计:日志中记录了用户的操作行为、系统的访问情况等信息,这些信息可以用于安全审计,检查是否有异常操作或入侵行为。
  4. 合规性要求:在某些行业或地区,法律法规要求企业或组织必须保留一定期限的日志记录,以便在需要时进行审计或调查。
  5. 系统恢复:在某些情况下,如系统崩溃或数据丢失时,可以通过日志中的信息来恢复系统或数据。
  6. 版本追踪:对于软件来说,日志可以记录软件的版本变化、功能更新等信息,方便开发人员进行版本追踪和回滚。
  7. 用户行为分析:通过分析用户的操作日志,可以了解用户的使用习惯、喜好等信息,从而优化产品设计和提高用户体验

实现一个简单日志

实现日志前,我们先介绍几个函数以及几个小技巧:

时间戳

时间戳(Timestamp) 是一个表示特定时间点的数字或字符串。它通常表示从某个固定时间点(1970年1月1日00:00:00 UTC,也被称为Unix纪元或Unix时间戳)到特定事件发生时经过的秒数。

我们在Linux系统中有这样几个函数:

clock_gettime

第一个参数我们填CLOCK_REALTIME即可,表示系统实时时间。

#include <stdio.h>  
#include <time.h>  int main() 
{  struct timespec ts;  if (clock_gettime(CLOCK_REALTIME, &ts) == 0) {  printf("Current time: %ld.%09ld\n", ts.tv_sec, ts.tv_nsec);  } else {  perror("clock_gettime");  return 1;  }  return 0;  
}
time & localtime

time函数获取当前时间的时间戳。

locltime函数将时间戳转换成我们平时使用的年月日时分秒。 

可变模板参数(使用C语言),va_start & va_end &  vsprintf
void message(const char* format, ...){}  //可变模板参数

我们如何获取可变模板参数中的参数呢?

使用vsprintf函数:

这个函数用来将可变模板参数以format格式,将其写入到str指向的char类型数组中。 

而可变模板参数,将会使用va_list类型变量指向,实际上他是一个void*类型指针,我们定义后,还需要使用函数初始化以及销毁。

va_list args;
va_start(&args, format);
//...
va_end(&args);

va_start,初始化va_list类型变量,last就是可变模板参数左边第一个参数,这样这个函数就可以将args初始化为指向可变模板参数的指针。

va_end,将va_list类型变量清空。

char buffer[1024];
vsprintf(buffer, format, args); 
//这样就将可变模板参数中的内容以我们希望的格式获取到
//类似于printf("%d %s", xx,xx); "%d %s"就是格式,后面就是可变模板参数
宏  __LINE__ & __FILE__ & ##__VA_ARGS__
  • __LINE__ 当前代码所在行数
  • __FILE__ 当前代码所在文件
  • __VA_ARGS__    C99及C++支持的宏可变模板参数

 //##__VA_ARGS__ 中的 ## 操作符。当 __VA_ARGS__ 为空时(即没有额外的参数),
  ## 操作符会将其前面的逗号去掉,以防止在编译时产生语法错误。

简单来说,就是没有可变模板参数,只有格式,那么格式后面还有个逗号,##操作符会将其去掉。

小技巧

在宏替换中,关于语句的替换,以及多语句的替换,我们可以将其写在do{}while(0)中。

如果上述讲解没有理解,那么可以在下面的代码中进行理解,所有讲解都会在下面代码中有体现。

代码实现

#include <iostream>
#include <string>
#include <ctime>
#include <cstdarg>
#include <pthread.h>
#include <fstream>
using namespace std;//##__VA_ARGS__ 中的 ## 操作符。当 __VA_ARGS__ 为空时(即没有额外的参数),## 操作符会将其前面的逗号去掉,以防止在编译时产生语法错误。
#define Log(level, format, ...) do{LogMessage(__FILE__, __LINE__, level, format, ##__VA_ARGS__);}while(0)
#define YSave do{IsSave = true;}while(0)
#define NSave do{IsSave = false;}while(0)pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
string file_name_path = "log.txt";
bool IsSave = false; enum Level
{Debug = 0,Info,Warning,Error,Fatal
};string LevelToString(int level)
{string name;switch (level){case Debug   : return "Debug";case Info    : return "Info";case Warning : return "Warning";case Error   : return "Error";case Fatal   : return "Fatal";default: return "阿西吧";}
}string TimeToString()
{time_t Time; time(&Time);struct tm* attr = localtime(&Time);char buffer[1024];sprintf(buffer,"%4d-%2d-%2d %2d:%2d:%2d",attr->tm_year+1900,attr->tm_mon+1,attr->tm_mday,attr->tm_hour,attr->tm_min,attr->tm_sec);return buffer;
}void Save(string ret)
{fstream out(file_name_path.c_str(), ios::app); if(out.is_open()){out << ret;}else{std::cerr << "无法打开文件: " << file_name_path << std::endl;}out.close();
}// 2. 日志是有格式的
// 日志等级 时间 代码所在的文件名/行数 日志的内容
void LogMessage(string filename, int line, int level, const char* format, ...)
{string levelname = LevelToString(level);string timename = TimeToString();va_list args;           //一个void*指针va_start(args, format); //将args初始化,指向可变参数列表char buffer[1024]; vsprintf(buffer, format, args);va_end(args);string ret = "[" + filename + "]" + "[" + "line: " + to_string(line)+ "]" + "[" + levelname + "]" + "[" + timename + "]" + "[" + buffer + "]" + "\n";pthread_mutex_lock(&log_mutex);if(IsSave){Save(ret);}else{cout << ret;}pthread_mutex_unlock(&log_mutex);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/841868.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从0入门FreeRTOS之第一节 什么是FreeRTOS?

简介与基本概念 什么是FreeRTOS&#xff1f; FreeRTOS&#xff08;Free Real-Time Operating System&#xff09;是一款开源的实时操作系统&#xff08;RTOS&#xff09;&#xff0c;专为嵌入式系统设计。由Real Time Engineers Ltd.开发和维护&#xff0c;FreeRTOS以其小巧、…

Digital Image Processing System(DIPS)

数字图像处理系统 Digital Image Processing System&#xff08;DIPS&#xff09; 早前版本&#xff1a; ​​​​​​​DIPS_YTPC OCR-CSDN博客

springAi使用教程

springAi使用教程 版本要求 环境版本号 springboot 3.2.4 java 17 springAI 0.8.1 导入依赖 1.步骤1 代码如下&#xff1a; <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</…

给页面元素添加水印

关键步骤 初始化和配置&#xff1a; 组件接受一系列配置参数&#xff0c;如水印文本、字体、颜色、旋转角度等。这些参数用于控制水印的外观和位置。 Canvas绘图&#xff1a; 创建一个隐藏的<canvas>元素。使用Canvas API绘制水印图案&#xff0c;根据配置参数设置文…

数据结构和算法|排序算法系列(二)|冒泡排序

首先需要你对排序算法的评价维度和一个理想排序算法应该是什么样的有一个基本的认知&#xff1a; 《Hello算法之排序算法》 主要内容来自&#xff1a;Hello算法11.3 冒泡排序 我觉得冒泡排序非常有意思&#xff0c;也非常简单&#xff0c;就是不停地交换相邻的元素即可&#…

多天线技术

多天线技术可以分为两类&#xff1a;分集技术和空间复用技术。分集技术利用多天线接收或者发射载有同一信息的信号&#xff0c;提高传输的可靠性。分集技术是将瑞利衰落无线信道换成更加稳定的信道。 发射端未知CSI时的信道容量 发射端已知CSI时的信道容量 信道估计&#xff…

基础—SQL—通用语法及分类

一、SQL的通用基本语法 &#xff08;1&#xff09;SQL语句可以单行或多行书写&#xff08;以分号结尾&#xff09;。 &#xff08;2&#xff09;在编写SQL语句的时候&#xff0c;如果长度比较长&#xff0c;我们可以允许空格/缩进来增强语句的可读性&#xff0c;而且空格或者…

ElasticSearch插件版本与ES版本不对应的解决方案

一、背景 最近需要给es安装ik、hanlp分词器和ingest-attachment管道&#xff0c;服务器已有的es版本为8.5.3&#xff08;似乎太新了&#xff09;&#xff0c;hanlp和ingest-attachment都没有这么高的版本&#xff0c;因此只能下载相对老的版本&#xff0c;然后自己修改配置文件…

安全设计 | 安全设计不得马虎!微软STRIDE威胁建模方法让你事半功倍,快速发现应用安全隐患!

STRIDE威胁建模方法最早发表于2006年11月的《MSDN杂志》&#xff0c;作者是微软的工程师Shawn Hernan、Scott Lambert 、Tomasz Ostwald 和 Adam Shostack。那我们为什么要进行威胁建模&#xff1f; 如何使用数据流图对系统进行威胁建模&#xff1f;如何减轻威胁&#xff1f;接…

java项目之桂林旅游景点导游平台源码(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的桂林旅游景点导游平台。 项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 桂林旅游景点导游…

mysql5.5版本安装过程

mysql是关系型数据库的管理系统 将安装包放在 c盘根目录 名称为mysql 在该路径下cmd进入命令执行窗口 出现此页面说明安装成功 需要修改配置文件内容 将my-medium.ini 复制粘贴并改名为 my.ini 并添加如下内容 改好之后在mysql目录下cmd进入命令执行窗口 切换到cd bin …

变电站的SCD文件

SCD文件是智能变电站配置描述文件&#xff0c;是IEC 61850标准定义的一种文件类型&#xff0c;用于描述整个变电站所有设备的信息。它包含变电站一次系统配置&#xff08;含一次、二次设备关联信息配置&#xff09;、二次设备配置&#xff08;包含信号描述、GOOSE信号连接配置&…

唠唠叨叨,每日进度

今天学了一个strcpy’的模拟实现&#xff0c;现在需要去写水课作业了&#xff0c;加油&#xff01;&#xff01;&#xff01;

【文末附gpt升级方案】Lumina-T2X:大型扩散DiTs在多模态内容生成中的新篇章

Lumina-T2X&#xff1a;大型扩散DiTs在多模态内容生成中的新篇章 摘要 随着人工智能技术的飞速发展&#xff0c;多模态内容生成已成为计算机视觉和自然语言处理领域的研究热点。本文介绍了Lumina-T2X&#xff0c;一个基于大型扩散变换器&#xff08;Diffusion Transformers, …

Java实现图书系统

首先实现一个图书管理系统,我们要知道有哪些元素? 1.用户分成为管理员和普通用户 2.书:书架 书 3.操作的是: 书架 目录 第一步:建包 第二步:搭建框架 首先:完成book中的方法 其次:完成BookList 然后:完成管理员界面和普通用户界面 最后:Main 第三步:细分方法 1.退…

Spring—Spring配置文件概念及应用(实现一个图形验证码)

文章目录 配置文件配置文件作用配置文件的格式配置文件优先级说明配置文件书写代码的格式yml文件代码的格式 Value注解 properties 缺点分析properties VS yml实现一个验证码程序 配置文件 配置文件作用 整个项目的重要信息我们都会配置在配置文件中&#xff0c;比如说我们数…

视频拼接融合产品的产品与架构设计(四)分布式GPU运算合并单元

上一篇如下 视频拼接融合产品的产品与架构设计(三&#xff09;内存和显存单元数据迁移 视频合并单元说明 对下面这张图做些说明&#xff0c;视频接入是比较常见&#xff0c;可以说是普通&#xff0c;但是做到接入后随即进行比较重的算法运算&#xff0c;这个在视频领域并不多…

Makefile学习笔记14|u-boot顶层Makefile00

Makefile学习笔记14|u-boot顶层Makefile00 希望看到这篇文章的朋友能在评论区留下宝贵的建议来让我们共同成长&#xff0c;谢谢。 这里是目录 本系列文章分析使用的Makefile # SPDX-License-Identifier: GPL-2.0VERSION 2024 PATCHLEVEL 01 SUBLEVEL EXTRAVERSION -rc4 N…

评估SV模型的预测效果和性能因素

评估SV模型的预测效果和性能通常涉及多个方面的考量,以下是一些关键的评估方法和指标: 均方误差(Mean Squared Error, MSE):MSE衡量了模型预测值与实际值之间差异的平方的均值。较小的MSE值意味着模型预测更为准确。 均方根误差(Root Mean Squared Error, RMSE):RMSE是…

SDN简介

一、SDN 定义与概念 SDN&#xff08;Software-defined Networking&#xff0c;软件定义网络&#xff09;是一种新型网络管理方法&#xff0c;支持动态可编程的网络配置&#xff0c;提高了网络性能和管理效率&#xff0c;使网络服务能够像云计算一样提供灵活的定制能力。SDN 将…