一、前言
用户:“那谁,你的程序出问题了,来看看。”。
你:“问题是怎么出现的”。(为了复现)
用户:“我也不知道,就这样点点点就出问题了。”。
你:“。。。”。
这个时候,日志文件的重要性就凸显出来了。
别指望用户能描述清楚问题出现的经过,最靠谱的还是看日志文件。
二、多说两句
2.1、日志文件是分等级的。一般为:调试、警告、错误。
调试级别是在程序开发阶段打的,信息内容啰哩啰嗦,好吧,是很详细,基本记录了程序内部各接口的调用顺序,重要数据值。
警告级别一般是记录一些不重要的错误提示,这些错误不致命(重启程序后,它又活了),或当时不影响使用,过后就不敢保证程序死不死。
错误级别一般打印的是bug!!!对,就是bug。是由程序本身设计缺陷导致的问题。
在软件打包发布时,一般会把日志级别调到警告。这样,调试信息就不会记录到文件。一是记录的东西多了,怕硬盘占满。试想一个运行了一个月的服务器,他的调试记录得有多少个G,怕整个硬盘都要记满吧。二是软件都到发布阶段了,一般的问题都解决了,调试信息都不怎么重要了。
2.2、日志文件应该有专门的目录
写日志时应该为日志文件创建一个目录,存放所有日志文件。使用到的函数:
//判断路径是否存在
PathIsDirectory(char* path);
//创建文件夹,第二个参数是文件夹属性,null,使用默认属性。
CreateDirectory(char* path, nullptr);
2.3 日志文件名最好体现出日期
特别是服务器,连续运行几个月是标配。如果所有日志信息写在一个文件夹里,嘿嘿,几十万行的信息,头都会大。还有就是,若2018/8/26程序崩了,就能通过文件名中的日期信息直接定位到某个文件。
创建文件名我使用fstream::open
string sday = getTimeForDay(); //这是我写的一个功能函数,返回2018826
m_file.open(LOG_DIR + string("\\") + sday + ".txt", fstream::out | fstream::app);
m_day = sday; //记录文件创建日期,想想程序运行到第二天,
//就可以通过它创建新的文件了
2.4 日志文件写入方便
最好是能这样写入,log(“小编是一个傻逼, ID:%d”, 666);
这类似与sprintf(char* buff, char* fmt, …)
我就要参照它了,在vs中右键sprintf(),看它的实现代码,就可以移植了。
void log(char* fmt, ...)
{
char buffer[1024] = {0};
va_list args;
va_start(args, fmt);
vsprintf_s(buffer, fmt, args);
va_end(args);
//buferr就是你的菜
}
三、撸代码
撸啊撸啊撸代码_
FileLog.h
#pragma once
#include <string>
#include <fstream>
using namespace std;
class FileLog
{
public:
enum eLevel { INFO, WARN, ERROR };
FileLog();
~FileLog();
void setLevel(eLevel lvl);
inline void log(eLevel lvl, const char* fmt, ...);
private:
void createDir();
void openFile();
void closeFile();
private:
eLevel m_level;
fstream m_file; //文件句柄
string m_day; //日志记录日期
string m_levelText[3]; //等级文本信息
};
FileLog.cpp
#include "FileLog.h"
#include <shlwapi.h>
#include "../function/Time.h"
#pragma comment(lib, "shlwapi.lib")
#define LOG_LEN 1024 //单条日志长度限制
#define LOG_DIR "Log" //日志目录
FileLog::FileLog()
: m_day("")
, m_level(FileLog::INFO)
{
m_levelText[0] = "<INFO>";
m_levelText[1] = "<WARN>";
m_levelText[2] = "<ERR >";
createDir();
}
FileLog::~FileLog()
{
closeFile();
}
void FileLog::setLevel(eLevel lvl)
{
m_level = lvl;
}
void FileLog::log(eLevel lvl, const char* fmt, ...)
{
if (lvl >= m_level)
{
if (getTimeForDay() != m_day)
{
openFile();
}
char buffer[LOG_LEN] = { 0 };
va_list args;
va_start(args, fmt);
vsprintf_s(buffer, fmt, args);
va_end(args);
m_file << m_levelText[lvl] << getTimeForMs() << " " << buffer << endl;
}
}
void FileLog::createDir()
{
if (!PathIsDirectory(LOG_DIR))
{
CreateDirectory(LOG_DIR, nullptr);
}
}
void FileLog::openFile()
{
closeFile();
string sday = getTimeForDay();
m_file.open(LOG_DIR + string("\\") + sday + ".txt", fstream::out | fstream::app);
m_day = sday;
}
void FileLog::closeFile()
{
if (m_file.is_open())
{
m_file.close();
}
}
积累生活的点点滴滴,不为你看到,只怕突然回忆。