【Linux】日志

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

  • 时间戳:记录日志条目创建的确切时间。这对于追踪事件发生的时间顺序至关重要。
  • 日志级别:表示日志信息的严重性或重要性,常见的级别包括 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等。这些库提供了更高级的日志管理功能,包括日志级别控制、异步日志记录、日志回滚等

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

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

相关文章

RisingWave 用例:流式 ETL、实时分析、事件驱动应用

RisingWave 非常适合以下类别的用例。 流式 ETL实时分析事件驱动应用 流式 ETL 是实时分析和事件驱动应用的基础。实时分析通过引入数据看板&#xff0c;扩展了流式 ETL&#xff0c;而事件驱动应用则在实时分析的基础上增加了逻辑&#xff0c;以评估条件是否触发后续行动。 …

【测开能力提升-fastapi框架】fastapi模版引擎简单使用

1.6 通过模版引擎返回HTM页面 import uvicorn from fastapi import FastAPI, Request from fastapi.templating import Jinja2Templatesapp FastAPI()# 初始化模版引擎存放位置 templates Jinja2Templates(directory"templates")app.get("/") async def…

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

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

分布式应用系统设计:即时消息系统

即时消息(IM)系统&#xff0c;涉及&#xff1a;站内消息系统 组件如下&#xff1b; 客户端&#xff1a; WEB页面&#xff0c;IM桌面客户端。通过WebSocket 跟ChatService后端服务连接 Chat Service&#xff1a; 提供WebSocket接口&#xff0c;并保持跟“客户端”状态的维护。…

彻底解决找不到d3dcompiler_43.dll问题,总结几种有效的方法

运行软件时提示找不到d3dcompiler_43.dll无法继续执行代码&#xff0c;如何解决&#xff1f;解决这个问题的方法有很多&#xff0c;但具体问题需要具体分析&#xff0c;有些方法可能并不适用于解决d3dcompiler_43.dll的问题。因此&#xff0c;需要根据实际情况来选择合适的方法…

8627 数独

为了判断数独解是否合法&#xff0c;我们需要遵循以下步骤&#xff1a; 1. **检查每一行**&#xff1a;确保1到9每个数字在每一行中只出现一次。 2. **检查每一列**&#xff1a;确保1到9每个数字在每一列中只出现一次。 3. **检查每个3x3的宫**&#xff1a;确保1到9每个数字在…

模式物种葡萄基因组(T2T)--文献精读29

The complete reference genome for grapevine (Vitis vinifera L.) genetics and breeding 葡萄&#xff08;Vitis vinifera L.&#xff09;遗传学和育种的完整参考基因组 摘要 葡萄是全球最具经济重要性的作物之一。然而&#xff0c;以往版本的葡萄参考基因组通常由成千上万…

星辰考古:TiDB v4.0 进化前夜

前情回顾TiDB v4 时间线TiDB v4 新特性 TiDBTiKVPDTiFlashTiCDCTiDB v4 兼容性变化 TiDBTiKVPD其他TiDB 社区互助升级活动TiDB 3.0.20 升级到 4.0.16 注意事项升级速览直观变化总结素材来源&#x1f33b; 往期精彩 ▼ 前情回顾 在前面的章节中&#xff0c;我们共同梳理了 TiDB …

【刷题汇总 -- 最长回文子串、买卖股票的最好时机(一)、[NOIP2002 普及组] 过河卒】

C日常刷题积累 今日刷题汇总 - day0101、最长回文子串1.1、题目1.2、思路1.3、程序实现 2、买卖股票的最好时机(一)2.1、题目2.2、思路2.3、程序实现2.4、程序实现 -- 优化 3、[NOIP2002 普及组] 过河卒3.1、题目3.2、思路3.3、程序实现 -- dp 4、题目链接 今日刷题汇总 - day0…

一个便捷的web截图库~【送源码】

随着时间的发展&#xff0c;前端开发的范围越来越广&#xff0c;能够实现的功能也越来越多&#xff0c;要实现的功能也五花八门&#xff0c;今天就给大家介绍一个web截图库,让前端也能实现截图功能—— js-web-screen-shot js-web-screen-shot js-web-screen-shot 是一个基于 …

Linux服务器CPU占用率达到100%排查思路

1、找到最耗CPU的进程pid&#xff0c;执行命令 top 2、找到最耗CPU的线程tid // 执行 top -Hp [pid] 定位应用进程对应的线程 tid // 按shift p 组合键&#xff0c;按照CPU占用率排序 > top -Hp 14246 3、将线程pid转化为16进制 // printf "%x\n" [tid] 将tid…

Redis+Caffeine 实现两级缓存实战

RedisCaffeine 实现两级缓存 背景 ​ 事情的开始是这样的&#xff0c;前段时间接了个需求&#xff0c;给公司的商城官网提供一个查询预计送达时间的接口。接口很简单&#xff0c;根据请求传的城市仓库发货时间查询快递的预计送达时间。因为商城下单就会调用这个接口&#xff…

camunda最终章-springboot

1.实现并行流子流程 1.画图 2.创建实体 package com.jmj.camunda7test.subProcess.entity;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;import java.io.Serializable; import java.util.ArrayList; import java.util.List;Data …

ComfyUI+MuseV+MuseTalk图片数字人

电脑配置 GPU12G&#xff0c;如果自己电脑配置不够&#xff0c;选择云gpu&#xff0c;我就是用的这个&#xff0c;自己电脑太老配置跟不上 环境&#xff1a; Python 3.11.8 torch 2.2.1 cuda_12.1 资源提供&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1_idZbF…

开始Linux之路(暑假提升)

人生得一知己足矣&#xff0c;斯世当以同怀视之。——鲁迅 Linux操作系统简单操作指令 1、ls指令2、pwd命令3、cd指令4、mkdir指令(重要)5、whoami命令6、创建一个普通用户7、重新认识指令8、which指令9、alias命令10、touch指令11、rmdir指令 及 rm指令(重要)12、man指令(重要…

【视频】R语言广义加性模型GAMs非线性效应、比较分析草种耐寒性实验数据可视化

全文链接&#xff1a;https://tecdat.cn/?p36979 原文出处&#xff1a;拓端数据部落公众号 广义加法模型&#xff08;Generalized Additive Models, GAMs&#xff09;作为一种高度灵活的统计工具&#xff0c;显著扩展了广义线性模型&#xff08;Generalized Linear Models, …

C基础day9

一、思维导图 二、课后练习 1> 使用递归实现 求 n 的 k 次方 #include<myhead.h>int Pow(int n,int k) {if(k 0 ) //递归出口{return 1;}else{return n*Pow(n,k-1); //递归主体} }int main(int argc, const char *argv[]) {int n0,k0;printf("请输入n和k:&…

Python统计实战:时间序列分析之绘制观测值图和按年折叠图

为了解决特定问题而进行的学习是提高效率的最佳途径。这种方法能够使我们专注于最相关的知识和技能&#xff0c;从而更快地掌握解决问题所需的能力。 &#xff08;以下练习题来源于《统计学—基于Python》。请在Q群455547227下载原始数据。&#xff09; 练习题 下表是某地区2…

复杂度(上卷)

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

如何保证RocketMQ消息不丢失

rocket mq在生产阶段、Brocker存储阶段、消费阶段都会出现消息丢失。 1、生产者防止丢失消息。 a.同步阻塞的方式发送消息&#xff0c;加上失败重试机制&#xff0c;可能broker存储失败&#xff0c;可以通过查询确认 b.异步发送需要重写回调方法&#xff0c;检查发送结果 c…