Przeglądaj źródła

feat: Add systemd detection functionality to Logger class

- Add isRunningUnderSystemd() method to detect if running under systemd
- Implement hybrid detection approach with multiple fallback methods:
  1. Environment variable detection (NOTIFY_SOCKET, JOURNAL_STREAM)
  2. Cgroup filesystem check (/sys/fs/cgroup/systemd)
  3. PID 1 command line check for 'systemd'
- Cache detection result at initialization for thread-safe access
- Add private member variables for caching detection state
- Detection is performed once when Logger is first initialized
- Thread-safe implementation using mutex protection
- No compile-time dependencies on systemd libraries
Fszontagh 3 miesięcy temu
rodzic
commit
2a948a6010
2 zmienionych plików z 95 dodań i 0 usunięć
  1. 13 0
      include/logger.h
  2. 82 0
      src/logger.cpp

+ 13 - 0
include/logger.h

@@ -8,6 +8,10 @@
 #include <sstream>
 #include <chrono>
 #include <iomanip>
+#include <cstdlib>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fstream>
 
 /**
  * @brief Log level enumeration
@@ -104,6 +108,12 @@ public:
      */
     void close();
 
+    /**
+     * @brief Check if running under systemd
+     * @return true if running under systemd, false otherwise
+     */
+    bool isRunningUnderSystemd();
+
 private:
     Logger() = default;
     ~Logger();
@@ -116,6 +126,7 @@ private:
     std::string levelToString(LogLevel level);
     std::string levelToSystemdPriority(LogLevel level);
     std::string typeToString(LoggerType type);
+    bool detectSystemd();
 
     bool m_fileLoggingEnabled = false;
     std::string m_logFilePath;
@@ -123,6 +134,8 @@ private:
     LogLevel m_internalMinLevel = LogLevel::INFO;
     std::ofstream m_logFile;
     mutable std::mutex m_mutex;
+    bool m_isRunningUnderSystemd = false;
+    bool m_systemdDetected = false;
 };
 
 // Convenience macros for logging

+ 82 - 0
src/logger.cpp

@@ -1,6 +1,7 @@
 #include "logger.h"
 #include <iostream>
 #include <ctime>
+#include <fstream>
 
 Logger& Logger::getInstance() {
     static Logger instance;
@@ -19,6 +20,12 @@ void Logger::initialize(bool enableFileLogging, const std::string& logFilePath,
     m_internalMinLevel = minLevel;
     m_httpMinLevel = minLevel;
 
+    // Perform systemd detection once during initialization
+    if (!m_systemdDetected) {
+        m_isRunningUnderSystemd = detectSystemd();
+        m_systemdDetected = true;
+    }
+
     if (m_fileLoggingEnabled && !m_logFilePath.empty()) {
         m_logFile.open(m_logFilePath, std::ios::app);
         if (!m_logFile.is_open()) {
@@ -124,3 +131,78 @@ void Logger::log(LogLevel level, const std::string& message, LoggerType type) {
         m_logFile.flush();
     }
 }
+
+bool Logger::isRunningUnderSystemd() {
+    std::lock_guard<std::mutex> lock(m_mutex);
+    
+    // Perform detection if not already done
+    if (!m_systemdDetected) {
+        m_isRunningUnderSystemd = detectSystemd();
+        m_systemdDetected = true;
+    }
+    
+    return m_isRunningUnderSystemd;
+}
+
+bool Logger::detectSystemd() {
+    // Method 1: Try sd_booted() if systemd development libraries are available
+    // This is the most reliable method when available
+    #ifdef HAVE_SYSTEMD
+    // If we have systemd development libraries, we could use sd_booted()
+    // But we'll implement fallback methods for broader compatibility
+    #endif
+    
+    // Method 2: Check for NOTIFY_SOCKET environment variable
+    // This is set by systemd when using sd_notify()
+    const char* notifySocket = std::getenv("NOTIFY_SOCKET");
+    if (notifySocket && notifySocket[0] != '\0') {
+        return true;
+    }
+    
+    // Method 3: Check for JOURNAL_STREAM environment variable
+    // This is set by systemd for services with StandardOutput=journal
+    const char* journalStream = std::getenv("JOURNAL_STREAM");
+    if (journalStream && journalStream[0] != '\0') {
+        return true;
+    }
+    
+    // Method 4: Check cgroup filesystem for systemd
+    // Look for systemd-specific cgroup paths
+    std::ifstream cgroupFile("/proc/1/cgroup");
+    if (cgroupFile.is_open()) {
+        std::string line;
+        while (std::getline(cgroupFile, line)) {
+            if (line.find("systemd") != std::string::npos) {
+                return true;
+            }
+        }
+        cgroupFile.close();
+    }
+    
+    // Method 5: Check if /sys/fs/cgroup/systemd exists
+    struct stat sb;
+    if (stat("/sys/fs/cgroup/systemd", &sb) == 0 && S_ISDIR(sb.st_mode)) {
+        return true;
+    }
+    
+    // Method 6: Check PID 1 command line for "systemd"
+    std::ifstream cmdlineFile("/proc/1/cmdline");
+    if (cmdlineFile.is_open()) {
+        std::string cmdline;
+        std::getline(cmdlineFile, cmdline);
+        cmdlineFile.close();
+        
+        // cmdline contains null-separated arguments, replace nulls with spaces for searching
+        for (size_t i = 0; i < cmdline.length(); ++i) {
+            if (cmdline[i] == '\0') {
+                cmdline[i] = ' ';
+            }
+        }
+        
+        if (cmdline.find("systemd") != std::string::npos) {
+            return true;
+        }
+    }
+    
+    return false;
+}