Skip to main content

wide_log/
lib.rs

1//! # wide-log
2//!
3//! A high-speed wide-event logging system for Rust. A single structured event
4//! accumulates fields throughout a request/task lifecycle and is emitted as
5//! one JSON line on completion.
6//!
7//! ## Quick Start
8//!
9//! The [`wide_log!`] macro takes a JSON object literal and generates the key
10//! enum, `Key` trait impl, thread-local storage, guard builder, `current()`
11//! accessor, `scope()` / `scope_default()` async functions (behind the
12//! `tokio` feature), `WideLogLayer` tower middleware (behind the `tokio`
13//! feature), and all logging macros (`wl_set!`, `wl_inc!`, `info!`, etc.) in
14//! one invocation.
15//!
16//! ```
17//! use wide_log::wide_log;
18//!
19//! wide_log!({
20//!     "service": {
21//!         "name": null,
22//!         "version": "1.0.0",
23//!     },
24//!     "requests": counter!,
25//! });
26//!
27//! # fn main() {
28//! let _guard = WideLogGuard::builder().build();
29//! wl_set!("service.name", "example-service");
30//! wl_inc!("requests");
31//! info!("request received");
32//! // _guard drops → duration.total_ms set, timestamp set,
33//! // event emitted as a JSON line to non-blocking stdout.
34//! # wide_log::stdout_emit::flush();
35//! # }
36//! ```
37//!
38//! ## Auto-Added Keys
39//!
40//! - **`"log"`** — log entries from `info!()`, `warn!()`, etc. Handled
41//!   internally; never declared by the user.
42//! - **`"duration"`** — elapsed time in ms. Auto-added as
43//!   `"duration": { "total_ms": duration! }` if not declared.
44//! - **`"event"`** — event metadata. Auto-added as
45//!   `"event": { "timestamp": null, "id": null }` if not declared.
46//!   The `timestamp` is set to an RFC 3339 string on drop. The `id` is
47//!   set to a ULID string (or UUIDv4 with the `uuid` feature) on `build()`.
48//!
49//! ## Customizable Key Strings
50//!
51//! All 8 built-in key strings can be renamed using an optional bracketed
52//! override list before the JSON object:
53//!
54//! ```
55//! use wide_log::wide_log;
56//!
57//! wide_log!([
58//!   Event.Id => "correlation_id",
59//!   Log.Level => "severity",
60//! ], {
61//!   "service": { "name": null },
62//!   "requests": counter!,
63//! });
64//! # fn main() {
65//! # let _guard = WideLogGuard::builder().build();
66//! # wl_inc!("requests");
67//! # info!("request received");
68//! # wide_log::stdout_emit::flush();
69//! # }
70//! ```
71//!
72//! See the README for the full list of override paths.
73//!
74//! ## Builder Pattern
75//!
76//! Use `WideLogGuard::builder()` to construct a guard. The builder allows
77//! specifying a custom timezone, ID generator, and emit function:
78//!
79//! ```
80//! use wide_log::wide_log;
81//!
82//! wide_log!({ "service": { "name": null }, "requests": counter! });
83//!
84//! # fn main() {
85//! // Default: UTC timezone, ULID ID, non-blocking stdout emit
86//! let _guard = WideLogGuard::builder().build();
87//!
88//! // Custom timezone
89//! use chrono_tz::Tz;
90//! let _guard = WideLogGuard::builder()
91//!     .with_timezone(Tz::America__New_York)
92//!     .build();
93//!
94//! // Custom ID generator
95//! let _guard = WideLogGuard::builder()
96//!     .with_id(|| "my-custom-id".to_string())
97//!     .build();
98//!
99//! // Custom emit function
100//! let _guard = WideLogGuard::builder()
101//!     .with_emit(|ev| { println!("{}", ev.to_json().unwrap()); })
102//!     .build();
103//! # wide_log::stdout_emit::flush();
104//! # }
105//! ```
106//!
107//! UUIDv4 IDs are available with the `uuid` feature: `WideLogGuard::builder().with_uuid().build()`.
108//!
109//! ## `info!` Shadowing
110//!
111//! The generated `info!`, `warn!`, `error!`, `debug!`, `trace!` macros shadow
112//! `tracing::info!` etc. when both are in scope. To call the real tracing
113//! macros, use the fully qualified path: `::tracing::info!(...)`. (The default
114//! `default_emit` no longer routes through `tracing`; it writes the
115//! serialized JSON line directly to non-blocking stdout via
116//! [`stdout_emit::submit`](crate::stdout_emit::submit).)
117//!
118//! ## Features
119//!
120//! - `tokio` — enables async support: `scope()`, `scope_default()`,
121//!   `WideLogLayer` tower middleware, and `tokio::task_local!` storage.
122//! - `uuid` — enables `WideLogGuardBuilder::with_uuid()` for UUIDv4 ID
123//!   generation instead of the default ULID.
124
125pub(crate) mod context;
126pub(crate) mod error;
127pub(crate) mod guard;
128pub(crate) mod key;
129pub(crate) mod log;
130pub(crate) mod value;
131pub(crate) mod wide_event;
132
133#[cfg(feature = "tokio")]
134pub(crate) mod middleware;
135
136pub use error::Error;
137pub use guard::ScopedGuard;
138pub use key::Key;
139pub use value::Value;
140pub use wide_event::WideEvent;
141
142pub use context::ContextCell;
143pub use context::RestoreOnDrop;
144
145/// Public API surface used by the `wide_log!` macro expansion. The macro
146/// needs to construct a [`WideEvent`], call mutators like
147/// [`WideEvent::add_path`], and read `values` / `present_count` to
148/// implement the inlined fast path for the guard's drop. The mutators
149/// are `pub(crate)` for end users (so they don't bypass the
150/// schema-first API), but the macro is expanded in user crates and
151/// therefore needs a public surface.
152///
153/// Stability: the contents of this module are an internal
154/// implementation detail of the `wide_log!` macro and may change
155/// between releases. Do not call these directly.
156#[doc(hidden)]
157pub mod __macro_internals {
158    pub use crate::value::Value;
159}
160
161pub mod stdout_emit;
162
163/// The `wide_log!` proc-macro. See the [crate-level documentation](crate)
164/// for syntax and usage details.
165///
166/// Takes a JSON object literal as its only parameter. The JSON structure
167/// defines all keys, their nesting/paths, default values, and which keys
168/// are counters or durations. The macro generates:
169///
170/// - The `EventKey` enum (`#[repr(u8)]`, one variant per unique JSON key)
171/// - The `Key` trait impl (`as_str`, `MAX_KEYS`, `as_index`,
172///   `DURATION_PATH`, `TIMESTAMP_PATH`, `ID_PATH`)
173/// - `__wl_resolve_path` — compile-time path resolution function
174/// - Thread-local storage (`CURRENT_EVENT: ContextCell<WideEvent<EventKey>>`)
175/// - `default_emit` — serializes via `sonic_rs` and writes the JSON line to
176///   non-blocking stdout via `stdout_emit::submit`
177/// - `WideLogGuardBuilder` — builder for constructing guards with timezone,
178///   ID generator, and emit function
179/// - `WideLogGuard` — guard type (constructed via `builder().build()`)
180/// - `current()` — returns the innermost active event
181/// - `scope()` / `scope_default()` (behind `tokio` feature)
182/// - `WideLogLayer` tower middleware (behind `tokio` feature)
183/// - All logging macros: `wl_set!`, `wl_inc!`, `wl_dec!`, `wl_add!`,
184///   `wl_null!`, `info!`, `warn!`, `error!`, `debug!`, `trace!`
185///
186/// # Value Markers
187///
188/// | Marker | Meaning |
189/// |---|---|
190/// | `duration!` | Duration leaf; set to elapsed ms on drop |
191/// | `counter!` | Incrementable counter; init to 0 (absent) |
192/// | `null` | No default value; set via `wl_set!` |
193/// | `"literal"` | String default; set on guard creation |
194/// | `123` | Numeric default; set on guard creation |
195/// | `true`/`false` | Boolean default; set on guard creation |
196///
197/// # Duration Auto-Add Rules
198///
199/// If no `"duration"` key is declared, the macro adds
200/// `"duration": { "total_ms": duration! }` automatically. See the README for
201/// the full duration resolution table.
202///
203/// # Event Auto-Add Rules
204///
205/// If no `"event"` key is declared, the macro adds
206/// `"event": { "timestamp": null, "id": null }` automatically.
207/// The `timestamp` is set to an RFC 3339 string on drop.
208/// The `id` is set to a ULID string (or UUIDv4 with the `uuid` feature)
209/// on `build()`.
210pub use wide_log_macros::wide_log;
211
212#[cfg(feature = "tokio")]
213pub mod __re_exports {
214    pub use tokio;
215    pub use tower;
216}
217
218pub mod __re_exports_core {
219    pub use chrono;
220    pub use chrono_tz;
221    pub use ulid;
222}
223
224#[cfg(feature = "uuid")]
225pub mod __re_exports_uuid {
226    pub use uuid;
227}