Log
The Log module is the global bridge between Xila logging calls and a concrete backend implementation.
The Log module is the global bridge between Xila logging calls and a concrete backend implementation.
Role in system
Section titled “Role in system”- Provides uniform log macros (
error!,warning!,information!,debug!,trace!) across modules. - Adapts Xila-specific
LoggerTraitto the externallogcrate runtime. - Centralizes level filtering and formatted record emission policy.
Responsibilities and boundaries
Section titled “Responsibilities and boundaries”In scope
- Global logger initialization and registration.
- Severity-level mapping and default formatting.
- Backend trait abstraction (
enabled,write, optionalflush).
Out of scope
- Transport/storage mechanics (console, serial, file, remote).
- Advanced aggregation/query infrastructure.
Internal architecture
Section titled “Internal architecture”LOGGER_INSTANCE: OnceLock<Logger>stores single logger adapter.LoggerTraitis backend contract;Loggeradapter implementslog_external::Log.Recordstructure captures normalized level/target/arguments.- Default
LoggerTrait::logformatting decorates lines with level tag and ANSI color tokens.
Contract vs implementation
- Contract: backend
LoggerTraitmethods and macro-level behavior. - Implementation: concrete formatting/color tokens and
set_max_levelpolicy.
graph TD
Clients@{ shape: processes, label: "Modules / executables" }
Macros[error!/warning!/information!/debug!/trace!]
Bridge[log module bridge]
Once[LOGGER_INSTANCE OnceLock]
Backend[LoggerTrait backend]
Clients --> Macros
Macros --> Bridge
Bridge --> Once
Once --> Backend
Backend -->|write/flush| Output[Console / file / platform sink]
Lifecycle and execution model
Section titled “Lifecycle and execution model”- Platform creates backend implementing
LoggerTrait. - Runtime calls
log::initialize(...)once. - Module macros emit through
logecosystem into adapter and backend sink.
Data/control flow
Section titled “Data/control flow”- Macro invocation ->
log_external->Loggeradapter ->LoggerTrait::enabled/log/write. - Initialization attempts after first registration do not replace logger; they emit an error log.
Concurrency and synchronization model
Section titled “Concurrency and synchronization model”- Singleton registration guarded by
OnceLock. - Thread-safety at runtime relies on backend
LoggerTrait: Send + Syncand backend internals.
Dependency model
Section titled “Dependency model”- Depends on
logecosystem crate for macro/runtime integration. - Consumed by nearly all core modules for diagnostics.
Failure semantics and recovery behavior
Section titled “Failure semantics and recovery behavior”initializereturnsOk(())even if logger was already set inlogruntime; duplicate init is reported via error record.- Backend write/flush behavior is backend-defined; module itself does not buffer/retry.
Extension points
Section titled “Extension points”- Provide alternative backend implementations for each platform.
- Override
LoggerTrait::logfor custom formatting or structured payload conventions. - Add runtime filtering policy in backend or wrapper layer.
Known limitations and trade-offs
Section titled “Known limitations and trade-offs”- Single global logger; dynamic replacement/reconfiguration is limited.
- Formatting includes ANSI control sequences by default, which may be undesirable in non-terminal sinks unless backend adapts.
- Reliability guarantees (buffering, durability) are sink-specific.
Backend contract and global initialization
Section titled “Backend contract and global initialization”A backend implements LoggerTrait: Send + Sync, supplying enabled(Level) and write(fmt::Arguments). The default log(Record) method formats severity, target and arguments with ANSI escape sequences; flush() defaults to a no-op and may be overridden. Level covers Error, Warn, Info, Debug and Trace.
initialize(&'static dyn LoggerTrait) stores a logger adapter in a OnceLock and registers it with the Rust log facade. This is process-global integration, unlike managers that can be freely instantiated. The facade maximum level is set to Trace, but the backend’s enabled() still decides which records are emitted.
Important initialization caveat: if set_logger() fails, the current implementation logs an error directly to the supplied backend and still returns Ok(()). Consequently a successful return does not prove that this backend became the active global logger. is_initialized() checks whether the internal OnceLock contains an adapter, not whether the requested backend was installed.
Applications can use the re-exported error!, warning!, information!, debug!, and trace! macros. Transport, persistence and concurrency behavior belong to the concrete backend, not the facade.