Skip to content

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 LoggerTrait to the external log crate 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, optional flush).

Out of scope

  • Transport/storage mechanics (console, serial, file, remote).
  • Advanced aggregation/query infrastructure.

Internal architecture ​

  • LOGGER_INSTANCE: OnceLock<Logger> stores single logger adapter.
  • LoggerTrait is backend contract; Logger adapter implements log_external::Log.
  • Record structure captures normalized level/target/arguments.
  • Default LoggerTrait::log formatting decorates lines with level tag and ANSI color tokens.

Contract vs implementation

  • Contract: backend LoggerTrait methods and macro-level behavior.
  • Implementation: concrete formatting/color tokens and set_max_level policy.

Lifecycle and execution model ​

  1. Platform creates backend implementing LoggerTrait.
  2. Runtime calls log::initialize(...) once.
  3. Module macros emit through log ecosystem into adapter and backend sink.

Data/control flow ​

  • Macro invocation -> log_external -> Logger adapter -> 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 + Sync and backend internals.

Dependency model ​

  • Depends on log ecosystem crate for macro/runtime integration.
  • Consumed by nearly all core modules for diagnostics.

Failure semantics and recovery behavior ​

  • initialize returns Ok(()) even if logger was already set in log runtime; 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::log for 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.

Implementation references ​

References / See also ​