Module log

log
Stability: unstable — one name is a known convention violation and one piece of the record shape is missing. `get_level` carries a `get_` prefix that D2 rules out (Rust would spell it `level()`); it is listed among the D2 violations in `plans/STD_API_STABILIZATION.md` §1 and renaming it is breaking, so it has not happened yet. The `Sink` trait and `YO_LOG` are themselves one release old (#494). Three gaps against Rust's `log`, each of which would change a signature here: there is no `Record` — a sink gets `(level, target, msg)` and cannot learn the file, line or module a line came from, because `target` is caller-supplied text rather than metadata; `YO_LOG` takes a bare level where `env_logger` takes per-target directives (`RUST_LOG=mymod=debug`), which is the filtering everyone actually wants; and `set_sink` is re-settable at any time, where Rust's `set_logger` is set-once and returns a `Result`, so here a library can silently steal the application's sink. Freezing follows those decisions. — stable modules only change additively; this one may still change.

Structured logging — level-filtered, optionally timestamped and target-tagged, thread-safe, with a free-function facade (plans/archive/STD_API_AUDIT.md §7 log row: the zero-user rewrite window).

log :: import "std/log";
log.set_level(log.Level.Debug);
log.info(`server started on ${port}`);         // any ToString value
log.info_lazy(() => expensive_summary());        // String, built only if it passes
log.set_timestamps(true);
log.warn_target(`db`, `slow query: ${ms}ms`);   // "[WARN ] [db] ..."

The level filter runs BEFORE the message is rendered — the plain forms still evaluate their argument at the call site (the value already exists), but the *_lazy forms take a () -> String closure CALLED ONLY when the message will actually be emitted. A single mutex serializes the filter check and the write, so lines from different OS threads never interleave (the parallelism runtime is the multi-threaded path; the async runtime is single-threaded and never contends).

Choosing a level follows Rust's log crate: Error for a failure the program could not handle, Warn for a hazard it recovered from, Info for the handful of lines an operator wants, Debug for developer detail, Trace for per-step verbosity. The default filter is Info, so Debug and Trace produce nothing until set_level or YO_LOG lowers it.

Stability

unstable — one name is a known convention violation and one piece of the record shape is missing.

get_level carries a get_ prefix that D2 rules out (Rust would spell it level()); it is listed among the D2 violations in plans/STD_API_STABILIZATION.md §1 and renaming it is breaking, so it has not happened yet. The Sink trait and YO_LOG are themselves one release old (#494).

Three gaps against Rust's log, each of which would change a signature here: there is no Record — a sink gets (level, target, msg) and cannot learn the file, line or module a line came from, because target is caller-supplied text rather than metadata; YO_LOG takes a bare level where env_logger takes per-target directives (RUST_LOG=mymod=debug), which is the filtering everyone actually wants; and set_sink is re-settable at any time, where Rust's set_logger is set-once and returns a Result, so here a library can silently steal the application's sink. Freezing follows those decisions.

Types

Level enum
Level

Log severity, ascending. Off disables all output — filtering against it drops every message, including Error.

Variants

VariantFieldsDescription
Trace
Debug
Info
Warn
Error
Off

Trait Implementations

impl(generic(T : Type), where(T <: ToString), T : (ToString))
impl(generic(T : Type), where(T <: ToString), T : (ToString), Format)
format : fn(self : Self, spec : str) -> String

Render self under spec. An unrecognised spec degrades to the plain to_string() rendering rather than failing.

Parameters

NameTypeNotes
selfSelf
specstr

Returns: String

impl(Level, ToString(...))
to_string : (Level) fn(self : Level) -> String

Render self as the text a USER should read — Rust's Display::fmt, not its Debug. Hand-written (or generated by derive(Error) from a per-variant format string) whenever the structural form would be wrong.

Parameters

NameTypeNotes
selfLevel

Returns: String

impl(Level, Eq(Level))
Methods
== : (Level) fn(lhs : Level, rhs : Level) -> bool

Parameters

NameTypeNotes
lhsLevel
rhsLevel

Returns: bool

!= : (Level) fn(lhs : Level, rhs : Level) -> bool

Parameters

NameTypeNotes
lhsLevel
rhsLevel

Returns: bool

LogOutput enum
LogOutput

Where log lines are written.

Variants

VariantFieldsDescription
Stderr
Stdout

Traits / Modules

Sink trait
Sink

A pluggable log destination — implement it to send records somewhere other than stdout/stderr (a file, a ring buffer, a test recorder, a network collector).

write_line receives the record's PARTS, not a formatted line, so a sink is free to render its own format — JSON, say — instead of re-parsing ours. target is empty when the caller used the untargeted forms.

It is called with the module's mutex HELD, which is what keeps concurrent lines from interleaving. A sink must therefore not log, directly or indirectly: that would deadlock.

Methods

write_line : fn(self : Self, level : Level, target : String, msg : String) -> unit

Parameters

NameTypeNotes
selfSelf
levelLevel
targetString
msgString

Returns: unit

Functions

fn(name : String) -> Option(Level)

Parse a level name, case-insensitively — trace, debug, info, warn, error, off. .None for anything else.

warning is accepted for warn because it is the spelling people reach for, and rejecting it silently would be the worst of the three options.

Parameters

NameTypeNotes
nameString

Returns: Option(Level)

set_sink function
fn(sink : Dyn(Sink)) -> unit

Send every record to sink instead of stdout/stderr.

set_output and set_timestamps stop having any effect while a sink is installed — rendering is the sink's job. The LEVEL filter still applies, so a sink never sees a record the configuration suppressed.

Parameters

NameTypeNotes
sinkDyn(Sink)

Returns: unit

clear_sink function
fn() -> unit

Go back to writing to stdout/stderr.

Returns: unit

init_from_env function
fn() -> Level

Apply YO_LOG to the level filter, if it is set to a name level_from_string recognises. Returns the level in force afterwards.

Explicit, not automatic, for the same reason Rust's env_logger::init() is: a library that silently reconfigured logging on first use would be impossible to reason about. Call it once at startup.

An unset or unrecognised YO_LOG leaves the current level alone — a typo must not silence a program.

Returns: Level

set_level function
fn(level : Level) -> unit

Set the minimum level that is emitted (Off silences everything). The default, before any call to this, is Info.

Parameters

NameTypeNotes
levelLevel

Returns: unit

get_level function
fn() -> Level

The current minimum level.

Returns: Level

set_output function
fn(output : LogOutput) -> unit

Choose stdout or stderr (default stderr).

Parameters

NameTypeNotes
outputLogOutput

Returns: unit

set_timestamps function
fn(on : bool) -> unit

Prefix each line with an RFC 3339 UTC timestamp when true.

Parameters

NameTypeNotes
onbool

Returns: unit

enabled function
fn(level : Level) -> bool

True iff a message at level would be emitted right now — the guard the lazy forms check before building their message.

Parameters

NameTypeNotes
levelLevel

Returns: bool

log function
fn(generic(T : Type), level : Level, msg : T, where(T <: ToString)) -> unit

Log a ToString value at level.

Type Parameters

NameTypeNotes
TTypecomptime

Parameters

NameTypeNotes
levelLevel
msgT

Returns: unit

log_target function
fn(generic(T : Type), level : Level, target : str, msg : T, where(T <: ToString)) -> unit

Log a ToString value at level, tagged with a target/module string.

Type Parameters

NameTypeNotes
TTypecomptime

Parameters

NameTypeNotes
levelLevel
targetstr
msgT

Returns: unit

log_lazy function
fn(level : Level, make : Impl(Fn() -> String)) -> unit

Log at level, building the message from make ONLY when it passes the filter — for messages that are costly to construct.

Parameters

NameTypeNotes
levelLevel
makeImpl(Fn() -> String)

Returns: unit

trace function
fn(generic(T : Type), msg : T, where(T <: ToString)) -> unit

Per-step verbosity at Trace — Rust's trace!. Silent under the default Info filter.

Type Parameters

NameTypeNotes
TTypecomptime

Parameters

NameTypeNotes
msgT

Returns: unit

debug function
fn(generic(T : Type), msg : T, where(T <: ToString)) -> unit

Developer detail at Debug — Rust's debug!. Also silent under the default Info filter.

Type Parameters

NameTypeNotes
TTypecomptime

Parameters

NameTypeNotes
msgT

Returns: unit

info function
fn(generic(T : Type), msg : T, where(T <: ToString)) -> unit

A line an operator should see, at Info — Rust's info!. This is the lowest level the default filter admits.

Type Parameters

NameTypeNotes
TTypecomptime

Parameters

NameTypeNotes
msgT

Returns: unit

warn function
fn(generic(T : Type), msg : T, where(T <: ToString)) -> unit

A hazard the program recovered from, at Warn — Rust's warn!.

Type Parameters

NameTypeNotes
TTypecomptime

Parameters

NameTypeNotes
msgT

Returns: unit

error function
fn(generic(T : Type), msg : T, where(T <: ToString)) -> unit

A failure, at Error — Rust's error!. The highest level, but still suppressed by Level.Off, which drops everything.

Type Parameters

NameTypeNotes
TTypecomptime

Parameters

NameTypeNotes
msgT

Returns: unit

trace_target function
fn(generic(T : Type), target : str, msg : T, where(T <: ToString)) -> unit

trace tagged with a subsystem name, which renders as [db] between the level and the message and reaches a Sink as its own argument — Rust's trace!(target: "db", ...).

The tag is caller-supplied text; nothing derives or checks it, and it does not participate in filtering (the level is the only filter).

Type Parameters

NameTypeNotes
TTypecomptime

Parameters

NameTypeNotes
targetstr
msgT

Returns: unit

debug_target function
fn(generic(T : Type), target : str, msg : T, where(T <: ToString)) -> unit

debug with a subsystem tag; see trace_target.

Type Parameters

NameTypeNotes
TTypecomptime

Parameters

NameTypeNotes
targetstr
msgT

Returns: unit

info_target function
fn(generic(T : Type), target : str, msg : T, where(T <: ToString)) -> unit

info with a subsystem tag; see trace_target.

Type Parameters

NameTypeNotes
TTypecomptime

Parameters

NameTypeNotes
targetstr
msgT

Returns: unit

warn_target function
fn(generic(T : Type), target : str, msg : T, where(T <: ToString)) -> unit

warn with a subsystem tag; see trace_target.

Type Parameters

NameTypeNotes
TTypecomptime

Parameters

NameTypeNotes
targetstr
msgT

Returns: unit

error_target function
fn(generic(T : Type), target : str, msg : T, where(T <: ToString)) -> unit

error with a subsystem tag; see trace_target.

Type Parameters

NameTypeNotes
TTypecomptime

Parameters

NameTypeNotes
targetstr
msgT

Returns: unit

trace_lazy function
fn(make : Impl(Fn() -> String)) -> unit

trace, with the message built by make ONLY if Trace passes the filter — the form to use when rendering costs real work (a formatted dump, a query plan). The plain forms cannot help there: their argument is evaluated at the call site whatever the filter says.

Untagged; there is no lazy *_target form.

Parameters

NameTypeNotes
makeImpl(Fn() -> String)

Returns: unit

debug_lazy function
fn(make : Impl(Fn() -> String)) -> unit

debug with the message built only if Debug passes the filter; see trace_lazy.

Parameters

NameTypeNotes
makeImpl(Fn() -> String)

Returns: unit

info_lazy function
fn(make : Impl(Fn() -> String)) -> unit

info with the message built only if Info passes the filter; see trace_lazy.

Parameters

NameTypeNotes
makeImpl(Fn() -> String)

Returns: unit

warn_lazy function
fn(make : Impl(Fn() -> String)) -> unit

warn with the message built only if Warn passes the filter; see trace_lazy.

Parameters

NameTypeNotes
makeImpl(Fn() -> String)

Returns: unit

error_lazy function
fn(make : Impl(Fn() -> String)) -> unit

error with the message built only if Error passes the filter; see trace_lazy.

Parameters

NameTypeNotes
makeImpl(Fn() -> String)

Returns: unit