emit_core/
lib.rs

1/*!
2A diagnostic framework for Rust applications.
3
4This library is the core API of `emit`, defining the fundamental abstractions used by the higher-level `emit` crate. This library is home to [`event::Event`], `emit`'s model of diagnostic data through with their [`template::Template`], [`props::Props`], and [`extent::Extent`].
5
6In this library is also the all-encapsulating [`runtime::Runtime`], which collects the platform capabilities and event processing pipeline into a single value that powers the diagnostics for your applications.
7
8If you're looking to explore and understand `emit`'s API, you can start with [`runtime::Runtime`] and [`event::Event`] and follow their encapsulated types.
9
10If you're looking to use `emit` in an application you can use this library directly, but `emit` itself is recommended.
11*/
12
13#![doc(html_logo_url = "https://raw.githubusercontent.com/emit-rs/emit/main/asset/logo.svg")]
14#![deny(missing_docs)]
15#![cfg_attr(not(test), no_std)]
16
17#[cfg(feature = "std")]
18extern crate std;
19
20#[cfg(feature = "alloc")]
21extern crate alloc;
22
23extern crate core;
24
25mod buf;
26
27pub mod and;
28pub mod clock;
29pub mod ctxt;
30pub mod emitter;
31pub mod empty;
32pub mod event;
33pub mod extent;
34pub mod filter;
35pub mod or;
36pub mod path;
37pub mod props;
38pub mod rng;
39pub mod runtime;
40pub mod str;
41pub mod template;
42pub mod timestamp;
43pub mod value;
44pub mod well_known;
45
46/**
47Emit an event.
48
49This function uses the components of the runtime to process the event. It will:
50
511. Attempt to assign an extent to the event using [`clock::Clock::now`] if the event doesn't already have one.
522. Add [`ctxt::Ctxt::Current`] to the event properties.
533. Ensure the event passes [`filter::Filter::matches`].
544. Emit the event through [`emitter::Emitter::emit`].
55*/
56pub fn emit(
57    emitter: impl emitter::Emitter,
58    filter: impl filter::Filter,
59    ctxt: impl ctxt::Ctxt,
60    clock: impl clock::Clock,
61    evt: impl event::ToEvent,
62) {
63    use self::{extent::ToExtent, props::Props};
64
65    ctxt.with_current(|ctxt| {
66        let evt = evt.to_event();
67
68        let extent = evt.extent().cloned().or_else(|| clock.now().to_extent());
69
70        let evt = evt
71            .with_extent(extent)
72            .map_props(|props| props.and_props(ctxt));
73
74        if filter.matches(&evt) {
75            emitter.emit(evt);
76        }
77    });
78}
79
80mod internal {
81    pub struct Erased<T>(pub(crate) T);
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87
88    use std::{cell::Cell, time::Duration};
89
90    use crate::props::Props as _;
91
92    struct MyClock(Option<timestamp::Timestamp>);
93
94    impl clock::Clock for MyClock {
95        fn now(&self) -> Option<timestamp::Timestamp> {
96            self.0
97        }
98    }
99
100    struct MyCtxt(&'static str, usize);
101
102    impl ctxt::Ctxt for MyCtxt {
103        type Current = (&'static str, usize);
104        type Frame = ();
105
106        fn open_root<P: props::Props>(&self, _: P) -> Self::Frame {}
107
108        fn enter(&self, _: &mut Self::Frame) {}
109
110        fn exit(&self, _: &mut Self::Frame) {}
111
112        fn close(&self, _: Self::Frame) {}
113
114        fn with_current<R, F: FnOnce(&Self::Current) -> R>(&self, with: F) -> R {
115            with(&(self.0, self.1))
116        }
117    }
118
119    #[test]
120    fn emit_uses_clock_ctxt() {
121        let called = Cell::new(false);
122
123        emit(
124            emitter::from_fn(|evt| {
125                assert_eq!(13, evt.props().pull::<usize, _>("ctxt_prop").unwrap());
126                assert_eq!(true, evt.props().pull::<bool, _>("evt_prop").unwrap());
127
128                assert_eq!(
129                    timestamp::Timestamp::from_unix(Duration::from_secs(77)).unwrap(),
130                    evt.extent().unwrap().as_point()
131                );
132
133                called.set(true);
134            }),
135            empty::Empty,
136            MyCtxt("ctxt_prop", 13),
137            MyClock(timestamp::Timestamp::from_unix(Duration::from_secs(77))),
138            event::Event::new(
139                path::Path::new_raw("test"),
140                template::Template::literal("text"),
141                empty::Empty,
142                ("evt_prop", true),
143            ),
144        );
145
146        assert!(called.get());
147    }
148
149    #[test]
150    fn emit_uses_filter() {
151        emit(
152            emitter::from_fn(|_| panic!("filter should apply")),
153            filter::from_fn(|_| false),
154            empty::Empty,
155            empty::Empty,
156            event::Event::new(
157                path::Path::new_raw("test"),
158                template::Template::literal("text"),
159                empty::Empty,
160                ("evt_prop", true),
161            ),
162        );
163    }
164}