【Linux】日志

news2024/9/28 17:23:04

日志是记录软件运行过程中发生的事件的一种手段,通常包含以下内容:

  • 时间戳:记录日志条目创建的确切时间。这对于追踪事件发生的时间顺序至关重要。
  • 日志级别:表示日志信息的严重性或重要性,常见的级别包括 DEBUG、INFO、WARNING、ERROR 和 FATAL。
  • 消息:日志条目的主要文本内容,描述了发生了什么事件或情况。
  • 来源:生成日志条目的组件、模块、类或函数名,有助于定位日志信息在代码中的位置。
  • 线程信息:在多线程应用程序中,记录产生日志的线程ID或名称。
  • 进程信息:记录产生日志的进程ID或名称。
  • 用户信息:如果是用户驱动的应用程序,可能需要记录进行操作的用户ID或名称。
  • 主机信息:记录生成日志的服务器或主机的名称或IP地址。
  • 异常信息:如果日志是由于异常情况而产生的,通常包括异常的类型、消息、堆栈跟踪等。
  • 自定义上下文:根据应用程序的需要,可能包括与事件相关的特定上下文信息,如交易ID、会话ID、请求参数等。

在C++标准库中,并没有直接提供专门的日志记录功能,然而,C++标准库中的一些组件可以用来模拟实现日志记录。

需要实现:

  • 日志级别:Debug, Info, Warning, Error, Fatal:这些枚举值定义了不同的日志级别。
  • 日志输出风格:Screen, OneFile, ClassFile:定义了日志消息的输出方式,分别对应控制台输出、单个文件输出和按类别分文件输出。
  • 获取当前时间戳:TimeStampToLocalTime获取当前时间戳并转换为本地时间。
  • 输出日志消息:屏幕、单个文件、多类文件。

Log.hpp如下:

#pragma once

#include <iostream>
#include <vector>
#include <string>
#include <cstdarg>
#include <sys/stat.h>
#include <sys/types.h>
#include <ctime>
#include <fcntl.h>
#include <unistd.h>

// 日志级别
enum
{
    Debug = 0,
    Info,
    Warning,
    Error,
    Fatal
};

// 输出风格
enum
{
    Screen = 10,
    OneFile,
    ClassFile
};

// 日志级别的字符串输出
std::string LevelToString(int level)
{
    switch (level)
    {
    case Debug:
        return "Debug";
    case Info:
        return "Info";
    case Warning:
        return "Warning";
    case Error:
        return "Error";
    case Fatal:
        return "Fatal";
    default:
        return "Unknown";
    }
}

// 获取当前时间戳并转换为本地时间
std::string TimeStampToLocalTime()
{
    time_t curtime = time(nullptr);
    struct tm *cur = localtime(&curtime);
    char time_buffer[128];
    snprintf(time_buffer, sizeof(time_buffer), "%d/%d/%d %d:%d:%d",
             cur->tm_year + 1900, cur->tm_mon + 1, cur->tm_mday,
             cur->tm_hour, cur->tm_min, cur->tm_sec);
    return time_buffer;
}

const int default_Style = Screen;
const std::string default_filename = "log.";
const std::string default_logdir = "log"; // 文件的默认存储路径

class Log
{
public:
    Log()
        : _style(default_Style),
          _filename(default_filename)
    {
        mkdir(default_logdir.c_str(), 0775);
    }

    // 更改输出风格
    void ChangeStyle(int style)
    {
        _style = style;
    }

    // 输出消息到单个文件
    void WriteLogToOneFile(const std::string &logname, const std::string &message)
    {
        umask(0);
        int fd = open(logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666);
        if (fd < 0)
            return;
        write(fd, message.c_str(), message.size());
        close(fd);
    }

    // 输出消息到多类文件
    void WriteLogToClassFile(const std::string &levelstr, const std::string &message)
    {
        std::string logname = default_logdir;
        logname += "/";
        logname += _filename;
        logname += levelstr;
        WriteLogToOneFile(logname, message);
    }

    void WriteLog(const std::string &levelstr, const std::string &message)
    {
        switch (_style)
        {
        case Screen:
            std::cout << message << std::endl;
            break;
        case OneFile:
            WriteLogToOneFile("all", message);
            break;
        case ClassFile:
            WriteLogToClassFile(levelstr, message);
            break;
        default:
            break;
        }
    }

    void LogMessage(int level, const char *format, ...)
    {
        char leftbuffer[1024];
        std::string levelstr = LevelToString(level);
        std::string curtime = TimeStampToLocalTime();
        std::string pid = std::to_string(getpid());
        snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%s][%s]  ",
            levelstr.c_str(),curtime.c_str(),pid.c_str());
        
        char rightbuffer[1024];
        va_list args;   //用于访问可变参数列表
        va_start(args, format); //使用 va_start 宏初始化 args,使其指向 format 后面的第一个可变参数
        // args 指向了可变参数部分
        vsnprintf(rightbuffer,sizeof(rightbuffer),format,args);//使用 vsnprintf 函数将可变参数列表按照 format 格式化后的字符串写入 rightbuffer,同时限制写入的字符数不超过 rightbuffer 的大小
        va_end(args);   //args = nullptr;

        std::string loginfo = leftbuffer;
        loginfo += rightbuffer;
        WriteLog(levelstr, loginfo);
    }

    ~Log()
    {}
private:
    int _style;            // 输出风格
    std::string _filename; // 文件名称
};

Main.cc如下:

#include "Log.hpp"

int main()
{
    Log lg;
    // lg.ChangeStyle(Screen);
    lg.ChangeStyle(ClassFile);
    lg.LogMessage(Debug, "this is a log message: %d, %lf\n", 123, 3.14);
    lg.LogMessage(Info, "this is a log message: %d, %lf\n", 123, 3.14);
    lg.LogMessage(Warning, "this is a log message: %d, %lf\n", 123, 3.14);
    lg.LogMessage(Error, "this is a log message: %d, %lf\n", 123, 3.14);
    lg.LogMessage(Fatal, "this is a log message: %d, %lf\n", 123, 3.14);
    lg.LogMessage(Debug, "this is a log message: %d, %lf\n", 123, 3.14);
    lg.LogMessage(Info, "this is a log message: %d, %lf\n", 123, 3.14);
    lg.LogMessage(Warning, "this is a log message: %d, %lf\n", 123, 3.14);
    lg.LogMessage(Error, "this is a log message: %d, %lf\n", 123, 3.14);
    lg.LogMessage(Fatal, "this is a log message: %d, %lf\n", 123, 3.14);
    lg.LogMessage(Debug, "this is a log message: %d, %lf\n", 123, 3.14);
    lg.LogMessage(Info, "this is a log message: %d, %lf\n", 123, 3.14);
    lg.LogMessage(Warning, "this is a log message: %d, %lf\n", 123, 3.14);
    lg.LogMessage(Error, "this is a log message: %d, %lf\n", 123, 3.14);
    lg.LogMessage(Fatal, "this is a log message: %d, %lf\n", 123, 3.14);
    return 0;
}

虽然C++标准库可以用来实现基本的日志记录功能,但如果需要一个更完整、功能更强大的日志系统,通常会选择使用专门的日志库,如spdlog、Log4cpp、Boost.Log等。这些库提供了更高级的日志管理功能,包括日志级别控制、异步日志记录、日志回滚等

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

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

相关文章

2024年西安铁一中集训DAY1---- 杂题选讲

文章目录 牛客练习赛125 E 联谊活动&#xff08;枚举&#xff0c;分讨&#xff09;牛客练习赛125 F 玻璃弹珠&#xff08;类莫队&#xff0c;离线询问&#xff0c;数据结构&#xff09;2024ccpc长春邀请赛 D Parallel Lines&#xff08;随机化&#xff09;2024ccpc长春邀请赛 E…

Java高级重点知识点-24-函数式接口

文章目录 函数式接口函数式编程常用函数式接口 函数式接口 有且仅有一个抽象方法的接口。 格式&#xff1a; 修饰符 interface 接口名称 {public abstract 返回值类型 方法名称(可选参数信息);// 其他非抽象方法内容 }public interface MyFunctionalInterface {void myMethod…

二进制补码计算

基本知识 原码&#xff08;Sign and Magnitude&#xff09;:原码是一种最简单的表示法&#xff0c;使用符号位和数值位来表示整数。 符号位&#xff1a;最高位是符号位&#xff0c;0表示正数&#xff0c;1表示负数。 数值位&#xff1a;剩下的位表示数值的大小。反码&#xf…

2串锂电池5V升压15V 18V 2.5A 升压恒压IC H6391芯片 低待机功耗

H6391是一款升压恒压转换器芯片&#xff0c;适用于多种需要2.6-5V输入升压至较高电压的应用场景。但值得注意的是&#xff0c;在您提供的描述中提到输出可调达。 输出电压范围&#xff1a;H6391的直接输出电压可能无法直接达到15V或18V。 输出电流&#xff1a;H6391支持的可调…

Python类与对象01

1、理解使用对象完成数据组织的思路 1.1类和对象的基本理解 理解类&#xff1a;从现实世界到编程世界 类由三个部分组成&#xff1a;类名、类的属性、类的方法。类的定义实际上是描述事物的一种方法&#xff0c;在现实世界中&#xff0c;事物都是有属性和行为的。通过类&…

机器学习 | 对K-Means聚类假设的研究演示及实践示例

我们在Scikit-learn对K-means假设的调查中探索了揭示算法优势和局限性的场景。我们研究了K-means对不正确的聚类大小的敏感性&#xff0c;它在各向异性分布中面临的困难&#xff0c;它在不同的聚类方差中面临的困难&#xff0c;以及使用合成数据集的大小不均匀的聚类问题。我们…

2024.7.11作业

1.使用递归实现 求 n 的 k 次方 #include <stdio.h> int digui(int n,int k) { if(k0) //任何数的0次方等于1 { return 1; } else { return n*digui(n,k-1); //递归 } } int main(int argc,const char *argv[]) { in…

龙旗科技在线测评、招聘笔试 如何通过、考点分析|备考建议

龙旗电子入职在线测验真题考点分析&#xff0c;通过技巧&#xff1f; ​言语逻辑部分的考试时间是10分钟&#xff0c;需要完成10道题目。每题的作答时间被限定为60秒&#xff0c;一旦提交后无法返回修改。这部分的题目类型包括总结中心思想、选词填空和推理文章意思。考生需要快…

大模型真能模拟人类语言?中国人民大学提出新的数据增强方法

获取本文论文原文PDF&#xff0c;请在公众号【AI论文解读】留言&#xff1a;论文解读 论文标题:LLM-Generated Natural Language Meets Scaling Laws: New Explorations and Data Augmentation Methods 机构: School of Information Resource Management, Renmin University …

springboot定制化书籍销售系统-计算机毕业设计源码71193

摘要 随着电子商务的快速发展和图书市场的不断变革&#xff0c;定制化书籍销售系统的需求日益凸显。本文介绍了一种基于SpringBoot框架的定制化书籍销售系统的设计与实现。该系统旨在满足用户对于个性化、专业化的书籍需求&#xff0c;为用户提供高效、便捷的定制化购书体验。 …

C# HuaYun出口服务器

直连 串口转网口&#xff1a;通过请求帧写入波特率 或者地址位 或者温度 湿度等数据 读取时候 [0x01,0x03] 写入的时候[0x01&#xff0c;0x03] 写入波特率的时候请求帧 [0x01,0x06,0x07,0xD1,0x01,0x14] 把波特率改成0x01,0x14 namespace _01_HuaYun出口服务器 {public partia…

如何监控别人的聊天记录?三种监控聊天记录的方式,千万别让老板看见

监控别人的聊天记录&#xff0c;无论是出于父母对子女的关心、企业管理层对员工的监管&#xff0c;还是其他目的&#xff0c;都必须在法律许可的范围内进行&#xff0c;并且通常需要获得被监控者的明确同意。 非法监控他人的通信记录是严重侵犯隐私权的行为&#xff0c;违反了…

《昇思25天学习打卡营第18天|onereal》

RNN实现情感分类 概述 情感分类是自然语言处理中的经典任务&#xff0c;是典型的分类问题。本节使用MindSpore实现一个基于RNN网络的情感分类模型&#xff0c;实现如下的效果&#xff1a; 输入: This film is terrible 正确标签: Negative 预测标签: Negative输入: This film…

pdf压缩文件怎么压缩到小于10M或5m 且文件质量不影响画质清晰度

在数字化办公和学习中&#xff0c;pdf格式因其良好的兼容性和稳定性而受到广泛应用。然而&#xff0c;pdf文件体积较大时&#xff0c;会给我们带来传输和存储上的困扰。本文将为您介绍几种简单有效的方法&#xff0c;帮助您轻松压缩pdf文件&#xff0c;提高传输效率&#xff0c…

掉打面试官之Java的SPI机制理解

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰…

鸿蒙开发:Universal Keystore Kit(密钥管理服务)【HMAC(ArkTS)】

HMAC(ArkTS) HMAC是密钥相关的哈希运算消息认证码&#xff08;Hash-based Message Authentication Code&#xff09;&#xff0c;是一种基于Hash函数和密钥进行消息认证的方法。 开发步骤 生成密钥 指定密钥别名。初始化密钥属性集。调用[generateKeyItem]生成密钥&#xf…

武夷山细节决定成败抓质量求生存

在当今竞争激烈的市场环境中&#xff0c;细节决定成败&#xff0c;质量求生存的理念已成为企业发展的关键。蓝鹏测控科技有限公司&#xff0c;一家专业从事工业测量领域的高新技术企业&#xff0c;正是秉持这一理念&#xff0c;在工业测径仪领域取得了显著成就。 蓝鹏测控科技…

tensorflow卷积层操作

全连接NN&#xff1a; 每个神经元与前后相邻层的每一个神经元都有全连接关系。输入是特征&#xff0c;输出为预测结果。 参数个数(前层*后层后层&#xff09; 实际应用时&#xff0c;会先对原始图像进行特征提取&#xff0c;再把提取到的特征送给全连接网络 会先进行若干层提…

复杂度(上卷)

前言 在正式进入今天的主题之前&#xff0c;我们不妨先来回顾一下初步学习数据结构后必须知道的概念。&#x1f3b6; 数据结构 数据结构是计算机存储、组织数据的方式&#xff0c;指相互间存在一种或多种特定关系的数据元素的集合。 &#xff08;没有一种单一的数据结构能够…

在centos7中安装MySQL5.7,是否必须卸载centos7自带的mariadb?

在CentOS 7 中安装 MySQL 5.7 时&#xff0c;不一定必须卸载系统自带的 MariaDB&#xff0c;但为了避免冲突和确保 MySQL 的正常运行&#xff0c;通常建议先卸载 MariaDB。以下是具体的步骤&#xff1a; 卸载 MariaDB&#xff08;如果已经安装&#xff09;&#xff1a; sudo sy…