Skip to content

Commit 746e9a3

Browse files
committed
feat(profiling)!: take mime types in profile exporter
1 parent d5f1bbf commit 746e9a3

File tree

6 files changed

+80
-11
lines changed

6 files changed

+80
-11
lines changed

examples/cxx/profiling.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,8 @@ int main() {
253253
// Files to compress and attach
254254
{AttachmentFile{
255255
.name = "app_metadata.json",
256-
.data = {metadata_bytes.data(), metadata_bytes.size()}
256+
.data = {metadata_bytes.data(), metadata_bytes.size()},
257+
.mime = MimeType::ApplicationJson
257258
}},
258259
// Additional per-profile tags
259260
{

libdd-profiling-ffi/cbindgen.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ renaming_overrides_prefixing = true
5959
"VoidResult" = "ddog_VoidResult"
6060

6161
"CbindgenIsDumbStringId" = "ddog_prof_StringId"
62+
"MimeType" = "ddog_prof_MimeType"
6263

6364
"Slice_GenerationalIdLabelId" = "ddog_prof_Slice_LabelId"
6465
"Slice_GenerationalIdLocationId" = "ddog_prof_Slice_LocationId"
@@ -126,3 +127,4 @@ must_use = "DDOG_CHECK_RETURN"
126127
[parse]
127128
parse_deps = true
128129
include = ["libdd-common", "libdd-common-ffi", "libdd-profiling", "libdd-profiling-protobuf", "libdd-crashtracker"]
130+
exclude = ["cxx"]

libdd-profiling-ffi/src/exporter.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use libdd_common::tag::Tag;
99
use libdd_common_ffi::slice::{AsBytes, ByteSlice, CharSlice, Slice};
1010
use libdd_common_ffi::{wrap_with_ffi_result, Handle, Result, ToInner};
1111
use libdd_profiling::exporter;
12-
use libdd_profiling::exporter::ProfileExporter;
12+
use libdd_profiling::exporter::{MimeType, ProfileExporter};
1313
use libdd_profiling::internal::EncodedProfile;
1414
use std::borrow::Cow;
1515
use std::str::FromStr;
@@ -29,6 +29,7 @@ pub enum ProfilingEndpoint<'a> {
2929
pub struct File<'a> {
3030
name: CharSlice<'a>,
3131
file: ByteSlice<'a>,
32+
mime: MimeType,
3233
}
3334

3435
#[must_use]
@@ -184,7 +185,8 @@ unsafe fn into_vec_files<'a>(slice: Slice<'a, File>) -> Vec<exporter::File<'a>>
184185
.map(|file| {
185186
let name = file.name.try_to_utf8().unwrap_or("{invalid utf-8}");
186187
let bytes = file.file.as_slice();
187-
exporter::File { name, bytes }
188+
let mime = file.mime;
189+
exporter::File { name, bytes, mime }
188190
})
189191
.collect()
190192
}

libdd-profiling/src/cxx.rs

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@ use crate::internal;
1515

1616
#[cxx::bridge(namespace = "datadog::profiling")]
1717
pub mod ffi {
18+
// Shared enums
19+
#[derive(Debug)]
20+
#[repr(u8)]
21+
enum MimeType {
22+
ApplicationJson,
23+
ApplicationOctetStream,
24+
TextCsv,
25+
TextPlain,
26+
TextXml,
27+
}
28+
1829
// Shared structs - CXX-friendly types
1930
struct ValueType<'a> {
2031
type_: &'a str,
@@ -68,6 +79,7 @@ pub mod ffi {
6879
struct AttachmentFile<'a> {
6980
name: &'a str,
7081
data: &'a [u8],
82+
mime: MimeType,
7183
}
7284

7385
// Opaque Rust types
@@ -274,12 +286,30 @@ impl<'a> From<&ffi::Label<'a>> for api::Label<'a> {
274286
}
275287
}
276288

277-
impl<'a> From<&ffi::AttachmentFile<'a>> for exporter::File<'a> {
278-
fn from(file: &ffi::AttachmentFile<'a>) -> Self {
279-
exporter::File {
289+
impl TryFrom<ffi::MimeType> for exporter::MimeType {
290+
type Error = anyhow::Error;
291+
292+
fn try_from(mime: ffi::MimeType) -> Result<Self, Self::Error> {
293+
match mime {
294+
ffi::MimeType::ApplicationJson => Ok(exporter::MimeType::ApplicationJson),
295+
ffi::MimeType::ApplicationOctetStream => Ok(exporter::MimeType::ApplicationOctetStream),
296+
ffi::MimeType::TextCsv => Ok(exporter::MimeType::TextCsv),
297+
ffi::MimeType::TextPlain => Ok(exporter::MimeType::TextPlain),
298+
ffi::MimeType::TextXml => Ok(exporter::MimeType::TextXml),
299+
_ => anyhow::bail!("Unknown MimeType variant: {:?}", mime),
300+
}
301+
}
302+
}
303+
304+
impl<'a> TryFrom<&ffi::AttachmentFile<'a>> for exporter::File<'a> {
305+
type Error = anyhow::Error;
306+
307+
fn try_from(file: &ffi::AttachmentFile<'a>) -> Result<Self, Self::Error> {
308+
Ok(exporter::File {
280309
name: file.name,
281310
bytes: file.data,
282-
}
311+
mime: file.mime.try_into()?,
312+
})
283313
}
284314
}
285315

@@ -620,8 +650,10 @@ impl ProfileExporter {
620650
let end_time = Some(std::time::SystemTime::now());
621651
let encoded = old_profile.serialize_into_compressed_pprof(end_time, None)?;
622652

623-
let files_to_compress_vec: Vec<exporter::File> =
624-
files_to_compress.iter().map(Into::into).collect();
653+
let files_to_compress_vec: Vec<exporter::File> = files_to_compress
654+
.iter()
655+
.map(TryInto::try_into)
656+
.collect::<Result<Vec<_>, _>>()?;
625657

626658
let additional_tags_vec: Vec<libdd_common::tag::Tag> = additional_tags
627659
.iter()
@@ -901,10 +933,16 @@ mod tests {
901933
let file: exporter::File = (&ffi::AttachmentFile {
902934
name: "test.bin",
903935
data: &data,
936+
mime: ffi::MimeType::ApplicationOctetStream,
904937
})
905-
.into();
938+
.try_into()
939+
.expect("Failed to convert AttachmentFile");
906940
assert_eq!(file.name, "test.bin");
907941
assert_eq!(file.bytes, data.as_slice());
942+
assert!(matches!(
943+
file.mime,
944+
exporter::MimeType::ApplicationOctetStream
945+
));
908946

909947
// Tag conversion with special characters
910948
let tag: libdd_common::tag::Tag = (&ffi::Tag {
@@ -996,6 +1034,7 @@ mod tests {
9961034
vec![ffi::AttachmentFile {
9971035
name: "metadata.json",
9981036
data: &attachment_data,
1037+
mime: ffi::MimeType::ApplicationJson,
9991038
}],
10001039
vec![
10011040
ffi::Tag {

libdd-profiling/src/exporter/profile_exporter.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,32 @@ pub struct ProfileExporter {
4545
runtime: Option<Runtime>,
4646
}
4747

48+
#[repr(C)]
49+
#[derive(Debug, Copy, Clone)]
50+
pub enum MimeType {
51+
ApplicationJson,
52+
ApplicationOctetStream,
53+
TextCsv,
54+
TextPlain,
55+
TextXml,
56+
}
57+
58+
impl MimeType {
59+
pub fn as_str(&self) -> &'static str {
60+
match self {
61+
MimeType::ApplicationJson => mime::APPLICATION_JSON.as_ref(),
62+
MimeType::ApplicationOctetStream => mime::APPLICATION_OCTET_STREAM.as_ref(),
63+
MimeType::TextCsv => mime::TEXT_CSV.as_ref(),
64+
MimeType::TextPlain => mime::TEXT_PLAIN.as_ref(),
65+
MimeType::TextXml => mime::TEXT_XML.as_ref(),
66+
}
67+
}
68+
}
69+
4870
pub struct File<'a> {
4971
pub name: &'a str,
5072
pub bytes: &'a [u8],
73+
pub mime: MimeType,
5174
}
5275

5376
impl ProfileExporter {

libdd-profiling/tests/exporter_e2e.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
88
use libdd_profiling::exporter::config;
99
use libdd_profiling::exporter::utils::parse_http_request;
10-
use libdd_profiling::exporter::{File, ProfileExporter};
10+
use libdd_profiling::exporter::{File, MimeType, ProfileExporter};
1111
use libdd_profiling::internal::EncodedProfile;
1212
use std::collections::HashMap;
1313
use std::path::PathBuf;
@@ -226,10 +226,12 @@ async fn export_full_profile(
226226
File {
227227
name: "jit.pprof",
228228
bytes: b"fake-jit-data",
229+
mime: MimeType::ApplicationOctetStream,
229230
},
230231
File {
231232
name: "metadata.json",
232233
bytes: b"{\"test\": true}",
234+
mime: MimeType::ApplicationJson,
233235
},
234236
];
235237

0 commit comments

Comments
 (0)