Skip to content

Commit ed2fc8c

Browse files
authored
feat(profiles): Extract thread ID and name in spans (#3771)
1 parent e59b49b commit ed2fc8c

File tree

9 files changed

+177
-3
lines changed

9 files changed

+177
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- Add web vitals support for mobile browsers. ([#3762](https://github.com/getsentry/relay/pull/3762))
1616
- Ingest profiler_id in the profile context and in spans. ([#3714](https://github.com/getsentry/relay/pull/3714), [#3784](https://github.com/getsentry/relay/pull/3784))
1717
- Support extrapolation of metrics extracted from sampled data, as long as the sample rate is set in the DynamicSamplingContext. ([#3753](https://github.com/getsentry/relay/pull/3753))
18+
- Extract thread ID and name in spans. ([#3771](https://github.com/getsentry/relay/pull/3771))
1819

1920
## 24.6.0
2021

relay-event-normalization/src/normalize/span/tag_extraction.rs

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ pub enum SpanTagKey {
8282
TraceStatus,
8383
MessagingDestinationName,
8484
MessagingMessageId,
85+
ThreadName,
86+
ThreadId,
8587
ProfilerId,
8688
}
8789

@@ -134,7 +136,8 @@ impl SpanTagKey {
134136
SpanTagKey::TraceStatus => "trace.status",
135137
SpanTagKey::MessagingDestinationName => "messaging.destination.name",
136138
SpanTagKey::MessagingMessageId => "messaging.message.id",
137-
139+
SpanTagKey::ThreadName => "thread.name",
140+
SpanTagKey::ThreadId => "thread.id",
138141
SpanTagKey::ProfilerId => "profiler_id",
139142
}
140143
}
@@ -343,6 +346,19 @@ fn extract_shared_tags(event: &Event) -> BTreeMap<SpanTagKey, String> {
343346
event.platform.as_str().unwrap_or("other").into(),
344347
);
345348

349+
if let Some(data) = event
350+
.context::<TraceContext>()
351+
.and_then(|trace_context| trace_context.data.value())
352+
{
353+
if let Some(thread_id) = data.thread_id.value() {
354+
tags.insert(SpanTagKey::ThreadId, thread_id.to_string());
355+
}
356+
357+
if let Some(thread_name) = data.thread_name.value() {
358+
tags.insert(SpanTagKey::ThreadName, thread_name.to_string());
359+
}
360+
}
361+
346362
tags
347363
}
348364

@@ -763,6 +779,16 @@ pub fn extract_tags(
763779
span_tags.insert(SpanTagKey::BrowserName, browser_name.clone());
764780
}
765781

782+
if let Some(data) = span.data.value() {
783+
if let Some(thread_id) = data.thread_id.value() {
784+
span_tags.insert(SpanTagKey::ThreadId, thread_id.to_string());
785+
}
786+
787+
if let Some(thread_name) = data.thread_name.value().and_then(|name| name.as_str()) {
788+
span_tags.insert(SpanTagKey::ThreadName, thread_name.into());
789+
}
790+
}
791+
766792
span_tags
767793
}
768794

@@ -2486,4 +2512,100 @@ LIMIT 1
24862512
"admin@sentry.io"
24872513
);
24882514
}
2515+
2516+
#[test]
2517+
fn extract_thread_id_name_from_span_data_into_sentry_tags() {
2518+
let json = r#"
2519+
{
2520+
"type": "transaction",
2521+
"platform": "javascript",
2522+
"start_timestamp": "2021-04-26T07:59:01+0100",
2523+
"timestamp": "2021-04-26T08:00:00+0100",
2524+
"transaction": "foo",
2525+
"contexts": {
2526+
"trace": {
2527+
"trace_id": "ff62a8b040f340bda5d830223def1d81",
2528+
"span_id": "bd429c44b67a3eb4"
2529+
}
2530+
},
2531+
"spans": [
2532+
{
2533+
"op": "before_first_display",
2534+
"span_id": "bd429c44b67a3eb1",
2535+
"start_timestamp": 1597976300.0000000,
2536+
"timestamp": 1597976302.0000000,
2537+
"trace_id": "ff62a8b040f340bda5d830223def1d81",
2538+
"data": {
2539+
"thread.name": "main",
2540+
"thread.id": 42
2541+
}
2542+
}
2543+
]
2544+
}
2545+
"#;
2546+
2547+
let mut event = Annotated::<Event>::from_json(json).unwrap();
2548+
2549+
normalize_event(
2550+
&mut event,
2551+
&NormalizationConfig {
2552+
enrich_spans: true,
2553+
..Default::default()
2554+
},
2555+
);
2556+
2557+
let spans = get_value!(event.spans!);
2558+
let span = &spans[0];
2559+
2560+
assert_eq!(get_value!(span.sentry_tags["thread.id"]!), "42",);
2561+
assert_eq!(get_value!(span.sentry_tags["thread.name"]!), "main",);
2562+
}
2563+
2564+
#[test]
2565+
fn extract_thread_id_name_from_trace_context_into_sentry_tags() {
2566+
let json = r#"
2567+
{
2568+
"type": "transaction",
2569+
"platform": "python",
2570+
"start_timestamp": "2021-04-26T07:59:01+0100",
2571+
"timestamp": "2021-04-26T08:00:00+0100",
2572+
"transaction": "foo",
2573+
"contexts": {
2574+
"trace": {
2575+
"op": "queue.process",
2576+
"status": "ok",
2577+
"data": {
2578+
"thread.name": "main",
2579+
"thread.id": 42
2580+
}
2581+
}
2582+
},
2583+
"spans": [
2584+
{
2585+
"op": "before_first_display",
2586+
"span_id": "bd429c44b67a3eb1",
2587+
"start_timestamp": 1597976300.0000000,
2588+
"timestamp": 1597976302.0000000,
2589+
"trace_id": "ff62a8b040f340bda5d830223def1d81"
2590+
}
2591+
]
2592+
}
2593+
"#;
2594+
2595+
let mut event = Annotated::<Event>::from_json(json).unwrap();
2596+
2597+
normalize_event(
2598+
&mut event,
2599+
&NormalizationConfig {
2600+
enrich_spans: true,
2601+
..Default::default()
2602+
},
2603+
);
2604+
2605+
let spans = get_value!(event.spans!);
2606+
let span = &spans[0];
2607+
2608+
assert_eq!(get_value!(span.sentry_tags["thread.id"]!), "42",);
2609+
assert_eq!(get_value!(span.sentry_tags["thread.name"]!), "main",);
2610+
}
24892611
}

relay-event-schema/src/protocol/contexts/trace.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use relay_jsonschema_derive::JsonSchema;
66
use relay_protocol::{Annotated, Empty, Error, FromValue, IntoValue, Object, Value};
77

88
use crate::processor::ProcessValue;
9-
use crate::protocol::{OperationType, OriginType, SpanStatus};
9+
use crate::protocol::{OperationType, OriginType, SpanStatus, ThreadId};
1010

1111
/// A 32-character hex string as described in the W3C trace context spec.
1212
#[derive(Clone, Debug, Default, PartialEq, Empty, IntoValue, ProcessValue)]
@@ -191,6 +191,14 @@ pub struct Data {
191191
#[metastructure(field = "messaging.message.body.size")]
192192
pub messaging_message_body_size: Annotated<Value>,
193193

194+
/// The ID of the thread from which the transaction originated from
195+
#[metastructure(field = "thread.id")]
196+
pub thread_id: Annotated<ThreadId>,
197+
198+
/// The name of the thread from which the transaction originated from
199+
#[metastructure(field = "thread.name")]
200+
pub thread_name: Annotated<String>,
201+
194202
/// Additional arbitrary fields for forwards compatibility.
195203
#[metastructure(
196204
additional_properties,

relay-event-schema/src/protocol/span.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use relay_protocol::{Annotated, Empty, FromValue, Getter, IntoValue, Object, Val
77
use crate::processor::ProcessValue;
88
use crate::protocol::{
99
EventId, JsonLenientString, LenientString, Measurements, MetricsSummary, OperationType,
10-
OriginType, SpanId, SpanStatus, Timestamp, TraceId,
10+
OriginType, SpanId, SpanStatus, ThreadId, Timestamp, TraceId,
1111
};
1212

1313
#[derive(Clone, Debug, Default, PartialEq, Empty, FromValue, IntoValue, ProcessValue)]
@@ -314,6 +314,10 @@ pub struct SpanData {
314314
#[metastructure(field = "thread.name")]
315315
pub thread_name: Annotated<Value>,
316316

317+
/// ID of thread from where the span originated.
318+
#[metastructure(field = "thread.id")]
319+
pub thread_id: Annotated<ThreadId>,
320+
317321
/// Name of the segment that this span belongs to (see `segment_id`).
318322
///
319323
/// This corresponds to the transaction name in the transaction-based model.
@@ -673,6 +677,7 @@ mod tests {
673677
ai_input_messages: ~,
674678
ai_responses: ~,
675679
thread_name: ~,
680+
thread_id: ~,
676681
segment_name: ~,
677682
ui_component_name: ~,
678683
url_scheme: ~,

relay-event-schema/src/protocol/span/convert.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ mod tests {
300300
ai_input_messages: ~,
301301
ai_responses: ~,
302302
thread_name: ~,
303+
thread_id: ~,
303304
segment_name: "my 1st transaction",
304305
ui_component_name: ~,
305306
url_scheme: ~,

relay-event-schema/src/protocol/thread.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::fmt;
2+
13
#[cfg(feature = "jsonschema")]
24
use relay_jsonschema_derive::JsonSchema;
35
use relay_protocol::{
@@ -71,6 +73,15 @@ impl Empty for ThreadId {
7173
}
7274
}
7375

76+
impl fmt::Display for ThreadId {
77+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78+
match self {
79+
ThreadId::Int(id) => write!(f, "{}", id),
80+
ThreadId::String(id) => write!(f, "{}", id),
81+
}
82+
}
83+
}
84+
7485
/// Possible lock types responsible for a thread's blocked state
7586
#[derive(Debug, Copy, Clone, Eq, PartialEq, ProcessValue, Empty)]
7687
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]

relay-server/src/metrics_extraction/snapshots/relay_server__metrics_extraction__event__tests__extract_span_metrics_mobile.snap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ expression: "(&event.value().unwrap().spans, metrics)"
104104
ai_input_messages: ~,
105105
ai_responses: ~,
106106
thread_name: ~,
107+
thread_id: ~,
107108
segment_name: ~,
108109
ui_component_name: ~,
109110
url_scheme: ~,
@@ -426,6 +427,7 @@ expression: "(&event.value().unwrap().spans, metrics)"
426427
ai_input_messages: ~,
427428
ai_responses: ~,
428429
thread_name: ~,
430+
thread_id: ~,
429431
segment_name: ~,
430432
ui_component_name: ~,
431433
url_scheme: ~,
@@ -526,6 +528,7 @@ expression: "(&event.value().unwrap().spans, metrics)"
526528
ai_input_messages: ~,
527529
ai_responses: ~,
528530
thread_name: ~,
531+
thread_id: ~,
529532
segment_name: ~,
530533
ui_component_name: ~,
531534
url_scheme: ~,
@@ -674,6 +677,7 @@ expression: "(&event.value().unwrap().spans, metrics)"
674677
ai_input_messages: ~,
675678
ai_responses: ~,
676679
thread_name: ~,
680+
thread_id: ~,
677681
segment_name: ~,
678682
ui_component_name: ~,
679683
url_scheme: ~,
@@ -774,6 +778,7 @@ expression: "(&event.value().unwrap().spans, metrics)"
774778
ai_input_messages: ~,
775779
ai_responses: ~,
776780
thread_name: ~,
781+
thread_id: ~,
777782
segment_name: ~,
778783
ui_component_name: ~,
779784
url_scheme: ~,

relay-server/tests/snapshots/test_fixtures__event_schema.snap

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,26 @@ expression: "relay_event_schema::protocol::event_json_schema()"
10791079
"type": "null"
10801080
}
10811081
]
1082+
},
1083+
"thread.id": {
1084+
"description": " The ID of the thread from which the transaction originated from",
1085+
"default": null,
1086+
"anyOf": [
1087+
{
1088+
"$ref": "#/definitions/ThreadId"
1089+
},
1090+
{
1091+
"type": "null"
1092+
}
1093+
]
1094+
},
1095+
"thread.name": {
1096+
"description": " The name of the thread from which the transaction originated from",
1097+
"default": null,
1098+
"type": [
1099+
"string",
1100+
"null"
1101+
]
10821102
}
10831103
},
10841104
"additionalProperties": false

relay-spans/src/span.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,7 @@ mod tests {
654654
ai_input_messages: ~,
655655
ai_responses: ~,
656656
thread_name: ~,
657+
thread_id: ~,
657658
segment_name: "my 1st transaction",
658659
ui_component_name: ~,
659660
url_scheme: ~,

0 commit comments

Comments
 (0)