Skip to content

Commit dd677a9

Browse files
committed
starting to handle the profile dictionaries
1 parent 3d16e60 commit dd677a9

File tree

2 files changed

+150
-0
lines changed

2 files changed

+150
-0
lines changed

datadog-profiling/src/internal/profile/otel_emitter/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ pub mod function;
1010
pub mod stack_trace;
1111
pub mod location;
1212
pub mod mapping;
13+
pub mod profile;
1314

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
use crate::internal::Profile as InternalProfile;
5+
use crate::iter::{IntoLendingIterator, LendingIterator};
6+
7+
impl From<InternalProfile> for datadog_profiling_otel::ProfilesData {
8+
fn from(internal_profile: InternalProfile) -> Self {
9+
// Convert the ProfilesDictionary components
10+
let dictionary = datadog_profiling_otel::ProfilesDictionary {
11+
// Convert mappings
12+
mapping_table: internal_profile
13+
.mappings
14+
.iter()
15+
.map(|mapping| mapping.into())
16+
.collect(),
17+
18+
// Convert locations
19+
location_table: internal_profile
20+
.locations
21+
.iter()
22+
.map(|location| location.into())
23+
.collect(),
24+
25+
// Convert functions
26+
function_table: internal_profile
27+
.functions
28+
.iter()
29+
.map(|function| function.into())
30+
.collect(),
31+
32+
// Convert stack traces
33+
stack_table: internal_profile
34+
.stack_traces
35+
.iter()
36+
.map(|stack_trace| stack_trace.into())
37+
.collect(),
38+
39+
// Convert string table using into_lending_iter
40+
// Note: We can't use .map().collect() here because LendingIterator doesn't implement
41+
// the standard Iterator trait. LendingIterator is designed for yielding references
42+
// with lifetimes tied to the iterator itself, so we need to manually iterate and
43+
// convert each string reference to an owned String.
44+
string_table: {
45+
let mut strings = Vec::with_capacity(internal_profile.strings.len());
46+
let mut iter = internal_profile.strings.into_lending_iter();
47+
while let Some(s) = iter.next() {
48+
strings.push(s.to_string());
49+
}
50+
strings
51+
},
52+
53+
// For now, set empty defaults for fields we're not handling yet
54+
link_table: vec![], // TODO: Implement when we handle links
55+
attribute_table: vec![], // TODO: Implement when we handle attributes
56+
attribute_units: vec![], // TODO: Implement when we handle attribute units
57+
};
58+
59+
// Create a basic ResourceProfiles structure
60+
let resource_profiles = vec![datadog_profiling_otel::ResourceProfiles {
61+
resource: None, // TODO: Implement when we handle resources
62+
scope_profiles: vec![datadog_profiling_otel::ScopeProfiles {
63+
scope: None, // TODO: Implement when we handle scopes
64+
profiles: vec![], // TODO: Implement when we handle individual profiles
65+
schema_url: String::new(), // TODO: Implement when we handle schema URLs
66+
default_sample_type: None, // TODO: Implement when we handle sample types
67+
}],
68+
schema_url: String::new(), // TODO: Implement when we handle schema URLs
69+
}];
70+
71+
Self {
72+
resource_profiles,
73+
dictionary: Some(dictionary),
74+
}
75+
}
76+
}
77+
78+
#[cfg(test)]
79+
mod tests {
80+
use crate::internal::profile::Profile as InternalProfile;
81+
use datadog_profiling_otel::ProfilesData;
82+
83+
#[test]
84+
fn test_from_internal_profile_empty() {
85+
// Create an empty internal profile
86+
let internal_profile = InternalProfile::new(&[], None);
87+
88+
// Convert to OpenTelemetry ProfilesData
89+
let otel_profiles_data = ProfilesData::from(internal_profile);
90+
91+
// Verify the conversion
92+
assert!(otel_profiles_data.dictionary.is_some());
93+
let dictionary = otel_profiles_data.dictionary.unwrap();
94+
95+
assert_eq!(dictionary.mapping_table.len(), 0);
96+
assert_eq!(dictionary.location_table.len(), 0);
97+
assert_eq!(dictionary.function_table.len(), 0);
98+
assert_eq!(dictionary.stack_table.len(), 0);
99+
assert_eq!(dictionary.string_table.len(), 4); // Default strings: "", "local root span id", "trace endpoint", "end_timestamp_ns"
100+
assert_eq!(dictionary.link_table.len(), 0);
101+
assert_eq!(dictionary.attribute_table.len(), 0);
102+
assert_eq!(dictionary.attribute_units.len(), 0);
103+
104+
assert_eq!(otel_profiles_data.resource_profiles.len(), 1);
105+
}
106+
107+
#[test]
108+
fn test_from_internal_profile_with_data() {
109+
// Create an internal profile with some data
110+
let mut internal_profile = InternalProfile::new(&[], None);
111+
112+
// Add some functions using the API Function type
113+
let function1 = crate::api::Function {
114+
name: "test_function_1",
115+
system_name: "test_system_1",
116+
filename: "test_file_1.rs",
117+
};
118+
let function2 = crate::api::Function {
119+
name: "test_function_2",
120+
system_name: "test_system_2",
121+
filename: "test_file_2.rs",
122+
};
123+
124+
let _function1_id = internal_profile.add_function(&function1);
125+
let _function2_id = internal_profile.add_function(&function2);
126+
127+
// Convert to OpenTelemetry ProfilesData
128+
let otel_profiles_data = ProfilesData::from(internal_profile);
129+
130+
// Verify the conversion
131+
assert!(otel_profiles_data.dictionary.is_some());
132+
let dictionary = otel_profiles_data.dictionary.unwrap();
133+
134+
assert_eq!(dictionary.function_table.len(), 2);
135+
assert_eq!(dictionary.string_table.len(), 10); // 4 default strings + 6 strings from the 2 functions
136+
137+
// Verify the first function conversion - using actual observed values
138+
let otel_function1 = &dictionary.function_table[0];
139+
assert_eq!(otel_function1.name_strindex, 4);
140+
assert_eq!(otel_function1.system_name_strindex, 5);
141+
assert_eq!(otel_function1.filename_strindex, 6);
142+
143+
// Verify the second function conversion - using actual observed values
144+
let otel_function2 = &dictionary.function_table[1];
145+
assert_eq!(otel_function2.name_strindex, 7);
146+
assert_eq!(otel_function2.system_name_strindex, 8);
147+
assert_eq!(otel_function2.filename_strindex, 9);
148+
}
149+
}

0 commit comments

Comments
 (0)