A tracing layer that outputs JSON-formatted logs without pulling in serde, serde_json, or tracing-serde.
Quick Links: Why? | Who is this for? | Usage | Configuration | Comparisons | MSRV
Enabling the json feature on tracing-subscriber pulls in 7 additional crates
(serde, serde_json, tracing-serde, and their transitive dependencies).
tracing-microjson produces the same output format using a hand-written JSON
formatter with zero serialization framework dependencies.
- Projects where compile time and binary size matter
- Environments with strict dependency auditing requirements
- Anyone who wants structured JSON logging with a minimal dependency footprint
[dependencies]
tracing-microjson = "0.3"use tracing_microjson::JsonLayer;
use tracing_subscriber::prelude::*;
tracing_subscriber::registry()
.with(JsonLayer::new(std::io::stderr))
.init();use tracing_microjson::JsonLayer;
use tracing_subscriber::prelude::*;
tracing_subscriber::registry()
.with(
JsonLayer::new(std::io::stderr)
.with_target(true) // include event target (default: true)
.with_file(true) // include source filename (default: false)
.with_line_number(true) // include source line number (default: false)
.with_thread_ids(true) // include thread ID (default: false)
.with_thread_names(true) // include thread name (default: false)
.flatten_event(true) // flatten fields to top level (default: false)
.without_time(), // disable timestamps (default: SystemTimestamp)
)
.init();All comparisons are against tracing-subscriber with its json feature enabled.
| Feature | tracing-subscriber json |
tracing-microjson |
|---|---|---|
| JSON event output | ✅ Yes | ✅ Yes |
| Span fields & nesting | ✅ Yes | ✅ Yes |
| Target, file, line | ✅ Yes | ✅ Yes |
flatten_event |
✅ Yes | ✅ Yes |
| Custom timestamps | ✅ Yes | ✅ Yes |
| Thread ID / name | ✅ Yes | ✅ Yes |
| Custom field formatters | ✅ Yes | ❌ No |
| Serialization deps | serde + serde_json + tracing-serde | ✅ None |
Both configurations start from tracing + tracing-subscriber with the fmt + registry features (14 crates in common).
| Approach | Additional crates | Total |
|---|---|---|
tracing-microjson |
+1 (this crate) | 15 |
tracing-subscriber json |
+7 (serde ecosystem) | 21 |
Minimal "hello world" JSON logging binary (release, LTO, stripped):
| Approach | Size |
|---|---|
tracing-microjson |
377 KiB (23% smaller) |
tracing-subscriber json |
490 KiB |
aarch64-apple-darwin, Rust 1.93, strip = true, lto = true.
Head-to-head timing benchmarks (lower is better):
| Scenario | tracing-microjson | tracing-subscriber | Speedup |
|---|---|---|---|
| Simple event | 315 ns | 748 ns | 2.4x |
| Event with fields | 425 ns | 1,045 ns | 2.5x |
| Nested spans | 877 ns | 2,508 ns | 2.9x |
Heap allocations per event (after first-event warmup):
| Scenario | tracing-microjson | tracing-subscriber |
|---|---|---|
| Simple event | 0 | 0 |
| Event with fields | 0 | 0 |
| Nested spans | 6 | 17 |
Apple M1 Max, Rust 1.93, criterion 0.8. Run cargo bench --features _bench_internals to reproduce.
The minimum supported Rust version is 1.88 (edition 2024).
Licensed under the GNU General Public License v3.0 or later.