jsonrustrust-tracing

How to make rust tracing_subscriber output valid JSON (i.e. `null`) for log facets with `Option::None`


I'm using rust's tracing and tracing_subscriber crates with .json() to enable JSON formatting of logs:

tracing_subscriber::fmt()
    .json()
    .flatten_event(true)
    .finish()
    .init();

Consider the following example:

let v: Option<i32> = Some(5);
info!(v); // {"timestamp":"2024-08-12T23:40:48.487599Z","level":"INFO","v":5,"target":"hello_world"}

let v: Option<i32> = None;
info!(v); // {"timestamp":"2024-08-12T23:40:48.487624Z","level":"INFO","target":"hello_world"}

Whilst both produce valid JSON, the v field is omitted when the v is None.

I would like the field to still be printed with "v": null, so it's clear to a reader that the field would normally be present but has no value.

Does anyone know of a way to do this?


Solution

  • This isn't supported by the provided tracing-subscriber formatters. This goes against the norm. It is intended that subscribers use .record() using a Visit implementation to record the fields, but this does not yield None values (just as it does not yield Empty fields).

    To get this behavior, you would need to use a custom FormatEvent implementation or a completely different subscriber/layer. Such an implementation would have to look through the event's .field()s and cross-check that with the values you recorded to see if any were missing.


    I looked at using tracing's unstable valuable feature, but that can't yield null either (closest analogue is the "unit" variant, but that would output "v": "()" from the JSON serializer).