#include "logger.h" #include #include Logger& Logger::getInstance() { static Logger instance; return instance; } Logger::~Logger() { close(); } void Logger::initialize(bool enableFileLogging, const std::string& logFilePath, LogLevel minLevel) { std::lock_guard lock(m_mutex); m_fileLoggingEnabled = enableFileLogging; m_logFilePath = logFilePath; m_minLevel = minLevel; if (m_fileLoggingEnabled && !m_logFilePath.empty()) { m_logFile.open(m_logFilePath, std::ios::app); if (!m_logFile.is_open()) { std::cerr << "<3>ERROR: Failed to open log file: " << m_logFilePath << std::endl; m_fileLoggingEnabled = false; } else { // Write startup marker m_logFile << "\n=== Log started at " << getCurrentTimestamp() << " ===" << std::endl; m_logFile.flush(); } } } void Logger::close() { std::lock_guard lock(m_mutex); if (m_logFile.is_open()) { m_logFile << "=== Log closed at " << getCurrentTimestamp() << " ===" << std::endl; m_logFile.close(); } } std::string Logger::getCurrentTimestamp() { auto now = std::chrono::system_clock::now(); auto time_t_now = std::chrono::system_clock::to_time_t(now); auto ms = std::chrono::duration_cast( now.time_since_epoch()) % 1000; std::tm tm_buf; localtime_r(&time_t_now, &tm_buf); std::ostringstream oss; oss << std::put_time(&tm_buf, "%Y-%m-%d %H:%M:%S"); oss << '.' << std::setfill('0') << std::setw(3) << ms.count(); return oss.str(); } std::string Logger::levelToString(LogLevel level) { switch (level) { case LogLevel::DEBUG: return "DEBUG"; case LogLevel::INFO: return "INFO"; case LogLevel::WARNING: return "WARNING"; case LogLevel::ERROR: return "ERROR"; default: return "UNKNOWN"; } } std::string Logger::levelToSystemdPriority(LogLevel level) { // systemd journal priority levels: // 0=emerg, 1=alert, 2=crit, 3=err, 4=warning, 5=notice, 6=info, 7=debug switch (level) { case LogLevel::DEBUG: return "<7>"; // debug case LogLevel::INFO: return "<6>"; // info case LogLevel::WARNING: return "<4>"; // warning case LogLevel::ERROR: return "<3>"; // error default: return "<6>"; } } void Logger::log(LogLevel level, const std::string& message) { if (level < m_minLevel) { return; } std::lock_guard lock(m_mutex); std::string timestamp = getCurrentTimestamp(); std::string levelStr = levelToString(level); std::string priority = levelToSystemdPriority(level); // Console output with systemd priority prefix std::cout << priority << "[" << timestamp << "] " << levelStr << ": " << message << std::endl; // File output (without systemd priority) if (m_fileLoggingEnabled && m_logFile.is_open()) { m_logFile << "[" << timestamp << "] " << levelStr << ": " << message << std::endl; m_logFile.flush(); } }