logger.cpp 4.3 KB

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