日志的介绍及简单实现

个人主页: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,一经查实,立即删除!

相关文章

Digital Image Processing System(DIPS)

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

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

首先需要你对排序算法的评价维度和一个理想排序算法应该是什么样的有一个基本的认知&#xff1a; 《Hello算法之排序算法》 主要内容来自&#xff1a;Hello算法11.3 冒泡排序 我觉得冒泡排序非常有意思&#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 …

Java实现图书系统

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

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

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

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

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

软件项目详细设计说明书实际项目参考(word原件下载及全套软件资料包)

系统详细设计说明书案例&#xff08;直接套用&#xff09; 1.系统总体设计 2.性能设计 3.系统功能模块详细设计 4.数据库设计 5.接口设计 6.系统出错处理设计 7.系统处理规定 软件开发全文档下载&#xff08;下面链接或者本文末个人名片直接获取)&#xff1a;软件开发全套资料-…

C++ 常用UI库

AWTK github gitee doc scons 类似RT-Thread element github C Cross platfrom C GUI libraries&#xff0c;QT可替代方案。调试包 SDL GUI cegui 创作不易&#xff0c; 小小的支持一下吧&#xff01;

泛型...

定义&#xff1a;在编译过程中约束操作的数据类型。&#xff08;统一数据类型&#xff09; 格式&#xff1a;<数据类型> 泛型中不能写基本数据类型。 泛型类 在一个类中&#xff0c;某个变量的数据类型不确定时&#xff0c;可以定义带有泛型的类。 泛型的底层是Obje…

电量计量芯片HLW8110的前端电路设计与误差分析校正.pdf 下载

电量计量芯片HLW8110的前端电路设计与误差分析校正.pdf 下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1vlCtC3LGFMzYpSUUDY-tEg 提取码&#xff1a;8110

十四天学会Vue——Vue核心(理论+实战)(第一天)上篇

&#xff01;&#xff01;&#xff01;声明必看&#xff1a;由于本篇开始就写了Vue&#xff0c;内容过多&#xff0c;本篇部分内容还有待完善&#xff0c;小编先去将连续更新的js高阶第四天完成~本篇部分待完善内容明日更新 一、Vue核心&#xff08;上篇&#xff09; 热身top…

vue3+electron+typescript 项目安装、打包、多平台踩坑记录

环境说明 这里的测试如果没有其他特别说明的&#xff0c;就是在win10/i7环境&#xff0c;64位 创建项目 vite官方是直接支持创建electron项目的&#xff0c;所以&#xff0c;这里就简单很多了。我们已经不需要向开始那样自己去慢慢搭建 yarn create vite这里使用yarn创建&a…

外企也半夜发布上线吗?

0 别把问题想得太复杂 如果有灰度发布的能力&#xff0c;最好白天发布&#xff1b;如果没有灰度发布&#xff0c;只能在半夜发布。 即使有灰度发布能力&#xff0c;也不要沾沾自喜&#xff0c;好好反思一下你们的灰度发布是否真的经得起考验&#xff0c;还是仅仅是装装样子。…

golang创建式设计模式---工厂模式

创建式设计模式—工厂模式 目录导航 创建式设计模式---工厂模式1)什么是工厂模式2)使用场景3)实现方式4)实践案例5)优缺点分析 1)什么是工厂模式 工厂模式(Factory Method Pattern)是一种设计模式&#xff0c;旨在创建对象时&#xff0c;将对象的创建与使用进行分离。通过定义…

深度学习中的多GPU训练(Pytorch 20)

一 多GPU训练 下面详细介绍如何从零开始并行地训练网络&#xff0c;这里需要运用小批量随机梯度下降算法。后面我还讲介绍如何使用高级API并行训练网络。 我们从一个简单的计算机视觉问题和一个稍稍过时的网络开始。这个网络有多个卷积层和汇聚层&#xff0c;最后可能 有几个…

picamera配opencv做发现移动物体后录像50秒

本来是想配合上一篇写的测距传感器数据打开摄像头录制个50秒实时画面&#xff0c;后来这个测距传感器&#xff08;因为我是歪用&#xff0c;用来识别范围内的移动物体&#xff09;给的数据&#xff0c;false alarming还是太高了。于是想到使用本人之前深恶痛绝的opencv来试一试…

【编译原理--- 汇编、编译、解释系统】

汇编、编译、解释系统 1.编译方式和解释方式 程序种类是否生成目标程序是否参与程序的运行过程程序执行速度可移植性编译程序生成不参与快差解释程序不生成参与慢好 编译方式过程&#xff1a;词法分析、语法分析、语义分析、&#xff08;中间代码生成、代码优化、&#xff0…