C++日志记录类

工作几年后,发现自己从来不写博客,不是一个好习惯。往往总结的东西不记录下来,下次再来用时,总感觉疲态百出。所以吧,是该总结总结一点东西了。进入正题吧!

很多程序员不太注重日志记录,其实不是一个好的习惯。有些人觉得用DebugViewer就可以查看一些打印信息了,写日志有什么用呢? 但是,当我们发布的产品给用户使用时,出现异常时如何处理呢?难道需要远程TeamViewer去用DebugViewer查看Debug?肯定不太可能吧?这个时候,如果让客服人员跟客户拿日志还是可以实现的,日志记录了客户的一些操作手法,帮助重现bug有很重要的作用。下面提供一套QT的日志记录类,有需要的可以直接拿去用!

CLogLockWiper.h头文件如下:

// 记录log信息的类.

#ifndef		_CLOGLOCKWIPER_H_
#define		_CLOGLOCKWIPER_H_

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

/// 日志管理类:
//
//
 定义为全局变量,支持多线程的记录
 用法:
 调用InitFolder初始化日志
 调用KeepDays备份或者清空nDay前的日志
 尽量保存7天的日志吧
//
//

class CLogLockWiper : public QObject
{
	 Q_OBJECT
public:
	CLogLockWiper();
	~CLogLockWiper();
	bool		InitFolder( const char* pszFileFolder, int nMaxFileSize=1024*500, const char* pszFileNamePrefix=NULL, const char* pszFileExt=".log");	/// 初始化日志
	QString		GetFileName(const char* szFileFolder, const char* szFileNamePrefix, const char* szTime, const char* szFileNameExt);						///  获取完整文件名
	QString		GetCurrDate();					/// 获取当前时间
	bool		WriteLog(QString strMsg);		/// 写入文件
	bool        Log(QString str);			/// 不带日期的记录
	bool        LogExt(QString str);			/// 带日期的记录
	void		Close();

	/// 注意:	InitFolder接口进行初始化,必须初始化文件前缀pszFileNamePrefix
	/// @param: nDays, 清空nDays之前的所有日志
	/// @param: szBackupFolder, 指定清空的日志的备份目录,为空表示不备份直接删除
	void		KeepDays(int nDays, QString szBackupFolder);
	/// 删除过期日志并备份
	bool		ClearLogFolder(QString szBackupFolder = QString(""));

public:

	QFile		m_File;
	QTextStream m_logTextStream;
	QMutex 		m_Mutex;
	QString		m_strFileFolder;			/// 文件夹名称
	QString		m_strFileNamePrefix;		/// 文件名
	QString		m_strFileNameExt;			/// 文件名后缀
	QString     m_strFileName;				/// 完成路径+文件名
	QString     m_strCreateDate;			/// 文件创建时间
	quint64		m_nMaxFileSize;				/// 写入的最大字节
	int 		m_nKeepDays;				/// 保留前多少天的日志
} ;

extern CLogLockWiper g_lockWiperLog;
#endif

CLogLockWiper.cpp如下:

/// 记录log信息的类.
#include "CLogLockWiper.h"

CLogLockWiper g_lockWiperLog;

CLogLockWiper::CLogLockWiper()
{
	m_strFileFolder = QString("");
	m_strFileNamePrefix = QString("");
	m_strFileNameExt = QString("");
	m_strFileName = QString("");
	m_strCreateDate = QString("");
	m_nMaxFileSize = 0;
	m_nKeepDays = 0;
}

CLogLockWiper::~CLogLockWiper()
{
	Close();
}

void CLogLockWiper::Close()
{
	bool hasOepned  = m_File.isOpen();
	if ( true == hasOepned )    
	{
		m_File.flush();
		m_File.close();
	}
}

void CLogLockWiper::KeepDays(int nDays, QString szBackupFolder)
{
	/// 没有文件前缀,无法实现功能
	if (m_strFileNamePrefix.isEmpty()) 
		return;

	if (0 > m_nKeepDays) 
		return;

	m_nKeepDays = nDays;

	if (0 == m_nKeepDays) return;

	LogExt(QString("Process KeepDays(%1), begin....").arg(m_nKeepDays));
	
	/// 判断目录是否存在,不存在就创建备份目录
	if (!szBackupFolder.isEmpty())
	{
		QDir dir(szBackupFolder);
		if (false == dir.exists())
		{
			dir.mkpath(szBackupFolder);
		}
	}

	ClearLogFolder(szBackupFolder);
	LogExt("Process KeepDays end.");
}

bool CLogLockWiper::ClearLogFolder(QString szBackupFolder)
{
	if (0 >= m_nKeepDays) 
		return false;

	QString strFile = m_strFileFolder;

	QDir dir(strFile);
	QDate curDate = QDate::currentDate();
	m_nKeepDays = - m_nKeepDays;
	QDate startCurDate = curDate.addDays(m_nKeepDays);
	//qDebug() << startCurDate.toString(QString("yyyy-MM-dd"));
	QStringList strFindNameList;
	strFindNameList.clear();

	foreach (QFileInfo fileInfo, dir.entryInfoList(QDir::Files))
	{
		QString strName = fileInfo.fileName();
		/// 如果是目录的话,不处理吧
		if (fileInfo.isDir() || strName == QString(".") || strName == QString(".."))		
		{
			continue;
		}
		/// 如果比文件名的长度小也不处理
		if (strName.size() < m_strFileNamePrefix.size() + m_strCreateDate.size())
				continue;
		
		/// 如果不是日志的格式文件不处理
		QString strFileStartDate = strName.mid(m_strFileNamePrefix.size() + QString("/").size(), m_strCreateDate.size());
		strFileStartDate.insert(6, "-");
		strFileStartDate.insert(4, "-");
		QDate fileDateTime = QDate::fromString(strFileStartDate, "yyyy-MM-dd");
		//qDebug() << fileDateTime.toString(QString("yyyy-MM-dd"));
		if (!fileDateTime.isValid())
			continue;

		if (fileDateTime < startCurDate)
		{
			strFindNameList.append(strName);
		}
	}
	
	QString strBackup(szBackupFolder);
	for (int i = 0; i < strFindNameList.size(); i++)
	{
		QString strBackOldPath = m_strFileFolder + QString("/");
		strBackOldPath += strFindNameList.at(i);
		bool bSuccess = false;
		if (strBackup.isEmpty())
		{
			bSuccess = QFile::remove(strBackOldPath);
			LogExt(QString("No Backup delete outdate file(%1):(%2)").arg(strFindNameList.at(i), bSuccess == true ? QString("true") : QString("false")));
		}
		else
		{
			bSuccess = QFile::copy(strBackOldPath, strBackup + "/" + strFindNameList.at(i));
			LogExt(QString("First Backup copy outdate file(%1):(%2)").arg(strFindNameList.at(i), bSuccess == true ? QString("true") : QString("false")));
			if (!bSuccess)
			{
				QString strBackupFile;
				strBackupFile = strFindNameList.at(i) + QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
				bSuccess = QFile::copy(strBackOldPath, strBackup + "/" + strBackupFile);
				LogExt(QString("Sencond Backup copy outdate file(%1):(%2)").arg(strFindNameList.at(i), bSuccess == true ? QString("true") : QString("false")));
				bSuccess = QFile::remove(strBackOldPath);
				LogExt(QString("Sencond Backup delete outdate file(%1):(%2)").arg(strFindNameList.at(i), bSuccess == true ? QString("true") : QString("false")));
			}
			else
			{
				bSuccess = QFile::remove(strBackOldPath);
				LogExt(QString("First Backup delete outdate file(%1):(%2)").arg(strFindNameList.at(i), bSuccess == true ? QString("true") : QString("false")));
			}
		}
	}

    return true;
}



bool CLogLockWiper::InitFolder(const char *pszFileFolder, int nMaxFileSize, const char *pszFileNamePrefix, const char *pszFileExt)
{
	if( pszFileFolder==NULL || strlen(pszFileFolder)<=0 )
		return false ;

	QString logPath = qApp->applicationDirPath() +"/" + QString(pszFileFolder);
    QDir dir(logPath);
	if (false == dir.exists())
	{
        dir.mkpath(logPath);    
	}
	
	m_Mutex.lock();
	m_strFileFolder = logPath;
	m_strFileNamePrefix = QString(pszFileNamePrefix);
	m_strFileNameExt = QString(pszFileExt);
	m_nMaxFileSize = nMaxFileSize > 1024 ? nMaxFileSize : 1024;
	m_strCreateDate = GetCurrDate();
	m_strFileName = m_strFileFolder + "/" + m_strFileNamePrefix + "_" + m_strCreateDate + m_strFileNameExt;
	m_Mutex.unlock();
	return true ;
}

bool CLogLockWiper::WriteLog(QString strMsg)
{
	m_File.setFileName(m_strFileName);
	bool openFlag = m_File.open(QIODevice::Text | QIODevice::WriteOnly | QIODevice::Append);
	if (false == openFlag)
	{
		return false;
	}

	QFileInfo qFileInfo(m_strFileName);
	if (qFileInfo.size() > m_nMaxFileSize)
	{
		/// 重命名:备份
		QString strTmpCurTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
		strTmpCurTime.remove(QString("-"));
		strTmpCurTime.remove(QString(" "));
		strTmpCurTime.remove(QString(":"));
		/// 获取文件的创建时间
		QString  strCreateTime = qFileInfo.created().toString("yyyy-MM-dd hh:mm:ss");
		strCreateTime.remove(QString("-"));
		strCreateTime.remove(QString(" "));
		strCreateTime.remove(QString(":"));

		m_strCreateDate = GetCurrDate();
		QString strNewName = m_strFileFolder + "/" + m_strFileNamePrefix + "_" + strCreateTime + "_" + strTmpCurTime + m_strFileNameExt + ".bak";
		m_File.rename(strNewName);
		m_File.flush();
		m_File.close();
		/// 在继续写第二个文件
		///
		m_strFileName = m_strFileFolder + "/" + m_strFileNamePrefix + "_" + m_strCreateDate + m_strFileNameExt;
		m_File.setFileName(m_strFileName);
		bool openFlag = m_File.open(QIODevice::Text | QIODevice::WriteOnly | QIODevice::Append);
		if (false == openFlag)
		{
			return false;
		}

	}

	m_logTextStream.setDevice(&m_File);
	m_logTextStream << strMsg << endl;
	m_logTextStream.flush();
	m_File.close();

	return true;
}

QString CLogLockWiper::GetCurrDate()
{
	QString strData = QString(QDateTime::currentDateTime().toString("yyyy-MM-dd"));
	strData.remove(QString("-"));
	return strData;
}

bool CLogLockWiper::Log(QString str)
{
	QString strResult = str;
	bool bWriteSuccess = false;
	m_Mutex.lock();
	bWriteSuccess = WriteLog(strResult);
	m_Mutex.unlock();
	return bWriteSuccess;
}


bool CLogLockWiper::LogExt(QString str)
{   
	QString date = QString(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz")) + QString(": ");

	QString strResult = date + str;
	bool bWriteSuccess = false;
	m_Mutex.lock();
	bWriteSuccess = WriteLog(strResult);
	m_Mutex.unlock();
	return bWriteSuccess;
}

这个日志类用法很简单,在程序启动的时候,初始化即可:

 /// 初始化记录文件夹,在应用程序当前目录下
 g_lockWiperLog.InitFolder("Log", 5 * 1024 * 1024, "TestLog");
 /// 保留7天的记录
 g_lockWiperLog.KeepDays(7, "");                                                  
 /// 普通记录
 g_lockWiperLog.LogExt(QString("================start TestLog================"));     
 /// 带参数记录
 g_lockWiperLog.LogExt(QString("================param1:%1,param2:%2================").arg(param1).arg(param2));
     

    日志记录的效果:

C++日志记录类_第1张图片

C++日志记录类_第2张图片

日志记录的优点:

1.可以按每天的日期记录,带时间和不带时间的记录日志。

2.有清理日志的功能,例如,保留7天,3天等。

3.可以备份日志,文件后缀结尾是.bak。

日志的缺点:没有使用单实例来打印。

 

你可能感兴趣的:(C++工作笔记)