logger.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. #include "logger.h"
  2. #include <iostream>
  3. #include <ctime>
  4. Logger& Logger::getInstance() {
  5. static Logger instance;
  6. return instance;
  7. }
  8. Logger::~Logger() {
  9. close();
  10. }
  11. void Logger::initialize(bool enableFileLogging, const std::string& logFilePath, LogLevel minLevel) {
  12. std::lock_guard<std::mutex> lock(m_mutex);
  13. m_fileLoggingEnabled = enableFileLogging;
  14. m_logFilePath = logFilePath;
  15. m_minLevel = minLevel;
  16. if (m_fileLoggingEnabled && !m_logFilePath.empty()) {
  17. m_logFile.open(m_logFilePath, std::ios::app);
  18. if (!m_logFile.is_open()) {
  19. std::cerr << "<3>ERROR: Failed to open log file: " << m_logFilePath << std::endl;
  20. m_fileLoggingEnabled = false;
  21. } else {
  22. // Write startup marker
  23. m_logFile << "\n=== Log started at " << getCurrentTimestamp() << " ===" << std::endl;
  24. m_logFile.flush();
  25. }
  26. }
  27. }
  28. void Logger::close() {
  29. std::lock_guard<std::mutex> lock(m_mutex);
  30. if (m_logFile.is_open()) {
  31. m_logFile << "=== Log closed at " << getCurrentTimestamp() << " ===" << std::endl;
  32. m_logFile.close();
  33. }
  34. }
  35. std::string Logger::getCurrentTimestamp() {
  36. auto now = std::chrono::system_clock::now();
  37. auto time_t_now = std::chrono::system_clock::to_time_t(now);
  38. auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
  39. now.time_since_epoch()) % 1000;
  40. std::tm tm_buf;
  41. localtime_r(&time_t_now, &tm_buf);
  42. std::ostringstream oss;
  43. oss << std::put_time(&tm_buf, "%Y-%m-%d %H:%M:%S");
  44. oss << '.' << std::setfill('0') << std::setw(3) << ms.count();
  45. return oss.str();
  46. }
  47. std::string Logger::levelToString(LogLevel level) {
  48. switch (level) {
  49. case LogLevel::DEBUG: return "DEBUG";
  50. case LogLevel::INFO: return "INFO";
  51. case LogLevel::WARNING: return "WARNING";
  52. case LogLevel::ERROR: return "ERROR";
  53. default: return "UNKNOWN";
  54. }
  55. }
  56. std::string Logger::levelToSystemdPriority(LogLevel level) {
  57. // systemd journal priority levels:
  58. // 0=emerg, 1=alert, 2=crit, 3=err, 4=warning, 5=notice, 6=info, 7=debug
  59. switch (level) {
  60. case LogLevel::DEBUG: return "<7>"; // debug
  61. case LogLevel::INFO: return "<6>"; // info
  62. case LogLevel::WARNING: return "<4>"; // warning
  63. case LogLevel::ERROR: return "<3>"; // error
  64. default: return "<6>";
  65. }
  66. }
  67. void Logger::log(LogLevel level, const std::string& message) {
  68. if (level < m_minLevel) {
  69. return;
  70. }
  71. std::lock_guard<std::mutex> lock(m_mutex);
  72. std::string timestamp = getCurrentTimestamp();
  73. std::string levelStr = levelToString(level);
  74. std::string priority = levelToSystemdPriority(level);
  75. // Console output with systemd priority prefix
  76. std::cout << priority << "[" << timestamp << "] "
  77. << levelStr << ": " << message << std::endl;
  78. // File output (without systemd priority)
  79. if (m_fileLoggingEnabled && m_logFile.is_open()) {
  80. m_logFile << "[" << timestamp << "] "
  81. << levelStr << ": " << message << std::endl;
  82. m_logFile.flush();
  83. }
  84. }