Skip to content

feat: add native Rust logging facade - #242

Open
tisonkun wants to merge 2 commits into
mainfrom
codex/native-rust-facade
Open

tisonkun wants to merge 2 commits into
mainfrom
codex/native-rust-facade

Conversation

@tisonkun

@tisonkun tisonkun commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Application code currently needs to construct records manually or go through log to emit Logforth events. This adds an explicit-logger native facade over the existing record, value, and dispatch APIs.

let logger = logforth::builder()
    .dispatch(|d| d.append(logforth::append::Stderr::default()))
    .build();
logforth::info!(logger, {
    "completed" => 3u64,
    "healthy" => true,
}, "batch complete");
logforth::info!(logger, { "queue.depth" => 0 });
logger.flush();
  • log! accepts every native level; trace! through fatal! provide the same field-map and message syntax. Macros borrow the logger and fields, evaluate expressions once, and prefilter before evaluating event data. Full-record filtering still runs; formatters may consume the same event more than once.
  • Fields use standard From conversions into the existing kv::Value, with no new conversion trait. Scalars preserve their value kinds, strings and existing values are borrowed, and Value::display/debug, Value::list/map, and Value::none cover explicit text, nested data, and absence.
  • The target is the calling module; source module/file/line/column identify the actual call site. Existing module filters apply. Custom targets remain available through RecordBuilder and the log bridge.
  • Logger ownership and dispatch behavior stay unchanged. Build separate loggers for separate output policies, or share a logger with Arc<Logger>. The optional bridge can use the same logger. Flush stays explicit; fatal! does not terminate or flush.

This PR deliberately stops at native event construction. It adds no logger name, logger-bound context, field merging precedence, or context propagation model. Context governance needs a separate design covering event fields, diagnostics, collisions, and capture timing across appenders. Native Serde capture and serializer relocation are also deferred; the existing bridge serializer is unchanged.

The README and crate docs use the native facade as the primary entry point, and CI runs a featureless native example. Integration tests cover lazy evaluation, borrowed and nested fields, source metadata, full-record filtering, module filtering, independent logger policies, and native/bridge interoperability.

Validation: workspace tests with all features; cargo x lint; Rust 1.91 core and featureless facade tests; native integration tests with bridge-log and bridge-log-serde separately; the featureless native example; strict core/facade rustdoc. The CI matrix checks Linux, macOS, and Windows on stable and Rust 1.91.

Related to #205.

@tisonkun
tisonkun marked this pull request as ready for review September 22, 2026 12:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant