Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Wide events

Wide events are a pattern for application diagnostics that collects all the context for an operation together during its execution, and then emits a single event at the end with all of it. Wide events help you better structure your diagnostics by giving you a fixed paradigm to conform to so your diagnostics are more consistent. Span events are a natural fit for wide events because they already represent the execution of some operation, and carry additional timing and context. You could also use regular log events implement wide events.

You can implement wide events using emit by attaching an additional property collection to your outer-most span call and sharing it with child procedures. See Adding properties to a span as it runs for details. A simple example could look like:

#![allow(unused)]
fn main() {
extern crate emit;
use std::{collections::HashMap, io, ops::{ControlFlow, DerefMut}};
// In our outer-most span we create our wide event context
#[emit::span(guard, evt_props: WideEvent::begin(), ok_lvl: "info", "exec")]
fn exec() -> io::Result<()> {
    let mut cx = WideEvent::cx(guard.props_mut());

    // Our span guard carries our `WideEvent` context, so we can access it
    check(&mut cx, 7)?;

    // When `exec` completes, the accumulated context will be emitted

    Ok(())
}

// Child operations add to the context
fn check(cx: &mut WideEvent, i: i32) -> io::Result<()> {
    cx.set("i", i);

    if i > 4 {
        cx.set("is_big", true);

        Err(io::Error::new(io::ErrorKind::Other, "value is too big"))
    } else {
        Ok(())
    }
}

// Our container for the wide event context
// This type just makes pushing props a little more ergonomic

struct WideEvent<'a>(Option<&'a mut WideEventProps>);

type WideEventProps = HashMap<String, emit::value::OwnedValue>;

impl<'a> WideEvent<'a> {
    pub fn begin() -> WideEventProps {
        Default::default()
    }

    pub fn cx(props: Option<&'a mut impl DerefMut<Target = WideEventProps>>) -> WideEvent<'a> {
        // `props` will be `None` if filtering excluded the span
        // For wide events, you're more likely to want tail sampling in case context changes what you want to emit
        WideEvent(props.map(|props| &mut **props))
    }

    pub fn set(&mut self, k: impl Into<String>, v: impl emit::value::ToValue) {
        let Some(ref mut props) = self.0 else {
            return;
        };

        props.insert(k.into(), v.to_value().to_owned());
    }
}

impl emit::Props for WideEvent<'_> {
    fn for_each<'v, F: FnMut(emit::Str<'v>, emit::Value<'v>) -> ControlFlow<()>>(&'v self, for_each: F) -> ControlFlow<()> {
        let Some(ref props) = self.0 else {
            return ControlFlow::Continue(());
        };

        emit::Props::for_each(&**props, for_each)
    }
}
}
Event {
    mdl: "my_app",
    tpl: "example",
    extent: Some(
        "2026-05-28T01:05:04.957599420Z".."2026-05-28T01:05:04.957604581Z",
    ),
    props: {
        "evt_kind": span,
        "span_name": "example",
        "is_big": true,
        "i": 7,
        "trace_id": 2d9bb14ac65f414e1be85923000a3c30,
        "span_id": ac0115090dd86335,
    },
}

Applications may already have established patterns for handling this kind of context. All that’s needed is for the value attached to the wide event span via its evt_props control parameter to implement Props, yielding any context pushed during its execution.