Files
QTradeProgram/Sqbase/qlogmanager.cpp
2025-08-15 15:56:40 +08:00

592 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

////#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();
}
}
}