前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >【Linux】日志插件

【Linux】日志插件

作者头像
s-little-monster
发布2025-03-11 08:41:38
发布2025-03-11 08:41:38
3600
代码可运行
举报
运行总次数:0
代码可运行

一、日志文件的重要性

故障排查与问题定位 快速发现问题:日志能够实时记录系统运行过程中的各种事件和状态信息,当系统出现故障或异常时,通过查看日志可以快速察觉到问题的发生,例如,服务器突然崩溃,日志中可能会记录下崩溃前的错误信息、异常堆栈,帮助运维人员第一时间得知系统出现了故障

精准定位根源:详细的日志可以提供问题发生时的上下文信息,如函数调用顺序、变量值等,以数据库连接失败为例,日志可能会记录下数据库的连接地址、端口、用户名、密码验证情况等,帮助开发人员精准定位是配置问题、网络问题还是数据库本身的问题

系统监控与性能分析 监控系统状态:通过对日志的实时分析,可以监控系统的运行状态,例如,记录系统的 CPU 使用率、内存占用情况、网络流量等信息,一旦这些指标超出正常范围,日志会及时反映出来,以便管理员采取相应的措施,如增加服务器资源、优化代码等

性能瓶颈分析:日志可以记录每个操作的执行时间,通过对这些时间数据的分析,可以找出系统的性能瓶颈,比如,在一个 Web 应用中,通过日志可以发现某个 API 接口的响应时间过长,进而对该接口的代码进行优化,提高系统的整体性能

安全审计与合规性 安全事件追踪:日志能够记录用户的操作行为,包括登录、数据访问、权限变更等,当发生安全事件,如数据泄露、非法登录时,可以通过查看日志追踪事件的源头和过程,确定是否存在内部人员违规操作或外部攻击

满足合规要求:许多行业和地区都有相关的法规和标准要求企业对系统操作和数据进行记录和审计,例如,金融行业的 PCI-DSS 标准、医疗行业的 HIPAA 法规等,详细的日志记录可以帮助企业满足这些合规要求,避免因违规而面临的法律风险

二、日志文件的简单实现

1、comm.hpp

comm.hpp用来建立信道,Init类用于建立命名管道和退出时自动销毁命名管道

代码语言:javascript
代码运行次数:0
复制
#pragma once

#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
//命名管道文件路径
#define FIFO_FILE "./myfifo"
//文件权限
#define MODE 0664
//枚举命名管道错误
enum
{
    FIFO_CREATE_ERR = 1,
    FIFO_DELETE_ERR,
    FIFO_OPEN_ERR
};

class Init
{
public:
    Init()
    {
        // 创建命名管道
        int n = mkfifo(FIFO_FILE, MODE);
        if (n == -1)
        {
            perror("mkfifo");
            exit(FIFO_CREATE_ERR);
        }
    }
    ~Init()
    {
		//销毁命名管道
        int m = unlink(FIFO_FILE);
        if (m == -1)
        {
            perror("unlink");
            exit(FIFO_DELETE_ERR);
        }
    }
};

2、log.hpp

log.hpp中存放的是日志真正的实现,将来我们可以在写代码的过程中使用这个文件来打印错误信息到日志上

代码语言:javascript
代码运行次数:0
复制
#pragma once

#include <iostream>
#include <time.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.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 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 &logname, const std::string &logtxt)
    {
    	//将路径与文件名称结合起来就可以用open打开文件
        std::string _logname = path + logname;
        int fd = open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666); 
        if (fd < 0)
            return;
            //将日志信息logtxt写到文件当中
        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()
    {
    }
    //运算符重载,可变参数列表
    void operator()(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);
		//va_list用于处理可变参数列表
        va_list s;
        //初始化s,使其指向可变参数列表第一个参数,format是可变参数列表前面那个参数
        va_start(s, format);
        char rightbuffer[SIZE];
        //将可变参数按照format字符串的格式写入rightbuffer中
        vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);
        //结束对可变参数列表的访问
        va_end(s);

        // 格式:默认部分+自定义部分
        //定义一个数组logtxt,用于存储完整的日志信息
        char logtxt[SIZE * 2];
        //将日志左侧部分也就是时间戳与等级部分(默认部分)
        //和右侧部分也就是自定义部分组合成一条完整的日志信息
        snprintf(logtxt, sizeof(logtxt), "%s %s\n", leftbuffer, rightbuffer);
        //将日志信息输出
        printLog(level, logtxt);
    }

private:
    int printMethod;//打印模式
    std::string path;//路径
};

三、测试用例

代码语言:javascript
代码运行次数:0
复制
#include "log.hpp"
#include <cstdlib>
#include <unistd.h>

int main()
{
    Log log;
    int cnt = 10;
    log.Enable(Onefile);
    while (cnt--)
    {
        log.printOneFile("log","i am super little monster\n");
        
        log.printClassFile(0,"this is 1\n");
        log.printClassFile(1,"this is 2\n");
        log.printClassFile(2,"this is 3\n");
        log.printClassFile(3,"this is 4\n");
        log.printClassFile(4,"this is 5\n");

    }
    return 0;
}

今日分享就到这里了~

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-03-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、日志文件的重要性
  • 二、日志文件的简单实现
    • 1、comm.hpp
    • 2、log.hpp
  • 三、测试用例
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档