Log
The Log module is the global bridge between Xila logging calls and a concrete backend implementation.
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
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
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.
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
- 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
- Singleton registration guarded by
OnceLock. - Thread-safety at runtime relies on backend
LoggerTrait: Send + Syncand backend internals.
Dependency model
- Depends on
logecosystem crate for macro/runtime integration. - Consumed by nearly all core modules for diagnostics.
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
- 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
- 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
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.