Skip to content

Commit f89aafb

Browse files
authored
feat(mobile-ui): Add slow, frozen, and total frames metrics (#3473)
Adds gauge metrics for slow, frozen, and total frames metrics for the Mobile UI Starfish module. The tags I've chosen are common and already applied to other mobile conditions. The data source for these metrics come from the `data` property on spans, which I've extracted into `measurements` on spans.
1 parent f16435e commit f89aafb

9 files changed

Lines changed: 308 additions & 8 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
## Unreleased
44

5-
65
**Bug fixes:**
76

87
- Respect country code TLDs when scrubbing span tags. ([#3458](https://github.com/getsentry/relay/pull/3458))
@@ -11,6 +10,7 @@
1110

1211
- Use same keys for OTel span attributes and Sentry span data. ([#3457](https://github.com/getsentry/relay/pull/3457))
1312
- Support passing owner when upserting Monitors. ([#3468](https://github.com/getsentry/relay/pull/3468))
13+
- Extract `frames.slow`, `frames.frozen`, and `frames.total` metrics from mobile spans. ([#3473](https://github.com/getsentry/relay/pull/3473))
1414

1515
**Internal**:
1616

relay-dynamic-config/src/defaults.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,102 @@ fn span_metrics(
631631
.always(), // already guarded by condition on metric
632632
],
633633
},
634+
MetricSpec {
635+
category: DataCategory::Span,
636+
mri: "g:spans/mobile.slow_frames@none".into(),
637+
field: Some("span.measurements.frames.slow.value".into()),
638+
condition: Some(is_mobile.clone() & duration_condition.clone()),
639+
tags: vec![
640+
Tag::with_key("transaction")
641+
.from_field("span.sentry_tags.transaction")
642+
.always(),
643+
Tag::with_key("environment")
644+
.from_field("span.sentry_tags.environment")
645+
.always(),
646+
Tag::with_key("release")
647+
.from_field("span.sentry_tags.release")
648+
.always(),
649+
Tag::with_key("span.description")
650+
.from_field("span.sentry_tags.description")
651+
.always(),
652+
Tag::with_key("span.op")
653+
.from_field("span.sentry_tags.op")
654+
.always(),
655+
Tag::with_key("span.group")
656+
.from_field("span.sentry_tags.group")
657+
.always(),
658+
Tag::with_key("device.class")
659+
.from_field("span.sentry_tags.device.class")
660+
.always(),
661+
Tag::with_key("os.name")
662+
.from_field("span.sentry_tags.os.name")
663+
.always(),
664+
],
665+
},
666+
MetricSpec {
667+
category: DataCategory::Span,
668+
mri: "g:spans/mobile.frozen_frames@none".into(),
669+
field: Some("span.measurements.frames.frozen.value".into()),
670+
condition: Some(is_mobile.clone() & duration_condition.clone()),
671+
tags: vec![
672+
Tag::with_key("transaction")
673+
.from_field("span.sentry_tags.transaction")
674+
.always(),
675+
Tag::with_key("environment")
676+
.from_field("span.sentry_tags.environment")
677+
.always(),
678+
Tag::with_key("release")
679+
.from_field("span.sentry_tags.release")
680+
.always(),
681+
Tag::with_key("span.description")
682+
.from_field("span.sentry_tags.description")
683+
.always(),
684+
Tag::with_key("span.op")
685+
.from_field("span.sentry_tags.op")
686+
.always(),
687+
Tag::with_key("span.group")
688+
.from_field("span.sentry_tags.group")
689+
.always(),
690+
Tag::with_key("device.class")
691+
.from_field("span.sentry_tags.device.class")
692+
.always(),
693+
Tag::with_key("os.name")
694+
.from_field("span.sentry_tags.os.name")
695+
.always(),
696+
],
697+
},
698+
MetricSpec {
699+
category: DataCategory::Span,
700+
mri: "g:spans/mobile.total_frames@none".into(),
701+
field: Some("span.measurements.frames.total.value".into()),
702+
condition: Some(is_mobile.clone() & duration_condition.clone()),
703+
tags: vec![
704+
Tag::with_key("transaction")
705+
.from_field("span.sentry_tags.transaction")
706+
.always(),
707+
Tag::with_key("environment")
708+
.from_field("span.sentry_tags.environment")
709+
.always(),
710+
Tag::with_key("release")
711+
.from_field("span.sentry_tags.release")
712+
.always(),
713+
Tag::with_key("span.description")
714+
.from_field("span.sentry_tags.description")
715+
.always(),
716+
Tag::with_key("span.op")
717+
.from_field("span.sentry_tags.op")
718+
.always(),
719+
Tag::with_key("span.group")
720+
.from_field("span.sentry_tags.group")
721+
.always(),
722+
Tag::with_key("device.class")
723+
.from_field("span.sentry_tags.device.class")
724+
.always(),
725+
Tag::with_key("os.name")
726+
.from_field("span.sentry_tags.os.name")
727+
.always(),
728+
],
729+
},
634730
];
635731

636732
if double_write_distributions_as_gauges {

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

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ pub fn extract_span_tags(event: &Event, spans: &mut [Annotated<Span>], max_tag_v
197197
.collect(),
198198
);
199199

200-
extract_measurements(span);
200+
extract_measurements(span, is_mobile);
201201
}
202202
}
203203

@@ -598,7 +598,7 @@ pub fn extract_tags(
598598
}
599599

600600
/// Copies specific numeric values from span data to span measurements.
601-
pub fn extract_measurements(span: &mut Span) {
601+
pub fn extract_measurements(span: &mut Span, is_mobile: bool) {
602602
let Some(span_op) = span.op.as_str() else {
603603
return;
604604
};
@@ -659,6 +659,33 @@ pub fn extract_measurements(span: &mut Span) {
659659
}
660660
}
661661
}
662+
663+
if is_mobile {
664+
if let Some(data) = span.data.value() {
665+
for (field, key) in [
666+
(&data.frames_frozen, "frames.frozen"),
667+
(&data.frames_slow, "frames.slow"),
668+
(&data.frames_total, "frames.total"),
669+
] {
670+
if let Some(value) = match field.value() {
671+
Some(Value::F64(f)) => Some(*f),
672+
Some(Value::I64(i)) => Some(*i as f64),
673+
Some(Value::U64(u)) => Some(*u as f64),
674+
_ => None,
675+
} {
676+
let measurements = span.measurements.get_or_insert_with(Default::default);
677+
measurements.insert(
678+
key.into(),
679+
Measurement {
680+
value: value.into(),
681+
unit: MetricUnit::None.into(),
682+
}
683+
.into(),
684+
);
685+
}
686+
}
687+
}
688+
}
662689
}
663690

664691
/// Finds first matching span and get its timestamp.

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,18 @@ pub struct SpanData {
303303
#[metastructure(field = "sentry.sdk.name")]
304304
pub sdk_name: Annotated<String>,
305305

306+
/// Slow Frames
307+
#[metastructure(field = "sentry.frames.slow", legacy_alias = "frames.slow")]
308+
pub frames_slow: Annotated<Value>,
309+
310+
/// Frozen Frames
311+
#[metastructure(field = "sentry.frames.frozen", legacy_alias = "frames.frozen")]
312+
pub frames_frozen: Annotated<Value>,
313+
314+
/// Total Frames
315+
#[metastructure(field = "sentry.frames.total", legacy_alias = "frames.total")]
316+
pub frames_total: Annotated<Value>,
317+
306318
/// Other fields in `span.data`.
307319
#[metastructure(additional_properties, pii = "true", retain = "true")]
308320
other: Object<Value>,
@@ -497,7 +509,10 @@ mod tests {
497509
"code.filepath": "task.py",
498510
"code.lineno": 123,
499511
"code.function": "fn()",
500-
"code.namespace": "ns"
512+
"code.namespace": "ns",
513+
"frames.slow": 1,
514+
"frames.frozen": 2,
515+
"frames.total": 9
501516
}"#;
502517
let data = Annotated::<SpanData>::from_json(data)
503518
.unwrap()
@@ -547,6 +562,15 @@ mod tests {
547562
user: ~,
548563
replay_id: ~,
549564
sdk_name: ~,
565+
frames_slow: I64(
566+
1,
567+
),
568+
frames_frozen: I64(
569+
2,
570+
),
571+
frames_total: I64(
572+
9,
573+
),
550574
other: {
551575
"bar": String(
552576
"3",

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,9 @@ mod tests {
288288
user: ~,
289289
replay_id: ~,
290290
sdk_name: "sentry.php",
291+
frames_slow: ~,
292+
frames_frozen: ~,
293+
frames_total: ~,
291294
other: {},
292295
},
293296
sentry_tags: ~,

relay-server/src/metrics_extraction/event.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1151,7 +1151,12 @@ mod tests {
11511151
"span_id": "bd429c44b67a3eb2",
11521152
"start_timestamp": 1597976300.0000000,
11531153
"timestamp": 1597976303.0000000,
1154-
"trace_id": "ff62a8b040f340bda5d830223def1d81"
1154+
"trace_id": "ff62a8b040f340bda5d830223def1d81",
1155+
"data": {
1156+
"frames.slow": 1,
1157+
"frames.frozen": 2,
1158+
"frames.total": 9
1159+
}
11551160
},
11561161
{
11571162
"op": "app.start.cold",

0 commit comments

Comments
 (0)