Skip to content

Commit de2371a

Browse files
committed
duration
1 parent 1c34d78 commit de2371a

File tree

1 file changed

+108
-3
lines changed
  • datadog-profiling/src/internal/profile/otel_emitter

1 file changed

+108
-3
lines changed

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

Lines changed: 108 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,23 @@ impl InternalProfile {
1818
/// earlier time. The duration will be set to zero these cases.
1919
pub fn serialize_into_otel(
2020
mut self,
21-
_end_time: Option<std::time::SystemTime>,
22-
_duration: Option<std::time::Duration>,
21+
end_time: Option<std::time::SystemTime>,
22+
duration: Option<std::time::Duration>,
2323
) -> anyhow::Result<datadog_profiling_otel::ProfilesData> {
24+
// Calculate duration using the same logic as encode
25+
let end = end_time.unwrap_or_else(std::time::SystemTime::now);
26+
let start = self.start_time;
27+
let duration_nanos = duration
28+
.unwrap_or_else(|| {
29+
end.duration_since(start).unwrap_or({
30+
// Let's not throw away the whole profile just because the clocks were wrong.
31+
// todo: log that the clock went backward (or programmer mistake).
32+
std::time::Duration::ZERO
33+
})
34+
})
35+
.as_nanos()
36+
.min(i64::MAX as u128) as i64;
37+
2438
// Create individual OpenTelemetry Profiles for each ValueType
2539
let mut profiles = Vec::with_capacity(self.sample_types.len());
2640

@@ -42,7 +56,7 @@ impl InternalProfile {
4256
.duration_since(std::time::UNIX_EPOCH)
4357
.unwrap_or_default()
4458
.as_nanos() as i64,
45-
duration_nanos: 0, // TODO: Calculate from internal profile
59+
duration_nanos, // Use calculated duration
4660
period_type: None, // TODO: Implement when we handle period types
4761
period: 0, // TODO: Implement when we handle periods
4862
comment_strindices: vec![], // TODO: Implement when we handle comments
@@ -202,6 +216,15 @@ mod tests {
202216
assert_eq!(dictionary.attribute_units.len(), 0);
203217

204218
assert_eq!(otel_profiles_data.resource_profiles.len(), 1);
219+
220+
// Check duration calculation - only if profiles exist
221+
let scope_profile = &otel_profiles_data.resource_profiles[0].scope_profiles[0];
222+
if !scope_profile.profiles.is_empty() {
223+
let profile = &scope_profile.profiles[0];
224+
// When no duration is provided, it should calculate from current time - start time
225+
// Since we're testing with None, None, the duration should be > 0 (current time - start time)
226+
assert!(profile.duration_nanos > 0);
227+
}
205228
}
206229

207230
#[test]
@@ -245,6 +268,14 @@ mod tests {
245268
assert_eq!(otel_function2.name_strindex, 7);
246269
assert_eq!(otel_function2.system_name_strindex, 8);
247270
assert_eq!(otel_function2.filename_strindex, 9);
271+
272+
// Check duration calculation - only if profiles exist
273+
let scope_profile = &otel_profiles_data.resource_profiles[0].scope_profiles[0];
274+
if !scope_profile.profiles.is_empty() {
275+
let profile = &scope_profile.profiles[0];
276+
// When no duration is provided, it should calculate from current time - start time
277+
assert!(profile.duration_nanos > 0);
278+
}
248279
}
249280

250281
#[test]
@@ -314,6 +345,14 @@ mod tests {
314345
// and the unit should map to the "bytes" string index
315346
assert!(unit.attribute_key_strindex > 0);
316347
assert!(unit.unit_strindex > 0);
348+
349+
// Check duration calculation - only if profiles exist
350+
let scope_profile = &otel_profiles_data.resource_profiles[0].scope_profiles[0];
351+
if !scope_profile.profiles.is_empty() {
352+
let profile = &scope_profile.profiles[0];
353+
// When no duration is provided, it should calculate from current time - start time
354+
assert!(profile.duration_nanos > 0);
355+
}
317356
}
318357

319358
#[test]
@@ -350,6 +389,12 @@ mod tests {
350389
let allocations_sample_type = allocations_profile.sample_type.as_ref().unwrap();
351390
assert_eq!(allocations_sample_type.type_strindex, 6); // "allocations" string index
352391
assert_eq!(allocations_sample_type.unit_strindex, 7); // "count" string index
392+
393+
// Check duration calculation for both profiles
394+
for profile in &scope_profile.profiles {
395+
// When no duration is provided, it should calculate from current time - start time
396+
assert!(profile.duration_nanos > 0);
397+
}
353398
}
354399

355400
#[test]
@@ -429,6 +474,12 @@ mod tests {
429474
assert_eq!(memory_sample.values, vec![2048]);
430475
assert_eq!(memory_sample.stack_index, 0); // First stack trace
431476
assert_eq!(memory_sample.attribute_indices.len(), 0); // No labels
477+
478+
// Check duration calculation for both profiles
479+
for profile in &otel_profiles_data.resource_profiles[0].scope_profiles[0].profiles {
480+
// When no duration is provided, it should calculate from current time - start time
481+
assert!(profile.duration_nanos > 0);
482+
}
432483
}
433484

434485
#[test]
@@ -505,6 +556,10 @@ mod tests {
505556
assert_eq!(sample.attribute_indices.len(), 2);
506557
// The attribute indices should correspond to the labels in the attribute table
507558
assert!(sample.attribute_indices[0] >= 0);
559+
560+
// Check duration calculation
561+
// When no duration is provided, it should calculate from current time - start time
562+
assert!(profile.duration_nanos > 0);
508563
assert!(sample.attribute_indices[1] >= 0);
509564

510565
// Verify the attributes were converted correctly
@@ -568,6 +623,10 @@ mod tests {
568623
// Verify the sample has the correct timestamp
569624
assert_eq!(sample.timestamps_unix_nano.len(), 1);
570625
assert_eq!(sample.timestamps_unix_nano[0], 1234567890);
626+
627+
// Check duration calculation
628+
// When no duration is provided, it should calculate from current time - start time
629+
assert!(profile.duration_nanos > 0);
571630
}
572631

573632
#[test]
@@ -629,6 +688,12 @@ mod tests {
629688
assert_eq!(profile1.sample.len(), 1);
630689
let memory_sample = &profile1.sample[0];
631690
assert_eq!(memory_sample.values, vec![1024]);
691+
692+
// Check duration calculation for both profiles
693+
for profile in &otel_profiles_data.resource_profiles[0].scope_profiles[0].profiles {
694+
// When no duration is provided, it should calculate from current time - start time
695+
assert!(profile.duration_nanos > 0);
696+
}
632697
}
633698

634699
#[test]
@@ -703,5 +768,45 @@ mod tests {
703768
for sample in &profile.sample {
704769
assert_eq!(sample.stack_index, 0);
705770
}
771+
772+
// Check duration calculation
773+
// When no duration is provided, it should calculate from current time - start time
774+
assert!(profile.duration_nanos > 0);
775+
}
776+
777+
#[test]
778+
fn test_duration_calculation() {
779+
// Create an internal profile with sample types
780+
let sample_types = [crate::api::ValueType::new("cpu", "nanoseconds")];
781+
let internal_profile = InternalProfile::new(&sample_types, None);
782+
783+
// Test with explicit duration
784+
let explicit_duration = std::time::Duration::from_secs(5);
785+
let otel_profiles_data = internal_profile.serialize_into_otel(None, Some(explicit_duration)).unwrap();
786+
787+
let profile = &otel_profiles_data.resource_profiles[0].scope_profiles[0].profiles[0];
788+
// Should use the explicit duration (5 seconds = 5_000_000_000 nanoseconds)
789+
assert_eq!(profile.duration_nanos, 5_000_000_000);
790+
791+
// Test with explicit end_time
792+
let internal_profile2 = InternalProfile::new(&sample_types, None);
793+
let start_time = internal_profile2.start_time;
794+
let end_time = start_time + std::time::Duration::from_secs(3);
795+
let otel_profiles_data2 = internal_profile2.serialize_into_otel(Some(end_time), None).unwrap();
796+
797+
let profile2 = &otel_profiles_data2.resource_profiles[0].scope_profiles[0].profiles[0];
798+
// Should calculate duration from end_time - start_time (3 seconds = 3_000_000_000 nanoseconds)
799+
assert_eq!(profile2.duration_nanos, 3_000_000_000);
800+
801+
// Test with both end_time and duration (duration should take precedence)
802+
let internal_profile3 = InternalProfile::new(&sample_types, None);
803+
let start_time3 = internal_profile3.start_time;
804+
let end_time3 = start_time3 + std::time::Duration::from_secs(10);
805+
let duration3 = std::time::Duration::from_secs(7);
806+
let otel_profiles_data3 = internal_profile3.serialize_into_otel(Some(end_time3), Some(duration3)).unwrap();
807+
808+
let profile3 = &otel_profiles_data3.resource_profiles[0].scope_profiles[0].profiles[0];
809+
// Should use the explicit duration (7 seconds = 7_000_000_000 nanoseconds)
810+
assert_eq!(profile3.duration_nanos, 7_000_000_000);
706811
}
707812
}

0 commit comments

Comments
 (0)