tokio-rs / tracing

Application level tracing for Rust.
https://tracing.rs
MIT License
5.52k stars 725 forks source link

Support for `serde` in outputting JSON logs #3138

Closed ahmed-said-jax closed 1 week ago

ahmed-said-jax commented 1 week ago

Feature Request

I'm not sure how hard this would be, and I think others have brought up adjacent issues, but I really think it would be valuable (pun intended) to be able to log any type implementing Serialize as JSON the way serde_json would output it, using logs key-value feature.

Motivation

I have custom error types in my application that allow me to use other tools to analyze errors programmatically. If these could be natively logged using tracing, rather than me writing the output to a JSON file, it save lots of complexity.

Here's what I want to be able to do:

use serde::Serialize;

#[derive(Serialize)]
struct SomeStruct {
    field: String,
    other_field: i32,
}

fn main() {
    tracing_subscriber::fmt().json().init();

    let some_struct = SomeStruct {
        field: "string".to_string(),
        other_field: 42,
    };

    log::info!(some_struct:serde; "some message");
}

ideally, running this would give me the following (pretty-printed for readibility):

{
    "timestamp": "2024-11-14T21:50:03.501922Z",
    "level": "INFO",
    "fields": {
        "message": "some message",
        "some_struct": {
            "field": "string",
            "other_field": 42
        },
        "log.target": "tracing_test",
        "log.module_path": "tracing_test",
        "log.file": "src/main.rs",
        "log.line": 19
    },
    "target": "tracing_test"
}

right now, tracing-subscriber just ignores some_struct, printing the same as above without the "some_struct" object.

Proposal

Unfortunately, I'm not familiar enough with the workings of the tracing ecosystem to provide any valuable ideas at the moment, but I'm happy to try if this is a good idea.

ahmed-said-jax commented 1 week ago

Update: I was being dumb. I tried deriving Valuable on the struct, but it was resulting in stringified output, rather than JSON, leading to me creating this issue. I realized I hadn't turned on the valuable feature of both the tracing and tracing-subscriber crates.

To achieve what basically what I want, I just need:

tracing::error!(some_struct = some_struct.as_value())