【Linux】第三十三站:日志

2024-01-22 04:20
文章标签 linux 日志 第三十三

本文主要是介绍【Linux】第三十三站:日志,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 一、实现一个简单的日志
    • 1.简介
    • 2.可变参数
    • 3.错误等级
    • 4.时间
    • 5.打印每一条参数
    • 6.与前面的一些代码搭配使用
  • 二、完整代码

一、实现一个简单的日志

1.简介

我们运行代码的时候,我们希望有各种各样的运行时候的一些信息。这也就是日志

它一半有日志时间,日志的等级,日志的内容,文件的名称和行号。

对于日志等级一半有如下的

Info : 常规消息

Warning : 报警信息

Error : 比较严重了,可能需要立即处理

Fatal : 致命的

Debug : 调试

2.可变参数

关于可变参数我们主要用下面四个中的前三个

image-20240121184554880

我们用如下代码来简单的介绍一下

int sum(int n, ...)
{//char* 可以去提取一个一个的参数va_list s;va_start(s, n);int SUM = 0;for(int i = 0; i < n; i++){SUM += va_arg(s,int);}va_end(s); //s = NULLreturn SUM;
}

image-20240121191257243

在这段代码中,这个va_list其实就是一个char*类型的指针。

我们这个可变参数的函数至少需要带有一个参数。

因为我们传递参数的时候是从右向左传递的,所以我们是可以确定出栈顶的元素就是我们所确定的一个元素的地址

这个va_start是一个宏,代表着让s这个指针指向n。也就是栈顶

然后我们va_arg也是一个宏,它的作用是让s指针往栈里面移动第二个参数的类型大小,并解引用

va_end这个宏的作用是让指针置为空

最终我们就可以计算出这个sum的大小了。这个第一个参数我们一般是用作确定后面的参数有几个

image-20240121191705000

像我们所谓的printf里面也是类似的方法,不过要注意的时候,因为第一个参数是字符串参数,它是可以通过解析字符串里面的%s等格式化控制来确定后面有几个参数的,从而完成依次的替换的。

3.错误等级

我们现在来设计我们的日志的函数

只需要下面这样即可

void logmessage(int level, char* format, ...)
{}

首先对于等级,我们可以直接用宏来表示

#define Info 0
#define Debug 1
#define Warning 2
#define Error 3
#define Fatal 4

4.时间

接下是时间,我们可以使用时间戳,不过其实还有其他的系统调用接口

image-20240121193700415

#include <sys/time.h>
int gettimeofday(struct timeval *tv, struct timezone *tz);

第一个参数是一个结构体,里面的两个参数它可以获取秒,微秒。

第二个参数与时区相关,我们可以不用管,直接置为NULL即可

还有一个接口是这样的

#include <time.h>
struct tm *localtime(const time_t *timep);

image-20240121194806434

这个函数的功能是将时间戳转化为一个结构体,这个结构体里面有时分秒月年等信息

我们可以简单的应用一下

image-20240121200140083

我们会注意到时间存在一定的问题,这是因为它是从1900年开始计时的,这个月是从0开始的,所以我们可以进行一下调整

image-20240121200322663

如下所示就正确了

void logmessage(int level, char* format, ...)
{time_t t = time(nullptr);struct tm* ctime = localtime(&t);printf("%d-%d-%d %d:%d:%d\n",ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday, ctime->tm_hour, ctime->tm_min, ctime->tm_sec);
}

image-20240121200416569

5.打印每一条参数

我们可以用vsnprintf函数

image-20240121204556637

最终我们的代码为如下

void logmessage(int level, char* format, ...)
{char leftbuffer[SIZE];time_t t = time(nullptr);struct tm* ctime = localtime(&t);snprintf(leftbuffer, SIZE,"[%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);char rightbuffer[SIZE];va_list s;va_start(s, format);vsnprintf(rightbuffer, SIZE, format, s);va_end(s);char logtxt[2*SIZE];snprintf(logtxt, sizeof(logtxt), "%s %s\n", leftbuffer, rightbuffer);std::cout << logtxt << std::endl;
}  

image-20240121210712783

6.与前面的一些代码搭配使用

如下所示,这里我们就引进了我们刚刚使用的日志

image-20240121211321574

运行结果如下,我们现在可以看到,这样子就规范多了

image-20240121211442163

二、完整代码

如下代码所示,我们再将前面的日志给封装成一个类,然后实现一下分类打印,向文件打印,向显示屏打印等等功能。

#pragma once#include <stdarg.h>
#include <iostream>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.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, char* format, ...){char leftbuffer[SIZE];time_t t = time(nullptr);struct tm* ctime = localtime(&t);snprintf(leftbuffer, SIZE,"[%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);char rightbuffer[SIZE];va_list s;va_start(s, format);vsnprintf(rightbuffer, SIZE, format, s);va_end(s);char logtxt[2*SIZE];snprintf(logtxt, sizeof(logtxt), "%s %s\n", leftbuffer, rightbuffer);//std::cout << logtxt << std::endl;PrintLog(level, logtxt);}   // void logmessage(int level, char* format, ...)// {//     char leftbuffer[SIZE];//     time_t t = time(nullptr);//     struct tm* ctime = localtime(&t);//     snprintf(leftbuffer, SIZE,//         "[%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);//     char rightbuffer[SIZE];//     va_list s;//     va_start(s, format);//     vsnprintf(rightbuffer, SIZE, format, s);//     va_end(s);//     char logtxt[2*SIZE];//     snprintf(logtxt, sizeof(logtxt), "%s %s\n", leftbuffer, rightbuffer);//     //std::cout << logtxt << std::endl;//     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& filename, const std::string& logtxt){std::string logname = path + filename;int fd = open(logname.c_str(), O_WRONLY|O_CREAT|O_APPEND, 0666);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);PrintOnefile(filename, logtxt);}~Log(){}
private:int printMethod;std::string path;
};

这篇关于【Linux】第三十三站:日志的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/631831

相关文章

MySQL 打开binlog日志的方法及注意事项

《MySQL打开binlog日志的方法及注意事项》本文给大家介绍MySQL打开binlog日志的方法及注意事项,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录一、默认状态二、如何检查 binlog 状态三、如何开启 binlog3.1 临时开启(重启后失效)

基于Linux的ffmpeg python的关键帧抽取

《基于Linux的ffmpegpython的关键帧抽取》本文主要介绍了基于Linux的ffmpegpython的关键帧抽取,实现以按帧或时间间隔抽取关键帧,文中通过示例代码介绍的非常详细,对大家的学... 目录1.FFmpeg的环境配置1) 创建一个虚拟环境envjavascript2) ffmpeg-py

Linux脚本(shell)的使用方式

《Linux脚本(shell)的使用方式》:本文主要介绍Linux脚本(shell)的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述语法详解数学运算表达式Shell变量变量分类环境变量Shell内部变量自定义变量:定义、赋值自定义变量:引用、修改、删

SpringBoot项目配置logback-spring.xml屏蔽特定路径的日志

《SpringBoot项目配置logback-spring.xml屏蔽特定路径的日志》在SpringBoot项目中,使用logback-spring.xml配置屏蔽特定路径的日志有两种常用方式,文中的... 目录方案一:基础配置(直接关闭目标路径日志)方案二:结合 Spring Profile 按环境屏蔽关

Linux链表操作方式

《Linux链表操作方式》:本文主要介绍Linux链表操作方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、链表基础概念与内核链表优势二、内核链表结构与宏解析三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势六、典型应用场景七、调试技巧与

详解Linux中常见环境变量的特点与设置

《详解Linux中常见环境变量的特点与设置》环境变量是操作系统和用户设置的一些动态键值对,为运行的程序提供配置信息,理解环境变量对于系统管理、软件开发都很重要,下面小编就为大家详细介绍一下吧... 目录前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变

Linux系统中的firewall-offline-cmd详解(收藏版)

《Linux系统中的firewall-offline-cmd详解(收藏版)》firewall-offline-cmd是firewalld的一个命令行工具,专门设计用于在没有运行firewalld服务的... 目录主要用途基本语法选项1. 状态管理2. 区域管理3. 服务管理4. 端口管理5. ICMP 阻断

Linux实现线程同步的多种方式汇总

《Linux实现线程同步的多种方式汇总》本文详细介绍了Linux下线程同步的多种方法,包括互斥锁、自旋锁、信号量以及它们的使用示例,通过这些同步机制,可以解决线程安全问题,防止资源竞争导致的错误,示例... 目录什么是线程同步?一、互斥锁(单人洗手间规则)适用场景:特点:二、条件变量(咖啡厅取餐系统)工作流

Golang 日志处理和正则处理的操作方法

《Golang日志处理和正则处理的操作方法》:本文主要介绍Golang日志处理和正则处理的操作方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录1、logx日志处理1.1、logx简介1.2、日志初始化与配置1.3、常用方法1.4、配合defer

Linux中修改Apache HTTP Server(httpd)默认端口的完整指南

《Linux中修改ApacheHTTPServer(httpd)默认端口的完整指南》ApacheHTTPServer(简称httpd)是Linux系统中最常用的Web服务器之一,本文将详细介绍如何... 目录一、修改 httpd 默认端口的步骤1. 查找 httpd 配置文件路径2. 编辑配置文件3. 保存