149 lines
3.8 KiB
C++
149 lines
3.8 KiB
C++
#include "logger.hpp"
|
|
#include <Arduino.h>
|
|
#include <string.h>
|
|
#include <stdarg.h> // For va_list, vsnprintf
|
|
#include <sys/time.h>
|
|
|
|
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<Logger*>(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<void(const LogEntry& entry)> 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; |