Skip to content

key_value capable log macros #343

@yoshuawuyts

Description

@yoshuawuyts

Continuation of #328 (comment).

Description

kv_unstable is available in log and provides a key_values field on the Record to capture key-value pairs. However currently in order to write data to loggers Record types need to be constructed manually, rather than being able to use the log macros. As per RFC#296 we should experiment with logging macros out of tree, and use it to inform how to add key-value logging to log's macros.

Constraints

[tbi]

@KodrAus could you perhaps clarify what the constraints are?

Prior Art

Slog

The slog crate uses ;"key" => "value" pairs in the macros:

#[macro_use]
extern crate slog;

fn main() {
    let drain = slog::Discard;
    let root = slog::Logger::root(
        drain,
        o!("key1" => "value1", "key2" => "value2")
    );
    info!(root, "test info log"; "log-key" => true);
}

Tracing

tracing supports two kinds of log styles: "a message + key-value pairs", and "only key-value pairs":

use tracing::field;

let addr = Ipv4Addr::new(127, 0, 0, 1);
let conn = Connection { port: 40, speed: 3.20 };

info!({ port = conn.port }, "connected to {}", addr);
info!(
    target: "connection_events",
    ip = %addr,
    conn.port,
    ?conn.speed,
);

Update this section with more examples

Creating a manual record

For reference, this is how to create a manual record with key-value pairs:

use log::kv::{Error, Visitor, Source};

struct Pair {
    val: String
}

impl Source for Pair {
    fn visit(&self, visitor: &mut dyn Visitor<'_>) -> Result<(), Error> {
        visitor.visit_pair("some key".into(), self.val.into())
    }
}

log::logger().log(&log::Record::builder()
    .args(format_args!("hello world!"))
    .key_values(&Pair { val: "some value".to_string() })
    .level(log::Level::Info)
    .target(module_path!())
    .module_path(Some(module_path!()))
    .file(Some(file!()))
    .line(Some(line!()))
    .build());

Conclusion

We should experiment with logging macros that can capture key-value pairs and report back with our findings in this issue. It'd be great if we could discuss their tradeoffs, and eventually come up with a design that's suitable for an RFC.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions