Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

173 changes: 154 additions & 19 deletions datadog-live-debugger-ffi/src/sender.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
use crate::send_data::serialize_debugger_payload;
use datadog_live_debugger::debugger_defs::DebuggerPayload;
use datadog_live_debugger::sender;
use datadog_live_debugger::sender::{generate_tags, Config, DebuggerType};
use datadog_live_debugger::sender::{
debugger_intake_endpoint, generate_tags, Config, DebuggerType,
};
use libdd_common::tag::Tag;
use libdd_common::Endpoint;
use libdd_common_ffi::slice::AsBytes;
Expand Down Expand Up @@ -42,6 +44,20 @@ impl Drop for OwnedCharSlice {
enum SendData {
Raw(Vec<u8>, DebuggerType),
Wrapped(OwnedCharSlice, DebuggerType),
SymDB {
data: OwnedCharSlice,
content_type: String,
},
}

/// Returns a static name for a debugger track, used for logging without
/// allocating a string on every send.
fn debugger_type_name(debugger_type: DebuggerType) -> &'static str {
match debugger_type {
DebuggerType::Diagnostics => "Diagnostics",
DebuggerType::Snapshots => "Snapshots",
DebuggerType::Logs => "Logs",
}
}

async fn sender_routine(config: Arc<Config>, tags: String, mut receiver: mpsc::Receiver<SendData>) {
Expand All @@ -56,18 +72,37 @@ async fn sender_routine(config: Arc<Config>, tags: String, mut receiver: mpsc::R
let config = config.clone();
let tags = tags.clone();
tracker.spawn(async move {
let (debugger_type, data) = match data {
SendData::Raw(ref vec, r#type) => (r#type, vec.as_slice()),
SendData::Wrapped(ref wrapped, r#type) => (r#type, wrapped.slice.as_bytes()),
let (kind, len, result) = match data {
SendData::Raw(ref vec, r#type) => (
debugger_type_name(r#type),
vec.len(),
sender::send(vec.as_slice(), &config, r#type, &tags).await,
),
SendData::Wrapped(ref wrapped, r#type) => {
let bytes = wrapped.slice.as_bytes();
(
debugger_type_name(r#type),
bytes.len(),
sender::send(bytes, &config, r#type, &tags).await,
)
}
SendData::SymDB {
ref data,
ref content_type,
} => {
let bytes = data.slice.as_bytes();
(
"SymDB",
bytes.len(),
sender::send_symdb(bytes, content_type, &config, &tags).await,
)
}
};

if let Err(e) = sender::send(data, &config, debugger_type, &tags).await {
warn!("Failed to send {debugger_type:?} debugger data: {e:?}");
if let Err(e) = result {
warn!("Failed to send {kind} debugger data: {e:?}");
} else {
debug!(
"Successfully sent {} debugger data byte {debugger_type:?} payload",
data.len()
);
debug!("Successfully sent {len} byte {kind} debugger data payload");
}
});
}
Expand Down Expand Up @@ -102,24 +137,17 @@ pub extern "C" fn ddog_live_debugger_tags_from_raw(tags: CharSlice) -> Box<Strin
Box::new(percent_encode(tags.as_bytes(), CONTROLS).to_string())
}

#[no_mangle]
pub extern "C" fn ddog_live_debugger_spawn_sender(
endpoint: &Endpoint,
tags: Box<String>,
handle: &mut *mut SenderHandle,
) -> MaybeError {
fn spawn_sender_inner(config: Config, tags: String, handle: &mut *mut SenderHandle) -> MaybeError {
let runtime = try_c!(tokio::runtime::Builder::new_current_thread()
.enable_all()
.build());

let (tx, mailbox) = mpsc::channel(5000);
let mut config = Config::default();
try_c!(config.set_endpoint(endpoint.clone()));
let config = Arc::new(config);

*handle = Box::into_raw(Box::new(SenderHandle {
join: std::thread::spawn(move || {
runtime.block_on(sender_routine(config, *tags, mailbox));
runtime.block_on(sender_routine(config, tags, mailbox));
runtime.shutdown_background();
}),
channel: tx,
Expand All @@ -128,6 +156,95 @@ pub extern "C" fn ddog_live_debugger_spawn_sender(
MaybeError::None
}

#[no_mangle]
pub extern "C" fn ddog_live_debugger_spawn_sender(
endpoint: &Endpoint,
tags: Box<String>,
handle: &mut *mut SenderHandle,
) -> MaybeError {
let mut config = Config::default();
try_c!(config.set_endpoint(endpoint.clone()));
spawn_sender_inner(config, *tags, handle)
}

/// Builds an [`Endpoint`] for sending debugger and SymDB payloads directly to
/// the Datadog intake (agentless), targeting `debugger-intake.{site}`. The
/// returned endpoint must be freed with `ddog_endpoint_drop`.
#[no_mangle]
pub extern "C" fn ddog_live_debugger_endpoint_from_site_and_api_key(
site: CharSlice,
api_key: CharSlice,
endpoint: &mut *mut Endpoint,
) -> MaybeError {
let site = site.to_utf8_lossy();
let built = try_c!(debugger_intake_endpoint(
site.as_ref(),
api_key.to_utf8_lossy().to_string()
));
*endpoint = Box::into_raw(Box::new(built));
MaybeError::None
}

/// Creates an empty sender config. Configure it with the
/// `ddog_live_debugger_sender_config_*` functions, then hand it to
/// `ddog_live_debugger_spawn_sender_with_config` (which consumes it). If the
/// config is not spawned, free it with `ddog_live_debugger_sender_config_drop`.
#[no_mangle]
pub extern "C" fn ddog_live_debugger_sender_config_new() -> Box<Config> {
Box::new(Config::default())
}

#[no_mangle]
pub extern "C" fn ddog_live_debugger_sender_config_set_endpoint(
config: &mut Config,
endpoint: &Endpoint,
) -> MaybeError {
try_c!(config.set_endpoint(endpoint.clone()));
MaybeError::None
}

#[no_mangle]
pub extern "C" fn ddog_live_debugger_sender_config_set_symdb_endpoint(
config: &mut Config,
endpoint: &Endpoint,
) -> MaybeError {
try_c!(config.set_symdb_endpoint(endpoint.clone()));
MaybeError::None
}

#[no_mangle]
pub extern "C" fn ddog_live_debugger_sender_config_add_additional_endpoint(
config: &mut Config,
endpoint: &Endpoint,
) -> MaybeError {
try_c!(config.add_additional_debugger_endpoint(endpoint.clone()));
MaybeError::None
}

#[no_mangle]
pub extern "C" fn ddog_live_debugger_sender_config_add_additional_symdb_endpoint(
config: &mut Config,
endpoint: &Endpoint,
) -> MaybeError {
try_c!(config.add_additional_symdb_endpoint(endpoint.clone()));
MaybeError::None
}

#[no_mangle]
pub extern "C" fn ddog_live_debugger_sender_config_drop(_: Box<Config>) {}

/// Spawns a sender from a fully-configured [`Config`], consuming it. Supports
/// SymDB and additional dual-ship endpoints, unlike
/// `ddog_live_debugger_spawn_sender`.
#[no_mangle]
pub extern "C" fn ddog_live_debugger_spawn_sender_with_config(
config: Box<Config>,
tags: Box<String>,
handle: &mut *mut SenderHandle,
) -> MaybeError {
spawn_sender_inner(*config, *tags, handle)
}

#[no_mangle]
pub extern "C" fn ddog_live_debugger_send_raw_data(
handle: &mut SenderHandle,
Expand All @@ -140,6 +257,24 @@ pub extern "C" fn ddog_live_debugger_send_raw_data(
.is_ok()
}

/// Enqueues a raw SymDB (symbol database) payload to be forwarded to the SymDB
/// intake. The body is sent verbatim with the given `content_type`; `data` is
/// owned and freed once sent. Returns `true` if the payload was enqueued.
#[no_mangle]
pub extern "C" fn ddog_live_debugger_send_symdb_data(
handle: &mut SenderHandle,
content_type: CharSlice,
data: OwnedCharSlice,
) -> bool {
handle
.channel
.try_send(SendData::SymDB {
data,
content_type: content_type.to_utf8_lossy().to_string(),
})
.is_ok()
}

#[no_mangle]
pub extern "C" fn ddog_live_debugger_send_payload(
handle: &mut SenderHandle,
Expand Down
1 change: 1 addition & 0 deletions datadog-live-debugger/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ libdd-data-pipeline = { path = "../libdd-data-pipeline" }
http-body-util = "0.1"
"http" = "1"
bytes = "1.11.1"
futures = "0.3"

percent-encoding = "2.1"
serde = { version = "1.0", features = ["derive"] }
Expand Down
Loading
Loading