C++ 没有貌似自带的日志类,如果仅仅使用cout输出调试信息的话比较凌乱,所以我尝试自己实现了一个Logger类,主要考虑实现以下功能:
- 日志等级: 参考python的logger类,我设置了四个日志等级, 从低到高依次为debug, info, warning, error,这样的话我想输出一条debug信息就可以这样写
logger.debug("something...")
, (关于日志等级是什么意思可以参考一下python的logger类,简单来说就是当日志等级大于等于设置的初始等级时才会记录日志) - 输出目标: 我设置了三种输出目标: 仅输出到终端、仅输出到文件、既输出到终端又输出到文件
为了方便的设置日志等级,可以用一个枚举类表示四种日志等级,同理用一个枚举类表示三种输出目标
enum log_level{debug, info, warning, error};// 日志等级
enum log_target{file, terminal, file_and_terminal};// 日志输出目标
为了更好地管理日志,我用一个类封装了日志工具,在构造函数中设定日志等级、输出目标、日志文件路径等,并提供DEBUG、INFO、WARNING、ERROR四个接口
对于日志内容还增加了一些前缀,比如使用__FILE__宏表示当前运行位置所在的文件,封装一个currTime()函数用以记录日志记录时间等
头文件:
# ifndef LOG_SYS_H
# define LOG_SYS_H
# include <iostream>
# include <fstream>
# include <string>
# include <time.h>
# include <stdio.h>
# include <stdlib.h>
using std::cout;
using std::string;
using std::endl;
using std::to_string;
using std::ios;
string currTime(){
// 获取当前时间,并规范表示,
// 这函数有点问题,有需要的话请自己改一下。。。
// char tmp[64];
// time_t ptime;
// time(&ptime); // time_t time (time_t* timer);
// strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", localtime(&ptime));
// return tmp;
return "2022-09-21 12:12:36\0"
}
class Logger{
public:
enum log_level{debug, info, warning, error};// 日志等级
enum log_target{file, terminal, file_and_terminal};// 日志输出目标
private:
std::ofstream outfile; // 将日志输出到文件的流对象
log_target target; // 日志输出目标
string path; // 日志文件路径
log_level level; // 日志等级
void output(string text, log_level act_level); // 输出行为
public:
Logger(); // 默认构造函数
Logger(log_target target, log_level level, string path);
void DEBUG(string text);
void INFO(string text);
void WARNING(string text);
void ERROR(string text);
};
# endif
cpp文件
# include "log_sys.h"
Logger::Logger(){
// 默认构造函数
this->target = terminal;
this->level = debug;
cout << "[WELCOME] " << __FILE__ << " " << currTime() << " : " << "=== Start logging ===" << endl;
}
Logger::Logger(log_target target, log_level level, string path){
this->target = target;
this->path = path;
this->level = level;
string tmp = ""; // 双引号下的常量不能直接相加,所以用一个string类型做转换
string welcome_dialog = tmp + "[Welcome] " + __FILE__ + " " + currTime() + " : " + "=== Start logging ===\n";
if (target != terminal){
this->outfile.open(path, ios::out | ios::app); // 打开输出文件
this->outfile << welcome_dialog;
}
if (target != file){
// 如果日志对象不是仅文件
cout << welcome_dialog;
}
}
void Logger::output(string text, log_level act_level){
string prefix;
if(act_level == debug) prefix = "[DEBUG] ";
else if(act_level == info) prefix = "[INFO] ";
else if(act_level == warning) prefix = "[WARNING] ";
else if(act_level == error) prefix = "[ERROR] ";
else prefix = "";
prefix += __FILE__;
prefix += " ";
string output_content = prefix + currTime() + " : " + text + "\n";
if(this->level <= act_level && this->target != file){
// 当前等级设定的等级才会显示在终端,且不能是只文件模式
cout << output_content;
}
if(this->target != terminal)
outfile << output_content;
}
void Logger::DEBUG(string text){
this->output(text, debug);
}
void Logger::INFO(string text){
this->output(text, info);
}
void Logger::WARNING(string text){
this->output(text, warning);
}
void Logger::ERROR(string text){
this->output(text, error);
}
测试
void logger_test(){
Logger logger(Logger::file_and_terminal, Logger::debug, "result.log");
logger.DEBUG("What happend?");
logger.INFO("This is good.");
logger.WARNING("Yes...");
logger.ERROR("IO Error!");
}