Skip to content

Logging structs and vectors of structs via JSON subscriber (and Valuable) ... is broken? #3148

Open
@s-m-e

Description

@s-m-e

Bug Report

Version

├── tracing v0.1.40
│   ├── tracing-attributes v0.1.27 (proc-macro)
│   └── tracing-core v0.1.32
├── tracing-subscriber v0.3.18
│   ├── tracing-core v0.1.32 (*)
│   ├── tracing-log v0.2.0
│   │   └── tracing-core v0.1.32 (*)
│   └── tracing-serde v0.1.3
│       └── tracing-core v0.1.32 (*)

Platform

Linux e2 5.15.0-124-generic #134-Ubuntu SMP Fri Sep 27 20:20:17 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux

rustc 1.81.0 (eeb90cda1 2024-09-04)

Crates

[dependencies]
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["json"] }
valuable = { version = "0.1.0", features = ["derive"] }

Description

I tried to make sense of this and this in the context of logging JSON, which I could not really make work. Minimal example:

use std::fmt;

use tracing::info;
use tracing_subscriber;
use valuable::Valuable;

#[derive(Clone, Debug, Valuable)]
struct Foo {
    bar: String,
}

impl fmt::Display for Foo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<Foo bar={}>", self.bar)
    }
}

fn vec2str<T: fmt::Display>(data: &Vec<T>) -> String {
    let mut buffer = String::new();
    for item in data {
        buffer.push_str(&format!("{}", item));
    };
    buffer
}

fn main() {
    tracing_subscriber::fmt()
        .json()
        .with_max_level(tracing::Level::DEBUG)
        .with_current_span(false)
        .init();

    // WORKS
    //   Actual output: {"timestamp":"2024-11-20T15:00:24.868450Z","level":"INFO","fields":{"msg":"Hello world!"},"target":"rusttest"}
    info!(msg = "Hello world!");

    let stuff = Foo {
        bar: "abc".to_string(),
    };
    let otherstuff: Vec<Foo> = vec![
        Foo {bar: "def".to_string()},
        Foo {bar: "ghi".to_string()},
    ];

    println!("{}", stuff);  // just debugging
    println!("{}", vec2str(&otherstuff));  // just debugging

    // DOES NOT WORK CORRECTLY:
    //   Expected: {"timestamp":"2024-11-20T15:00:24.868450Z","level":"INFO","fields":{"msg":{"bar": "abc"}},"target":"rusttest"}
    //   In reality: {"timestamp":"2024-11-20T15:00:24.868450Z","level":"INFO","fields":{"msg":"Foo { bar: \"abc\" }"},"target":"rusttest"}
    info!(msg = stuff.as_value());

    // DOES NOT WORK CORRECTLY:
    //   Expected: {"timestamp":"2024-11-20T15:00:24.868450Z","level":"INFO","fields":{"msg":[{"bar": "def"}, {"bar": "ghi"}]},"target":"rusttest"}
    //   In reality: {"timestamp":"2024-11-20T15:00:24.868450Z","level":"INFO","fields":{"msg":"[Foo { bar: \"def\" }, Foo { bar: \"ghi\" }]"},"target":"rusttest"}
   info!(msg = otherstuff.as_value());

}

The JSON output is not really valid JSON.

Am I assuming correctly that, after reading #1570 and this comment on it, what I am attempting to do is not fully supported (yet)? Or am I missing something?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions