# tracing-microjson
[](https://crates.io/crates/tracing-microjson)
[](https://docs.rs/tracing-microjson)
[](https://github.com/JacobMillward/tracing-microjson/actions/workflows/ci.yml)
[](https://www.gnu.org/licenses/gpl-3.0)
A [`tracing`] layer that outputs JSON-formatted logs **without pulling in serde, serde_json, or tracing-serde**.
[`tracing`]: https://docs.rs/tracing
## Why?
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.
## Who is this for?
- 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**
## Usage
```toml
[dependencies]
tracing-microjson = "0.3"
```
```rust
use tracing_microjson::JsonLayer;
use tracing_subscriber::prelude::*;
tracing_subscriber::registry()
.with(JsonLayer::new(std::io::stderr))
.init();
```
## Configuration
```rust
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();
```
## Comparisons
All comparisons are against `tracing-subscriber` with its `json` feature enabled.
### Features
| 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 |
### Dependencies
Both configurations start from `tracing` + `tracing-subscriber` with the `fmt` + `registry` features (14 crates in common).
| `tracing-microjson` | **+1** (this crate) | **15** |
| `tracing-subscriber` `json` | +7 (serde ecosystem) | **21** |
### Binary size
Minimal "hello world" JSON logging binary (release, LTO, stripped):
| `tracing-microjson` | **377 KiB (23% smaller)** |
| `tracing-subscriber` `json` | 490 KiB |
<sub>aarch64-apple-darwin, Rust 1.93, `strip = true`, `lto = true`.</sub>
### Performance
Head-to-head timing benchmarks (lower is better):
| 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):
| Simple event | **0** | 0 |
| Event with fields | **0** | 0 |
| Nested spans | **6** | 17 |
<sub>Apple M1 Max, Rust 1.93, criterion 0.8. Run `cargo bench --features _bench_internals` to reproduce.</sub>
## MSRV
The minimum supported Rust version is **1.88** (edition 2024).
## License
Licensed under the [GNU General Public License v3.0 or later](https://www.gnu.org/licenses/gpl-3.0).