Files
spore/docs/LoggingService.md

6.0 KiB

LoggingService - Centralized Event-Based Logging

The LoggingService provides a centralized, event-driven logging system for the SPORE framework. It allows components to log messages through the event system, enabling flexible log routing and filtering.

Features

  • Event-Driven Architecture: Uses the SPORE event system for decoupled logging
  • Multiple Log Levels: DEBUG, INFO, WARN, ERROR with configurable filtering
  • Multiple Destinations: Serial output (extensible)
  • Component-Based Logging: Tag messages with component names
  • API Configuration: Configure logging via HTTP API endpoints
  • Easy Integration: Simple macros and functions for logging

Usage

Basic Logging

#include "spore/services/LoggingService.h"

// Using convenience macros (requires NodeContext)
LOG_DEBUG(ctx, "ComponentName", "Debug message");
LOG_INFO(ctx, "ComponentName", "Info message");
LOG_WARN(ctx, "ComponentName", "Warning message");
LOG_ERROR(ctx, "ComponentName", "Error message");

// Using global functions
logDebug(ctx, "ComponentName", "Debug message");
logInfo(ctx, "ComponentName", "Info message");
logWarn(ctx, "ComponentName", "Warning message");
logError(ctx, "ComponentName", "Error message");

Event System Integration

The logging system uses the following events:

  • log/debug - Debug level messages
  • log/info - Info level messages
  • log/warn - Warning level messages
  • log/error - Error level messages
  • log/serial - Messages routed to serial output

You can subscribe to these events for custom log handling:

// Subscribe to all debug messages
ctx.on("log/debug", [](void* data) {
    LogData* logData = static_cast<LogData*>(data);
    // Custom handling for debug messages
    delete logData;
});

// Subscribe to serial log output
ctx.on("log/serial", [](void* data) {
    LogData* logData = static_cast<LogData*>(data);
    // Custom serial formatting
    Serial.println("CUSTOM: " + logData->message);
    delete logData;
});

LoggingService Class

The LoggingService class provides programmatic control over logging:

LoggingService logger(ctx, apiServer);

// Configure logging
logger.setLogLevel(LogLevel::DEBUG);
logger.enableSerialLogging(true);

// Direct logging
logger.debug("MyComponent", "Debug message");
logger.info("MyComponent", "Info message");
logger.warn("MyComponent", "Warning message");
logger.error("MyComponent", "Error message");

API Endpoints

The LoggingService provides HTTP API endpoints for configuration with proper parameter validation:

Get Log Level

GET /api/logging/level

Returns current log level as JSON.

Response:

{
  "level": "INFO"
}

Set Log Level

POST /api/logging/level
Content-Type: application/x-www-form-urlencoded

level=DEBUG

Sets the log level with parameter validation.

Parameters:

  • level (required): One of DEBUG, INFO, WARN, ERROR

Success Response:

{
  "success": true,
  "level": "DEBUG"
}

Error Response:

{
  "error": "Invalid log level. Must be one of: DEBUG, INFO, WARN, ERROR"
}

Get Configuration

GET /api/logging/config

Returns complete logging configuration.

Response:

{
  "level": "INFO",
  "serialEnabled": true
}

Log Levels

  • DEBUG: Detailed information for debugging
  • INFO: General information about system operation
  • WARN: Warning messages for potentially harmful situations
  • ERROR: Error messages for serious problems

Only messages at or above the current log level are processed.

Log Format

Log messages are formatted as:

[timestamp] [level] [component] message

Example:

[12345] [INFO] [Spore] Framework setup complete
[12350] [DEBUG] [Network] WiFi connection established
[12355] [WARN] [Cluster] Node timeout detected
[12360] [ERROR] [API] Failed to start server

Integration with SPORE

The LoggingService is automatically registered as a core service in the SPORE framework. It's initialized before other services to ensure logging is available throughout the system.

Example

See examples/logging_example/main.cpp for a complete example demonstrating the logging system.

Extending the Logging System

Adding New Log Destinations

To add new log destinations (e.g., network logging, database logging):

  1. Subscribe to the appropriate log events:
ctx.on("log/info", [](void* data) {
    LogData* logData = static_cast<LogData*>(data);
    // Send to your custom destination
    sendToNetwork(logData->message);
    delete logData;
});
  1. Or create a custom LoggingService subclass:
class CustomLoggingService : public LoggingService {
public:
    CustomLoggingService(NodeContext& ctx, ApiServer& apiServer) 
        : LoggingService(ctx, apiServer) {
        // Register custom event handlers
        ctx.on("log/custom", [this](void* data) {
            this->handleCustomLog(data);
        });
    }
    
private:
    void handleCustomLog(void* data) {
        // Custom log handling
    }
};

Custom Log Formatting

Override the formatLogMessage method in a custom LoggingService to change log formatting:

String CustomLoggingService::formatLogMessage(const LogData& logData) {
    // Custom formatting
    return "CUSTOM[" + logData.component + "] " + logData.message;
}

Performance Considerations

  • Log messages are processed asynchronously through the event system
  • Memory is allocated for each log message (LogData struct)
  • Consider log level filtering to reduce overhead in production

Troubleshooting

Logs Not Appearing

  1. Check that LoggingService is registered
  2. Verify log level is set appropriately
  3. Ensure serial logging is enabled
  4. Check Serial.begin() is called before logging

Memory Issues

  1. Reduce log frequency
  2. Use higher log levels to filter messages

Custom Event Handlers Not Working

  1. Ensure event handlers are registered before logging starts
  2. Check that LogData is properly deleted in custom handlers
  3. Verify event names match exactly