1
1
use std:: collections:: BTreeMap ;
2
2
3
- use sentry_core:: protocol:: { Event , Value } ;
3
+ use sentry_core:: protocol:: { self , Event , TraceContext , Value } ;
4
4
use sentry_core:: { Breadcrumb , Level } ;
5
- use tracing_core:: field:: { Field , Visit } ;
5
+ use tracing_core:: {
6
+ field:: { Field , Visit } ,
7
+ span, Subscriber ,
8
+ } ;
9
+ use tracing_subscriber:: layer:: Context ;
10
+ use tracing_subscriber:: registry:: LookupSpan ;
11
+
12
+ use crate :: Trace ;
6
13
7
14
/// Converts a [`tracing_core::Level`] to a Sentry [`Level`]
8
15
pub fn convert_tracing_level ( level : & tracing_core:: Level ) -> Level {
@@ -15,7 +22,9 @@ pub fn convert_tracing_level(level: &tracing_core::Level) -> Level {
15
22
}
16
23
17
24
/// Extracts the message and metadata from an event
18
- pub fn extract_data ( event : & tracing_core:: Event ) -> ( Option < String > , BTreeMap < String , Value > ) {
25
+ pub fn extract_event_data (
26
+ event : & tracing_core:: Event ,
27
+ ) -> ( Option < String > , BTreeMap < String , Value > ) {
19
28
// Find message of the event, if any
20
29
let mut data = BTreeMapRecorder :: default ( ) ;
21
30
event. record ( & mut data) ;
@@ -28,6 +37,21 @@ pub fn extract_data(event: &tracing_core::Event) -> (Option<String>, BTreeMap<St
28
37
( message, data. 0 )
29
38
}
30
39
40
+ /// Extracts the message and metadata from a span
41
+ pub fn extract_span_data ( attrs : & span:: Attributes ) -> ( Option < String > , BTreeMap < String , Value > ) {
42
+ let mut data = BTreeMapRecorder :: default ( ) ;
43
+ attrs. record ( & mut data) ;
44
+
45
+ // Find message of the span, if any
46
+ let message = data
47
+ . 0
48
+ . remove ( "message" )
49
+ . map ( |v| v. as_str ( ) . map ( |s| s. to_owned ( ) ) )
50
+ . flatten ( ) ;
51
+
52
+ ( message, data. 0 )
53
+ }
54
+
31
55
#[ derive( Default ) ]
32
56
/// Records all fields of [`tracing_core::Event`] for easy access
33
57
struct BTreeMapRecorder ( pub BTreeMap < String , Value > ) ;
@@ -58,7 +82,7 @@ impl Visit for BTreeMapRecorder {
58
82
59
83
/// Creates a [`Breadcrumb`] from a given [`tracing_core::Event`]
60
84
pub fn breadcrumb_from_event ( event : & tracing_core:: Event ) -> Breadcrumb {
61
- let ( message, data) = extract_data ( event) ;
85
+ let ( message, data) = extract_event_data ( event) ;
62
86
Breadcrumb {
63
87
category : Some ( event. metadata ( ) . target ( ) . to_owned ( ) ) ,
64
88
ty : "log" . into ( ) ,
@@ -70,22 +94,55 @@ pub fn breadcrumb_from_event(event: &tracing_core::Event) -> Breadcrumb {
70
94
}
71
95
72
96
/// Creates an [`Event`] from a given [`tracing_core::Event`]
73
- pub fn event_from_event ( event : & tracing_core:: Event ) -> Event < ' static > {
74
- let ( message, extra) = extract_data ( event) ;
75
- Event {
97
+ pub fn event_from_event < S > ( event : & tracing_core:: Event , ctx : Context < S > ) -> Event < ' static >
98
+ where
99
+ S : Subscriber + for < ' a > LookupSpan < ' a > ,
100
+ {
101
+ let ( message, extra) = extract_event_data ( event) ;
102
+
103
+ let mut result = Event {
76
104
logger : Some ( event. metadata ( ) . target ( ) . to_owned ( ) ) ,
77
105
level : convert_tracing_level ( event. metadata ( ) . level ( ) ) ,
78
106
message,
79
107
extra,
80
108
..Default :: default ( )
109
+ } ;
110
+
111
+ let parent = event
112
+ . parent ( )
113
+ . and_then ( |id| ctx. span ( id) )
114
+ . or_else ( || ctx. lookup_current ( ) ) ;
115
+
116
+ if let Some ( parent) = parent {
117
+ let extensions = parent. extensions ( ) ;
118
+ if let Some ( trace) = extensions. get :: < Trace > ( ) {
119
+ let context = protocol:: Context :: from ( TraceContext {
120
+ span_id : trace. span . span_id ,
121
+ trace_id : trace. span . trace_id ,
122
+ ..TraceContext :: default ( )
123
+ } ) ;
124
+
125
+ result. contexts . insert ( context. type_name ( ) . into ( ) , context) ;
126
+ result. transaction = parent
127
+ . parent ( )
128
+ . into_iter ( )
129
+ . flat_map ( |span| span. scope ( ) )
130
+ . last ( )
131
+ . map ( |root| root. name ( ) . into ( ) ) ;
132
+ }
81
133
}
134
+
135
+ result
82
136
}
83
137
84
138
/// Creates an exception [`Event`] from a given [`tracing_core::Event`]
85
- pub fn exception_from_event ( event : & tracing_core:: Event ) -> Event < ' static > {
139
+ pub fn exception_from_event < S > ( event : & tracing_core:: Event , ctx : Context < S > ) -> Event < ' static >
140
+ where
141
+ S : Subscriber + for < ' a > LookupSpan < ' a > ,
142
+ {
86
143
// TODO: Exception records in Sentry need a valid type, value and full stack trace to support
87
144
// proper grouping and issue metadata generation. tracing_core::Record does not contain sufficient
88
145
// information for this. However, it may contain a serialized error which we can parse to emit
89
146
// an exception record.
90
- event_from_event ( event)
147
+ event_from_event ( event, ctx )
91
148
}
0 commit comments