From f888c07dc1ddcc0d0135ef3137c364baf9e30c90 Mon Sep 17 00:00:00 2001 From: KodrAus Date: Thu, 14 Mar 2024 07:59:43 +1000 Subject: [PATCH] make module path first class --- core/src/event.rs | 26 +++++++++-- core/src/lib.rs | 1 + core/src/path.rs | 98 +++++++++++++++++++++++++++++++++++++++++ core/src/runtime.rs | 3 +- macros/src/emit.rs | 3 ++ macros/src/event.rs | 12 ++--- macros/src/lib.rs | 1 + macros/src/source.rs | 5 +++ macros/src/span.rs | 9 +++- src/lib.rs | 5 ++- src/macro_hooks.rs | 11 +++-- targets/term/src/lib.rs | 8 +--- 12 files changed, 156 insertions(+), 26 deletions(-) create mode 100644 core/src/path.rs create mode 100644 macros/src/source.rs diff --git a/core/src/event.rs b/core/src/event.rs index e545665..256e409 100644 --- a/core/src/event.rs +++ b/core/src/event.rs @@ -2,32 +2,49 @@ use core::{fmt, ops::ControlFlow}; use crate::{ extent::{Extent, ToExtent}, + path::Path, props::{ByRef, ErasedProps, Props}, template::{Render, Template}, }; #[derive(Clone)] pub struct Event<'a, P> { + // "where" + source: Path<'a>, + // "when" extent: Option, + // "what" tpl: Template<'a>, + // "why" props: P, + // "how" is your problem } impl<'a, P> Event<'a, P> { - pub fn new(extent: impl ToExtent, tpl: Template<'a>, props: P) -> Self { + pub fn new( + source: impl Into>, + extent: impl ToExtent, + tpl: Template<'a>, + props: P, + ) -> Self { Event { + source: source.into(), extent: extent.to_extent(), tpl, props, } } + pub fn source(&self) -> &Path<'a> { + &self.source + } + pub fn extent(&self) -> Option<&Extent> { self.extent.as_ref() } - pub fn tpl(&self) -> Template { - self.tpl.by_ref() + pub fn tpl(&self) -> &Template<'a> { + &self.tpl } pub fn props(&self) -> &P { @@ -42,6 +59,7 @@ impl<'a, P: Props> Event<'a, P> { pub fn by_ref<'b>(&'b self) -> Event<'b, ByRef<'b, P>> { Event { + source: self.source.by_ref(), extent: self.extent.clone(), tpl: self.tpl.by_ref(), props: self.props.by_ref(), @@ -50,6 +68,7 @@ impl<'a, P: Props> Event<'a, P> { pub fn erase<'b>(&'b self) -> Event<'b, &'b dyn ErasedProps> { Event { + source: self.source.by_ref(), extent: self.extent.clone(), tpl: self.tpl.by_ref(), props: &self.props, @@ -77,6 +96,7 @@ impl<'a, P: Props> fmt::Debug for Event<'a, P> { let mut f = f.debug_struct("Event"); + f.field("source", &self.source); f.field("extent", &self.extent); f.field("msg", &self.msg()); f.field("tpl", &self.tpl); diff --git a/core/src/lib.rs b/core/src/lib.rs index 4437169..e6d3594 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -12,6 +12,7 @@ pub mod empty; pub mod event; pub mod extent; pub mod filter; +pub mod path; pub mod props; pub mod rng; pub mod runtime; diff --git a/core/src/path.rs b/core/src/path.rs new file mode 100644 index 0000000..e63f6d4 --- /dev/null +++ b/core/src/path.rs @@ -0,0 +1,98 @@ +use core::fmt; + +use crate::{ + str::Str, + value::{FromValue, ToValue, Value}, +}; + +#[derive(Clone)] +pub struct Path<'a>(Str<'a>); + +impl<'a> From<&'a str> for Path<'a> { + fn from(value: &'a str) -> Self { + Path(Str::from(value)) + } +} + +impl<'a> From> for Path<'a> { + fn from(value: Str<'a>) -> Self { + Path(value) + } +} + +impl<'a> ToValue for Path<'a> { + fn to_value(&self) -> Value { + self.0.to_value() + } +} + +impl<'a> FromValue<'a> for Path<'a> { + fn from_value(value: Value<'a>) -> Option { + Some(value.cast()?) + } +} + +impl Path<'static> { + pub const fn new(source: &'static str) -> Self { + Path(Str::new(source)) + } +} + +impl<'a> Path<'a> { + pub const fn new_ref(source: &'a str) -> Self { + Path(Str::new_ref(source)) + } + + pub fn by_ref<'b>(&'b self) -> Path<'b> { + Path(self.0.by_ref()) + } + + pub fn segments(&self) -> impl Iterator { + self.0.as_str().split("::") + } + + pub fn is_child_of<'b>(&self, other: &Path<'b>) -> bool { + let child = self.0.as_str(); + let parent = other.0.as_str(); + + if child.len() >= parent.len() && child.is_char_boundary(parent.len()) { + let (child_prefix, child_suffix) = child.split_at(parent.len()); + + child_prefix == parent && (child_suffix.is_empty() || child_suffix.starts_with("::")) + } else { + false + } + } +} + +impl<'a> fmt::Debug for Path<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } +} + +impl<'a> fmt::Display for Path<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn is_child_of() { + let a = Path::new("a"); + let aa = Path::new("aa"); + let b = Path::new("b"); + let a_b = Path::new("a::b"); + + assert!(!aa.is_child_of(&a)); + assert!(!b.is_child_of(&a)); + assert!(!a.is_child_of(&a_b)); + + assert!(a.is_child_of(&a)); + assert!(a_b.is_child_of(&a)); + } +} diff --git a/core/src/runtime.rs b/core/src/runtime.rs index 63ab001..b91f3b3 100644 --- a/core/src/runtime.rs +++ b/core/src/runtime.rs @@ -178,10 +178,11 @@ impl pub fn emit(&self, evt: &Event

) { self.ctxt.with_current(|ctxt| { let evt = Event::new( + evt.source().by_ref(), evt.extent() .cloned() .or_else(|| self.clock.now().to_extent()), - evt.tpl(), + evt.tpl().by_ref(), ctxt.chain(evt.props()), ); diff --git a/macros/src/emit.rs b/macros/src/emit.rs index df9d2cb..0706a1e 100644 --- a/macros/src/emit.rs +++ b/macros/src/emit.rs @@ -4,6 +4,7 @@ use syn::{parse::Parse, FieldValue}; use crate::{ args::{self, Arg}, event::push_event_props, + source::source_tokens, template, }; @@ -69,6 +70,7 @@ pub fn expand_tokens(opts: ExpandTokens) -> Result { let extent_tokens = args.extent; let rt_tokens = args.rt; let when_tokens = args.when; + let source_tokens = source_tokens(); let template_tokens = template.template_tokens(); @@ -77,6 +79,7 @@ pub fn expand_tokens(opts: ExpandTokens) -> Result { (#(#props_match_binding_tokens),*) => { emit::__private::__private_emit( #rt_tokens, + #source_tokens, #when_tokens, #extent_tokens, #template_tokens, diff --git a/macros/src/event.rs b/macros/src/event.rs index 94c26f0..3a2c85c 100644 --- a/macros/src/event.rs +++ b/macros/src/event.rs @@ -4,6 +4,7 @@ use syn::{parse::Parse, FieldValue, Ident}; use crate::{ args::{self, Arg}, props::Props, + source::source_tokens, template, }; @@ -52,9 +53,10 @@ pub fn expand_tokens(opts: ExpandTokens) -> Result { let base_props_tokens = args.props; let template_tokens = template.template_tokens(); let props_tokens = props.props_tokens(); + let source_tokens = source_tokens(); Ok( - quote!(emit::Event::new(#extent_tokens, #template_tokens, emit::Props::chain(&#base_props_tokens, #props_tokens))), + quote!(emit::Event::new(#source_tokens, #extent_tokens, #template_tokens, emit::Props::chain(&#base_props_tokens, #props_tokens))), ) } @@ -70,13 +72,5 @@ pub fn push_event_props(props: &mut Props, level: Option) -> Result )?; } - // Add the location as a property - let loc_ident = Ident::new(emit_core::well_known::MODULE_KEY, Span::call_site()); - props.push( - &syn::parse2::(quote!(#loc_ident: emit::__private::__private_module!()))?, - false, - true, - )?; - Ok(()) } diff --git a/macros/src/lib.rs b/macros/src/lib.rs index f6d9426..e4183a5 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -26,6 +26,7 @@ mod hook; mod key; mod optional; mod props; +mod source; mod span; mod template; mod util; diff --git a/macros/src/source.rs b/macros/src/source.rs new file mode 100644 index 0000000..651c8fb --- /dev/null +++ b/macros/src/source.rs @@ -0,0 +1,5 @@ +use proc_macro2::TokenStream; + +pub(crate) fn source_tokens() -> TokenStream { + quote!(emit::__private::__private_module!()) +} diff --git a/macros/src/span.rs b/macros/src/span.rs index 4da4b93..10a096d 100644 --- a/macros/src/span.rs +++ b/macros/src/span.rs @@ -8,6 +8,7 @@ use crate::{ args::{self, Arg}, event::push_event_props, props::Props, + source::source_tokens, template::{self, Template}, }; @@ -140,14 +141,16 @@ fn inject_sync( let ctxt_props_tokens = ctxt_props.props_tokens(); let evt_props_tokens = evt_props.props_tokens(); let template_tokens = template.template_tokens(); + let source_tokens = source_tokens(); quote!({ - let (mut __ctxt, __timer) = emit::__private::__private_push_span_ctxt(#rt_tokens, #when_tokens, #template_tokens, #ctxt_props_tokens, #evt_props_tokens); + let (mut __ctxt, __timer) = emit::__private::__private_push_span_ctxt(#rt_tokens, #source_tokens, #when_tokens, #template_tokens, #ctxt_props_tokens, #evt_props_tokens); let __ctxt_guard = __ctxt.enter(); let #span_arg = emit::__private::__private_begin_span(__timer, |extent| { emit::__private::__private_emit( #rt_tokens, + #source_tokens, Some(emit::always()), extent, #template_tokens, @@ -171,14 +174,16 @@ fn inject_async( let ctxt_props_tokens = ctxt_props.props_tokens(); let evt_props_tokens = evt_props.props_tokens(); let template_tokens = template.template_tokens(); + let source_tokens = source_tokens(); quote!({ - let (__ctxt, __timer) = emit::__private::__private_push_span_ctxt(#rt_tokens, #when_tokens, #template_tokens, #ctxt_props_tokens, #evt_props_tokens); + let (__ctxt, __timer) = emit::__private::__private_push_span_ctxt(#rt_tokens, #source_tokens, #when_tokens, #template_tokens, #ctxt_props_tokens, #evt_props_tokens); __ctxt.with_future(async { let #span_arg = emit::__private::__private_begin_span(__timer, |extent| { emit::__private::__private_emit( #rt_tokens, + #source_tokens, Some(emit::always()), extent, #template_tokens, diff --git a/src/lib.rs b/src/lib.rs index 2661de6..a43f2c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ #[cfg(feature = "alloc")] extern crate alloc; -use emit_core::extent::ToExtent; +use emit_core::{extent::ToExtent, path::Path}; #[doc(inline)] pub use emit_macros::*; @@ -50,6 +50,7 @@ pub use setup::*; #[track_caller] fn base_emit( to: impl Emitter, + source: Path, when: impl Filter, ctxt: impl Ctxt, ts: impl ToExtent, @@ -57,7 +58,7 @@ fn base_emit( props: impl Props, ) { ctxt.with_current(|ctxt| { - let evt = Event::new(ts, tpl, props.chain(ctxt)); + let evt = Event::new(source, ts, tpl, props.chain(ctxt)); if when.matches(&evt) { to.emit(&evt); diff --git a/src/macro_hooks.rs b/src/macro_hooks.rs index b040c24..40dab9d 100644 --- a/src/macro_hooks.rs +++ b/src/macro_hooks.rs @@ -6,6 +6,7 @@ use emit_core::{ emitter::Emitter, extent::{Extent, ToExtent}, filter::Filter, + path::Path, props::Props, rng::Rng, runtime::Runtime, @@ -502,6 +503,7 @@ impl Filter for FirstDefined { #[track_caller] pub fn __private_emit<'a, E: Emitter, F: Filter, C: Ctxt, T: Clock, R: Rng>( rt: &'a Runtime, + source: impl Into>, when: Option, extent: impl ToExtent, tpl: Template, @@ -509,6 +511,7 @@ pub fn __private_emit<'a, E: Emitter, F: Filter, C: Ctxt, T: Clock, R: Rng>( ) { base_emit( rt.emitter(), + source.into(), FirstDefined(when, rt.filter()), rt.ctxt(), extent.to_extent().or_else(|| rt.now().to_extent()), @@ -519,10 +522,11 @@ pub fn __private_emit<'a, E: Emitter, F: Filter, C: Ctxt, T: Clock, R: Rng>( #[track_caller] #[cfg(feature = "alloc")] -pub fn __private_push_span_ctxt<'a, E: Emitter, F: Filter, C: Ctxt, T: Clock, R: Rng>( +pub fn __private_push_span_ctxt<'a, 'b, E: Emitter, F: Filter, C: Ctxt, T: Clock, R: Rng>( rt: &'a Runtime, + source: impl Into>, when: Option, - tpl: Template, + tpl: Template<'b>, ctxt_props: impl Props, evt_props: impl Props, ) -> (Frame>, Option>) { @@ -573,8 +577,9 @@ pub fn __private_push_span_ctxt<'a, E: Emitter, F: Filter, C: Ctxt, T: Clock, R: let timer = Timer::start(rt.clock()); if FirstDefined(when, rt.filter()).matches(&Event::new( + source, timer.extent().map(|extent| *extent.as_point()), - tpl.by_ref(), + tpl, ctxt_props.by_ref().chain(&trace_ctxt).chain(&evt_props), )) { ( diff --git a/targets/term/src/lib.rs b/targets/term/src/lib.rs index 6ae716d..135b84e 100644 --- a/targets/term/src/lib.rs +++ b/targets/term/src/lib.rs @@ -3,9 +3,7 @@ use core::{fmt, str, time::Duration}; use std::{cell::RefCell, cmp, io::Write}; -use emit::well_known::{ - LVL_KEY, METRIC_NAME_KEY, METRIC_VALUE_KEY, MODULE_KEY, SPAN_ID_KEY, TRACE_ID_KEY, -}; +use emit::well_known::{LVL_KEY, METRIC_NAME_KEY, METRIC_VALUE_KEY, SPAN_ID_KEY, TRACE_ID_KEY}; use termcolor::{Buffer, BufferWriter, Color, ColorChoice, ColorSpec, WriteColor}; pub fn stdout() -> Stdout { @@ -242,9 +240,7 @@ fn print_event( } } - if let Some(module) = evt.props().get(MODULE_KEY) { - write_fg(buf, format_args!("{} ", module), MODULE); - } + write_fg(buf, format_args!("{} ", evt.source()), MODULE); let _ = evt.msg().write(Writer { buf }); write_plain(buf, "\n");