【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 = NULL
    return 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;
};

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

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

相关文章

神策 CDP 获评中国软件评测中心「优秀大数据产品」

近日&#xff0c;中国软件评测中心在第十三届软件大会上揭晓了「第十五期优秀大数据产品、解决方案和案例测评结果」。神策数据基于客户旅程编排的客户数据平台&#xff08;CDP&#xff09;1.3.0 凭借出色的产品能力获评「优秀大数据产品」&#xff0c;并获得大数据基础设施类产…

目标检测数据集 - MS COCO

文章目录 1. 数据集介绍2. 使用pycocotools读取数据3. 验证mAP 论文&#xff1a;Microsoft COCO: Common Objects in Context 网址&#xff1a;https://arxiv.org/abs/1405.0312 官网&#xff1a;https://cocodataset.org/ 1. 数据集介绍 MS COCO是一个非常大型&#xff0c;且…

AI短视频生成与制作从入门到精通

系列文章目录 送书第一期 《用户画像&#xff1a;平台构建与业务实践》 送书活动之抽奖工具的打造 《获取博客评论用户抽取幸运中奖者》 送书第二期 《Spring Cloud Alibaba核心技术与实战案例》 送书第三期 《深入浅出Java虚拟机》 送书第四期 《AI时代项目经理成长之道》 …

作者哪些不为人知的秘密,关于作者的八卦!!作者自述!!

各位粉丝&#xff0c;各位开发界的同仁们&#xff0c;你们好&#xff01;我是艾利克斯冰&#xff0c;也是公众号 IT技术馆 的馆长。 本人一直从事Java方向的技术研发工作&#xff0c;接触到最多的就是技术搭建和架构设计、微信小程序等。 除此之外&#xff0c;本人还学习了Go语…

Qt 开发环境配置 vs和Qt creator

Qt 开发环境配置 vs和Qt creator 1、安装的软件 1、vs_Enterprise.exe 2、Qt creator (最好是最新的版本,低版本不支持vs2019) 下载地址&#xff1a;https://gofile-3535697530.cn1.quickconnect.cn/sharing/zMCh5ENgZ 密码&#xff1a;qt_dev 2、Qt Creator配置 1、打开…

springcloud之链路追踪

写在前面 源码 。 本文一起来看下链路追踪的功能&#xff0c;链路追踪是一种找出病因的手段&#xff0c;可以类比医院的检查仪器&#xff0c;服务医生治病救人&#xff0c;而链路追踪技术是辅助开发人员查找线上问题的。 1&#xff1a;为什么微服务需要链路追踪 孔子同志月过…

崩溃了!我说用attach进行问题定位,面试官问我原理

Arthas&#xff08;阿尔萨斯&#xff09;是一款开源的Java诊断和监控工具&#xff0c;可以在生产环境中进行实时的应用程序分析和故障排查。Arthas的实现原理主要基于Java Instrumentation API和Java Agent技术。 Java Agent 是 Java 编程语言提供的一种特殊机制&#xff0c;允…

【Qt】—— Qt的基本介绍

目录 &#xff08;一&#xff09;什么是Qt &#xff08;二&#xff09; Qt的发展史 &#xff08;三&#xff09;Qt⽀持的平台 &#xff08;四&#xff09; Qt版本 &#xff08;五&#xff09;Qt的优点 &#xff08;六&#xff09;Qt的应⽤场景 &#xff08;七&#xff09…

77.网游逆向分析与插件开发-背包的获取-物品类的C++还原

内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;76.网游逆向分析与插件开发-背包的获取-背包地址的逆向分析-CSDN博客 码云地址&#xff08;ui显示角色数据 分支&#xff09;&#xff1a;https://gitee.com/dye_your_fingers/sro_-ex.git 码云版本…

【2020】百度校招Java研发工程师笔试卷(第二批)算法题

贴一下我去年9月份写的博客 三道编程题&#xff0c;一道数学题&#xff0c;两道图论&#xff0c;哎嘿嘿&#xff0c;我就是不会做&#xff0c;哎嘿嘿&#xff0c;哭了。。。 一.最小值 牛牛给度度熊出了一个数学题&#xff0c;牛牛给定数字n,m,k&#xff0c;希望度度熊能找到…

文件操作与IO(2)

Java中通过java.io.File类来对一个文件(包括目录)进行抽象的描述.注意,有File对象,并不代表真实存在该文件. File概述 我们先来看看File类中的常见属性,构造方法和方法. 属性 修饰符及类型属性说明static StringpathSeparator依赖系统的路径分隔符,String类型的表示static …

VM使用教程--SDK取图 视频笔记

本笔记均由海康机器人官网的V学院视频中记录所得&#xff0c;属于省流大师了[doge] 图像采集 图像采集包括1图像源&#xff0c;2多图采集&#xff0c;3输出图像&#xff0c;4缓存图像&#xff0c;5光源 1图像源 图像源包括本地图像&#xff0c;相机采图&#xff0c;SDK 本…

MySQL主从集群

MySQL主从集群 主从模式、集群模式&#xff0c;都是在一个项目中使用多个mysql节点进行存储和读取数据。 当单机模式部署&#xff0c;不满足安全性、高可用、高并发等需求的时候&#xff0c;就需要考虑主从模式或者集群模式部署。 什么是主从模式&#xff1f; 主从模式&…

结构体大揭秘:代码中的时尚之选(上)

目录 结构结构的声明结构成员的类型结构体变量的定义和初始化结构体成员的访问结构体传参 结构 结构是一些值的集合&#xff0c;这些值被称为成员变量。之前说过数组是相同类型元素的集合。结构的每个成员可以是不同类型的变量&#xff0c;当然也可以是相同类型的。 我们在生活…

【数据库原理】(38)数据仓库

数据仓库&#xff08;Data Warehouse, DW&#xff09;是为了满足企业决策分析需求而设计的数据环境&#xff0c;它与传统数据库有明显的不同。 一.数据库仓库概述 定义: 数据仓库是一个面向主题的、集成的、相对稳定的、反映历史变化的数据集合&#xff0c;用于支持企业管理和…

DAY06_SpringBoot—入门properties/YML文件lombok插件及使用

目录 1 SpringBoot1.1 SpringBoot介绍1.2 SpringBoot入门案例1.2.1 安装SpringBoot插件1.2.2 创建SpringBoot项目 1.3 关于SpringBoot项目说明1.3.1 关于POM.xml文件说明1.3.2 依赖配置项1.3.3 build标签 1.4 SpringBoot Maven操作1.4.1 项目打包1.4.2 java命令运行项目 1.5 关…

数据脱敏(二)脱敏算法-哈希脱敏

脱敏算法篇使用阿里云数据脱敏算法为模板,使用算子平台快速搭建流程来展示数据 哈希脱敏是一种数据安全处理技术&#xff0c;主要用于保护敏感信息。它将原始数据&#xff08;如密码、身份证号等&#xff09;通过哈希算法转换成固定长度的哈希值&#xff0c;即使哈希值被泄露&a…

【GitHub项目推荐--老照片变清晰】【转载】

先来看一个效果图&#xff0c;这个开源项目能把模糊爆浆的老照片 1 s 内变成清晰、高清的有色照片。 而以上这些效果&#xff0c;无需专业 PS 技能&#xff0c;只用一个网页端的 Demo、点点鼠标上传图片就能搞定。 这个修复神器&#xff0c;由腾讯 PCG ARC 实验室研发&#xf…

Java 面向对象 06 对象内存图(黑马)

之前设计的如下图&#xff1a; 方法区和内存在物理上是一块的&#xff0c;但是有不好的地方&#xff0c;所以变成了这种形式&#xff1a; 一个对象的内存图&#xff1a; 在创建对象时虚拟机至少做了以下七步&#xff1a; 解释&#xff1a; 第一步&#xff1a; 第二步&#x…

使用golang对接微软Azure AI翻译

文章目录 一、官方地址二、准备工作三、代码示例 一、官方地址 https://learn.microsoft.com/zh-CN/azure/ai-services/translator/translator-text-apis?tabsgo 二、准备工作 创建服务 创建服务连接地址&#xff1a;https://portal.azure.com/#create/Microsoft.CognitiveS…