Skip to content

Commit

Permalink
[crashtracker] Implement telemetry for RFC5 (#741)
Browse files Browse the repository at this point in the history
  • Loading branch information
danielsn authored Nov 22, 2024
1 parent 580c2f4 commit 191a68a
Show file tree
Hide file tree
Showing 10 changed files with 482 additions and 9 deletions.
1 change: 1 addition & 0 deletions crashtracker/src/collector/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ fn test_altstack_paradox() -> anyhow::Result<()> {
}

#[cfg(test)]
#[cfg(target_os = "linux")]
fn get_sigaltstack() -> Option<libc::stack_t> {
let mut sigaltstack = libc::stack_t {
ss_sp: std::ptr::null_mut(),
Expand Down
6 changes: 5 additions & 1 deletion crashtracker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@ mod collector;
mod crash_info;
#[cfg(all(unix, feature = "receiver"))]
mod receiver;
mod rfc5_crash_info;

// TODO: For now, we have name conflicts with the `crash_info` module.
// Once that module is removed, those conflicts will go away
// Till then, keep things in two name spaces
pub mod rfc5_crash_info;
#[cfg(all(unix, any(feature = "collector", feature = "receiver")))]
mod shared;

Expand Down
14 changes: 14 additions & 0 deletions crashtracker/src/rfc5_crash_info/error_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,17 @@ pub fn thread_data_from_additional_stacktraces(
.map(|x| x.into())
.collect()
}

#[cfg(test)]
impl super::test_utils::TestInstance for ErrorData {
fn test_instance(seed: u64) -> Self {
Self {
is_crash: true,
kind: ErrorKind::UnixSignal,
message: None,
source_type: SourceType::Crashtracking,
stack: StackTrace::test_instance(seed),
threads: vec![],
}
}
}
28 changes: 28 additions & 0 deletions crashtracker/src/rfc5_crash_info/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,31 @@ impl From<crate::crash_info::CrashtrackerMetadata> for Metadata {
}
}
}

#[cfg(test)]
mod tests {
use super::Metadata;
use crate::rfc5_crash_info::test_utils::TestInstance;

macro_rules! tag {
($key:expr, $val:expr) => {
format!("{}:{}", $key, $val)
};
}

impl TestInstance for Metadata {
fn test_instance(seed: u64) -> Self {
Self {
library_name: "libdatadog".to_owned(),
library_version: format!("{}.{}.{}", seed, seed + 1, seed + 2),
family: "native".to_owned(),
tags: vec![
tag!("service", "foo"),
tag!("service_version", "bar"),
tag!("runtime-id", "xyz"),
tag!("language", "native"),
],
}
}
}
}
73 changes: 65 additions & 8 deletions crashtracker/src/rfc5_crash_info/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,22 @@ mod proc_info;
mod sig_info;
mod spans;
mod stacktrace;
mod telemetry;
mod test_utils;

pub use error_data::{ErrorData, ErrorKind, SourceType};
pub use metadata::Metadata;
pub use os_info::OsInfo;
pub use proc_info::ProcInfo;
pub use sig_info::{SiCodes, SigInfo, SignalNames};
pub use spans::Span;
pub use stacktrace::{BuildIdType, FileType, StackFrame, StackTrace};
pub use telemetry::TelemetryCrashUploader;

use anyhow::Context;
use error_data::{thread_data_from_additional_stacktraces, ErrorData, ErrorKind, SourceType};
use metadata::Metadata;
use os_info::OsInfo;
use proc_info::ProcInfo;
use error_data::thread_data_from_additional_stacktraces;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use sig_info::SigInfo;
use spans::Span;
use std::{collections::HashMap, fs::File, path::Path};

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
Expand All @@ -36,7 +42,8 @@ pub struct CrashInfo {
pub metadata: Metadata,
pub os_info: OsInfo,
pub proc_info: ProcInfo,
pub sig_info: SigInfo,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub sig_info: Option<SigInfo>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub span_ids: Vec<Span>,
pub timestamp: String,
Expand Down Expand Up @@ -72,7 +79,7 @@ impl From<crate::crash_info::CrashInfo> for CrashInfo {
let metadata = value.metadata.unwrap().into();
let os_info = value.os_info.into();
let proc_info = value.proc_info.unwrap().into();
let sig_info = value.siginfo.unwrap().into();
let sig_info = value.siginfo.map(SigInfo::from);
let span_ids = value
.span_ids
.into_iter()
Expand Down Expand Up @@ -135,4 +142,54 @@ mod tests {
let schema = schemars::schema_for!(CrashInfo);
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
}

impl test_utils::TestInstance for CrashInfo {
fn test_instance(seed: u64) -> Self {
let mut counters = HashMap::new();
counters.insert("collecting_sample".to_owned(), 1);
counters.insert("not_profiling".to_owned(), 0);

let span_ids = vec![
Span {
id: "42".to_string(),
thread_name: Some("thread1".to_string()),
},
Span {
id: "24".to_string(),
thread_name: Some("thread2".to_string()),
},
];

let trace_ids = vec![
Span {
id: "345".to_string(),
thread_name: Some("thread111".to_string()),
},
Span {
id: "666".to_string(),
thread_name: Some("thread222".to_string()),
},
];

Self {
counters,
data_schema_version: "1.0".to_string(),
error: ErrorData::test_instance(seed),
files: HashMap::new(),
fingerprint: None,
incomplete: true,
log_messages: vec![],
metadata: Metadata::test_instance(seed),
os_info: ::os_info::Info::unknown().into(),
proc_info: ProcInfo::test_instance(seed),
sig_info: Some(SigInfo::test_instance(seed)),
span_ids,
timestamp: chrono::DateTime::from_timestamp(1568898000 /* Datadog IPO */, 0)
.unwrap()
.to_string(),
trace_ids,
uuid: uuid::uuid!("1d6b97cb-968c-40c9-af6e-e4b4d71e8781").to_string(),
}
}
}
}
7 changes: 7 additions & 0 deletions crashtracker/src/rfc5_crash_info/proc_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,10 @@ impl From<crate::crash_info::ProcessInfo> for ProcInfo {
Self { pid: value.pid }
}
}

#[cfg(test)]
impl super::test_utils::TestInstance for ProcInfo {
fn test_instance(seed: u64) -> Self {
Self { pid: seed as u32 }
}
}
13 changes: 13 additions & 0 deletions crashtracker/src/rfc5_crash_info/sig_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,16 @@ pub enum SiCodes {
SI_USER,
SYS_SECCOMP,
}

#[cfg(test)]
impl SigInfo {
pub fn test_instance(_seed: u64) -> Self {
Self {
si_addr: Some("0x0000000000001234".to_string()),
si_code: 1,
si_code_human_readable: SiCodes::SEGV_BNDERR,
si_signo: 11,
si_signo_human_readable: SignalNames::SIGSEGV,
}
}
}
47 changes: 47 additions & 0 deletions crashtracker/src/rfc5_crash_info/stacktrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,50 @@ fn byte_vec_as_hex(bv: Option<Vec<u8>>) -> Option<String> {
None
}
}

#[cfg(test)]
impl super::test_utils::TestInstance for StackTrace {
fn test_instance(_seed: u64) -> Self {
let frames = (0..10).map(StackFrame::test_instance).collect();
Self {
format: "Datadog Crashtracker 1.0".to_string(),
frames,
}
}
}

#[cfg(test)]
impl super::test_utils::TestInstance for StackFrame {
fn test_instance(seed: u64) -> Self {
let ip = Some(format!("{seed:#x}"));
let module_base_address = None;
let sp = None;
let symbol_address = None;

let build_id = Some(format!("abcde{seed:#x}"));
let build_id_type = Some(BuildIdType::GNU);
let file_type = Some(FileType::ELF);
let path = Some(format!("/usr/bin/foo{seed}"));
let relative_address = None;

let column = Some(2 * seed as u32);
let file = Some(format!("banana{seed}.rs"));
let function = Some(format!("Bar::baz{seed}"));
let line = Some((2 * seed + 1) as u32);
Self {
ip,
module_base_address,
sp,
symbol_address,
build_id,
build_id_type,
file_type,
path,
relative_address,
column,
file,
function,
line,
}
}
}
Loading

0 comments on commit 191a68a

Please sign in to comment.