Context, scope, and building blocks

arc42 §3 (context and scope) and §4 (building blocks) for the logging stack (Shared logging base library (FEAT_0070)). The two architecture directives below frame the runtime data flow and the control plane; the building blocks then name the crates and components that realise them.


Structural overview

The logging stack is two crates layered behind one facade: callers emit through taktora-log (taktora-log facade crate (BB_0090)); the default backend taktora-log-dlt (taktora-log-dlt DLT-backend... (BB_0091)) encodes and ships DLT to a co-located daemon via its own daemon client (DLT daemon client (within t... (BB_0092)).

        graph TD
    Caller["any taktora crate<br/>log::* / taktora_log::*"]
    Facade["taktora-log (facade)<br/>BB_0090 — LogSink trait,<br/>init builder, tracing bridge,<br/>console fallback"]
    Backend["taktora-log-dlt (backend)<br/>BB_0091 — dlt-core encoder,<br/>queue + flusher, offline ring,<br/>level table"]
    Client["DLT daemon client<br/>BB_0092 — UDS/TCP, reconnect"]
    Daemon["dlt-daemon<br/>(integrator-provided)"]
    Other["alternative log::Log<br/>(log4rs / env_logger / bespoke)"]

    Caller --> Facade
    Facade -->|"default LogSink"| Backend
    Facade -. "swap path (FEAT_0073)" .-> Other
    Backend --> Client
    Client --> Daemon
    

3. Context and scope

Architecture View: Logging runtime data flow ARCH_0072
status: open
refines: FEAT_0070

Caller code emits via log::* macros through the global log::Log (set once by taktora-log::init()), which routes to the active LogSink. The default LogSink is taktora-log-dlt: it pushes to a bounded queue (no allocation, no I/O on the caller’s thread), and a single background flusher in taktora-log-dlt encodes via dlt-core and writes to the daemon socket. On daemon-down the flusher diverts to the offline ring (per Bounded in-memory ring buff... (REQ_0814)) and resumes drain on reconnect.

        graph TB
  Caller["caller code<br/>log::info!(...)"]
  Macro["log crate facade<br/>(global log::Log)"]
  Sink["active LogSink<br/>(default: taktora-log-dlt)"]
  Queue["bounded SPSC/SPMC queue<br/>(no alloc, no I/O)"]
  Flusher["background flusher<br/>(single task)"]
  Encoder["dlt-core encoder<br/>(AUTOSAR R20-11)"]
  Client["daemon client<br/>UDS or TCP"]
  Daemon["dlt-daemon<br/>(integrator-provided)"]
  Ring["offline ring buffer<br/>(bounded, drop-oldest)"]
  Caller --> Macro
  Macro --> Sink
  Sink --> Queue
  Queue --> Flusher
  Flusher --> Encoder
  Encoder --> Client
  Client --> Daemon
  Flusher -. on daemon down .-> Ring
  Ring -. on reconnect .-> Client
    
Architecture View: Logging control-plane (runtime level changes) ARCH_0073
status: open
refines: FEAT_0075

The dlt-daemon accepts Set-Log-Level / Set-Default-Log-Level injections from DLT clients (dlt-control, DLT Viewer) and forwards them down the same socket connection that taktora-log-dlt’s daemon client owns. The receive half decodes the control message and updates a per-Context-ID atomic level table. Subsequent log::Log::enabled checks short-circuit against that table without re-emit cost.

        graph LR
  Tool["dlt-control /<br/>DLT Viewer"]
  Daemon["dlt-daemon"]
  ClientRx["daemon client<br/>(rx half)"]
  Table["per-context level table<br/>(AtomicU8 per CtxID)"]
  Enabled["log::Log::enabled<br/>short-circuit"]
  Tool -- "Set-Log-Level<br/>(AppID, CtxID, level)" --> Daemon
  Daemon -- "injection" --> ClientRx
  ClientRx --> Table
  Table --> Enabled
    

4. Building blocks

Building Block: taktora-log facade crate BB_0090
status: open
implements: FEAT_0071

The facade crate. Carries the LogSink trait surface, the one-shot init() builder, the global log::Log registration helper, the tracing-log bridge installer, and the console dev-fallback formatter. Re-exports the log crate’s macros and log::kv types so a downstream caller can depend on taktora-log alone. Contains no DLT code — DLT lives in taktora-log-dlt DLT-backend... (BB_0091). std only, per std required, no_std out of... (CON_0026).

Building Block: taktora-log-dlt DLT-backend crate BB_0091
status: open

The DLT backend. Implements both LogSink (for the facade path) and log::Log directly (so the crate is usable without taktora-log facade crate (BB_0090) if a caller wants only DLT). Owns the encoder (dlt-core), the producer→flusher queue, the flusher thread, the daemon client, the offline ring, the per-Context-ID level table, and the control-message receive path. std only. No libdlt build dep, per No build-time dependency on... (CON_0025).

Building Block: DLT daemon client (within taktora-log-dlt) BB_0092
status: open
implements: FEAT_0072
links incoming: REQ_0807

The component inside taktora-log-dlt DLT-backend... (BB_0091) that owns the socket lifecycle. Single connection, UDS by default, TCP opt-in. Reconnect is bounded exponential backoff. The transmit half drains the producer queue (or the offline ring during catch-up) and writes encoded DLT bytes; the receive half decodes inbound control messages and updates the level table. The daemon client is module-public so a downstream crate may reuse it without the log::Log integration if they want raw DLT emission only.