@@ -1003,6 +1003,78 @@ where
10031003 }
10041004 }
10051005
1006+ /// Returns a [`SpanRef`] for the parent span of the given [`Event`], if
1007+ /// it has a parent.
1008+ ///
1009+ /// If the event has an explicitly overridden parent, this method returns
1010+ /// a reference to that span. If the event's parent is the current span,
1011+ /// this returns a reference to the current span, if there is one. If this
1012+ /// returns `None`, then either the event's parent was explicitly set to
1013+ /// `None`, or the event's parent was defined contextually, but no span
1014+ /// is currently entered.
1015+ ///
1016+ /// Compared to [`Context::current_span`] and [`Context::lookup_current`],
1017+ /// this respects overrides provided by the [`Event`].
1018+ ///
1019+ /// Compared to [`Event::parent`], this automatically falls back to the contextual
1020+ /// span, if required.
1021+ ///
1022+ /// ```rust
1023+ /// use tracing::{Event, Subscriber};
1024+ /// use tracing_subscriber::{
1025+ /// layer::{Context, Layer},
1026+ /// prelude::*,
1027+ /// registry::LookupSpan,
1028+ /// };
1029+ ///
1030+ /// struct PrintingLayer;
1031+ /// impl<S> Layer<S> for PrintingLayer
1032+ /// where
1033+ /// S: Subscriber + for<'lookup> LookupSpan<'lookup>,
1034+ /// {
1035+ /// fn on_event(&self, event: &Event, ctx: Context<S>) {
1036+ /// let span = ctx.event_span(event);
1037+ /// println!("Event in span: {:?}", span.map(|s| s.name()));
1038+ /// }
1039+ /// }
1040+ ///
1041+ /// tracing::subscriber::with_default(tracing_subscriber::registry().with(PrintingLayer), || {
1042+ /// tracing::info!("no span");
1043+ /// // Prints: Event in span: None
1044+ ///
1045+ /// let span = tracing::info_span!("span");
1046+ /// tracing::info!(parent: &span, "explicitly specified");
1047+ /// // Prints: Event in span: Some("span")
1048+ ///
1049+ /// let _guard = span.enter();
1050+ /// tracing::info!("contextual span");
1051+ /// // Prints: Event in span: Some("span")
1052+ /// });
1053+ /// ```
1054+ ///
1055+ /// <div class="example-wrap" style="display:inline-block">
1056+ /// <pre class="ignore" style="white-space:normal;font:inherit;">
1057+ /// <strong>Note</strong>: This requires the wrapped subscriber to implement the
1058+ /// <a href="../registry/trait.LookupSpan.html"><code>LookupSpan</code></a> trait.
1059+ /// See the documentation on <a href="./struct.Context.html"><code>Context</code>'s
1060+ /// declaration</a> for details.
1061+ /// </pre></div>
1062+ #[ inline]
1063+ #[ cfg( feature = "registry" ) ]
1064+ #[ cfg_attr( docsrs, doc( cfg( feature = "registry" ) ) ) ]
1065+ pub fn event_span ( & self , event : & Event < ' _ > ) -> Option < SpanRef < ' _ , S > >
1066+ where
1067+ S : for < ' lookup > LookupSpan < ' lookup > ,
1068+ {
1069+ if event. is_root ( ) {
1070+ None
1071+ } else if event. is_contextual ( ) {
1072+ self . lookup_current ( )
1073+ } else {
1074+ event. parent ( ) . and_then ( |id| self . span ( id) )
1075+ }
1076+ }
1077+
10061078 /// Returns metadata for the span with the given `id`, if it exists.
10071079 ///
10081080 /// If this returns `None`, then no span exists for that ID (either it has
@@ -1165,6 +1237,36 @@ where
11651237 {
11661238 Some ( self . span ( id) ?. scope ( ) )
11671239 }
1240+
1241+ /// Returns an iterator over the [stored data] for all the spans in the
1242+ /// current context, starting with the parent span of the specified event,
1243+ /// and ending with the root of the trace tree and ending with the current span.
1244+ ///
1245+ /// <div class="example-wrap" style="display:inline-block">
1246+ /// <pre class="ignore" style="white-space:normal;font:inherit;">
1247+ /// <strong>Note</strong>: Compared to <a href="#method.scope"><code>scope</code></a> this
1248+ /// returns the spans in reverse order (from leaf to root). Use
1249+ /// <a href="../registry/struct.Scope.html#method.from_root"><code>Scope::from_root</code></a>
1250+ /// in case root-to-leaf ordering is desired.
1251+ /// </pre></div>
1252+ ///
1253+ /// <div class="example-wrap" style="display:inline-block">
1254+ /// <pre class="ignore" style="white-space:normal;font:inherit;">
1255+ /// <strong>Note</strong>: This requires the wrapped subscriber to implement the
1256+ /// <a href="../registry/trait.LookupSpan.html"><code>LookupSpan</code></a> trait.
1257+ /// See the documentation on <a href="./struct.Context.html"><code>Context</code>'s
1258+ /// declaration</a> for details.
1259+ /// </pre></div>
1260+ ///
1261+ /// [stored data]: ../registry/struct.SpanRef.html
1262+ #[ cfg( feature = "registry" ) ]
1263+ #[ cfg_attr( docsrs, doc( cfg( feature = "registry" ) ) ) ]
1264+ pub fn event_scope ( & self , event : & Event < ' _ > ) -> Option < registry:: Scope < ' _ , S > >
1265+ where
1266+ S : for < ' lookup > registry:: LookupSpan < ' lookup > ,
1267+ {
1268+ Some ( self . event_span ( event) ?. scope ( ) )
1269+ }
11681270}
11691271
11701272impl < ' a , S > Context < ' a , S > {
@@ -1194,6 +1296,8 @@ impl Identity {
11941296
11951297#[ cfg( test) ]
11961298pub ( crate ) mod tests {
1299+ use std:: sync:: { Arc , Mutex } ;
1300+
11971301 use super :: * ;
11981302
11991303 pub ( crate ) struct NopSubscriber ;
@@ -1308,4 +1412,41 @@ pub(crate) mod tests {
13081412 <dyn Subscriber >:: downcast_ref :: < StringLayer3 > ( & s) . expect ( "layer 3 should downcast" ) ;
13091413 assert_eq ! ( & layer. 0 , "layer_3" ) ;
13101414 }
1415+
1416+ #[ test]
1417+ fn context_event_span ( ) {
1418+ let last_event_span = Arc :: new ( Mutex :: new ( None ) ) ;
1419+
1420+ struct RecordingLayer {
1421+ last_event_span : Arc < Mutex < Option < & ' static str > > > ,
1422+ }
1423+
1424+ impl < S > Layer < S > for RecordingLayer
1425+ where
1426+ S : Subscriber + for < ' lookup > LookupSpan < ' lookup > ,
1427+ {
1428+ fn on_event ( & self , event : & Event < ' _ > , ctx : Context < ' _ , S > ) {
1429+ let span = ctx. event_span ( event) ;
1430+ * self . last_event_span . lock ( ) . unwrap ( ) = span. map ( |s| s. name ( ) ) ;
1431+ }
1432+ }
1433+
1434+ tracing:: subscriber:: with_default (
1435+ crate :: registry ( ) . with ( RecordingLayer {
1436+ last_event_span : last_event_span. clone ( ) ,
1437+ } ) ,
1438+ || {
1439+ tracing:: info!( "no span" ) ;
1440+ assert_eq ! ( * last_event_span. lock( ) . unwrap( ) , None ) ;
1441+
1442+ let parent = tracing:: info_span!( "explicit" ) ;
1443+ tracing:: info!( parent: & parent, "explicit span" ) ;
1444+ assert_eq ! ( * last_event_span. lock( ) . unwrap( ) , Some ( "explicit" ) ) ;
1445+
1446+ let _guard = tracing:: info_span!( "contextual" ) . entered ( ) ;
1447+ tracing:: info!( "contextual span" ) ;
1448+ assert_eq ! ( * last_event_span. lock( ) . unwrap( ) , Some ( "contextual" ) ) ;
1449+ } ,
1450+ ) ;
1451+ }
13111452}
0 commit comments