json_subscriber/lib.rs
1//! # `json-subscriber`
2//!
3//! `json-subscriber` is (mostly) a drop-in replacement for `tracing_subscriber::fmt().json()`.
4//!
5//! It provides helpers to be as compatible as possible with `tracing_subscriber` while also
6//! allowing for simple extensions to the format to include custom data in the log lines.
7//!
8//! The end goal is for each user to be able to define the structure of their JSON log lines as they
9//! wish. Currently, the library only allows what `tracing-subscriber` plus OpenTelemetry trace and
10//! span IDs.
11//!
12//! ## Compatibility
13//!
14//! However you created your `FmtSubscriber` or `fmt::Layer`, the same thing should work in this
15//! crate.
16//!
17//! For example in `README.md` in Tracing, you can see an yak-shaving example where if you just
18//! change `tracing_subscriber` to `json_subscriber`, everything will work the same, except the logs
19//! will be in JSON.
20//!
21//! ```rust
22//! use tracing::info;
23//! use json_subscriber;
24//! #
25//! # mod yak_shave { pub fn shave_all(n: u32) -> u32 { n } }
26//!
27//! // install global collector configured based on RUST_LOG env var.
28//! json_subscriber::fmt::init();
29//!
30//! let number_of_yaks = 3;
31//! // this creates a new event, outside of any spans.
32//! info!(number_of_yaks, "preparing to shave yaks");
33//!
34//! let number_shaved = yak_shave::shave_all(number_of_yaks);
35//! info!(
36//! all_yaks_shaved = number_shaved == number_of_yaks,
37//! "yak shaving completed."
38//! );
39//! ```
40//!
41//! Most configuration under `tracing_subscriber::fmt` should work equivalently. For example one can
42//! create a layer like this:
43//!
44//! ```rust
45//! json_subscriber::fmt()
46//! // .json()
47//! .with_max_level(tracing::Level::TRACE)
48//! .with_current_span(false)
49//! .init();
50//! ```
51//!
52//! Calling `.json()` is not needed and the method does nothing and is marked as deprecated. It is
53//! kept around for simpler migration from `tracing-subscriber` though.
54//!
55//! Trying to call `.pretty()` or `.compact()` will however result in an error. `json-tracing` does
56//! not support any output other than JSON.
57//!
58//! ## Extensions
59//!
60//! ### OpenTelemetry
61//!
62//! To include trace ID and span ID from opentelemetry in log lines, simply call
63//! `with_opentelemetry_ids`. This will have no effect if you don't also configure a
64//! `tracing-opentelemetry` layer.
65//!
66//! ```rust
67//! # #[cfg(opentelemetry)]
68//! # {
69//! let tracer = todo!();
70//! let opentelemetry = tracing_opentelemetry::layer().with_tracer(tracer);
71//! let json = json_subscriber::layer()
72//! .with_current_span(false)
73//! .with_span_list(false)
74//! .with_opentelemetry_ids(true);
75//!
76//! tracing_subscriber::registry()
77//! .with(opentelemetry)
78//! .with(json)
79//! .init();
80//! # }
81//! ```
82//!
83//! This will produce log lines like for example this (without the formatting):
84//!
85//! ```json
86//! {
87//! "fields": {
88//! "message": "shaving yaks"
89//! },
90//! "level": "INFO",
91//! "openTelemetry": {
92//! "spanId": "35249d86bfbcf774",
93//! "traceId": "fb4b6ae1fa52d4aaf56fa9bda541095f"
94//! },
95//! "target": "readme_opentelemetry::yak_shave",
96//! "timestamp": "2024-06-06T23:09:07.620167Z"
97//! }
98//! ```
99
100#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))]
101#![warn(clippy::pedantic)]
102#![allow(clippy::struct_excessive_bools)]
103#![allow(clippy::module_name_repetitions)]
104#![allow(clippy::too_many_lines)]
105
106mod cached;
107mod cursor;
108mod fields;
109pub mod fmt;
110mod layer;
111mod serde;
112mod visitor;
113
114#[cfg(test)]
115mod tests;
116
117pub use fmt::{fmt, layer};
118pub use layer::JsonLayer;