logger.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #include "Logger.h"
  2. #include <QDebug>
  3. #include <QDir>
  4. #include <QFileInfo>
  5. // Initialize static members
  6. QScopedPointer<Logger> Logger::m_instance; // Correct: Default constructs to a null pointer
  7. QMutex Logger::m_instanceMutex;
  8. Logger &Logger::getInstance(const QString &filePath) {
  9. // Use a QMutexLocker to ensure thread-safe initialization of the singleton
  10. QMutexLocker locker(&m_instanceMutex);
  11. if (m_instance.isNull()) {
  12. if (filePath.isEmpty()) {
  13. qWarning() << "Logger: No file path provided for initial singleton creation. Logging might be disabled.";
  14. // Fallback to a default or disable logging, or throw an error.
  15. // For simplicity, we'll proceed but warn.
  16. m_instance.reset(new Logger("default.log")); // Provide a default if not given
  17. } else {
  18. m_instance.reset(new Logger(filePath));
  19. }
  20. }
  21. return *m_instance;
  22. }
  23. // Private constructor
  24. Logger::Logger(const QString &filePath)
  25. : m_logFile(filePath),
  26. m_textStream(&m_logFile),
  27. m_maxFileSize(10 * 1024 * 1024), // Default to 10 MB
  28. m_maxBackupFiles(5) // Default to 5 backup files
  29. {
  30. QFileInfo fileInfo(filePath);
  31. QDir dir = fileInfo.absoluteDir();
  32. if (!dir.exists()) {
  33. dir.mkpath("."); // Create directory if it doesn't exist
  34. }
  35. if (!m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
  36. qWarning() << "Logger: Could not open log file for writing:" << m_logFile.errorString();
  37. } else {
  38. info("Logger initialized."); // Log the initialization
  39. }
  40. }
  41. // Private destructor
  42. Logger::~Logger() {
  43. if (m_logFile.isOpen()) {
  44. info("Logger shutting down."); // Log shutdown
  45. m_logFile.close();
  46. }
  47. }
  48. void Logger::debug(const QString &message) { writeLog(Debug, message); }
  49. void Logger::info(const QString &message) { writeLog(Info, message); }
  50. void Logger::warn(const QString &message) { writeLog(Warning, message); }
  51. void Logger::error(const QString &message) { writeLog(Error, message); }
  52. void Logger::critical(const QString &message) { writeLog(Critical, message); }
  53. void Logger::writeLog(LogLevel level, const QString &message) {
  54. QMutexLocker locker(&m_mutex);
  55. if (!m_logFile.isOpen()) {
  56. qWarning() << "Logger: Log file is not open. Message not written:" << message;
  57. return;
  58. }
  59. if (m_logFile.size() > m_maxFileSize) {
  60. rotateLogFile();
  61. }
  62. QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
  63. QString logLevelStr = logLevelToString(level);
  64. m_textStream << QString("[%1] [%2] %3\n").arg(timestamp).arg(logLevelStr).arg(message);
  65. m_textStream.flush();
  66. }
  67. void Logger::setMaxFileSize(qint64 bytes) { m_maxFileSize = bytes; }
  68. void Logger::setMaxBackupFiles(int count) { m_maxBackupFiles = count; }
  69. void Logger::rotateLogFile() {
  70. m_logFile.close();
  71. QFileInfo fileInfo(m_logFile.fileName());
  72. QString baseName = fileInfo.baseName();
  73. QString suffix = fileInfo.suffix();
  74. QString absolutePath = fileInfo.absolutePath();
  75. for (int i = m_maxBackupFiles - 1; i >= 0; --i) {
  76. QString oldLogFileName = QString("%1/%2.%3.%4").arg(absolutePath).arg(baseName).arg(i).arg(suffix);
  77. QFile oldLogFile(oldLogFileName);
  78. if (oldLogFile.exists()) {
  79. if (i == m_maxBackupFiles - 1) {
  80. oldLogFile.remove();
  81. } else {
  82. QString newLogFileName = QString("%1/%2.%3.%4").arg(absolutePath).arg(baseName).arg(i + 1).arg(suffix);
  83. oldLogFile.rename(newLogFileName);
  84. }
  85. }
  86. }
  87. QString newCurrentLogFileName = QString("%1/%2.%3.%4").arg(absolutePath).arg(baseName).arg(0).arg(suffix);
  88. m_logFile.rename(newCurrentLogFileName);
  89. if (!m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
  90. qWarning() << "Logger: Could not reopen log file after rotation:" << m_logFile.errorString();
  91. }
  92. }
  93. QString Logger::logLevelToString(LogLevel level) const {
  94. switch (level) {
  95. case Debug:
  96. return "DEBUG";
  97. case Info:
  98. return "INFO";
  99. case Warning:
  100. return "WARNING";
  101. case Error:
  102. return "ERROR";
  103. case Critical:
  104. return "CRITICAL";
  105. default:
  106. return "UNKNOWN";
  107. }
  108. }