#include "Logger.h" #include #include #include // Initialize static members QScopedPointer Logger::m_instance; // Correct: Default constructs to a null pointer QMutex Logger::m_instanceMutex; Logger& Logger::getInstance(const QString &filePath) { // Use a QMutexLocker to ensure thread-safe initialization of the singleton QMutexLocker locker(&m_instanceMutex); if (m_instance.isNull()) { if (filePath.isEmpty()) { qWarning() << "Logger: No file path provided for initial singleton creation. Logging might be disabled."; // Fallback to a default or disable logging, or throw an error. // For simplicity, we'll proceed but warn. m_instance.reset(new Logger("default.log")); // Provide a default if not given } else { m_instance.reset(new Logger(filePath)); } } return *m_instance; } // Private constructor Logger::Logger(const QString &filePath) : m_logFile(filePath), m_textStream(&m_logFile), m_maxFileSize(10 * 1024 * 1024), // Default to 10 MB m_maxBackupFiles(5) // Default to 5 backup files { QFileInfo fileInfo(filePath); QDir dir = fileInfo.absoluteDir(); if (!dir.exists()) { dir.mkpath("."); // Create directory if it doesn't exist } if (!m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) { qWarning() << "Logger: Could not open log file for writing:" << m_logFile.errorString(); } else { info("Logger initialized."); // Log the initialization } } // Private destructor Logger::~Logger() { if (m_logFile.isOpen()) { info("Logger shutting down."); // Log shutdown m_logFile.close(); } } void Logger::debug(const QString &message) { writeLog(Debug, message); } void Logger::info(const QString &message) { writeLog(Info, message); } void Logger::warn(const QString &message) { writeLog(Warning, message); } void Logger::error(const QString &message) { writeLog(Error, message); } void Logger::critical(const QString &message) { writeLog(Critical, message); } void Logger::writeLog(LogLevel level, const QString &message) { QMutexLocker locker(&m_mutex); if (!m_logFile.isOpen()) { qWarning() << "Logger: Log file is not open. Message not written:" << message; return; } if (m_logFile.size() > m_maxFileSize) { rotateLogFile(); } QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz"); QString logLevelStr = logLevelToString(level); m_textStream << QString("[%1] [%2] %3\n").arg(timestamp).arg(logLevelStr).arg(message); m_textStream.flush(); } void Logger::setMaxFileSize(qint64 bytes) { m_maxFileSize = bytes; } void Logger::setMaxBackupFiles(int count) { m_maxBackupFiles = count; } void Logger::rotateLogFile() { m_logFile.close(); QFileInfo fileInfo(m_logFile.fileName()); QString baseName = fileInfo.baseName(); QString suffix = fileInfo.suffix(); QString absolutePath = fileInfo.absolutePath(); for (int i = m_maxBackupFiles - 1; i >= 0; --i) { QString oldLogFileName = QString("%1/%2.%3.%4").arg(absolutePath).arg(baseName).arg(i).arg(suffix); QFile oldLogFile(oldLogFileName); if (oldLogFile.exists()) { if (i == m_maxBackupFiles - 1) { oldLogFile.remove(); } else { QString newLogFileName = QString("%1/%2.%3.%4").arg(absolutePath).arg(baseName).arg(i + 1).arg(suffix); oldLogFile.rename(newLogFileName); } } } QString newCurrentLogFileName = QString("%1/%2.%3.%4").arg(absolutePath).arg(baseName).arg(0).arg(suffix); m_logFile.rename(newCurrentLogFileName); if (!m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) { qWarning() << "Logger: Could not reopen log file after rotation:" << m_logFile.errorString(); } } QString Logger::logLevelToString(LogLevel level) const { switch (level) { case Debug: return "DEBUG"; case Info: return "INFO"; case Warning: return "WARNING"; case Error: return "ERROR"; case Critical: return "CRITICAL"; default: return "UNKNOWN"; } }