-
Notifications
You must be signed in to change notification settings - Fork 0
Logging
The SERP logging framework (serp::logger) provides structured, leveled, multi-strategy logging with thread tracking and a hierarchical context model. It is designed for multi-threaded service architectures where each log message should carry enough context to trace it back to the originating service, thread, and method call.
| Target | Includes |
|---|---|
Serp::logger |
Core API (levels, tags, strategies interface) |
Serp::logger_console |
Core + console output strategy |
Serp::logger_file |
Core + file output strategy (with rotation) |
Link the appropriate target in your CMakeLists.txt:
target_link_libraries(my_service PRIVATE Serp::logger_console)Application code
│
▼
logInfo()->info(...) ◄── fluent API (LogWriter)
│
▼
LogManager (singleton) ◄── thread registry, strategy dispatch
│
├──► LogStrategyConsole (stdout with color)
├──► LogStrategyFile (rotating file)
└──► MyCustomStrategy (your plugin)
Key components:
| Component | Role |
|---|---|
LogManager |
Global singleton. Owns strategy list, thread name registry, and global log level. |
LogWriter |
Fluent message builder returned by the log*() macros. |
LogTag |
Named tag for method/communication annotations. |
Loggable |
Mixin for objects that participate in the logging hierarchy. |
| Log strategies | Pluggable output handlers implementing a common interface. |
Levels are ordered from most verbose to most silent:
| Level | Macro | Use case |
|---|---|---|
verbose |
logVerbose() |
Detailed trace data; high frequency. |
debug |
logDebug() |
Developer diagnostics. |
info |
logInfo() |
Notable events, state changes. |
warn |
logWarn() |
Unexpected but recoverable situations. |
error |
logError() |
Failures that require attention. |
silent |
— | Suppresses all output (used as a filter threshold). |
Set the global minimum level:
serp::logger::setLevel(eLogLevel::debug);Include the header:
#include <serp/logger/Logger.hpp>Write log messages using the fluent macro interface:
logVerbose()->verbose("Detailed trace: value=" + std::to_string(val));
logDebug()->debug("Processing request id=" + std::to_string(id));
logInfo()->info("Service started successfully");
logWarn()->warning("Retry attempt " + std::to_string(n) + " of 3");
logError()->error("Connection failed: " + errMsg);Each log*() macro returns a LogWriter that captures the call site (file, line, thread) automatically. The ->level(message) call commits the message to all registered strategies.
Strategies must be registered before any log output is produced — typically at the top of main() or in the process entry point.
#include <serp/logger/strategies/LogStrategyConsole.hpp>
#include <serp/logger/strategies/LogStrategyFile.hpp>
// Console output (color-coded by level)
serp::logger::addStrategy<LogStrategyConsole>();
// File output with rotation
serp::logger::addStrategy<LogStrategyFile>("/var/log/myapp/myapp.log");
// Custom strategy
serp::logger::addStrategy(std::make_shared<MyCustomStrategy>());Multiple strategies may be active simultaneously. Every log message is dispatched to all registered strategies.
LogStrategyFile supports automatic log rotation by size and file count:
serp::logger::addStrategy<LogStrategyFile>(
"/var/log/myapp/myapp.log",
5 * 1024 * 1024, // rotate after 5 MB
4 // keep 4 rotated files
);When the active file reaches the size limit, it is renamed (e.g., myapp.log.1) and a new file is opened. Old rotation files beyond the count limit are deleted.
Log the entry and exit of service method calls with a structured tag:
logMethod("ClimateService.setTemperature", zone, temp);This emits a structured entry that can be filtered and visualized separately from general log messages. The logMethod macro is typically called at the top of a method implementation to record inbound traffic.
Log cross-thread communication explicitly, capturing caller thread, callee thread, service name, and arguments:
itcLog(eLogLevel::info,
"UIThread", // caller thread name
"ClimateThread", // callee thread name
"ClimateService::setTemperature",
zone, temp);ITC log entries are decorated differently from general messages to make cross-thread call flows easy to trace.
serp::Loggable is a mixin that allows an object to participate in the logging hierarchy. When mixed in, the object can link itself to a parent context, and log messages it emits carry that context chain.
#include <serp/logger/Loggable.hpp>
class MyService : public serp::Service, public serp::Loggable {
public:
MyService(serp::EventLoop& loop)
: serp::Service(loop, "MyService") {}
void initialize(std::shared_ptr<ParentContext> parent) {
Loggable::link(parent); // attach to parent for context chaining
}
void doSomething() {
logInfo()->info("Called from MyService");
// Message is tagged with MyService's context in the hierarchy
}
};Why use it? In a tree of services and components, Loggable::link() lets the log infrastructure know where a given object lives in the ownership graph. This context appears in log output and makes it possible to filter messages by subsystem.
Thread names appear in log output to identify which thread produced each message. SERP registers its own EventLoop threads automatically. For custom threads:
serp::logger::registerThread("MyWorkerThread");Call this once at thread startup.
Implement the strategy interface to route log output anywhere — a network socket, a database, a test recorder, etc.:
class MyCustomStrategy : public serp::logger::ILogStrategy {
public:
void log(eLogLevel level,
const std::string& thread,
const std::string& file,
int line,
const std::string& message) override
{
// Route message to your output
myOutput.write(level, thread, message);
}
};
serp::logger::addStrategy(std::make_shared<MyCustomStrategy>());#include <serp/logger/Logger.hpp>
#include <serp/logger/strategies/LogStrategyConsole.hpp>
#include <serp/logger/strategies/LogStrategyFile.hpp>
int main(int argc, char** argv) {
// Set up logging before anything else
serp::logger::setLevel(eLogLevel::debug);
serp::logger::addStrategy<LogStrategyConsole>();
serp::logger::addStrategy<LogStrategyFile>(
"/var/log/myapp/myapp.log",
10 * 1024 * 1024, // 10 MB rotation
3 // keep 3 files
);
logInfo()->info("Process starting");
return serp::App::instance().run(argc, argv);
}- Services and Lifecycle — thread model that determines thread names in logs
- Runtime and Debug Tools — runtime method invocation for live debugging
Getting Started
The Development Model
Architecture Language
Code Generator
- Generator Overview
- Generated Code Layout
- Deployment Configurations
- Lifecycle Backends
- CMake Integration
Framework Internals
- Core Concepts
- Services & Lifecycle
- Methods
- Properties
- Notifications
- Timers & Watchdog
- Promises & Async
- Streams
- Commands
- Logging
- Test Engine
- Transports
- Runtime & Debug Tools
VS Code Plugin
Examples