#include "logger.hpp" #include #include #include // For va_list, vsnprintf #include Logger::Logger() : logCount(0), logIndex(0), currentLogLevel(LOG_INFO), logCallback(nullptr), logQueue(nullptr), logTaskHandle(nullptr) {} Logger::~Logger() { // Clean up FreeRTOS objects if (logTaskHandle) vTaskDelete(logTaskHandle); if (logQueue) vQueueDelete(logQueue); } void Logger::begin(UBaseType_t taskPriority, uint32_t taskStackSize) { // Create a queue that can hold up to 10 LogEntry items. logQueue = xQueueCreate(10, sizeof(LogEntry)); if (logQueue == nullptr) { Serial.println("FATAL: Failed to create logger queue!"); return; } // Create the background task. It passes 'this' so the static function // can access the instance's members. xTaskCreate( logProcessingTask, "LoggerTask", taskStackSize, this, // Pass the current object instance to the task taskPriority, &logTaskHandle ); if (logTaskHandle == nullptr) { Serial.println("FATAL: Failed to create logger task!"); } } void Logger::addLog(LogLevel level, const char* format, va_list args) { if (level < currentLogLevel) { return; } LogEntry entry; entry.level = level; // Verwende Systemzeit statt millis() struct timeval tv; if (gettimeofday(&tv, nullptr) != 0) { LOG_ERROR("Failed to get system time for log entry"); entry.timestamp = 0; // Fallback-Wert } else { entry.timestamp = tv.tv_sec; // Unix-Timestamp in Sekunden } vsnprintf(entry.message, sizeof(entry.message), format, args); // Add to internal circular buffer for history logs[logIndex] = entry; logIndex = (logIndex + 1) % MAX_LOGS; if (logCount < MAX_LOGS) { logCount++; } if (logQueue != nullptr) { xQueueSend(logQueue, &entry, pdMS_TO_TICKS(10)); } } // This is the function that runs in its own task. void Logger::logProcessingTask(void* instance) { // The instance pointer is the 'this' we passed in xTaskCreate. Logger* loggerInstance = static_cast(instance); LogEntry entryToProcess; while (true) { if (xQueueReceive(loggerInstance->logQueue, &entryToProcess, portMAX_DELAY) == pdPASS) { if (loggerInstance->logCallback) { loggerInstance->logCallback(entryToProcess); } } } } void Logger::setLogLevel(LogLevel level) { currentLogLevel = level; } LogLevel Logger::getLogLevel() const { return currentLogLevel; } void Logger::setLogCallback(std::function callback) { logCallback = callback; } // --- NEW: Public methods now handle the variable arguments --- void Logger::debug(const char* format, ...) { va_list args; va_start(args, format); addLog(LOG_DEBUG, format, args); va_end(args); } void Logger::info(const char* format, ...) { va_list args; va_start(args, format); addLog(LOG_INFO, format, args); va_end(args); } void Logger::warn(const char* format, ...) { va_list args; va_start(args, format); addLog(LOG_WARN, format, args); va_end(args); } void Logger::error(const char* format, ...) { va_list args; va_start(args, format); addLog(LOG_ERROR, format, args); va_end(args); } const LogEntry* Logger::getLogs(int& count) const { count = logCount; return logs; } void Logger::clear() { logCount = 0; logIndex = 0; } const char* Logger::levelToString(LogLevel level) const { switch (level) { case LOG_DEBUG: return "D"; case LOG_INFO: return "I"; case LOG_WARN: return "W"; case LOG_ERROR: return "E"; default: return "U"; } } Logger logger;