Skip to content

Commit

Permalink
feat(spans): Extract main_thread tag for spans (#2761)
Browse files Browse the repository at this point in the history
Extracts main_thread tag for spans based on span[data][thread.name].
Right now, we only expect to extract this if thread name is `main`.

#skip-changelog
  • Loading branch information
shruthilayaj authored Nov 27, 2023
1 parent 6f83edc commit 9c571cf
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 2 deletions.
1 change: 1 addition & 0 deletions relay-dynamic-config/src/defaults.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ pub fn add_span_metrics(project_config: &mut ProjectConfig) {
("", "file_extension"), // only set for resource spans
("", "ttid"), // only set for mobile spans
("", "ttfd"), // only set for mobile spans
("span.", "main_thread"), // only set for mobile spans
]
.map(|(prefix, key)| TagSpec {
key: format!("{prefix}{key}"),
Expand Down
103 changes: 101 additions & 2 deletions relay-event-normalization/src/normalize/span/tag_extraction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ use url::Url;

use crate::span::description::{parse_query, scrub_span_description};
use crate::utils::{
extract_transaction_op, get_eventuser_tag, http_status_code_from_span, MOBILE_SDKS,
extract_transaction_op, get_eventuser_tag, http_status_code_from_span, MAIN_THREAD_NAME,
MOBILE_SDKS,
};

/// A list of supported span tags for tag extraction.
Expand Down Expand Up @@ -51,6 +52,8 @@ pub enum SpanTagKey {
TimeToFullDisplay,
/// File extension for resource spans.
FileExtension,
/// Span started on main thread.
MainTread,
}

impl SpanTagKey {
Expand Down Expand Up @@ -83,6 +86,7 @@ impl SpanTagKey {
SpanTagKey::TimeToFullDisplay => "ttfd",
SpanTagKey::TimeToInitialDisplay => "ttid",
SpanTagKey::FileExtension => "file_extension",
SpanTagKey::MainTread => "main_thread",
}
}
}
Expand Down Expand Up @@ -128,6 +132,9 @@ pub(crate) fn extract_span_tags(event: &mut Event, config: &Config) {
// TODO: To prevent differences between metrics and payloads, we should not extract tags here
// when they have already been extracted by a downstream relay.
let shared_tags = extract_shared_tags(event);
let is_mobile = shared_tags
.get(&SpanTagKey::Mobile)
.is_some_and(|v| v.as_str() == "true");

let Some(spans) = event.spans.value_mut() else {
return;
Expand All @@ -141,7 +148,7 @@ pub(crate) fn extract_span_tags(event: &mut Event, config: &Config) {
continue;
};

let tags = extract_tags(span, config, ttid, ttfd);
let tags = extract_tags(span, config, ttid, ttfd, is_mobile);

span.sentry_tags = Annotated::new(
shared_tags
Expand Down Expand Up @@ -214,6 +221,7 @@ pub(crate) fn extract_tags(
config: &Config,
initial_display: Option<Timestamp>,
full_display: Option<Timestamp>,
is_mobile: bool,
) -> BTreeMap<SpanTagKey, String> {
let mut span_tags: BTreeMap<SpanTagKey, String> = BTreeMap::new();

Expand Down Expand Up @@ -384,6 +392,19 @@ pub(crate) fn extract_tags(
span_tags.insert(SpanTagKey::StatusCode, status_code);
}

if is_mobile {
if let Some(thread_name) = span
.data
.value()
.and_then(|data| data.get("thread.name"))
.and_then(|value| value.as_str())
{
if thread_name == MAIN_THREAD_NAME {
span_tags.insert(SpanTagKey::MainTread, "true".to_owned());
}
}
}

if let Some(end_time) = span.timestamp.value() {
if let Some(initial_display) = initial_display {
if end_time <= &initial_display {
Expand Down Expand Up @@ -959,4 +980,82 @@ LIMIT 1
Some("3.3"),
);
}

#[test]
fn test_main_thread() {
let json = r#"
{
"type": "transaction",
"platform": "android",
"start_timestamp": "2021-04-26T07:59:01+0100",
"timestamp": "2021-04-26T08:00:00+0100",
"transaction": "foo",
"sdk": {"name": "sentry.java.android"},
"contexts": {
"trace": {
"trace_id": "ff62a8b040f340bda5d830223def1d81",
"span_id": "bd429c44b67a3eb4"
}
},
"spans": [
{
"op": "ui.load",
"span_id": "bd429c44b67a3eb1",
"start_timestamp": 1597976300.0000000,
"timestamp": 1597976302.0000000,
"trace_id": "ff62a8b040f340bda5d830223def1d81",
"data": {
"thread.id": 1,
"thread.name": "main"
}
},
{
"op": "ui.load",
"span_id": "bd429c44b67a3eb1",
"start_timestamp": 1597976300.0000000,
"timestamp": 1597976302.0000000,
"trace_id": "ff62a8b040f340bda5d830223def1d81",
"data": {
"thread.id": 2,
"thread.name": "not main"
}
},
{
"op": "file.write",
"span_id": "bd429c44b67a3eb1",
"start_timestamp": 1597976300.0000000,
"timestamp": 1597976302.0000000,
"trace_id": "ff62a8b040f340bda5d830223def1d81"
}
]
}
"#;

let mut event = Annotated::<Event>::from_json(json)
.unwrap()
.into_value()
.unwrap();

extract_span_tags(
&mut event,
&Config {
max_tag_value_size: 200,
},
);

let span = &event.spans.value().unwrap()[0];

let tags = span.value().unwrap().sentry_tags.value().unwrap();
assert_eq!(tags.get("main_thread").unwrap().as_str(), Some("true"));

let span = &event.spans.value().unwrap()[1];

let tags = span.value().unwrap().sentry_tags.value().unwrap();
assert_eq!(tags.get("main_thread"), None);

let span = &event.spans.value().unwrap()[2];

let tags = span.value().unwrap().sentry_tags.value().unwrap();
assert_eq!(tags.get("main_thread"), None);
}
}
3 changes: 3 additions & 0 deletions relay-event-normalization/src/normalize/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ pub const MOBILE_SDKS: [&str; 4] = [
"sentry.javascript.react-native",
];

/// Allowed value for main thread name.
pub const MAIN_THREAD_NAME: &str = "main";

/// Maximum length of a mobile span or measurement in milliseconds.
///
/// Spans like `ui.load` with an `exclusive_time` that exceeds this number will be removed,
Expand Down

0 comments on commit 9c571cf

Please sign in to comment.