Skip to content

Commit 0cc3f7f

Browse files
feat(config): add support for process tags and container ids. (#1226)
* feat: add support for process tags and container ids. This PR introduces support for two new metadata fields: - process_tags: a comma-separated list of tags that will be used to identify a process. - container_id: the container id computed by the tracing library. I also took the opportunity to rework the FFI to be easier to interface with, which also provide ABI stability. Changes: - Rework the FFI to be easier to use and ABI stability over time. - Bump the schema version to v2. Co-authored-by: raphael.gavache <[email protected]> * format files * format files 2/x * format files 3/x * fix FFI tests --------- Co-authored-by: raphael.gavache <[email protected]>
1 parent b5db494 commit 0cc3f7f

File tree

2 files changed

+132
-43
lines changed

2 files changed

+132
-43
lines changed

datadog-library-config-ffi/src/tracer_metadata.rs

Lines changed: 108 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
#[cfg(target_os = "linux")]
55
use datadog_library_config::tracer_metadata::AnonymousFileHandle;
66
use datadog_library_config::tracer_metadata::{self, TracerMetadata};
7-
use ddcommon_ffi::{CharSlice, Result};
8-
use std::os::raw::c_int;
7+
use ddcommon_ffi::Result;
8+
use std::ffi::CStr;
9+
use std::os::raw::{c_char, c_int};
910

1011
/// C-compatible representation of an anonymous file handle
1112
#[repr(C)]
@@ -14,53 +15,118 @@ pub struct TracerMemfdHandle {
1415
pub fd: c_int,
1516
}
1617

17-
/// Store tracer metadata to a file handle
18+
/// Represents the types of metadata that can be set on a `TracerMetadata` object.
19+
#[repr(C)]
20+
pub enum MetadataKind {
21+
RuntimeId = 0,
22+
TracerLanguage = 1,
23+
TracerVersion = 2,
24+
Hostname = 3,
25+
ServiceName = 4,
26+
ServiceVersion = 5,
27+
ProcessTags = 6,
28+
ContainerId = 7,
29+
}
30+
31+
/// Allocates and returns a pointer to a new `TracerMetadata` object on the heap.
1832
///
1933
/// # Safety
34+
/// This function returns a raw pointer. The caller is responsible for calling
35+
/// `ddog_tracer_metadata_free` to deallocate the memory.
36+
///
37+
/// # Returns
38+
/// A non-null pointer to a newly allocated `TracerMetadata` instance.
39+
#[no_mangle]
40+
pub unsafe extern "C" fn ddog_tracer_metadata_new() -> *mut TracerMetadata {
41+
Box::into_raw(Box::new(TracerMetadata::default()))
42+
}
43+
44+
/// Frees a `TracerMetadata` instance previously allocated with `ddog_tracer_metadata_new`.
45+
///
46+
/// # Safety
47+
/// - `ptr` must be a pointer previously returned by `ddog_tracer_metadata_new`.
48+
/// - Double-freeing or passing an invalid pointer results in undefined behavior.
49+
/// - Passing a null pointer is safe and does nothing.
50+
#[no_mangle]
51+
pub unsafe extern "C" fn ddog_tracer_metadata_free(ptr: *mut TracerMetadata) {
52+
if ptr.is_null() {
53+
return;
54+
}
55+
unsafe {
56+
drop(Box::from_raw(ptr));
57+
}
58+
}
59+
60+
/// Sets a field of the `TracerMetadata` object pointed to by `ptr`.
61+
///
62+
/// # Arguments
63+
/// - `ptr`: Pointer to a `TracerMetadata` instance.
64+
/// - `kind`: The metadata field to set (as defined in `MetadataKind`).
65+
/// - `value`: A null-terminated C string representing the value to set.
66+
///
67+
/// # Safety
68+
/// - Both `ptr` and `value` must be non-null.
69+
/// - `value` must point to a valid UTF-8 null-terminated string.
70+
/// - If the string is not valid UTF-8, the function does nothing.
71+
#[no_mangle]
72+
pub unsafe extern "C" fn ddog_tracer_metadata_set(
73+
ptr: *mut TracerMetadata,
74+
kind: MetadataKind,
75+
value: *const c_char,
76+
) {
77+
if ptr.is_null() || value.is_null() {
78+
return;
79+
}
80+
81+
unsafe {
82+
let c_str = CStr::from_ptr(value);
83+
let str_value = match c_str.to_str() {
84+
Ok(v) => v.to_string(),
85+
Err(_) => return,
86+
};
87+
88+
let metadata = &mut *ptr;
89+
90+
match kind {
91+
MetadataKind::RuntimeId => metadata.runtime_id = Some(str_value),
92+
MetadataKind::TracerLanguage => metadata.tracer_language = str_value,
93+
MetadataKind::TracerVersion => metadata.tracer_version = str_value,
94+
MetadataKind::Hostname => metadata.hostname = str_value,
95+
MetadataKind::ServiceName => metadata.service_name = Some(str_value),
96+
MetadataKind::ServiceVersion => metadata.service_version = Some(str_value),
97+
MetadataKind::ProcessTags => metadata.process_tags = Some(str_value),
98+
MetadataKind::ContainerId => metadata.container_id = Some(str_value),
99+
}
100+
}
101+
}
102+
103+
/// Serializes the `TracerMetadata` into a platform-specific memory handle (e.g., memfd on Linux).
104+
///
105+
/// # Safety
106+
/// - `ptr` must be a valid, non-null pointer to a `TracerMetadata`.
107+
///
108+
/// # Returns
109+
/// - On Linux: a `TracerMemfdHandle` containing a raw file descriptor to a memory file.
110+
/// - On unsupported platforms: an error.
111+
/// - On failure: propagates any internal errors from the metadata storage process.
20112
///
21-
/// Accepts raw C-compatible strings
113+
/// # Platform Support
114+
/// This function currently only supports Linux via `memfd`. On other platforms,
115+
/// it will return an error.
22116
#[no_mangle]
23-
pub unsafe extern "C" fn ddog_store_tracer_metadata(
24-
schema_version: u8,
25-
runtime_id: CharSlice,
26-
tracer_language: CharSlice,
27-
tracer_version: CharSlice,
28-
hostname: CharSlice,
29-
service_name: CharSlice,
30-
service_env: CharSlice,
31-
service_version: CharSlice,
117+
pub unsafe extern "C" fn ddog_tracer_metadata_store(
118+
ptr: *mut TracerMetadata,
32119
) -> Result<TracerMemfdHandle> {
33-
// Convert C strings to Rust types
34-
let metadata = TracerMetadata {
35-
schema_version,
36-
runtime_id: if runtime_id.is_empty() {
37-
None
38-
} else {
39-
Some(runtime_id.to_string())
40-
},
41-
tracer_language: tracer_language.to_string(),
42-
tracer_version: tracer_version.to_string(),
43-
hostname: hostname.to_string(),
44-
service_name: if service_name.is_empty() {
45-
None
46-
} else {
47-
Some(service_name.to_string())
48-
},
49-
service_env: if service_env.is_empty() {
50-
None
51-
} else {
52-
Some(service_env.to_string())
53-
},
54-
service_version: if service_version.is_empty() {
55-
None
56-
} else {
57-
Some(service_version.to_string())
58-
},
59-
};
120+
if ptr.is_null() {
121+
return Err::<TracerMemfdHandle, _>(anyhow::anyhow!(
122+
"Failed to store tracer metadata: received a null pointer"
123+
))
124+
.into();
125+
}
60126

61-
// Call the actual implementation
127+
let metadata = &mut *ptr;
62128
let result: anyhow::Result<TracerMemfdHandle> =
63-
match tracer_metadata::store_tracer_metadata(&metadata) {
129+
match tracer_metadata::store_tracer_metadata(metadata) {
64130
#[cfg(target_os = "linux")]
65131
Ok(handle) => {
66132
use std::os::fd::{IntoRawFd, OwnedFd};

datadog-library-config/src/tracer_metadata.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/
22
// SPDX-License-Identifier: Apache-2.0
3+
use std::default::Default;
34

45
/// This struct MUST be backward compatible.
56
#[derive(serde::Serialize, Debug)]
6-
#[repr(C)]
77
pub struct TracerMetadata {
88
/// Version of the schema.
99
pub schema_version: u8,
@@ -26,6 +26,29 @@ pub struct TracerMetadata {
2626
/// Version of the service being instrumented.
2727
#[serde(skip_serializing_if = "Option::is_none")]
2828
pub service_version: Option<String>,
29+
/// Process tags of the application being instrumented.
30+
#[serde(skip_serializing_if = "Option::is_none")]
31+
pub process_tags: Option<String>,
32+
/// Container id seen by the application.
33+
#[serde(skip_serializing_if = "Option::is_none")]
34+
pub container_id: Option<String>,
35+
}
36+
37+
impl Default for TracerMetadata {
38+
fn default() -> Self {
39+
TracerMetadata {
40+
schema_version: 2,
41+
runtime_id: None,
42+
tracer_language: String::new(),
43+
tracer_version: String::new(),
44+
hostname: String::new(),
45+
service_name: None,
46+
service_env: None,
47+
service_version: None,
48+
process_tags: None,
49+
container_id: None,
50+
}
51+
}
2952
}
3053

3154
pub enum AnonymousFileHandle {

0 commit comments

Comments
 (0)