日志介绍
- 运行日志:记录程序的运行过程,将关键一些信息或步骤记录下来,方便日后问题的定位或审计
- 日志级别:
DEBUG: 调试日志
INFO: 详细日志
WARNING: 警告日志
ERROR: 错误日志
FATAL: 致命错误日志 - 日志的信息:
时间 [模块] [文件名] [函数名] [行号] [线程id] [日志级别] 具体的信息
2022-06-22 17:01:16 [filename:main.c] [funcname:main] [line:36] [tid: 15263] [INFO] 程序已开始运行… - 日志打印的注意:
(1)日志中不能出现绝对路径
(2)日志中不能出现敏感信息,session, token, 密码,证书等
(3)日志应该有转储机制(比如:日志文件数量的限制,单个文件大小的限制(10M)
一、手动实现日志模块
主要涉及的技术点: IO流处理,多线程,单例模式,可变长形参
- 头文件代码:RunLog.h
#ifndef LOGPROJECT_RUNLOG_H
#define LOGPROJECT_RUNLOG_H
/**
* 日志模块:
* (1)支持两种打印日志的方式(函数内部已实现换行,写日志时不用添加换行)
* LOG_INFO("程序正在运行...");
* LOG_ERROR("连接数据库失败,错误码为:%d, 错误原因为:%s", 10060, "用户名或密码不正确");
* (2)最多支持10个日志文件,每一个日志文件最大50M
* (3)支持多线程写入日志
*/
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
using namespace std;
class RunLog {
private:
// 日志对象单例
static RunLog *logIns;
RunLog();
~RunLog() = default;
RunLog(const RunLog &other) = delete;
RunLog &operator=(const RunLog &other) = delete;
public:
// 日志文件对象
static ofstream *logFileStream;
// 当前日志文件夹路径
static string logDirPath;
// 获取当前运行日志类的单例
static RunLog *getInstance();
// 写入日志到文件的主要函数
static void log(const char *filepath, const char *funcname, int line, const char *level, const char *msg, ...);
// 获取当前时间
static void getCurrentTime(char *currTime, size_t size, const char *format);
// 生成日志文件的完整路径
static void genFileName(const string &dirname, string &fullFileName);
// 获取日志目录下的所有日志文件
static void getFiles(const string &path, vector<string> &files, const char *fType);
// 检查文件日志大小,判断是否需要换文件操作
static void checkFileSize();
// 程序异常情况下,可以调用该方法释放资源
static void release();
};
// ##__VA_ARGS__ 接收不定长的参数
#define LOG_INFO(msg, ...) RunLog::log(__FILE__, __FUNCTION__, __LINE__, "INFO", msg, ##__VA_ARGS__)
#define LOG_ERROR(msg, ...) RunLog::log(__FILE__, __FUNCTION__, __LINE__, "ERROR", msg, ##__VA_ARGS__)
#define LOG_DEBUG(msg, ...) RunLog::log(__FILE__, __FUNCTION__, __LINE__, "DEBUG", msg, ##__VA_ARGS__)
#define LOG_WARNING(msg, ...) RunLog::log(__FILE__, __