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 messageslog/info- Info level messageslog/warn- Warning level messageslog/error- Error level messageslog/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 ofDEBUG,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):
- 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;
});
- 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
- Check that LoggingService is registered
- Verify log level is set appropriately
- Ensure serial logging is enabled
- Check Serial.begin() is called before logging
Memory Issues
- Reduce log frequency
- Use higher log levels to filter messages
Custom Event Handlers Not Working
- Ensure event handlers are registered before logging starts
- Check that LogData is properly deleted in custom handlers
- Verify event names match exactly