Files
spore/docs/LoggingService.md

239 lines
6.0 KiB
Markdown

# 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
```cpp
#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:
```cpp
// 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:
```cpp
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:**
```json
{
"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:**
```json
{
"success": true,
"level": "DEBUG"
}
```
**Error Response:**
```json
{
"error": "Invalid log level. Must be one of: DEBUG, INFO, WARN, ERROR"
}
```
### Get Configuration
```
GET /api/logging/config
```
Returns complete logging configuration.
**Response:**
```json
{
"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:
```cpp
ctx.on("log/info", [](void* data) {
LogData* logData = static_cast<LogData*>(data);
// Send to your custom destination
sendToNetwork(logData->message);
delete logData;
});
```
2. Or create a custom LoggingService subclass:
```cpp
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:
```cpp
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