tokio-rs / tracing

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

logging full containers (structures) #2825

Open azr opened 9 months ago

azr commented 9 months ago

Hello !

Sorry if this is a duplicate, I couldn't find anything matching anywhere. (struct and log match a lot of things hehe)

Feature Request

Allow to trace full structures in an info! call for example.

Currently in the docs, I see a lot of examples looking like this:

    info!(
        all_yaks_shaved = number_shaved == number_of_yaks,
        "yak shaving completed."
    );

But, what I would like to do is something like this, eg:

    info!(
        my_struct,
        all_yaks_shaved = number_shaved == number_of_yaks,
        "yak shaving completed."
    );

Or, even better:

    info!(
        * = my_struct,
        "yay."
    );

That would take all the bottom fields of that struct and not require me to manually add or remove fields.

Motivation

~Laziness~, hem no I mean, when I change the fields of a struct, I sometimes forget to add them to the logs, etc.

Proposal

    info!(
        * = my_struct,
        all_yaks_shaved = number_shaved == number_of_yaks,
        "yay."
    );

Alternatives

    info!(
        my_struct,
        all_yaks_shaved = number_shaved == number_of_yaks,
        "yay."
    );
kaffarell commented 9 months ago

If the struct implements Debug (you can also easily derive it using #[derive(Debug)]) you can print the struct like this:

#[derive(Debug)]
struct Test {
    w: i32,
    x: i32,
}

let test = Test { w: 4, x: 2 };
tracing::info!(?test, "test");

Example output:

2023-12-07T15:16:21.357581Z  INFO fmt: test test=Test { w: 4, x: 2 }

Checkout the docs for more: https://docs.rs/tracing/latest/tracing/#recording-fields

dezyh commented 8 months ago

If @azr wants their struct fields to be flatly unpacked into the event fields (and not nested under the struct itself), maybe it's possible to the unstable valuable support to help achieve this in the future?

For example, something like:

#[derive(Clone, Debug, Valuable)]
struct Example {
    w: i32,
    x: i32,
}

let example = Example { w: 4, x: 2 };
tracing::info!(* = example.as_value(), "test");

Could hypothetically produce something like:

2023-12-07T15:16:21.357581Z  INFO fmt: test w=4 x=2

Although I think some kind of destructing operator/token such as like ... would make more sense than * =.