日志信息
日志:日志时间+日志等级+日志内容+文件的名称和代号
日志等级示范:Info:常规消息
Warning:报警信息
Error:必要严重了,可能要立即处理
Fatal:致命的
Debug:调试
日志时间获取
cpp
time_t t= time(nullptr);// 获取时间戳
struct tm* ctime=localtime(&t);// 将时间戳转换为年月日
//tm是个结构体,里面保存时间戳转换的年月日
//打印时间
printf("[%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)
注意点:
tm->year是从1900年开始算所以要加上1900,月份从0开始算tm_mon+1
levetToString是将int转换成string类型
日志等级处理
defin 信息的值,再转变成%s方便打印
cpp
#define Info 0
#define Debug 1
#define Warning 2
#define Error 3
#define Fatal 4
#define Size 1024
std::string levelToString(int level)
{
switch(level)
{
case Info:return "Info";
case Debug: return "Debug";
case Warning: return "Debug";
case Error: return "Debug";
case Fatal: return "Debug";
default: return "None";
}
}
处理可变参数
cpp
//n 表示前两个参数,当参数数量大于n时,只算从左到右的两个,参数从右往左压栈
int sum(int n,...)
{
va_list s;//char* 类型指针帮助我们找到可变类型参数
va_start(s,n); //让 s指向n的地址 s=&n+1
//va_start是宏
// 可变参数至少有一个具体的实参、
int sum=0;
while(n)
{
sum+=va_arg(s,int);//s指向的可变参数类型,int表示参数类型 ,每次返回一个值
n--;
}
va_end(s);//使得s为nullptr
return sum;
}
视解图
s=&n+1// 可变参数需要一个实参来确定位置,参数压栈是从左往右的
消息函数代码实现
cpp
// level表示等级,format表示格式,...表示日志等级
void logmessage(int level,char* format, ...)
{
char leftbuffer[Size];
time_t t= time(nullptr);// 获取时间戳
struct tm* ctime=localtime(&t);// 将时间戳转换为年月日
//snpritf,后面的参数和printf类似,按某种格式输出参数,前面是输出位置,输入到数组leftbuffer中
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 s;// va_list就是封装的char*
va_start(s,format);//s=&format+1
char rightbuffer[Size];
//vsnprinft,用来处理可变参数,后面的参数和printf类似,按某种格式输出参数,前面是输出位置,输入到数组righttbuffer中
vsnprintf(rightbuffer,sizeof(rightbuffer),format,s);//传入一个s指向第一个可变参数的指针
// 默认部分+自定义部分
char logtxt[Size*2];
//拼接字符串
snprintf(logtxt,sizeof(logtxt),"%s %s\n",leftbuffer,rightbuffer);
printf("%s",logtxt);
}
运用示例:代替perror
日志输入到文件
cpp
class Log
{
public:
Log()
{
printMethod=Screen;
path="./log/";
}
void Enable(int method)
{
printMethod=method;
}
std::string levelToString(int level)
{
......
}
void logmessage(int level,char* format, ...)
{
......
printLog(level,logtxt);
}
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)
{
std::string _logname=path+logname;
//打开创建文件
int fd=open(_logname.c_str(), O_WRONLY|O_CREAT|O_APPEND,0666);
if(fd<0) return ;
write(fd,logtxt.c_str(),logtxt.size());
close(fd);
}
void printClassFile(int level,const std::string &logtxt)
{
//将Warning/Fatal等分开
std::string filename = LogFile;
filename+=".";
filename+=levelToString(level); //"log.txt.Debug/Warning/Fatal"
printOneFile(filename,logtxt);
}
~Log()
{}
private:
int printMethod; //确定输出位置
std::string path; //输出地址
};