Skip to content

Commit 4be1fcc

Browse files
authored
feat!: root_span_id handling in otel thread ctx (#1834)
Depend on #1831. # What does this PR do? Follow-up of #1791. Add special handling of the `root_span_id` attribute, which is expected to be always provided by downstream users of libdatadog when publishing a thread context. # Motivation Addresses #1791 (comment). # Additional Notes Since we want to set it automatically and unconditionally, I've opted for the convention that the corresponding key is always set and is always the first in the string table located in the process context. I believe this is reasonable (since we always want to set this attribute) and achievable as long as we control the process-level context publication. But it might be a tad "magic". Another possibility is to request the user to provide the key for the `datadog.root_span_id` attribute. It is a bit less ergonomic for end-users who need to ensure the key is present, and propagate the index to the code that does the context switching so that it can provide it when calling into `libdatadog`. # How to test the change? Tests have been updated to reflect the change. Co-authored-by: yann.hamdaoui <yann.hamdaoui@datadoghq.com>
1 parent 11d4111 commit 4be1fcc

2 files changed

Lines changed: 155 additions & 72 deletions

File tree

libdd-library-config/src/tracer_metadata.rs

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,20 @@ pub struct TracerMetadata {
3434
#[serde(skip_serializing_if = "Option::is_none")]
3535
pub container_id: Option<String>,
3636
/// Ordered list of attribute key names for thread-level context records. Key indices from
37-
/// thread context records index into this table. Keep empty if thread-level context is not
38-
/// used.
37+
/// thread context records index into this table. Set to `None` to disable thread-level related
38+
/// attributes to the process-level context.
39+
///
40+
/// If set to `Some`, the first key will be automatically set to `datadog.local_root_span_id`
41+
/// in the OTel process context, because the thread context handling elsewhere in libdatadog
42+
/// relies on this key's index to be zero. Only set additional keys in
43+
/// `threadlocal_attribute_keys`; the root span id is considered to always be here implicitly.
3944
///
4045
/// This field is specific to OTel process context. It is ignored for (de)serialization, and is
4146
/// only used when converting to an OTel process context in
4247
/// [TracerMetadata::to_otel_process_ctx].
4348
#[cfg(feature = "otel-thread-ctx")]
4449
#[serde(skip)]
45-
pub threadlocal_attribute_keys: Vec<String>,
50+
pub threadlocal_attribute_keys: Option<Vec<String>>,
4651
}
4752

4853
impl Default for TracerMetadata {
@@ -59,7 +64,7 @@ impl Default for TracerMetadata {
5964
process_tags: None,
6065
container_id: None,
6166
#[cfg(feature = "otel-thread-ctx")]
62-
threadlocal_attribute_keys: vec![],
67+
threadlocal_attribute_keys: None,
6368
}
6469
}
6570
}
@@ -124,21 +129,25 @@ impl TracerMetadata {
124129
];
125130

126131
#[cfg(feature = "otel-thread-ctx")]
127-
if !threadlocal_attribute_keys.is_empty() {
132+
if let Some(threadlocal_attribute_keys) = threadlocal_attribute_keys.as_ref() {
128133
attributes.push(key_value(
129134
"threadlocal.schema_version",
130135
"tlsdesc_v1_dev".to_owned(),
131136
));
137+
132138
attributes.push(KeyValue {
133139
key: "threadlocal.attribute_key_map".to_owned(),
134140
value: Some(AnyValue {
135141
value: Some(any_value::Value::ArrayValue(ArrayValue {
136-
values: threadlocal_attribute_keys
137-
.iter()
138-
.map(|k| AnyValue {
139-
value: Some(any_value::Value::StringValue(k.clone())),
140-
})
141-
.collect(),
142+
values: std::iter::once(AnyValue {
143+
value: Some(any_value::Value::StringValue(
144+
"datadog.local_root_span_id".to_owned(),
145+
)),
146+
})
147+
.chain(threadlocal_attribute_keys.iter().map(|k| AnyValue {
148+
value: Some(any_value::Value::StringValue(k.clone())),
149+
}))
150+
.collect(),
142151
})),
143152
}),
144153
key_ref: 0,
@@ -250,11 +259,11 @@ mod tests {
250259
#[test]
251260
fn threadlocal_attrs_present_with_correct_values() {
252261
let ctx = TracerMetadata {
253-
threadlocal_attribute_keys: vec![
262+
threadlocal_attribute_keys: Some(vec![
254263
"span.id".to_owned(),
255264
"trace.id".to_owned(),
256265
"custom.key".to_owned(),
257-
],
266+
]),
258267
..Default::default()
259268
}
260269
.to_otel_process_ctx();
@@ -282,6 +291,14 @@ mod tests {
282291
other => panic!("expected StringValue, got {:?}", other),
283292
})
284293
.collect();
285-
assert_eq!(keys, ["span.id", "trace.id", "custom.key"]);
294+
assert_eq!(
295+
keys,
296+
[
297+
"datadog.local_root_span_id",
298+
"span.id",
299+
"trace.id",
300+
"custom.key"
301+
]
302+
);
286303
}
287304
}

0 commit comments

Comments
 (0)