qt日志功能扩展

qt日志是平时开发中常用的功能,qt也提供了相应的功能,但是功能并不完善,以下提供一个完善的日志功能,具有以下特点
1.非阻塞,并且开销几乎为零
2.具有日志等级分类功能,而且还能记录qt框架报告的错误
3.日志会根据日期变化,每天自动生成一个
4.使用极其简单,只要加载两个文件即可
5.demo链接https://github.com/MatchX/qtlogdemo 最好看看demo否则可能掉坑里

6.日志样式如下

#ifndef LOGMSG_H
#define LOGMSG_H

#include <iostream>
#include <mutex>
#include <set>
#include <QString>
#include <QDateTime>
#include <QCoreApplication>
#include <QDir>
#include <QTextStream>
#include <QDebug>

#define SAFEDELETE(Pt_t) {\
							if ((Pt_t) != nullptr)\
							{\
								delete (Pt_t);(Pt_t) = nullptr;\
							}\
						}
#define SAFEDELETEARRAY(Pt_t) {\
								if ((Pt_t) != nullptr)\
								{\
									delete[](Pt_t);(Pt_t) = nullptr;\
								}\
							}

//定义日志宏 difine log macro
#define logDebug QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).debug
#define logInfo QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).info
#define logWarning QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).warning
#define logCritical QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).critical
#define logFatal QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).fatal

class LogMsg final
{
public:
	LogMsg(const LogMsg&) = delete;
	LogMsg& operator=(const LogMsg&) = delete;
	LogMsg(const LogMsg&&) = delete;
	LogMsg& operator=(LogMsg&&) = delete;
	
	enum class LogMsgType : char {
		ALL = 1,//全部
		DebugMsg,//debug及以上
		InfoMsg,//info及以上
		WarningMsg,
		CriticalMsg,
		FatalMsg,
	};
	
public:
	static inline void outputMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg)
	{
		if (LogMsgType::InfoMsg == ms_LogMstType && QtDebugMsg == type)
		{
			return;
		}
		else if (LogMsgType::WarningMsg == ms_LogMstType && (QtDebugMsg == type || QtInfoMsg == type))
		{
			return;
		}
		else if (LogMsgType::CriticalMsg== ms_LogMstType && (QtDebugMsg == type || QtInfoMsg == type || QtWarningMsg == type))
		{
			return;
		}
		else if (LogMsgType::FatalMsg == ms_LogMstType && (QtDebugMsg == type || QtInfoMsg == type || QtWarningMsg == type || QtCriticalMsg == type))
		{
			return;
		}
		
		if (!ms_IsWorking)
		{
			return;
		}
		QString pretext;
		switch (type)
		{
			case QtDebugMsg:
			{
				pretext = QString("Debug:");
				break;
			}
			case QtInfoMsg:
			{
				pretext = QString("Info:");
				break;
			}
			case QtWarningMsg:
			{
				pretext = QString("Warning:");
				break;
			}
			case QtCriticalMsg:
			{
				pretext = QString("Critical:");
				break;
			}
			case QtFatalMsg:
			{
				pretext = QString("Fatal:");
				break;
			}
			default:
			{
				pretext = QString("Unknown:");
			};
		}

		const QString context_info = QString("File:(%1) Line:(%2)").arg(QString(context.file)).arg(context.line);
		const QString current_date_time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss ddd");
		const QString current_date = QString("(%1)").arg(current_date_time);
		const QString message = QString("%1 %2 %3 %4 %5").arg(pretext).arg(context_info).arg(msg).arg(current_date).arg(ms_TrailMSG) + "\n";

		//write log message
		{
			std::lock_guard<std::mutex> lock2(ms_manager->m_LogMsgBufDeqLock);
			ms_manager->m_LogMsgBufVec.push_back(message);
		}
		ms_manager->m_BufferCondVar.notify_all();
	}

	static void SetExtMsg(/*const std::string& headmsg,*/ const std::string& trailmsg)
	{
		//ms_manager->m_HeadMSG = QString::fromStdString(headmsg);
		ms_TrailMSG = QString::fromStdString(trailmsg);
	}

	static int Create(const LogMsgType logmsgtype)
	{
		int retval{ -1 };
		std::call_once(ms_CreateOnce, [&]()
		{
			const QString workdir = QCoreApplication::applicationDirPath();
			ms_LogDirPath = workdir + QDir::separator() + "Log";
			ms_LogDirPath = QDir::toNativeSeparators(ms_LogDirPath);
			const QDir dir(ms_LogDirPath);
			if (!dir.exists())
			{
				if (dir.mkpath(ms_LogDirPath))
				{
					retval = 0;
				}
				else
				{
					retval = -1;
				}
			}
			else
			{
				retval = 0;
			}
			std::lock_guard<std::mutex> lock(ms_WorkStarusLock);
			ms_manager = new LogMsg(logmsgtype);
		});
		return retval;
	}

	static void Destroy()
	{
		SAFEDELETE(ms_manager);
	}

private:
	explicit LogMsg(const LogMsgType logmsgtype = LogMsgType::ALL);
	~LogMsg();

	void OpenFile();
	void CloseFile();
	void WriteBufferThread();

private:
	static LogMsg* ms_manager;
	static bool ms_IsWorking;
	static std::mutex ms_WorkStarusLock;
	static std::once_flag ms_CreateOnce;
	static QString ms_LogDirPath;
	static LogMsgType ms_LogMstType;

	//mutable QString m_HeadMSG;
	static QString ms_TrailMSG;

	QFile* m_OutFile{ nullptr };
	mutable std::vector<QString> m_LogMsgBufVec;
	mutable std::mutex m_LogMsgBufDeqLock;
	bool m_FileIsOpen{ false };
	std::thread m_WriteBufferThread;
	//std::once_flag m_onceflg;
	std::mutex m_BufferMutex;
	std::condition_variable m_BufferCondVar;
};

#endif // LOGMSG_H
#include "logmsg.h"

LogMsg* LogMsg::ms_manager{ nullptr };
bool LogMsg::ms_IsWorking{ false };
std::mutex LogMsg::ms_WorkStarusLock;
std::once_flag LogMsg::ms_CreateOnce;
QString LogMsg::ms_LogDirPath;
LogMsg::LogMsgType LogMsg::ms_LogMstType;
QString LogMsg::ms_TrailMSG;

LogMsg::LogMsg(const LogMsgType logmsgtype)
{
	ms_LogMstType = logmsgtype;
	ms_IsWorking = true;
	m_WriteBufferThread = std::thread(&LogMsg::WriteBufferThread, this);
}

LogMsg::~LogMsg()
{
	try
	{
		ms_IsWorking = false;

		std::lock(ms_WorkStarusLock, ms_manager->m_LogMsgBufDeqLock);
		std::lock_guard<std::mutex> lock1(ms_WorkStarusLock, std::adopt_lock);
		std::lock_guard<std::mutex> lock2(ms_manager->m_LogMsgBufDeqLock, std::adopt_lock);

		//close write thread
		m_BufferCondVar.notify_all();
		if (m_WriteBufferThread.joinable())
		{
			m_WriteBufferThread.join();
		}

		//write buffer
		const auto vecsize = ms_manager->m_LogMsgBufVec.size();
		if (vecsize > 0)
		{
			OpenFile();
			if (nullptr != m_OutFile)
			{
				QTextStream text_stream(ms_manager->m_OutFile);
				text_stream.setCodec("UTF-8");
				for (size_t i = 0; i < vecsize; ++i)
				{
					text_stream << ms_manager->m_LogMsgBufVec[i];
				}
				text_stream.flush();
				ms_manager->m_LogMsgBufVec.clear();
			}
			CloseFile();
		}
	}
	catch (...)
	{
		std::cout << "~LogMsg throw exception msg=" /*<< expt.what()*/ << std::endl;
	}
}

void LogMsg::OpenFile()
{
	if (m_OutFile)
	{
		return;
	}
	
	const QString LogFileName = QDateTime::currentDateTime().toString("yyyy-MM-dd") + ".log";
	const QDir dir(ms_LogDirPath);
	if (!dir.exists())
	{
		int tryamount{ 0 };
		bool rval{ false };
		do
		{
			if (tryamount++ >= 3)
			{
				std::cout << "mkdir failed";
				break;
			}
			rval = dir.mkpath(ms_LogDirPath);
		} while (!rval);
	}
	QString logfilepath = ms_LogDirPath + QDir::separator() + LogFileName;
	logfilepath = QDir::toNativeSeparators(logfilepath);

	m_OutFile = new QFile(logfilepath);
	if (m_OutFile)
	{
		m_FileIsOpen = m_OutFile->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Unbuffered);
	}
}

void LogMsg::CloseFile()
{
	if (nullptr != m_OutFile)
	{
		m_OutFile->flush();
		m_OutFile->close();
		SAFEDELETE(m_OutFile);
	}
}

void LogMsg::WriteBufferThread()
{
	QDateTime lastcheckdatetime;
	while (ms_IsWorking)
	{
		std::unique_lock<std::mutex> ulock(m_BufferMutex);
		m_BufferCondVar.wait(ulock, [this] {
			return (!m_LogMsgBufVec.empty() || !ms_IsWorking);
		});
		if (!ms_IsWorking)
		{
			break;
		}

		if (!ms_WorkStarusLock.try_lock())
		{
			continue;
		}
		if (ms_IsWorking && !m_LogMsgBufVec.empty())
		{
			std::vector<QString> bufque;
			{
				std::lock_guard<std::mutex> veclock(m_LogMsgBufDeqLock);
				bufque.swap(m_LogMsgBufVec);
			}
			const auto nowtime = QDateTime::currentDateTime();
			if (!lastcheckdatetime.isValid() || 0 != nowtime.daysTo(lastcheckdatetime))
			{
				CloseFile();
				OpenFile();
			}
			lastcheckdatetime = nowtime;
			if (nullptr != m_OutFile && m_FileIsOpen)
			{
				const auto vecsize = bufque.size();
				QTextStream text_stream(m_OutFile);
				text_stream.setCodec("UTF-8");
				for (size_t i = 0; i < vecsize; ++i)
				{
					text_stream << bufque[i];
				}
				text_stream.flush();
			}
			else
			{
				std::cout << "open logfile failed";
			}
		}
		else if (!ms_IsWorking)
		{
			ms_WorkStarusLock.unlock();
			break;
		}
		ms_WorkStarusLock.unlock();
	}
	CloseFile();
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值