我们平常自己在写项目的过程中,经常把程序运行的信息打印在控制台上,但是真正实际在工作过程中,特别是在一些已经运行起来的服务器上,我们不可能一直盯着控制台在那边查看程序的运行情况吧。
针对这样的情况,我们一般会将需要打印出来的信息写在一个文件里面,即使隔了很多天,我们依旧可以回过头来查看程序的运行状况,这就是日志的作用。
首先,我们要明确,日志是分等级的。有些事情很重要,比方说程序的运行发生错误,我们一般会把错误信息存进日志里面。但是频繁的IO操作是非常消耗程序性能的,所以我们一般把那些无关痛痒的事情设定为低等级的日志,这些信息我们可以不写进文档里面。
日志的等级划分并没有什么非常官方的规定,大家可以根据实际需要进行判断。
这里介绍一些比较常规的划分(级别从低到高)。
文件名:log.h:
#ifndef _LOG_H__
#define _LOG_H__
#include
#include
extern FILE* pLogFile;
int get_loglevel();
enum LOG_LEVEL{
ALL,
DEBUG,
WARN,
ERROR,
FATAL,
OFF
};
#define LOG_DEBUG(fmt, args...) if(get_loglevel()<=DEBUG){time_t t = time(NULL);fprintf(pLogFile,"%s [debug] %s,%s():%d,"fmt,ctime(&t), __FILE__, __func__, __LINE__, ##args);}
#define LOG_WARN(fmt, args...) if(get_loglevel()<=WARN){time_t t = time(NULL);fprintf(pLogFile,"%s [warn ] %s,%s():%d, "fmt,ctime(&t), __FILE__, __func__, __LINE__, ##args);}
#define LOG_ERROR(fmt, args...) if(get_loglevel()<=ERROR){time_t t = time(NULL);fprintf(pLogFile,"%s [error] %s,%s():%d, "fmt,ctime(&t), __FILE__, __func__, __LINE__, ##args);}
#define LOG_FATAL(fmt, args...) if(get_loglevel()<=FATAL){time_t t = time(NULL);fprintf(pLogFile,"%s [fatal] %s,%s():%d, "fmt,ctime(&t), __FILE__, __func__, __LINE__, ##args);}
#endif
这里面的知识点其实还是蛮多的。
在log.h中,对日志的等级进行了枚举,相当于对每一种情况赋值0~5。
这样的做法是为了在之后设定日志等级的时候,可以直接申明一个string log_level的值,凡是低于这个等级的信息,一律不用写进文件里面。
在之后的程序使用过程中,如果我们要打印某些信息,就可以直接调用这些宏函数,这些宏函数会先去调用get_loglevel()函数,获取我们设定的日志等级,决定是否要进行打印。
这里可能有一点难理解,我们慢慢来。
首先,我们会在某个文件中设置一下 FILE* pLogFile ,志向写日志的那个文件,这个文件指针一般在其他的文件中定义,这里只是进行调用。宏函数在调用 fprintf() 函数的时候,会找到这个文件指针,把文件写进去。
LOG_DEBUG(fmt, args…)中的参数有三个点,表示这是不定长的参数,这就是我们希望打印的程序里面的具体的数据,可以打印任意多。
fprintf(pLogFile,"%s [debug] %s,%s():%d,"fmt,ctime(&t)); 中:fmt代表着我们传进去的所有参数,到args为止。t是我们获取到的时间,这里要将它转化为C语言可以识别的时间类型。
##表示会将这些参数拼接为一个合法的字符串。
__FILE__及 __func__和 __LINE__分别代表当前所在文件、所在函数、第几行。这些信息将按照格式填入要打印的字符串中。
文件名log.cpp:
#include "log.h"
#include
#include
#include
using namespace std;
extern string log_level;
int get_loglevel(){
if(strcasecmp(log_level.c_str(),"all")==0){
return ALL;
}
if(strcasecmp(log_level.c_str(),"debug")==0){
return DEBUG;
}
if(strcasecmp(log_level.c_str(),"warn")==0){
return WARN;
}
if(strcasecmp(log_level.c_str(),"error")==0){
return ERROR;
}
if(strcasecmp(log_level.c_str(),"fatal")==0){
return FATAL;
}
return OFF;
}
strcasecmp()表示忽略大小写比较字符串。
如果在实际使用过程中,需要些日志,就可以通过以下代码对日志信息进行打印:
int main(){
FILE* pLogFile = fopen("log.txt", "w+");
string log_level;
a = 2020;
b = 3.14;
c = "lalala";
LOG_WARN("%d %f %s", a, b, c);
fclose(pLogFile);
return 0;
}