Skip to content

Commit 71866e1

Browse files
authored
Merge pull request #845 from NVIDIA/release/0.8
Forward-merge release/0.8 into main
2 parents c7ea51f + 6dbde56 commit 71866e1

4 files changed

Lines changed: 88 additions & 11 deletions

File tree

crates/core/src/observability/otel.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,16 +1485,19 @@ impl OtelEventProcessor {
14851485
event: &Event,
14861486
protected_keys: &HashSet<String>,
14871487
) {
1488-
let issues = promote_event_metadata_attributes(
1488+
let mut issues = promote_event_metadata_attributes(
14891489
attributes,
14901490
event,
14911491
&self.promote_metadata_prefixes,
14921492
protected_keys,
14931493
);
14941494

1495+
issues.sort_by(|left, right| left.key.cmp(&right.key));
14951496
for issue in issues {
1497+
let diagnostic_code =
1498+
format!("otel.metadata_promotion_value_unsupported.{}", issue.key);
14961499
let diagnostic_count = self.runtime_diagnostics.record(
1497-
"otel.metadata_promotion_value_unsupported",
1500+
diagnostic_code,
14981501
format!(
14991502
"OpenTelemetry metadata attribute {:?} was not promoted: {}",
15001503
issue.key, issue.reason

crates/core/src/observability/otel_signal.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ impl OpenTelemetryRuntimeDiagnostics {
5757

5858
#[derive(Debug, Default)]
5959
struct RuntimeDiagnosticState {
60-
diagnostics: BTreeMap<&'static str, OpenTelemetryRuntimeDiagnostic>,
60+
diagnostics: BTreeMap<String, OpenTelemetryRuntimeDiagnostic>,
6161
}
6262

6363
/// Shared runtime-diagnostic recorder for one independently owned OTLP subscriber.
@@ -75,21 +75,22 @@ impl SignalRuntimeDiagnostics {
7575
}
7676
}
7777

78-
pub(super) fn record(&self, code: &'static str, message: String, count: u64) -> u64 {
78+
pub(super) fn record(&self, code: impl Into<String>, message: String, count: u64) -> u64 {
79+
let code = code.into();
7980
let count = count.max(1);
8081
let mut state = self
8182
.state
8283
.lock()
8384
.unwrap_or_else(|poisoned| poisoned.into_inner());
84-
let total = if let Some(diagnostic) = state.diagnostics.get_mut(code) {
85+
let total = if let Some(diagnostic) = state.diagnostics.get_mut(&code) {
8586
diagnostic.message = truncate_runtime_diagnostic_message(message.clone());
8687
diagnostic.count = diagnostic.count.saturating_add(count);
8788
diagnostic.count
8889
} else if state.diagnostics.len() < MAX_RUNTIME_DIAGNOSTICS {
8990
state.diagnostics.insert(
90-
code,
91+
code.clone(),
9192
OpenTelemetryRuntimeDiagnostic {
92-
code: code.to_string(),
93+
code: code.clone(),
9394
message: truncate_runtime_diagnostic_message(message.clone()),
9495
count,
9596
},
@@ -100,7 +101,7 @@ impl SignalRuntimeDiagnostics {
100101
};
101102
drop(state);
102103

103-
record_signal_runtime_diagnostic(code, self.plugin_field.clone(), message, count);
104+
record_signal_runtime_diagnostic(&code, self.plugin_field.clone(), message, count);
104105
total
105106
}
106107

crates/core/tests/unit/observability/otel_tests.rs

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -709,13 +709,81 @@ fn omits_scope_metadata_when_final_value_is_unsupported_across_trace_projections
709709

710710
let diagnostics = runtime_diagnostics.snapshot();
711711
let diagnostic = diagnostics
712-
.get("otel.metadata_promotion_value_unsupported")
712+
.get("otel.metadata_promotion_value_unsupported.nv.source")
713713
.expect("unsupported final metadata diagnostic");
714714
assert_eq!(diagnostic.count, 1);
715715
assert!(diagnostic.message.contains("nv.source"));
716716
}
717717
}
718718

719+
#[test]
720+
fn reports_each_unsupported_metadata_key_with_a_deterministic_diagnostic_code() {
721+
let (provider, exporter) = make_provider();
722+
let runtime_diagnostics = SignalRuntimeDiagnostics::new(None);
723+
let mut processor =
724+
OtelEventProcessor::new_with_mark_projection_and_exclusions_and_mappings_and_runtime_diagnostics(
725+
provider,
726+
"unsupported-metadata-promotion-keys-test".into(),
727+
OpenTelemetryType::Full,
728+
MarkProjection::default(),
729+
default_mark_exclude_names(),
730+
Vec::new(),
731+
vec!["tenant.".to_string()],
732+
runtime_diagnostics.clone(),
733+
);
734+
let uuid = Uuid::now_v7();
735+
let unsupported_metadata = json!({
736+
"tenant.plan": {"name": "enterprise"},
737+
"tenant.flags": null,
738+
"tenant.tags": [["nested"]],
739+
"tenant.mixed": [1, "string"],
740+
});
741+
742+
processor.process(&make_start_event_with_metadata(
743+
uuid,
744+
None,
745+
"unsupported-metadata-promotion-keys-scope",
746+
unsupported_metadata.clone(),
747+
));
748+
processor.process(&make_end_event_with_metadata(
749+
uuid,
750+
None,
751+
"unsupported-metadata-promotion-keys-scope",
752+
ScopeType::Agent,
753+
unsupported_metadata,
754+
));
755+
processor.force_flush().unwrap();
756+
757+
let spans = exporter.get_finished_spans().unwrap();
758+
assert_eq!(spans.len(), 1);
759+
let span_attributes = attr_map(&spans[0].attributes);
760+
for key in ["tenant.flags", "tenant.mixed", "tenant.plan", "tenant.tags"] {
761+
assert!(!span_attributes.contains_key(key));
762+
}
763+
764+
let diagnostics = runtime_diagnostics.snapshot();
765+
let expected_keys = ["tenant.flags", "tenant.mixed", "tenant.plan", "tenant.tags"];
766+
assert_eq!(
767+
diagnostics
768+
.entries()
769+
.iter()
770+
.map(|diagnostic| diagnostic.code.as_str())
771+
.collect::<Vec<_>>(),
772+
expected_keys
773+
.iter()
774+
.map(|key| format!("otel.metadata_promotion_value_unsupported.{key}"))
775+
.collect::<Vec<_>>()
776+
);
777+
for key in expected_keys {
778+
let code = format!("otel.metadata_promotion_value_unsupported.{key}");
779+
let diagnostic = diagnostics
780+
.get(&code)
781+
.expect("metadata-key-specific promotion diagnostic");
782+
assert_eq!(diagnostic.count, 2);
783+
assert!(diagnostic.message.contains(key));
784+
}
785+
}
786+
719787
#[test]
720788
fn promotes_start_only_scope_metadata_across_trace_projections() {
721789
for otel_type in [

docs/configure-plugins/observability/opentelemetry.mdx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,13 @@ Marks.
179179

180180
Promotion supports strings, booleans, signed 64-bit integers, floating-point
181181
numbers, empty arrays, and homogeneous arrays of those primitive types. Relay
182-
omits rejected values and records a bounded runtime diagnostic containing the
183-
key and reason, but it does not record the rejected value or stop trace export.
182+
omits rejected values and records one bounded runtime diagnostic per rejected
183+
key. The diagnostic code is
184+
`otel.metadata_promotion_value_unsupported.<metadata-key>`, its message contains
185+
the key and rejection reason, and its count is the number of occurrences for
186+
that key. Relay does not record the rejected value or stop trace export. Match
187+
the `otel.metadata_promotion_value_unsupported.` prefix to monitor all rejected
188+
metadata keys.
184189

185190
Projection-owned attributes take precedence over promoted metadata with the
186191
same key. For `full` and `openinference`, configured attribute-mapping aliases

0 commit comments

Comments
 (0)