Linux 日志系统·

目录

一、前言

二、实现一个简单的日志

1.可变参数

 2.日志等级

3.日志时间

4.打印每一条参数

5.合并两个缓冲区

6.封装日志函数

三、完整代码


一、前言

当我们写一个函数,例如打开文件open,当我们打开失败的时候,会调用perror看到错误信息。

接下来我们将带大家了解日志,并自主实现一个日志系统。

这个就是我们定义的日志类的对象。

二、实现一个简单的日志

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

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

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

Info:常规消息

Warning:报警信息

Error:严重,可能要立即处理

Fatal:致命的

Ddbug:调试

1.可变参数

在写日志之前,我们了解一下可变参数列表

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

我们先来看一段代码

 

va_list s我们可以定义可以访问可变参数部分的变量,是char* 类型的。

va_start使其对象指向可变参数列表部分。

va_arg使用 va_arg 宏依次获取每个可变参数。

最后输出是正确的。

 2.日志等级

我们用宏定义

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

3.日志时间

我们在用一个接口的时候,万一这个接口失败,我们要看在什么时间段出现了什么错误。

通过time接口获得时间戳。

但这个时间戳我们还要自己运算才能得到对应的年月日。

这里给大家介绍一个localtime时间类型转换函数。

这里返回的是一个名字叫tm的结构体

这里注意,mon月份从0月开始,year年份从1900年开始。

运行结果如下:

这里我们是直接打印到显示器上,但有时候我们写日志要写入到文件里,所以这个时候我们应该创建一个缓冲区,把时间先暂时放到缓冲区里。

4.打印每一条参数

我们可以用vsnprintf函数

这里我们要用到参数列表,我们把每一条参数写入到右缓冲区中。

5.合并两个缓冲区

我们把日志时间和日志参数全部写到另一个缓冲区里,如果要打印在屏幕上就直接打印,写在文件里,就把该缓冲区的数据写入。我们来测试一下。

我们这个时候已经完成了一个简易的日志系统。

接下来我们把这个函数封装一下形成一个类,我们有时候想把该日志打印到显示器,或者输出到一个文件中,或者多个文件中。

6.封装日志函数

这里我们创一个类Log

我们有时候既然想打印到显示器上或者一个文件里或者多个文件里时,我们要有一个成员变量OpenMethod,这个路径成员变量为了方便我们创建多个文件使用。

我们先把这个类的构造函数写了,我们默认是打印在显示器上的

再写两个成员函数,判断把日志写在哪里

我们先测试一下能不能打印在显示器上

#include <iostream>
#include <stdarg.h>
#include <ctime>
#include <string>
#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

using namespace std;
#define Screen 1
#define Onefile 2
#define Classfile 3

#define LogFile "log.txt"

class Log
{
public:
    Log()
    {
        OpenMethod=Screen;
        path="path->";
    }
    void ChoseMethod(int Method)
    { 
        OpenMethod=Method;
    }
    string levelToString(int level)
    {
        switch(level)
        {
            case Info:
                return "Info";
            case Debug:
              return "Debug";
            case Warning:
                return "Warining";
            case Error:
                return "Error";
            case Fatal:
                return "Fatal";
        }
    }
    void printlog(int level, const std::string &logtxt)
    {
        switch(OpenMethod)
        {
            case Screen:
                std::cout << logtxt << std::endl;
                break;
            case Onefile:
                printOneFile(LogFile, logtxt);
            case Classfile:
                printClassFile(level, logtxt);
                break;
            default:
                break;
        }
    }
    void printOneFile(const std::string &logname, const std::string &logtxt )
    {
        string Filename=logname+path;
        int fd = open(Filename.c_str(),O_CREAT|O_WRONLY|O_APPEND,0666);
        if(fd<0) return;
        write(fd,logtxt.c_str(),logtxt.size());
        close(fd);
    }
    void printClassFile(int level, const std::string &logtxt)
    {
            
    }
    void logmessage(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);

        //打印参数
        char rightbuffer[SIZE];
        va_list s;
        va_start(s,format);
        vsnprintf(rightbuffer,sizeof(rightbuffer),format,s);
        va_end(s);

        //合并
        char logtxt[SIZE*2];
        snprintf(logtxt,sizeof(logtxt),"%s %s",leftbuffer,rightbuffer);

        printlog(level,logtxt);

    }
private:
    int OpenMethod;
    string path;
}

结果显示

接下来我们把写在一个文件下和多个文件下的成员函数写了。

我们来运行一下看看。

确实是写入了。

测试一下多文件方法

 都打印到各个文件中。

我们在makefile里创建一个文件夹,在我们的path初始化找到这个log文件夹。

 

我们看看结果。

三、完整代码

#include <iostream>
#include <stdarg.h>
#include <ctime>
#include <string>
#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

using namespace std;
#define Screen 1
#define Onefile 2
#define Classfile 3

#define LogFile "log.txt"

class Log
{
public:
    Log()
    {
        OpenMethod=Screen;
        path = "./log/";
    }
    void ChoseMethod(int Method)
    { 
        OpenMethod=Method;
    }
    string levelToString(int level)
    {
        switch(level)
        {
            case Info:
                return "Info";
            case Debug:
              return "Debug";
            case Warning:
                return "Warining";
            case Error:
                return "Error";
            case Fatal:
                return "Fatal";
        }
    }
    void printlog(int level, const std::string &logtxt)
    {
        switch(OpenMethod)
        {
            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 )
    {
        string Filename = path + logname;
        int fd = open(Filename.c_str(),O_CREAT|O_WRONLY|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); // "log.txt.Debug/Warning/Fatal"
        printOneFile(filename, logtxt);
    }
    void logmessage(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);

        //打印参数
        char rightbuffer[SIZE];
        va_list s;
        va_start(s,format);
        vsnprintf(rightbuffer,sizeof(rightbuffer),format,s);
        va_end(s);

        //合并
        char logtxt[SIZE*2];
        snprintf(logtxt,sizeof(logtxt),"%s %s",leftbuffer,rightbuffer);

        printlog(level,logtxt);

    }
private:
    int OpenMethod;
    string path;
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【PromptCoder】使用 package.json 生成 cursorrules

【PromptCoder】使用 package.json 生成 cursorrules 在当今快节奏的开发世界中&#xff0c;效率和准确性至关重要。开发者们不断寻找能够优化工作流程、帮助他们更快编写高质量代码的工具。Cursor 作为一款 AI 驱动的代码编辑器&#xff0c;正在彻底改变我们的编程方式。但如…

【VUE】vue-i18n: Uncaught SyntaxError: Not available in legacy mode

报错&#xff1a; 解决方法&#xff1a; 找到 createI18n 并加上 legacy: false,

2025年SCI一区智能优化算法:混沌进化优化算法(Chaotic Evolution Optimization, CEO),提供MATLAB代码

一、混沌进化优化算法 https://github.com/ITyuanshou/MATLABCode 1. 算法简介 混沌进化优化算法&#xff08;Chaotic Evolution Optimization, CEO&#xff09;是2025年提出的一种受混沌动力学启发的新型元启发式算法。该算法的主要灵感来源于二维离散忆阻映射的混沌进化过…

网络安全之日志审计 网络安全审计制度

一、代码审计安全 代码编写安全: 程序的两大根本:变量与函数 漏洞形成的条件:可以控制的变量“一切输入都是有害的 ” 变量到达有利用价值的函数&#xff08;危险函数&#xff09;“一切进入函数的变量是有害的” 漏洞的利用效果取决于最终函数的功能&#xff0c;变量进入…

VScode+stfp插件,实现文件远程同步保存【2025实操有效】

目录 1 痛点2 准备工作3 操作步骤3.1 第一步&#xff0c;下载STFP插件3.2 第二步&#xff0c;修改配置文件3.3 第三步&#xff0c;测试是否成功 4 后记 1 痛点 我一直用vscode远程连接服务器&#xff0c;传代码文件等到服务器上面&#xff0c;突然有一次服务器那边尽心维修&am…

Java高频面试之SE-23

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本baby今天又来了&#xff01;哈哈哈哈哈嗝&#x1f436; Java 中的 Stream 是 Java 8 引入的一种全新的数据处理方式&#xff0c;它基于函数式编程思想&#xff0c;提供了一种高效、简洁且灵活的方式来…

python-leetcode-乘积最大子数组

152. 乘积最大子数组 - 力扣&#xff08;LeetCode&#xff09; class Solution:def maxProduct(self, nums: List[int]) -> int:if not nums:return 0max_prod nums[0]min_prod nums[0]result nums[0]for i in range(1, len(nums)):if nums[i] < 0:max_prod, min_prod…

NavVis VLX三维扫描:高层建筑数字化的革新力量【沪敖3D】

在三维激光扫描领域&#xff0c;楼梯结构因其复杂的空间形态和连续垂直移动的实际需求&#xff0c;一直是技术难点之一。利用NavVis VLX穿戴式移动扫描系统成功完成一栋34层建筑的高效扫描&#xff0c;其中楼梯部分的数据一遍成形且无任何分层或形变。本文将深入分析该项目的技…

docker安装register私库

一、使用自己的私库 1、安装register私库 docker pull registry运行 docker run -d -v /data/registry:/var/lib/registry -p 5000:5000 --name registry registry:2参数-v /data/registry:/var/lib/registry&#xff0c;挂载目录 2、拉取需要的镜像 docker pull hello-w…

PCI_PCIe子系统学习(一)概念理清

文章目录 1、其它学习文章2、PCI和PCIe总线简单介绍2.1、PCI2.2、PCIe 3、引脚概述3.1、PCI3.1.1、PCI引脚概述3.1.2、PCI引脚定义3.1.2.1、32位 PCI (124针)3.1.2.2、64位 PCI (188针) 3.1.3、PCI引脚功能分类 3.2、PCIe3.2.1、PCIe引脚概述3.2.2、PCIe引脚定义3.2.2.1、PCIe …

解决Deepseek“服务器繁忙,请稍后再试”问题,基于硅基流动和chatbox的解决方案

文章目录 前言操作步骤步骤1&#xff1a;注册账号步骤2&#xff1a;在线体验步骤3&#xff1a;获取API密钥步骤4&#xff1a;安装chatbox步骤5&#xff1a;chatbox设置 价格方面 前言 最近在使用DeepSeek时&#xff0c;开启深度思考功能后&#xff0c;频繁遇到“服务器繁忙&am…

【SpringBoot】——分组校验、自定义注解、登入验证(集成redis)、属性配置方式、多环境开发系统学习知识

&#x1f3bc;个人主页&#xff1a;【Y小夜】 &#x1f60e;作者简介&#xff1a;一位双非学校的大三学生&#xff0c;编程爱好者&#xff0c; 专注于基础和实战分享&#xff0c;欢迎私信咨询&#xff01; &#x1f386;入门专栏&#xff1a;&#x1f387;【MySQL&#xff0…

TCP/IP 5层协议簇:物理层

目录 1. 物理层&#xff08;physical layer&#xff09; 2. 网线/双绞线 1. 物理层&#xff08;physical layer&#xff09; 工作设备&#xff1a;网线、光纤、空气 传输的东西是比特bit 基本单位如下&#xff1a;数字信号 信号&#xff1a;【模拟信号&#xff08;放大器&a…

【C/C++】理解C++内存与Linux虚拟地址空间的关系---带你通透C++中所有数据

每日激励&#xff1a;“不设限和自我肯定的心态&#xff1a;I can do all things。 — Stephen Curry” 绪论&#xff1a; 本质编写的原因是我在复习过程中突然发现虚拟地址空间和C内存划分我好想有点分不清时&#xff0c;进行查询各类资料和整理各类文章后得出的文章&#xff…

(论文)检测部分欺骗音频的初步调查

Paper–An Initial Investigation for Detecting Partially Spoofed Audio 摘要 所有现有的欺骗性语音数据库都包含整个欺骗性的攻击数据。 在实践中&#xff0c;使用仅部分欺骗的话语来装载成功的攻击是完全合理的。根据定义&#xff0c;部分欺骗的话语包含欺骗和真实段的混…

P9420 [蓝桥杯 2023 国 B] 子 2023

P9420 [蓝桥杯 2023 国 B] 子 2023 题目 分析代码 题目 分析 刚拿到这道题&#xff0c;我大脑简单算了一下&#xff0c;这个值太大了&#xff0c;直观感觉就很难&#xff01;&#xff01; 但是&#xff0c;你仔仔细细的一看&#xff0c;先从最简单的第一步入手&#xff0c;再…

第4章 4.4 EF Core数据库迁移 Add-Migration UpDate-Database

4.4.1 数据库迁移原理 总结一下就是&#xff1a; 1. 数据库迁移命令的执行&#xff0c;其实就是生成在数据库执行的脚本代码&#xff08;两个文件&#xff1a;数字_迁移名.cs 数字_迁移名.Designer.cs&#xff09;&#xff0c;用于对数据库进行定义和修饰。 2. 数据库迁移…

C++程序员内功修炼——Linux C/C++编程技术汇总

在软件开发的宏大版图中&#xff0c;C 语言宛如一座巍峨的高山&#xff0c;吸引着无数开发者攀登探索。而 Linux 操作系统&#xff0c;以其开源、稳定、高效的特性&#xff0c;成为了众多开发者钟爱的开发平台。将 C 与 Linux 相结合&#xff0c;就如同为开发者配备了一把无坚不…

ubuntu:桌面版磁盘合并扩容

下载gparted磁盘编辑器 apt-get install gparted 打开gparted 更改目标分区大小 当遇到这个报错时&#xff0c;需要在命令行执行原分区的挂载指令 查看该分区信息 记住该目录&#xff0c;并在命令行执行 mount -o remount -rw /# 示例&#xff1a;mount -o remount -rw /v…

使用 Containerd 通过 HTTP 协议拉取 Harbor 私有镜像仓库的镜像

在 Kubernetes 1.24及以上版本环境中&#xff0c;docker不再被支持&#xff0c;主要使用Containerd 是常用的容器运行。默认情况下&#xff0c;Containerd 使用 HTTPS 协议与镜像仓库通信。然而&#xff0c;在某些场景下&#xff08;如测试环境或内部网络&#xff09;&#xff…