##一 摘要
我们在开发一个项目时,尤其在写后台程序时,程序运行过程中发生的各种错误信息都要做监控并及时的错误信息输出,方便我们通过日志来定位到错误出现的地方.及时优化,祛除错误.
那么日志打印语句应该输出哪些信息呢?
##二 日志信息内容
###1. 对于错误、异常情况
应尽量记录尽可能多的“上下文环境”信息.
###2. 函数调用失败信息
如果是函数调用失败,日志中必须包含返回值信息、以及函数调用的相关参数信息。
###3. 错误时场景信息
任何程序在返回错误码前,一定要通过日志记录具体的错误原因,并给出尽量多的场景信息。
##三 日志信息分级
日志信息,也是有分类了,也分轻重缓急,重要,不要之分,这对我们程序出了问题,通过日志来定位问题非常重要.那么等级分哪些呢?
之前写程序时,一般把日志等级分为4个等级:
1.LOG_LEVEL_ERR 错误
2.LOG_LEVEL_WRN 警告
3.LOG_LEVEL_INF 信息
LOG_LEVEL_DBG 调试
typedef enum
{
LOG_LEVEL_ERR,//错误
LOG_LEVEL_WRN,//警告
LOG_LEVEL_INF,//信息
LOG_LEVEL_DBG//调试
}E_LOG_LEVEL;
####LOG_LEVEL_ERR
该错误发生后程序仍然可以运行,但是极有可能运行在某种非正常的状态下,导致无法完成全部既定的功能。
####LOG_LEVEL_WRN
警告信息,表明程序处理中遇到非法数据或者某种可能的错误,该错误是一过性的、可恢复的,不会影响程序继续运行,程序仍处在正常状态。
####LOG_LEVEL_INF
LOG_LEVEL_INF的主要使用目的报告程序进度和转态信息。一般这种信息都是一过性的,不会大量反复输出。例如:连接商用库成功后,可以打印一条连库成功的信息,便于跟踪程序进展信息。
该级别日志,默认情况下会同时打印到终端和归档到日志文件(下同)。
####LOG_LEVEL_DBG
DEUG的主要使用目的是终端查看和在线调试。
该级别日志,默认情况下会打印到终端输出,但是不会归档到日志文件。因此,一般用于开发者在程序当前启动窗口上,查看日志流水信息。
##具体实现
####Logger.h
#ifndef LOGGER_H
#define LOGGER_H
typedef enum
{
LOG_LEVEL_ERR,
LOG_LEVEL_WRN,
LOG_LEVEL_INF,
LOG_LEVEL_DBG
}E_LOG_LEVEL;
#define LOG_ERR(X,...) Logger::Instance()->WriteLog(__FILE__, __func__, __LINE__, LOG_LEVEL_ERR, X, ##__VA_ARGS__)
#define LOG_WRN(X,...) Logger::Instance()->WriteLog(__FILE__, __func__, __LINE__, LOG_LEVEL_ERR, X, ##__VA_ARGS__)
#define LOG_INF(X,...) Logger::Instance()->WriteLog(__FILE__, __func__, __LINE__, LOG_LEVEL_INF, X, ##__VA_ARGS__)
#define LOG_DBG(X,...) Logger::Instance()->WriteLog(__FILE__, __func__, __LINE__, LOG_LEVEL_DBG, X, ##__VA_ARGS__)
class Logger
{
public:
~Logger();
static Logger* Instance();
void WriteLog(const char* fileNamePtr, const char* funcNamePtr,
int lineNum, E_LOG_LEVEL level, const char* format, ...);
private:
Logger();
private:
static Logger *m_loggerPtr;
char *m_buffPtr;
QString m_logFilename;
QFile m_logFile;
};
#endif // LOGGER_H
####Logger.cpp
#include <iostream>
#include <QString>
#include <QDateTime>
#include <stdio.h>
#include "Logger.h"
#define LOG_BUFF_SIZE 4096
Logger *Logger::m_loggerPtr = NULL;
Logger::Logger()
{
m_buffPtr = new char[LOG_BUFF_SIZE];
#ifdef Q_OS_WIN32
m_logFilename = "F:/log.txt";
#else
m_logFilename = "/DCM/parking/log.txt";
#endif
m_logFile.setFileName(m_logFilename);
// m_logFile.open(QIODevice::Append|QIODevice::WriteOnly);
}
Logger::~Logger()
{
delete [] m_buffPtr;
}
Logger* Logger::Instance()
{
if(NULL == m_loggerPtr)
{
m_loggerPtr = new Logger();
}
return m_loggerPtr;
}
void Logger::WriteLog(const char* fileNamePtr, const char* funcNamePtr,
int lineNum, E_LOG_LEVEL level, const char* format, ...)
{
QString logLevelStr;
switch(level)
{
case LOG_LEVEL_ERR:
logLevelStr.append("ERR");
break;
case LOG_LEVEL_WRN:
logLevelStr.append("WRN");
break;
case LOG_LEVEL_INF:
logLevelStr.append("INF");
break;
case LOG_LEVEL_DBG:
logLevelStr.append("DBG");
break;
default:
logLevelStr.append("DBG");
}
QDateTime dateTime = QDateTime::currentDateTime();
QString dateTimeStr = dateTime.toString("yyyy/MM/dd hh:mm:ss:zzz");
/* 组调试信息头 */
int logLength = sprintf(m_buffPtr, "[%s][%s][%s]: [%s] ",
dateTimeStr.toUtf8().data(),fileNamePtr, funcNamePtr,logLevelStr.toUtf8().data());
va_list valst;
va_start(valst, format);
logLength += vsprintf(&m_buffPtr[logLength], format, valst);
m_buffPtr[logLength] = 0x00;
printf("%s", m_buffPtr);
/* log to file */
va_end(valst);
m_logFile.open(QIODevice::Append|QIODevice::WriteOnly);
m_logFile.write(m_buffPtr);
m_logFile.flush();
m_logFile.close();
/* log to terminal, add color */
}
/* END OF FILE */