relay_event_schema/protocol/span/
convert.rs1use relay_conventions::attributes::{
4 BROWSER__NAME, HTTP__QUERY, SENTRY__ENVIRONMENT, SENTRY__RELEASE, SENTRY__SDK__NAME,
5 SENTRY__SDK__VERSION, SENTRY__SEGMENT__NAME, URL__QUERY,
6};
7use relay_protocol::IntoValue;
8
9use crate::protocol::{BrowserContext, Event, ProfileContext, Span, SpanData, TraceContext};
10
11impl From<&Event> for Span {
12 fn from(event: &Event) -> Self {
13 let Event {
14 transaction,
15
16 platform,
17 timestamp,
18 start_timestamp,
19 received,
20 release,
21 environment,
22 tags,
23
24 measurements,
25 _metrics,
26 ..
27 } = event;
28
29 let trace = event.context::<TraceContext>();
30
31 let mut data = trace
33 .map(|c| c.data.clone().map_value(SpanData::from))
34 .unwrap_or_default();
35
36 let span_data = data.get_or_insert_with(Default::default);
38 span_data.insert(
39 SENTRY__SEGMENT__NAME,
40 transaction.clone().map_value(IntoValue::into_value),
41 );
42 span_data.insert(
44 "sentry.name",
45 transaction.clone().map_value(IntoValue::into_value),
46 );
47 span_data.insert(
48 SENTRY__RELEASE,
49 release.clone().map_value(IntoValue::into_value),
50 );
51 span_data.insert(
52 SENTRY__ENVIRONMENT,
53 environment.clone().map_value(IntoValue::into_value),
54 );
55 if let Some(browser) = event.context::<BrowserContext>() {
56 span_data.insert(
57 BROWSER__NAME,
58 browser.name.clone().map_value(IntoValue::into_value),
59 );
60 }
61 if let Some(client_sdk) = event.client_sdk.value() {
62 span_data.insert(
63 SENTRY__SDK__NAME,
64 client_sdk.name.clone().map_value(IntoValue::into_value),
65 );
66 span_data.insert(
67 SENTRY__SDK__VERSION,
68 client_sdk.version.clone().map_value(IntoValue::into_value),
69 );
70 }
71 if let Some(request) = event.request.value()
72 && let Some(query) = request.query_string.value()
73 && let Some(qs) = query.to_query_string()
74 {
75 span_data.insert_value(HTTP__QUERY, format!("?{qs}"));
76 span_data.insert_value(URL__QUERY, qs);
77 }
78
79 Self {
80 timestamp: timestamp.clone(),
81 start_timestamp: start_timestamp.clone(),
82 exclusive_time: trace.map(|c| c.exclusive_time.clone()).unwrap_or_default(),
83 op: trace.map(|c| c.op.clone()).unwrap_or_default(),
84 span_id: trace.map(|c| c.span_id.clone()).unwrap_or_default(),
85 parent_span_id: trace.map(|c| c.parent_span_id.clone()).unwrap_or_default(),
86 trace_id: trace.map(|c| c.trace_id.clone()).unwrap_or_default(),
87 segment_id: trace.map(|c| c.span_id.clone()).unwrap_or_default(),
88 is_segment: true.into(),
89 is_remote: true.into(),
94 status: trace.map(|c| c.status.clone()).unwrap_or_default(),
95 description: transaction.clone(),
96 tags: tags.clone().map_value(|t| t.into()),
97 origin: trace.map(|c| c.origin.clone()).unwrap_or_default(),
98 profile_id: event
99 .context::<ProfileContext>()
100 .map(|c| c.profile_id.clone())
101 .unwrap_or_default(),
102 data,
103 links: trace.map(|c| c.links.clone()).unwrap_or_default(),
104 sentry_tags: Default::default(),
105 received: received.clone(),
106 measurements: measurements.clone(),
107 platform: platform.clone(),
108 was_transaction: true.into(),
109 kind: Default::default(),
110 other: Default::default(),
111 }
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use relay_protocol::Annotated;
118
119 use super::*;
120
121 #[test]
122 fn convert() {
123 let event = Annotated::<Event>::from_json(
124 r#"{
125 "type": "transaction",
126 "platform": "php",
127 "sdk": {"name": "sentry.php", "version": "1.2.3"},
128 "release": "myapp@1.0.0",
129 "environment": "prod",
130 "transaction": "my 1st transaction",
131 "contexts": {
132 "browser": {"name": "Chrome"},
133 "profile": {"profile_id": "a0aaaaaaaaaaaaaaaaaaaaaaaaaaaaab"},
134 "trace": {
135 "trace_id": "4C79F60C11214EB38604F4AE0781BFB2",
136 "span_id": "FA90FDEAD5F74052",
137 "type": "trace",
138 "origin": "manual",
139 "op": "myop",
140 "status": "ok",
141 "exclusive_time": 123.4,
142 "parent_span_id": "FA90FDEAD5F74051",
143 "data": {
144 "custom_attribute": 42
145 },
146 "links": [
147 {
148 "trace_id": "4c79f60c11214eb38604f4ae0781bfb2",
149 "span_id": "fa90fdead5f74052",
150 "sampled": true,
151 "attributes": {
152 "sentry.link.type": "previous_trace"
153 }
154 }
155 ]
156 }
157 },
158 "request": {
159 "url": "http://example.com/api/0/organizations/",
160 "method": "GET",
161 "query_string": "project=1&sort=date"
162 },
163 "measurements": {
164 "memory": {
165 "value": 9001.0,
166 "unit": "byte"
167 }
168 }
169 }"#,
170 )
171 .unwrap()
172 .into_value()
173 .unwrap();
174
175 let span_from_event = Span::from(&event);
176 insta::assert_debug_snapshot!(span_from_event, @r#"
177 Span {
178 timestamp: ~,
179 start_timestamp: ~,
180 exclusive_time: 123.4,
181 op: "myop",
182 span_id: SpanId("fa90fdead5f74052"),
183 parent_span_id: SpanId("fa90fdead5f74051"),
184 trace_id: TraceId("4c79f60c11214eb38604f4ae0781bfb2"),
185 segment_id: SpanId("fa90fdead5f74052"),
186 is_segment: true,
187 is_remote: true,
188 status: Ok,
189 description: "my 1st transaction",
190 tags: ~,
191 origin: "manual",
192 profile_id: EventId(
193 a0aaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaab,
194 ),
195 data: SpanData {
196 other: {
197 "browser.name": String(
198 "Chrome",
199 ),
200 "custom_attribute": I64(
201 42,
202 ),
203 "http.query": String(
204 "?project=1&sort=date",
205 ),
206 "sentry.environment": String(
207 "prod",
208 ),
209 "sentry.name": String(
210 "my 1st transaction",
211 ),
212 "sentry.release": String(
213 "myapp@1.0.0",
214 ),
215 "sentry.sdk.name": String(
216 "sentry.php",
217 ),
218 "sentry.sdk.version": String(
219 "1.2.3",
220 ),
221 "sentry.segment.name": String(
222 "my 1st transaction",
223 ),
224 "url.query": String(
225 "project=1&sort=date",
226 ),
227 },
228 },
229 links: [
230 SpanLink {
231 trace_id: TraceId("4c79f60c11214eb38604f4ae0781bfb2"),
232 span_id: SpanId("fa90fdead5f74052"),
233 sampled: true,
234 attributes: {
235 "sentry.link.type": String(
236 "previous_trace",
237 ),
238 },
239 other: {},
240 },
241 ],
242 sentry_tags: ~,
243 received: ~,
244 measurements: Measurements(
245 {
246 "memory": Measurement {
247 value: 9001.0,
248 unit: Information(
249 Byte,
250 ),
251 },
252 },
253 ),
254 platform: "php",
255 was_transaction: true,
256 kind: ~,
257 other: {},
258 }
259 "#);
260 }
261}