Skip to content

Commit 8c22595

Browse files
committed
support in c++
1 parent 2632ccf commit 8c22595

File tree

2 files changed

+120
-110
lines changed

2 files changed

+120
-110
lines changed

examples/cxx/profiling.cpp

Lines changed: 80 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -176,134 +176,104 @@ int main() {
176176
profile->add_endpoint_count("/api/products", 200);
177177
std::cout << "✅ Added endpoint mappings and counts" << std::endl;
178178

179-
// Check if we should export to Datadog or save to file
179+
// Create exporter based on environment variables
180180
const char* agent_url = std::getenv("DD_AGENT_URL");
181181
const char* api_key = std::getenv("DD_API_KEY");
182182

183-
if (agent_url || api_key) {
184-
// Export to Datadog
185-
std::cout << "\n=== Exporting to Datadog ===" << std::endl;
186-
187-
try {
188-
// Example: Create an additional file to attach (e.g., application metadata)
189-
std::string app_metadata = R"({
190-
"app_version": "1.2.3",
191-
"build_id": "abc123",
192-
"profiling_mode": "continuous",
193-
"sample_count": 100
194-
})";
195-
std::vector<uint8_t> metadata_bytes(app_metadata.begin(), app_metadata.end());
196-
197-
if (api_key) {
198-
// Agentless mode - send directly to Datadog intake
199-
const char* site = std::getenv("DD_SITE");
200-
std::string dd_site = site ? site : "datadoghq.com";
201-
202-
std::cout << "Creating agentless exporter (site: " << dd_site << ")..." << std::endl;
203-
auto exporter = ProfileExporter::create_agentless_exporter(
204-
"dd-trace-cpp",
205-
"1.0.0",
206-
"native",
183+
std::cout << "\n=== Creating Exporter ===" << std::endl;
184+
185+
// Create appropriate exporter based on configuration
186+
std::unique_ptr<rust::Box<ProfileExporter>> exporter;
187+
try {
188+
if (api_key) {
189+
// Agentless mode - send directly to Datadog intake
190+
const char* site = std::getenv("DD_SITE");
191+
std::string dd_site = site ? site : "datadoghq.com";
192+
std::cout << "Creating agentless exporter (site: " << dd_site << ")..." << std::endl;
193+
exporter = std::make_unique<rust::Box<ProfileExporter>>(
194+
ProfileExporter::create_agentless_exporter(
195+
"dd-trace-cpp", "1.0.0", "native",
207196
{
208197
Tag{.key = "service", .value = "profiling-example"},
209198
Tag{.key = "env", .value = "dev"},
210199
Tag{.key = "example", .value = "cxx"}
211200
},
212-
dd_site.c_str(),
213-
api_key,
214-
10000 // 10 second timeout (0 = use default)
215-
);
216-
std::cout << "✅ Exporter created" << std::endl;
217-
218-
std::cout << "Exporting profile to Datadog with additional metadata..." << std::endl;
219-
220-
exporter->send_profile(
221-
*profile,
222-
// Files to compress and attach
223-
{AttachmentFile{
224-
.name = "app_metadata.json",
225-
.data = {metadata_bytes.data(), metadata_bytes.size()}
226-
}},
227-
// Additional per-profile tags
228-
{
229-
Tag{.key = "export_id", .value = "12345"},
230-
Tag{.key = "host", .value = "example-host"}
231-
},
232-
// Process-level tags (comma-separated)
233-
"language:cpp,profiler_version:1.0,runtime:native",
234-
// Internal metadata (JSON string)
235-
R"({"profiler_version": "1.0", "custom_field": "demo"})",
236-
// System info (JSON string)
237-
R"({"os": "macos", "arch": "arm64", "cores": 8})"
238-
);
239-
std::cout << "✅ Profile exported successfully!" << std::endl;
240-
} else {
241-
// Agent mode - send to local Datadog agent
242-
std::cout << "Creating agent exporter (url: " << agent_url << ")..." << std::endl;
243-
auto exporter = ProfileExporter::create_agent_exporter(
244-
"dd-trace-cpp",
245-
"1.0.0",
246-
"native",
201+
dd_site.c_str(), api_key, 10000
202+
)
203+
);
204+
} else if (agent_url) {
205+
// Agent mode - send to local Datadog agent
206+
std::cout << "Creating agent exporter (url: " << agent_url << ")..." << std::endl;
207+
exporter = std::make_unique<rust::Box<ProfileExporter>>(
208+
ProfileExporter::create_agent_exporter(
209+
"dd-trace-cpp", "1.0.0", "native",
247210
{
248211
Tag{.key = "service", .value = "profiling-example"},
249212
Tag{.key = "env", .value = "dev"},
250213
Tag{.key = "example", .value = "cxx"}
251214
},
252-
agent_url,
253-
10000 // 10 second timeout (0 = use default)
254-
);
255-
std::cout << "✅ Exporter created" << std::endl;
256-
257-
std::cout << "Exporting profile to Datadog with additional metadata..." << std::endl;
258-
259-
exporter->send_profile(
260-
*profile,
261-
// Files to compress and attach
262-
{AttachmentFile{
263-
.name = "app_metadata.json",
264-
.data = {metadata_bytes.data(), metadata_bytes.size()}
265-
}},
266-
// Additional per-profile tags
215+
agent_url, 10000
216+
)
217+
);
218+
} else {
219+
// File mode - dump HTTP request for debugging/testing
220+
std::cout << "Creating file exporter (profile_dump.txt)..." << std::endl;
221+
exporter = std::make_unique<rust::Box<ProfileExporter>>(
222+
ProfileExporter::create_file_exporter(
223+
"dd-trace-cpp", "1.0.0", "native",
267224
{
268-
Tag{.key = "export_id", .value = "12345"},
269-
Tag{.key = "host", .value = "example-host"}
225+
Tag{.key = "service", .value = "profiling-example"},
226+
Tag{.key = "env", .value = "dev"},
227+
Tag{.key = "example", .value = "cxx"}
270228
},
271-
// Process-level tags (comma-separated)
272-
"language:cpp,profiler_version:1.0,runtime:native",
273-
// Internal metadata (JSON string)
274-
R"({"profiler_version": "1.0", "custom_field": "demo"})",
275-
// System info (JSON string)
276-
R"({"os": "macos", "arch": "arm64", "cores": 8})"
277-
);
278-
std::cout << "✅ Profile exported successfully!" << std::endl;
279-
}
280-
281-
} catch (const std::exception& e) {
282-
std::cerr << "⚠️ Failed to export profile: " << e.what() << std::endl;
283-
std::cerr << " Falling back to file export..." << std::endl;
284-
285-
// Fall back to file export on error
286-
auto serialized = profile->serialize_to_vec();
287-
std::ofstream out("profile.pprof", std::ios::binary);
288-
out.write(reinterpret_cast<const char*>(serialized.data()), serialized.size());
289-
out.close();
290-
std::cout << "✅ Profile written to profile.pprof" << std::endl;
229+
"profile_dump.txt"
230+
)
231+
);
291232
}
292-
} else {
293-
// Save to file
294-
std::cout << "\n=== Saving to File ===" << std::endl;
295-
std::cout << "Serializing profile..." << std::endl;
296-
auto serialized = profile->serialize_to_vec();
297-
std::cout << "✅ Profile serialized to " << serialized.size() << " bytes" << std::endl;
233+
std::cout << "✅ Exporter created" << std::endl;
234+
235+
// Prepare metadata (same for all export modes)
236+
std::string app_metadata = R"({
237+
"app_version": "1.2.3",
238+
"build_id": "abc123",
239+
"profiling_mode": "continuous",
240+
"sample_count": 100
241+
})";
242+
std::vector<uint8_t> metadata_bytes(app_metadata.begin(), app_metadata.end());
298243

299-
std::ofstream out("profile.pprof", std::ios::binary);
300-
out.write(reinterpret_cast<const char*>(serialized.data()), serialized.size());
301-
out.close();
302-
std::cout << "✅ Profile written to profile.pprof" << std::endl;
244+
// Export the profile (unified code path)
245+
std::cout << "Exporting profile with additional metadata..." << std::endl;
246+
(*exporter)->send_profile(
247+
*profile,
248+
// Files to compress and attach
249+
{AttachmentFile{
250+
.name = "app_metadata.json",
251+
.data = {metadata_bytes.data(), metadata_bytes.size()}
252+
}},
253+
// Additional per-profile tags
254+
{
255+
Tag{.key = "export_id", .value = "12345"},
256+
Tag{.key = "host", .value = "example-host"}
257+
},
258+
// Process-level tags (comma-separated)
259+
"language:cpp,profiler_version:1.0,runtime:native",
260+
// Internal metadata (JSON string)
261+
R"({"profiler_version": "1.0", "custom_field": "demo"})",
262+
// System info (JSON string)
263+
R"({"os": "macos", "arch": "arm64", "cores": 8})"
264+
);
265+
std::cout << "✅ Profile exported successfully!" << std::endl;
303266

304-
std::cout << "\nℹ️ To export to Datadog instead, set environment variables:" << std::endl;
305-
std::cout << " Agent mode: DD_AGENT_URL=http://localhost:8126" << std::endl;
306-
std::cout << " Agentless mode: DD_API_KEY=<your-api-key> [DD_SITE=datadoghq.com]" << std::endl;
267+
// Print mode-specific info
268+
if (!agent_url && !api_key) {
269+
std::cout << "ℹ️ HTTP request written to profile_dump.txt" << std::endl;
270+
std::cout << "ℹ️ Use the utils in libdd-profiling to parse the HTTP dump" << std::endl;
271+
std::cout << "\nℹ️ To export to Datadog instead, set environment variables:" << std::endl;
272+
std::cout << " Agent mode: DD_AGENT_URL=http://localhost:8126" << std::endl;
273+
std::cout << " Agentless mode: DD_API_KEY=<your-api-key> [DD_SITE=datadoghq.com]" << std::endl;
274+
}
275+
} catch (const std::exception& e) {
276+
std::cerr << "⚠️ Failed to export profile: " << e.what() << std::endl;
307277
}
308278

309279
std::cout << "\n✅ Success!" << std::endl;

libdd-profiling/src/cxx.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,15 @@ pub mod ffi {
138138
timeout_ms: u64,
139139
) -> Result<Box<ProfileExporter>>;
140140

141+
#[Self = "ProfileExporter"]
142+
fn create_file_exporter(
143+
profiling_library_name: &str,
144+
profiling_library_version: &str,
145+
family: &str,
146+
tags: Vec<Tag>,
147+
output_path: &str,
148+
) -> Result<Box<ProfileExporter>>;
149+
141150
// ProfileExporter methods
142151
/// Sends a profile to Datadog.
143152
///
@@ -437,6 +446,37 @@ impl ProfileExporter {
437446
Ok(Box::new(ProfileExporter { inner }))
438447
}
439448

449+
pub fn create_file_exporter(
450+
profiling_library_name: &str,
451+
profiling_library_version: &str,
452+
family: &str,
453+
tags: Vec<ffi::Tag>,
454+
output_path: &str,
455+
) -> anyhow::Result<Box<ProfileExporter>> {
456+
let endpoint = exporter::config::file(output_path)?;
457+
458+
let tags_vec: Vec<exporter::Tag> = tags
459+
.iter()
460+
.map(TryInto::try_into)
461+
.collect::<Result<Vec<_>, _>>()?;
462+
463+
let tags_option = if tags_vec.is_empty() {
464+
None
465+
} else {
466+
Some(tags_vec)
467+
};
468+
469+
let inner = exporter::ProfileExporter::new(
470+
profiling_library_name.to_string(),
471+
profiling_library_version.to_string(),
472+
family.to_string(),
473+
tags_option,
474+
endpoint,
475+
)?;
476+
477+
Ok(Box::new(ProfileExporter { inner }))
478+
}
479+
440480
/// Sends a profile to Datadog.
441481
///
442482
/// # Arguments

0 commit comments

Comments
 (0)