592 lines
16 KiB
C++
592 lines
16 KiB
C++
|
|
////#include "qlogmanager.h"
|
|||
|
|
////#include <QDateTime>
|
|||
|
|
////#include <QFile>
|
|||
|
|
////#include <QTextStream>
|
|||
|
|
////#include <QFileInfo>
|
|||
|
|
////
|
|||
|
|
////QLogManager* QLogManager::instance = nullptr;
|
|||
|
|
////
|
|||
|
|
////QLogManager::QLogManager(QObject* parent) : QObject(parent) {
|
|||
|
|
//// // 创建日志目录
|
|||
|
|
//// logDirectory = QDir::currentPath() + "/logs/";
|
|||
|
|
//// QDir dir;
|
|||
|
|
//// if (!dir.exists(logDirectory)) {
|
|||
|
|
//// dir.mkpath(logDirectory);
|
|||
|
|
//// }
|
|||
|
|
////
|
|||
|
|
//// // 清理旧日志
|
|||
|
|
//// cleanOldLogs();
|
|||
|
|
////}
|
|||
|
|
////
|
|||
|
|
////QLogManager* QLogManager::getInstance() {
|
|||
|
|
//// static QMutex mutex;
|
|||
|
|
//// QMutexLocker locker(&mutex);
|
|||
|
|
//// if (!instance) {
|
|||
|
|
//// instance = new QLogManager;
|
|||
|
|
//// }
|
|||
|
|
//// return instance;
|
|||
|
|
////}
|
|||
|
|
////
|
|||
|
|
////void QLogManager::log(LogLevel level, const QString& message, const QString& module) {
|
|||
|
|
//// QMutexLocker locker(&mutex);
|
|||
|
|
//// QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
|
|||
|
|
//// QString levelStr;
|
|||
|
|
////
|
|||
|
|
//// switch (level) {
|
|||
|
|
//// case SQ_DEBUG: levelStr = "DEBUG"; break;
|
|||
|
|
//// case SQ_INFO: levelStr = "INFO"; break;
|
|||
|
|
//// case SQ_WARNING: levelStr = "WARNING"; break;
|
|||
|
|
//// case SQ_ERROR: levelStr = "ERROR"; break;
|
|||
|
|
//// case SQ_FATAL: levelStr = "FATAL"; break;
|
|||
|
|
//// }
|
|||
|
|
////
|
|||
|
|
//// QString logLine = QString("[%1][%2][%3] %4")
|
|||
|
|
//// .arg(timestamp, levelStr, module, message);
|
|||
|
|
////
|
|||
|
|
//// // 输出到控制台
|
|||
|
|
//// emit newLog(level, logLine);
|
|||
|
|
////
|
|||
|
|
//// // 写入文件
|
|||
|
|
//// writeToFile(level, logLine);
|
|||
|
|
////}
|
|||
|
|
////
|
|||
|
|
////QString QLogManager::getLogFileName(LogLevel level) {
|
|||
|
|
//// QString levelStr;
|
|||
|
|
//// switch (level) {
|
|||
|
|
//// case SQ_DEBUG: levelStr = "debug"; break;
|
|||
|
|
//// case SQ_INFO: levelStr = "info"; break;
|
|||
|
|
//// case SQ_WARNING: levelStr = "warning"; break;
|
|||
|
|
//// case SQ_ERROR: levelStr = "error"; break;
|
|||
|
|
//// case SQ_FATAL: levelStr = "fatal"; break;
|
|||
|
|
//// default: levelStr = "system"; break;
|
|||
|
|
//// }
|
|||
|
|
////
|
|||
|
|
//// return QString("%1_%2.log")
|
|||
|
|
//// .arg(levelStr)
|
|||
|
|
//// .arg(QDateTime::currentDateTime().toString("yyyyMMdd"));
|
|||
|
|
////}
|
|||
|
|
////
|
|||
|
|
////void QLogManager::writeToFile(LogLevel level, const QString& logLine) {
|
|||
|
|
//// // 为不同级别的日志创建不同文件
|
|||
|
|
//// QString logFileName = logDirectory + getLogFileName(level);
|
|||
|
|
//// QFile file(logFileName);
|
|||
|
|
////
|
|||
|
|
//// if (file.open(QIODevice::WriteOnly | QIODevice::Append)) {
|
|||
|
|
//// QTextStream stream(&file);
|
|||
|
|
//// stream << logLine << "\n";
|
|||
|
|
//// file.close();
|
|||
|
|
//// } else {
|
|||
|
|
//// // 如果文件打开失败,发出错误日志
|
|||
|
|
//// emit newLog(SQ_ERROR, QString("[LogSystem] Failed to open log file: %1").arg(logFileName));
|
|||
|
|
//// }
|
|||
|
|
////}
|
|||
|
|
////
|
|||
|
|
////void QLogManager::cleanOldLogs() {
|
|||
|
|
//// QDir dir(logDirectory);
|
|||
|
|
//// QStringList logFiles = dir.entryList(QStringList() << "*.log", QDir::Files);
|
|||
|
|
////
|
|||
|
|
//// QDateTime now = QDateTime::currentDateTime();
|
|||
|
|
//// for (const QString& fileName : logFiles) {
|
|||
|
|
//// QFileInfo fileInfo(dir.filePath(fileName));
|
|||
|
|
//// if (fileInfo.lastModified().daysTo(now) > maxLogDays) {
|
|||
|
|
//// QFile::remove(fileInfo.absoluteFilePath());
|
|||
|
|
//// }
|
|||
|
|
//// }
|
|||
|
|
////}
|
|||
|
|
//#include "qlogmanager.h"
|
|||
|
|
//#include <QDateTime>
|
|||
|
|
//#include <QFile>
|
|||
|
|
//#include <QTextStream>
|
|||
|
|
//#include <QFileInfo>
|
|||
|
|
//#include <QThread>
|
|||
|
|
//#include <QSemaphore>
|
|||
|
|
//
|
|||
|
|
//QLogManager* QLogManager::instance = nullptr;
|
|||
|
|
//const int QLogManager::maxLogDays = 7;
|
|||
|
|
//const qint64 QLogManager::maxFileSize = 10 * 1024 * 1024; // 10MB
|
|||
|
|
//
|
|||
|
|
//QLogManager::QLogManager(QObject* parent) : QObject(parent), minLevel(SQ_INFO), running(true) {
|
|||
|
|
// // 创建日志目录 - 修正exists检查
|
|||
|
|
// logDirectory = QDir::currentPath() + "/logs/";
|
|||
|
|
// QDir dir(logDirectory); // 使用QString构造QDir
|
|||
|
|
// if (!dir.exists()) { // 无参数调用exists()
|
|||
|
|
// if (!dir.mkpath(".")) {
|
|||
|
|
// QString msg = "Failed to create log directory:" + logDirectory.path();
|
|||
|
|
// emit newLog(SQ_WARNING, msg);
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
//
|
|||
|
|
// // 清理旧日志
|
|||
|
|
// cleanOldLogs();
|
|||
|
|
//
|
|||
|
|
// // 启动工作线程
|
|||
|
|
// workerThread = new QThread();
|
|||
|
|
// QObject::connect(workerThread, &QThread::started, [this]() {
|
|||
|
|
// this->processLogs();
|
|||
|
|
// });
|
|||
|
|
// workerThread->start();
|
|||
|
|
// //workerThread = QThread::create([this] { processLogs(); });
|
|||
|
|
// //workerThread->start();
|
|||
|
|
//}
|
|||
|
|
//
|
|||
|
|
//QLogManager::~QLogManager() {
|
|||
|
|
// if (workerThread) {
|
|||
|
|
// workerThread->quit();
|
|||
|
|
// workerThread->wait();
|
|||
|
|
// delete workerThread;
|
|||
|
|
// }
|
|||
|
|
//
|
|||
|
|
// running = false;
|
|||
|
|
// queueSemaphore.release(); // 唤醒线程以退出
|
|||
|
|
//
|
|||
|
|
// // 关闭所有打开的文件
|
|||
|
|
// for (auto& file : openFiles) {
|
|||
|
|
// if (!file.isNull()) {
|
|||
|
|
// file->close();
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
//}
|
|||
|
|
//
|
|||
|
|
//QLogManager* QLogManager::getInstance() {
|
|||
|
|
// static QMutex mutex;
|
|||
|
|
// QMutexLocker locker(&mutex);
|
|||
|
|
// if (!instance) {
|
|||
|
|
// instance = new QLogManager;
|
|||
|
|
// }
|
|||
|
|
// return instance;
|
|||
|
|
//}
|
|||
|
|
//
|
|||
|
|
//void QLogManager::setLogLevel(LogLevel level) {
|
|||
|
|
// QMutexLocker locker(&mutex);
|
|||
|
|
// minLevel = level;
|
|||
|
|
//}
|
|||
|
|
//
|
|||
|
|
//void QLogManager::log(LogLevel level, const QString& message, const QString& module) {
|
|||
|
|
// if (level < minLevel) {
|
|||
|
|
// return;
|
|||
|
|
// }
|
|||
|
|
//
|
|||
|
|
// // 优化时间戳获取
|
|||
|
|
// static thread_local QString lastTimeStr;
|
|||
|
|
// static thread_local qint64 lastTimeMs = 0;
|
|||
|
|
//
|
|||
|
|
// qint64 now = QDateTime::currentMSecsSinceEpoch();
|
|||
|
|
// if (now - lastTimeMs > 100) { // 每100ms更新一次
|
|||
|
|
// lastTimeStr = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
|
|||
|
|
// lastTimeMs = now;
|
|||
|
|
// }
|
|||
|
|
//
|
|||
|
|
// QString levelStr;
|
|||
|
|
// switch (level) {
|
|||
|
|
// case SQ_DEBUG: levelStr = "DEBUG"; break;
|
|||
|
|
// case SQ_INFO: levelStr = "INFO"; break;
|
|||
|
|
// case SQ_WARNING: levelStr = "WARNING"; break;
|
|||
|
|
// case SQ_ERROR: levelStr = "ERROR"; break;
|
|||
|
|
// case SQ_FATAL: levelStr = "FATAL"; break;
|
|||
|
|
// }
|
|||
|
|
//
|
|||
|
|
// QString logLine = QString("[%1][%2][%3] %4")
|
|||
|
|
// .arg(lastTimeStr, levelStr, module, message);
|
|||
|
|
//
|
|||
|
|
// // 控制台输出不需要加锁
|
|||
|
|
// emit newLog(level, logLine);
|
|||
|
|
//
|
|||
|
|
// // 快速入队
|
|||
|
|
// {
|
|||
|
|
// QMutexLocker locker(&mutex);
|
|||
|
|
// logQueue.enqueue(qMakePair(level, logLine));
|
|||
|
|
// }
|
|||
|
|
// queueSemaphore.release(); // 通知工作线程
|
|||
|
|
//}
|
|||
|
|
//
|
|||
|
|
//void QLogManager::processLogs() {
|
|||
|
|
// while (running) {
|
|||
|
|
// queueSemaphore.acquire(); // 等待新日志
|
|||
|
|
//
|
|||
|
|
// QPair<LogLevel, QString> logEntry;
|
|||
|
|
// {
|
|||
|
|
// QMutexLocker locker(&mutex);
|
|||
|
|
// if (!logQueue.isEmpty()) {
|
|||
|
|
// logEntry = logQueue.dequeue();
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
//
|
|||
|
|
// if (!logEntry.second.isEmpty()) {
|
|||
|
|
// writeToFile(logEntry.first, logEntry.second);
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
//
|
|||
|
|
// // 退出前处理剩余日志
|
|||
|
|
// while (true) {
|
|||
|
|
// QPair<LogLevel, QString> logEntry;
|
|||
|
|
// {
|
|||
|
|
// QMutexLocker locker(&mutex);
|
|||
|
|
// if (logQueue.isEmpty()) break;
|
|||
|
|
// logEntry = logQueue.dequeue();
|
|||
|
|
// }
|
|||
|
|
// writeToFile(logEntry.first, logEntry.second);
|
|||
|
|
// }
|
|||
|
|
//}
|
|||
|
|
//
|
|||
|
|
//QString QLogManager::getLogFileName(LogLevel level) {
|
|||
|
|
// QString levelStr;
|
|||
|
|
// switch (level) {
|
|||
|
|
// case SQ_DEBUG: levelStr = "debug"; break;
|
|||
|
|
// case SQ_INFO: levelStr = "info"; break;
|
|||
|
|
// case SQ_WARNING: levelStr = "warning"; break;
|
|||
|
|
// case SQ_ERROR: levelStr = "error"; break;
|
|||
|
|
// case SQ_FATAL: levelStr = "fatal"; break;
|
|||
|
|
// default: levelStr = "system"; break;
|
|||
|
|
// }
|
|||
|
|
//
|
|||
|
|
// return QString("%1_%2.log")
|
|||
|
|
// .arg(levelStr)
|
|||
|
|
// .arg(QDateTime::currentDateTime().toString("yyyyMMdd"));
|
|||
|
|
//}
|
|||
|
|
//
|
|||
|
|
////void QLogManager::writeToFile(LogLevel level, const QString& logLine) {
|
|||
|
|
//// if (!openFiles.contains(level)) {
|
|||
|
|
//// QString fileName = logDirectory.path() + getLogFileName(level);
|
|||
|
|
//// QSharedPointer<QFile> file(new QFile(fileName));
|
|||
|
|
//// if (file->open(QIODevice::WriteOnly | QIODevice::Append)) {
|
|||
|
|
//// openFiles[level] = file;
|
|||
|
|
//// }
|
|||
|
|
//// else {
|
|||
|
|
//// emit newLog(SQ_ERROR, QString("[LogSystem] Failed to open log file: %1").arg(fileName));
|
|||
|
|
//// return;
|
|||
|
|
//// }
|
|||
|
|
//// }
|
|||
|
|
////
|
|||
|
|
//// if (!openFiles[level].isNull()) {
|
|||
|
|
//// QTextStream stream(openFiles[level].data());
|
|||
|
|
//// stream << logLine << "\n";
|
|||
|
|
////
|
|||
|
|
//// // 检查文件大小,超过限制则滚动
|
|||
|
|
//// if (openFiles[level]->size() > maxFileSize) {
|
|||
|
|
//// openFiles[level]->close();
|
|||
|
|
//// openFiles.remove(level);
|
|||
|
|
////
|
|||
|
|
//// // 添加时间戳到旧文件名
|
|||
|
|
//// QString oldName = logDirectory + getLogFileName(level);
|
|||
|
|
//// QString newName = oldName + "." + QDateTime::currentDateTime().toString("hhmmsszzz");
|
|||
|
|
//// QFile::rename(oldName, newName);
|
|||
|
|
//// }
|
|||
|
|
//// }
|
|||
|
|
////}
|
|||
|
|
//
|
|||
|
|
//void QLogManager::writeToFile(LogLevel level, const QString& logLine)
|
|||
|
|
//{
|
|||
|
|
// // 检查并维护打开的文件
|
|||
|
|
// if (!openFiles.contains(level)) {
|
|||
|
|
// QString fileName = logDirectory.path()+"/" + getLogFileName(level);
|
|||
|
|
// QSharedPointer<QFile> file(new QFile(fileName));
|
|||
|
|
// if (file->open(QIODevice::WriteOnly | QIODevice::Append)) {
|
|||
|
|
// openFiles[level] = file;
|
|||
|
|
// }
|
|||
|
|
// else {
|
|||
|
|
// emit newLog(SQ_ERROR, QString("[LogSystem] Failed to open log file: %1").arg(fileName));
|
|||
|
|
// return;
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
//
|
|||
|
|
// // 修正:避免创建临时QTextStream
|
|||
|
|
// if (!openFiles[level].isNull()) {
|
|||
|
|
// QTextStream stream(openFiles[level].data());
|
|||
|
|
// stream << logLine << "\n";
|
|||
|
|
// stream.flush(); // 确保立即写入
|
|||
|
|
//
|
|||
|
|
// // 检查文件大小
|
|||
|
|
// if (openFiles[level]->size() > maxFileSize) {
|
|||
|
|
// rotateLogFile(level);
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
//}
|
|||
|
|
//
|
|||
|
|
//void QLogManager::rotateLogFile(LogLevel level)
|
|||
|
|
//{
|
|||
|
|
// if (!openFiles.contains(level)) return;
|
|||
|
|
//
|
|||
|
|
// openFiles[level]->close();
|
|||
|
|
//
|
|||
|
|
// QString oldName = logDirectory.path() + getLogFileName(level);
|
|||
|
|
// QString newName = oldName + "." + QDateTime::currentDateTime().toString("hhmmsszzz");
|
|||
|
|
//
|
|||
|
|
// QFile::rename(oldName, newName);
|
|||
|
|
// openFiles.remove(level);
|
|||
|
|
//}
|
|||
|
|
//
|
|||
|
|
//void QLogManager::cleanOldLogs() {
|
|||
|
|
// QDir dir(logDirectory);
|
|||
|
|
// QStringList logFiles = dir.entryList(QStringList() << "*.log" << "*.log.*", QDir::Files);
|
|||
|
|
//
|
|||
|
|
// QDateTime now = QDateTime::currentDateTime();
|
|||
|
|
// for (const QString& fileName : logFiles) {
|
|||
|
|
// QFileInfo fileInfo(dir.filePath(fileName));
|
|||
|
|
// if (fileInfo.lastModified().daysTo(now) > maxLogDays) {
|
|||
|
|
// QFile::remove(fileInfo.absoluteFilePath());
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
//}
|
|||
|
|
//
|
|||
|
|
//void QLogManager::flush() {
|
|||
|
|
// QMutexLocker locker(&mutex);
|
|||
|
|
// for (auto& file : openFiles) {
|
|||
|
|
// if (!file.isNull()) {
|
|||
|
|
// file->flush();
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
//}
|
|||
|
|
// qlogmanager.cpp
|
|||
|
|
// qlogmanager.h
|
|||
|
|
#include "qlogmanager.h"
|
|||
|
|
#include <QTextStream>
|
|||
|
|
#include <QCoreApplication>
|
|||
|
|
|
|||
|
|
QBasicAtomicPointer<QLogManager> QLogManager::s_instance = Q_BASIC_ATOMIC_INITIALIZER(0);
|
|||
|
|
QMutex QLogManager::s_mutex;
|
|||
|
|
|
|||
|
|
QLogManager::QLogManager(QObject* parent)
|
|||
|
|
: QObject(parent),
|
|||
|
|
m_minLevel(SQ_INFO),
|
|||
|
|
m_workerThread(nullptr),
|
|||
|
|
m_running(true)
|
|||
|
|
{
|
|||
|
|
// 创建日志目录
|
|||
|
|
m_logDirectory = QDir(QCoreApplication::applicationDirPath() + "/logs/");
|
|||
|
|
if (!m_logDirectory.exists()) {
|
|||
|
|
if (!m_logDirectory.mkpath(".")) {
|
|||
|
|
emit newLog(SQ_ERROR, QString("Failed to create log directory: %1").arg(m_logDirectory.path()));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 清理旧日志
|
|||
|
|
cleanOldLogs();
|
|||
|
|
|
|||
|
|
// 启动工作线程
|
|||
|
|
m_workerThread = new QThread();
|
|||
|
|
QObject::connect(m_workerThread, &QThread::started, [this]() {
|
|||
|
|
this->processLogs();
|
|||
|
|
});
|
|||
|
|
m_workerThread->start();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QLogManager::~QLogManager()
|
|||
|
|
{
|
|||
|
|
m_running = false;
|
|||
|
|
m_queueSemaphore.release(); // 唤醒线程以退出
|
|||
|
|
|
|||
|
|
if (m_workerThread) {
|
|||
|
|
m_workerThread->quit();
|
|||
|
|
if (!m_workerThread->wait(3000)) { // 等待3秒
|
|||
|
|
m_workerThread->terminate();
|
|||
|
|
m_workerThread->wait();
|
|||
|
|
}
|
|||
|
|
delete m_workerThread;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 处理剩余日志
|
|||
|
|
LogEntry entry;
|
|||
|
|
while (m_logQueue.dequeue(entry)) {
|
|||
|
|
writeToFile(entry.level, entry.message);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 关闭所有打开的文件
|
|||
|
|
for (auto& file : m_openFiles) {
|
|||
|
|
if (!file.isNull()) {
|
|||
|
|
file->close();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QLogManager* QLogManager::getInstance()
|
|||
|
|
{
|
|||
|
|
// 双重检查锁定
|
|||
|
|
if (!s_instance.load()) {
|
|||
|
|
QMutexLocker locker(&s_mutex);
|
|||
|
|
if (!s_instance.load()) {
|
|||
|
|
QLogManager* instance = new QLogManager();
|
|||
|
|
s_instance.store(instance);
|
|||
|
|
qAddPostRoutine(QLogManager::destroyInstance);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return s_instance.load();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QLogManager::destroyInstance()
|
|||
|
|
{
|
|||
|
|
QMutexLocker locker(&s_mutex);
|
|||
|
|
QLogManager* instance = s_instance.load();
|
|||
|
|
if (instance) {
|
|||
|
|
delete instance;
|
|||
|
|
s_instance.store(nullptr);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QLogManager::setLogLevel(LogLevel level)
|
|||
|
|
{
|
|||
|
|
QMutexLocker locker(&s_mutex);
|
|||
|
|
m_minLevel = level;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QLogManager::log(LogLevel level, const QString& message, const QString& module)
|
|||
|
|
{
|
|||
|
|
if (level < m_minLevel) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 优化时间戳获取
|
|||
|
|
static thread_local QString lastTimeStr;
|
|||
|
|
static thread_local qint64 lastTimeMs = 0;
|
|||
|
|
|
|||
|
|
qint64 now = QDateTime::currentMSecsSinceEpoch();
|
|||
|
|
if (now - lastTimeMs > TIMESTAMP_CACHE_DURATION_MS) {
|
|||
|
|
lastTimeStr = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
|
|||
|
|
lastTimeMs = now;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QString levelStr;
|
|||
|
|
switch (level) {
|
|||
|
|
case SQ_DEBUG: levelStr = "DEBUG"; break;
|
|||
|
|
case SQ_INFO: levelStr = "INFO"; break;
|
|||
|
|
case SQ_WARNING: levelStr = "WARNING"; break;
|
|||
|
|
case SQ_ERROR: levelStr = "ERROR"; break;
|
|||
|
|
case SQ_FATAL: levelStr = "FATAL"; break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QString logLine = QString("[%1][%2][%3] %4")
|
|||
|
|
.arg(lastTimeStr, levelStr, module, message);
|
|||
|
|
|
|||
|
|
// 控制台输出
|
|||
|
|
emit newLog(level, logLine);
|
|||
|
|
|
|||
|
|
// 入队
|
|||
|
|
LogEntry entry;
|
|||
|
|
entry.level = level;
|
|||
|
|
entry.message = logLine;
|
|||
|
|
entry.timestamp = now;
|
|||
|
|
|
|||
|
|
m_logQueue.enqueue(entry);
|
|||
|
|
m_queueSemaphore.release(); // 通知工作线程
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QLogManager::processLogs()
|
|||
|
|
{
|
|||
|
|
while (m_running) {
|
|||
|
|
m_queueSemaphore.acquire();
|
|||
|
|
|
|||
|
|
LogEntry entry;
|
|||
|
|
while (m_logQueue.dequeue(entry)) {
|
|||
|
|
writeToFile(entry.level, entry.message);
|
|||
|
|
|
|||
|
|
// 批量处理时检查是否还需要继续运行
|
|||
|
|
if (!m_running) {
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QString QLogManager::getLogFileName(LogLevel level)
|
|||
|
|
{
|
|||
|
|
QString levelStr;
|
|||
|
|
switch (level) {
|
|||
|
|
case SQ_DEBUG: levelStr = "debug"; break;
|
|||
|
|
case SQ_INFO: levelStr = "info"; break;
|
|||
|
|
case SQ_WARNING: levelStr = "warning"; break;
|
|||
|
|
case SQ_ERROR: levelStr = "error"; break;
|
|||
|
|
case SQ_FATAL: levelStr = "fatal"; break;
|
|||
|
|
default: levelStr = "system"; break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return QString("%1_%2.log")
|
|||
|
|
.arg(levelStr)
|
|||
|
|
.arg(QDateTime::currentDateTime().toString("yyyyMMdd"));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QLogManager::writeToFile(LogLevel level, const QString& logLine)
|
|||
|
|
{
|
|||
|
|
try {
|
|||
|
|
// 检查并维护打开的文件
|
|||
|
|
if (!m_openFiles.contains(level)) {
|
|||
|
|
QString fileName = m_logDirectory.filePath(getLogFileName(level));
|
|||
|
|
QSharedPointer<QFile> file(new QFile(fileName));
|
|||
|
|
|
|||
|
|
if (!file->open(QIODevice::WriteOnly | QIODevice::Append)) {
|
|||
|
|
emit newLog(SQ_ERROR, QString("[LogSystem] Failed to open log file: %1").arg(fileName));
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
m_openFiles[level] = file;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 写入文件
|
|||
|
|
if (!m_openFiles[level].isNull()) {
|
|||
|
|
QTextStream stream(m_openFiles[level].data());
|
|||
|
|
stream << logLine << "\n";
|
|||
|
|
stream.flush();
|
|||
|
|
|
|||
|
|
// 检查文件大小
|
|||
|
|
if (m_openFiles[level]->size() > MAX_FILE_SIZE) {
|
|||
|
|
rotateLogFile(level);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (...) {
|
|||
|
|
emit newLog(SQ_ERROR, "[LogSystem] Exception occurred while writing log");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QLogManager::rotateLogFile(LogLevel level)
|
|||
|
|
{
|
|||
|
|
if (!m_openFiles.contains(level)) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
m_openFiles[level]->close();
|
|||
|
|
|
|||
|
|
QString oldName = m_logDirectory.filePath(getLogFileName(level));
|
|||
|
|
QString newName = oldName + "." + QDateTime::currentDateTime().toString("hhmmsszzz");
|
|||
|
|
|
|||
|
|
if (!QFile::rename(oldName, newName)) {
|
|||
|
|
emit newLog(SQ_ERROR, QString("[LogSystem] Failed to rotate log file from %1 to %2")
|
|||
|
|
.arg(oldName, newName));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
m_openFiles.remove(level);
|
|||
|
|
}
|
|||
|
|
catch (...) {
|
|||
|
|
emit newLog(SQ_ERROR, "[LogSystem] Exception occurred while rotating log file");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QLogManager::cleanOldLogs()
|
|||
|
|
{
|
|||
|
|
try {
|
|||
|
|
QStringList logFiles = m_logDirectory.entryList(QStringList() << "*.log" << "*.log.*", QDir::Files);
|
|||
|
|
|
|||
|
|
QDateTime now = QDateTime::currentDateTime();
|
|||
|
|
for (const QString& fileName : logFiles) {
|
|||
|
|
QFileInfo fileInfo(m_logDirectory.filePath(fileName));
|
|||
|
|
if (fileInfo.lastModified().daysTo(now) > MAX_LOG_DAYS) {
|
|||
|
|
if (!QFile::remove(fileInfo.absoluteFilePath())) {
|
|||
|
|
emit newLog(SQ_WARNING, QString("Failed to remove old log file: %1")
|
|||
|
|
.arg(fileInfo.absoluteFilePath()));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (...) {
|
|||
|
|
emit newLog(SQ_ERROR, "[LogSystem] Exception occurred while cleaning old logs");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QLogManager::flush()
|
|||
|
|
{
|
|||
|
|
QMutexLocker locker(&s_mutex);
|
|||
|
|
for (auto& file : m_openFiles) {
|
|||
|
|
if (!file.isNull()) {
|
|||
|
|
file->flush();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|