Skip to content

Commit 1f8c3ca

Browse files
committed
Merge branch 'master' into ref/kafka-ingest-spans
* master: fix(otlp): Propagate all attributes (#4779) fix(ourlogs): Add observed nanos for parity with OTel logs (#4795) fix(spans): Add `gen_ai.request.max_tokens` to `SpanData` (#4792)
2 parents 9bf633f + 9a5e575 commit 1f8c3ca

File tree

9 files changed

+198
-36
lines changed

9 files changed

+198
-36
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
- Use sentry prefix for browser name/version in logs. ([#4783](https://github.com/getsentry/relay/pull/4783))
1515
- Do not overcount the number of bytes in logs. ([#4786](https://github.com/getsentry/relay/pull/4786))
16+
- Record observed time for logs. ([#4795](https://github.com/getsentry/relay/pull/4795))
1617

1718
**Internal**:
1819

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,10 @@ pub struct SpanData {
455455
#[metastructure(field = "app_start_type")] // TODO: no dot?
456456
pub app_start_type: Annotated<Value>,
457457

458+
/// The maximum number of tokens that should be used by an LLM call.
459+
#[metastructure(field = "gen_ai.request.max_tokens")]
460+
pub gen_ai_request_max_tokens: Annotated<Value>,
461+
458462
/// The total tokens that were used by an LLM call
459463
#[metastructure(
460464
field = "gen_ai.usage.total_tokens",
@@ -809,6 +813,7 @@ impl Getter for SpanData {
809813
"db.operation" => self.db_operation.value()?.into(),
810814
"db\\.system" => self.db_system.value()?.into(),
811815
"environment" => self.environment.as_str()?.into(),
816+
"gen_ai\\.request\\.max_tokens" => self.gen_ai_request_max_tokens.value()?.into(),
812817
"gen_ai\\.usage\\.total_tokens" => self.gen_ai_usage_total_tokens.value()?.into(),
813818
"gen_ai\\.usage\\.total_cost" => self.gen_ai_usage_total_cost.value()?.into(),
814819
"http\\.decoded_response_content_length" => {
@@ -1257,9 +1262,10 @@ mod tests {
12571262
.unwrap()
12581263
.into_value()
12591264
.unwrap();
1260-
insta::assert_debug_snapshot!(data, @r#"
1265+
insta::assert_debug_snapshot!(data, @r###"
12611266
SpanData {
12621267
app_start_type: ~,
1268+
gen_ai_request_max_tokens: ~,
12631269
gen_ai_usage_total_tokens: ~,
12641270
gen_ai_usage_input_tokens: ~,
12651271
gen_ai_usage_output_tokens: ~,
@@ -1364,7 +1370,7 @@ mod tests {
13641370
),
13651371
},
13661372
}
1367-
"#);
1373+
"###);
13681374

13691375
assert_eq!(data.get_value("foo"), Some(Val::U64(2)));
13701376
assert_eq!(data.get_value("bar"), Some(Val::String("3")));

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ mod tests {
134134
.unwrap();
135135

136136
let span_from_event = Span::from(&event);
137-
insta::assert_debug_snapshot!(span_from_event, @r#"
137+
insta::assert_debug_snapshot!(span_from_event, @r###"
138138
Span {
139139
timestamp: ~,
140140
start_timestamp: ~,
@@ -155,6 +155,7 @@ mod tests {
155155
),
156156
data: SpanData {
157157
app_start_type: ~,
158+
gen_ai_request_max_tokens: ~,
158159
gen_ai_usage_total_tokens: ~,
159160
gen_ai_usage_input_tokens: ~,
160161
gen_ai_usage_output_tokens: ~,
@@ -263,6 +264,6 @@ mod tests {
263264
_performance_issues_spans: ~,
264265
other: {},
265266
}
266-
"#);
267+
"###);
267268
}
268269
}

relay-ourlogs/src/ourlog.rs

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,10 @@ pub fn ourlog_merge_otel(ourlog: &mut Annotated<OurLog>) {
163163
})
164164
.unwrap_or_default();
165165

166+
// This is separate from the sdk provided time since Relay always acts as the collector in Sentry.
167+
// We may change this in the future with forwarding Relays.
168+
let observed_time_unix_nano = UnixTimestamp::now().as_nanos();
169+
166170
attributes.insert(
167171
"sentry.severity_text".to_owned(),
168172
Annotated::new(Attribute::new(
@@ -203,7 +207,7 @@ pub fn ourlog_merge_otel(ourlog: &mut Annotated<OurLog>) {
203207
"sentry.observed_timestamp_nanos".to_owned(),
204208
Annotated::new(Attribute::new(
205209
AttributeType::String,
206-
Value::String(timestamp_nanos.to_string()),
210+
Value::String(observed_time_unix_nano.to_string()),
207211
)),
208212
);
209213
attributes.insert(
@@ -476,8 +480,34 @@ mod tests {
476480
}
477481
}"#;
478482

483+
let before_test = UnixTimestamp::now().as_nanos();
479484
let mut merged_log = Annotated::<OurLog>::from_json(json).unwrap();
480485
ourlog_merge_otel(&mut merged_log);
486+
let after_test = UnixTimestamp::now().as_nanos();
487+
488+
// Test the observed timestamp separately
489+
let observed_timestamp = merged_log
490+
.value()
491+
.and_then(|log| log.attribute("sentry.observed_timestamp_nanos"))
492+
.and_then(|attr| attr.as_str().and_then(|s| s.parse::<u64>().ok()))
493+
.unwrap_or(0);
494+
495+
assert!(observed_timestamp > 0);
496+
assert!(observed_timestamp >= before_test);
497+
assert!(observed_timestamp <= after_test);
498+
499+
// Set observed timestamp to a fixed value for snapshot testing
500+
if let Some(log) = merged_log.value_mut() {
501+
if let Some(attributes) = log.attributes.value_mut() {
502+
attributes.insert(
503+
"sentry.observed_timestamp_nanos".to_owned(),
504+
Annotated::new(Attribute::new(
505+
AttributeType::String,
506+
Value::String("946684800000000000".to_string()),
507+
)),
508+
);
509+
}
510+
}
481511

482512
insta::assert_debug_snapshot!(merged_log, @r###"
483513
OurLog {
@@ -608,7 +638,34 @@ mod tests {
608638
body: Annotated::new("somebody".into()),
609639
..Default::default()
610640
});
641+
642+
let before_test = UnixTimestamp::now().as_nanos();
611643
ourlog_merge_otel(&mut ourlog);
644+
let after_test = UnixTimestamp::now().as_nanos();
645+
646+
// Test the observed timestamp separately
647+
let observed_timestamp = ourlog
648+
.value()
649+
.and_then(|log| log.attribute("sentry.observed_timestamp_nanos"))
650+
.and_then(|attr| attr.as_str().and_then(|s| s.parse::<u64>().ok()))
651+
.unwrap_or(0);
652+
653+
assert!(observed_timestamp > 0);
654+
assert!(observed_timestamp >= before_test);
655+
assert!(observed_timestamp <= after_test);
656+
657+
// Set observed timestamp to a fixed value for snapshot testing
658+
if let Some(log) = ourlog.value_mut() {
659+
if let Some(attributes) = log.attributes.value_mut() {
660+
attributes.insert(
661+
"sentry.observed_timestamp_nanos".to_owned(),
662+
Annotated::new(Attribute::new(
663+
AttributeType::String,
664+
Value::String("1638144000000000000".to_string()),
665+
)),
666+
);
667+
}
668+
}
612669

613670
insta::assert_debug_snapshot!(ourlog, @r#"
614671
OurLog {

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
@@ -137,6 +137,7 @@ expression: "(&event.value().unwrap().spans, metrics.project_metrics)"
137137
profile_id: ~,
138138
data: SpanData {
139139
app_start_type: ~,
140+
gen_ai_request_max_tokens: ~,
140141
gen_ai_usage_total_tokens: ~,
141142
gen_ai_usage_input_tokens: ~,
142143
gen_ai_usage_output_tokens: ~,
@@ -795,6 +796,7 @@ expression: "(&event.value().unwrap().spans, metrics.project_metrics)"
795796
app_start_type: String(
796797
"cold",
797798
),
799+
gen_ai_request_max_tokens: ~,
798800
gen_ai_usage_total_tokens: ~,
799801
gen_ai_usage_input_tokens: ~,
800802
gen_ai_usage_output_tokens: ~,
@@ -980,6 +982,7 @@ expression: "(&event.value().unwrap().spans, metrics.project_metrics)"
980982
app_start_type: String(
981983
"cold",
982984
),
985+
gen_ai_request_max_tokens: ~,
983986
gen_ai_usage_total_tokens: ~,
984987
gen_ai_usage_input_tokens: ~,
985988
gen_ai_usage_output_tokens: ~,
@@ -1274,6 +1277,7 @@ expression: "(&event.value().unwrap().spans, metrics.project_metrics)"
12741277
profile_id: ~,
12751278
data: SpanData {
12761279
app_start_type: ~,
1280+
gen_ai_request_max_tokens: ~,
12771281
gen_ai_usage_total_tokens: ~,
12781282
gen_ai_usage_input_tokens: ~,
12791283
gen_ai_usage_output_tokens: ~,
@@ -1459,6 +1463,7 @@ expression: "(&event.value().unwrap().spans, metrics.project_metrics)"
14591463
profile_id: ~,
14601464
data: SpanData {
14611465
app_start_type: ~,
1466+
gen_ai_request_max_tokens: ~,
14621467
gen_ai_usage_total_tokens: ~,
14631468
gen_ai_usage_input_tokens: ~,
14641469
gen_ai_usage_output_tokens: ~,

relay-spans/src/otel_to_sentry.rs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ mod tests {
4141
"startTimeUnixNano": "1697620454980000000",
4242
"endTimeUnixNano": "1697620454980078800",
4343
"attributes": [
44+
{
45+
"key": "http.route", "value": {
46+
"stringValue": "/home"
47+
}
48+
},
49+
{
50+
"key": "http.request.method",
51+
"value": {
52+
"stringValue": "GET"
53+
}
54+
},
4455
{
4556
"key": "sentry.environment",
4657
"value": {
@@ -107,10 +118,13 @@ mod tests {
107118
"parent_span_id": "0c7a7dea069bf5a6",
108119
"trace_id": "89143b0763095bd9c9955e8175d1fb23",
109120
"status": "ok",
121+
"description": "GET /home",
110122
"data": {
111123
"sentry.environment": "test",
112124
"fastify.type": "middleware",
113125
"hook.name": "onResponse",
126+
"http.request.method": "GET",
127+
"http.route": "/home",
114128
"plugin.name": "fastify -> @fastify/multipart",
115129
"sentry.parentSampled": true,
116130
"sentry.sample_rate": 1
@@ -236,7 +250,11 @@ mod tests {
236250
"trace_id": "89143b0763095bd9c9955e8175d1fb23",
237251
"status": "unknown",
238252
"description": "SELECT \"table\".\"col\" FROM \"table\" WHERE \"table\".\"col\" = %s",
239-
"data": {},
253+
"data": {
254+
"db.name": "database",
255+
"db.statement": "SELECT \"table\".\"col\" FROM \"table\" WHERE \"table\".\"col\" = %s",
256+
"db.type": "sql"
257+
},
240258
"links": [],
241259
"kind": "client"
242260
}
@@ -294,7 +312,11 @@ mod tests {
294312
"trace_id": "89143b0763095bd9c9955e8175d1fb23",
295313
"status": "unknown",
296314
"description": "index view query",
297-
"data": {},
315+
"data": {
316+
"db.name": "database",
317+
"db.statement": "SELECT \"table\".\"col\" FROM \"table\" WHERE \"table\".\"col\" = %s",
318+
"db.type": "sql"
319+
},
298320
"links": [],
299321
"kind": "client"
300322
}
@@ -340,7 +362,10 @@ mod tests {
340362
"trace_id": "89143b0763095bd9c9955e8175d1fb23",
341363
"status": "unknown",
342364
"description": "GET /api/search?q=foobar",
343-
"data": {},
365+
"data": {
366+
"http.request.method": "GET",
367+
"url.path": "/api/search?q=foobar"
368+
},
344369
"links": [],
345370
"kind": "client"
346371
}

relay-spans/src/otel_to_sentry_v2.rs

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ pub fn otel_to_sentry_span(otel_span: OtelSpan) -> Result<SentrySpanV2, Error> {
6666
}) {
6767
match key.as_str() {
6868
"sentry.description" => {
69-
description = otel_value_to_string(value);
69+
description = otel_value_to_string(value.clone());
7070
}
7171
key if key.starts_with("db") => {
7272
name = name.or(Some("db".to_owned()));
@@ -80,17 +80,17 @@ pub fn otel_to_sentry_span(otel_span: OtelSpan) -> Result<SentrySpanV2, Error> {
8080
3 => "http.client",
8181
_ => "http",
8282
};
83-
http_method = otel_value_to_string(value);
83+
http_method = otel_value_to_string(value.clone());
8484
name = name.or(Some(http_op.to_owned()));
8585
}
8686
"http.route" | "url.path" => {
87-
http_route = otel_value_to_string(value);
88-
}
89-
_ => {
90-
if let Some(v) = otel_value_to_attr(value) {
91-
sentry_attributes.insert(key, Annotated::new(v));
92-
}
87+
http_route = otel_value_to_string(value.clone());
9388
}
89+
_ => (),
90+
}
91+
92+
if let Some(v) = otel_value_to_attr(value) {
93+
sentry_attributes.insert(key, Annotated::new(v));
9494
}
9595
}
9696

@@ -415,6 +415,18 @@ mod tests {
415415
"end_timestamp": 1697620454.980079,
416416
"links": [],
417417
"attributes": {
418+
"db.name": {
419+
"type": "string",
420+
"value": "database"
421+
},
422+
"db.statement": {
423+
"type": "string",
424+
"value": "SELECT \"table\".\"col\" FROM \"table\" WHERE \"table\".\"col\" = %s"
425+
},
426+
"db.type": {
427+
"type": "string",
428+
"value": "sql"
429+
},
418430
"sentry.description": {
419431
"type": "string",
420432
"value": "SELECT \"table\".\"col\" FROM \"table\" WHERE \"table\".\"col\" = %s"
@@ -475,6 +487,18 @@ mod tests {
475487
"end_timestamp": 1697620454.980079,
476488
"links": [],
477489
"attributes": {
490+
"db.name": {
491+
"type": "string",
492+
"value": "database"
493+
},
494+
"db.statement": {
495+
"type": "string",
496+
"value": "SELECT \"table\".\"col\" FROM \"table\" WHERE \"table\".\"col\" = %s"
497+
},
498+
"db.type": {
499+
"type": "string",
500+
"value": "sql"
501+
},
478502
"sentry.description": {
479503
"type": "string",
480504
"value": "index view query"
@@ -523,9 +547,17 @@ mod tests {
523547
"end_timestamp": 1697620454.980079,
524548
"links": [],
525549
"attributes": {
550+
"http.request.method": {
551+
"type": "string",
552+
"value": "GET"
553+
},
526554
"sentry.description": {
527555
"type": "string",
528556
"value": "GET /api/search?q=foobar"
557+
},
558+
"url.path": {
559+
"type": "string",
560+
"value": "/api/search?q=foobar"
529561
}
530562
}
531563
}

relay-spans/src/v2_to_v1.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,12 @@ pub fn span_v2_to_span_v1(span_v2: SpanV2) -> SpanV1 {
6868
exclusive_time_ms = value / 1e6f64;
6969
}
7070
"http.status_code" => {
71-
http_status_code = i64::from_value(value);
71+
http_status_code = i64::from_value(value.clone());
72+
data.insert(key.to_owned(), value);
7273
}
7374
"rpc.grpc.status_code" => {
74-
grpc_status_code = i64::from_value(value);
75+
grpc_status_code = i64::from_value(value.clone());
76+
data.insert(key.to_owned(), value);
7577
}
7678
"sentry.platform" => {
7779
platform = String::from_value(value);
@@ -218,7 +220,7 @@ mod tests {
218220
"value": "fastify -> @fastify/multipart",
219221
"type": "string"
220222
},
221-
"hook.name": {
223+
"hook.name": {
222224
"value": "onResponse",
223225
"type": "string"
224226
},

0 commit comments

Comments
 (0)