Tracing can't generate log messages dynamically

I'm working on an application which uses the tracing library for logging, however a different component will generate events at runtime[1] and as far as I can tell it's not possible to construct a tracing::Event object because it requires 'static metadata (the thing tracking log level, target, etc.).

Here is a snippet showing roughly what I'm trying to achieve:

use tracing::field::ValueSet;

pub enum LogLevel {
    Trace,
    Debug,
    Info,
    Warn,
    Error,
}

pub struct LogMetadata<'a> {
    pub name: &'a str,
    pub target: &'a str,
    pub level: LogLevel,
    pub file: Option<&'a str>,
    pub line: Option<u32>,
    pub module: Option<&'a str>,
}

pub enum LogValue<'a> {
    Null,
    Boolean(bool),
    Integer(i64),
    Float(f64),
    String(&'a str),
}

pub type LogValueMap<'a> = Vec<(&'a str, LogValue<'a>)>;

fn is_enabled(meta: LogMetadata<'_>) -> bool {
    tracing::dispatcher::get_default(|dispatch| {
        let meta = tracing::Metadata::from(meta);
        dispatch.enabled(&meta)
    })
}

fn log(meta: LogMetadata<'_>, message: &str, data: LogValueMap<'_>) {
    let meta = tracing::Metadata::from(meta);
    let values = value_set(message, &data);
    tracing::Event::dispatch(&meta, &values)
}

impl<'a> From<LogMetadata<'a>> for tracing::Metadata<'a> {
    fn from(_: LogMetadata<'a>) -> Self {
        todo!();
    }
}

fn value_set<'a>(message: &'a str, values: &'a [(&'a str, LogValue<'a>)]) -> ValueSet<'a> {
    todo!();
}

(playground)

The compile error shows that Event::dispatch() requires a &'static Metadata.

error[E0759]: `meta` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
  --> src/lib.rs:38:40
   |
37 | fn log(meta: LogMetadata<'_>, message: &str, data: LogValueMap<'_>) {
   |              --------------- this data with an anonymous lifetime `'_`...
38 |     let meta = tracing::Metadata::from(meta);
   |                                        ^^^^ ...is used here...
39 |     let values = value_set(message, &data);
40 |     tracing::Event::dispatch(&meta, &values)
   |                              ----- ...and is required to live as long as `'static` here

For more information about this error, try `rustc --explain E0759`.
error: could not compile `playground` due to previous error
Warnings

Does anyone have any solutions or workarounds for my problem?

The main thing I care about is having the log level and target in my final log event so that the dynamically generated log messages look just like any other message (styled differently based on levels, filtering by target/level works, etc.).

I could use unsafe to pretend my data is all 'static, but that's unsound and I'd prefer to avoid going down that path if possible.


  1. In this case, a WebAssembly guest calls my application's log() function with things like the log level, target, file, message, structured data, and so on. The data is almost identical to the ValueSet and Metadata types used when constructing a tracing::Event, except everything borrows from WebAssembly linear memory instead of being compile time literals. ↩︎