-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[crashtracker] Implement RFC 0005 (#738)
- Loading branch information
Showing
13 changed files
with
1,068 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
use super::stacktrace::StackTrace; | ||
use schemars::JsonSchema; | ||
use serde::{Deserialize, Serialize}; | ||
use std::collections::HashMap; | ||
|
||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)] | ||
pub struct ErrorData { | ||
pub is_crash: bool, | ||
pub kind: ErrorKind, | ||
#[serde(default, skip_serializing_if = "Option::is_none")] | ||
pub message: Option<String>, | ||
pub source_type: SourceType, | ||
pub stack: StackTrace, | ||
#[serde(default, skip_serializing_if = "Vec::is_empty")] | ||
pub threads: Vec<ThreadData>, | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)] | ||
pub enum SourceType { | ||
Crashtracking, | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)] | ||
pub enum ErrorKind { | ||
Panic, | ||
UnhandledException, | ||
UnixSignal, | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)] | ||
pub struct ThreadData { | ||
pub crashed: bool, | ||
pub name: String, | ||
pub stack: StackTrace, | ||
#[serde(default, skip_serializing_if = "Option::is_none")] | ||
pub state: Option<String>, | ||
} | ||
|
||
impl From<(String, Vec<crate::StackFrame>)> for ThreadData { | ||
fn from(value: (String, Vec<crate::StackFrame>)) -> Self { | ||
let crashed = false; // Currently, only .Net uses this, and I believe they don't put the crashing thread here | ||
let name = value.0; | ||
let stack = value.1.into(); | ||
let state = None; | ||
Self { | ||
crashed, | ||
name, | ||
stack, | ||
state, | ||
} | ||
} | ||
} | ||
|
||
pub fn thread_data_from_additional_stacktraces( | ||
additional_stacktraces: HashMap<String, Vec<crate::StackFrame>>, | ||
) -> Vec<ThreadData> { | ||
additional_stacktraces | ||
.into_iter() | ||
.map(|x| x.into()) | ||
.collect() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
use schemars::JsonSchema; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)] | ||
pub struct Metadata { | ||
pub library_name: String, | ||
pub library_version: String, | ||
pub family: String, | ||
#[serde(default, skip_serializing_if = "Vec::is_empty")] | ||
/// A list of "key:value" tuples. | ||
pub tags: Vec<String>, | ||
} | ||
|
||
impl From<crate::crash_info::CrashtrackerMetadata> for Metadata { | ||
fn from(value: crate::crash_info::CrashtrackerMetadata) -> Self { | ||
let tags = value | ||
.tags | ||
.into_iter() | ||
.map(|t: ddcommon::tag::Tag| t.to_string()) | ||
.collect(); | ||
Self { | ||
library_name: value.library_name, | ||
library_version: value.library_version, | ||
family: value.family, | ||
tags, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
mod error_data; | ||
mod metadata; | ||
mod os_info; | ||
mod proc_info; | ||
mod sig_info; | ||
mod spans; | ||
mod stacktrace; | ||
|
||
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 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)] | ||
pub struct CrashInfo { | ||
#[serde(default, skip_serializing_if = "HashMap::is_empty")] | ||
pub counters: HashMap<String, i64>, | ||
pub data_schema_version: String, | ||
pub error: ErrorData, | ||
#[serde(default, skip_serializing_if = "HashMap::is_empty")] | ||
pub files: HashMap<String, Vec<String>>, | ||
#[serde(default, skip_serializing_if = "Option::is_none")] | ||
pub fingerprint: Option<String>, | ||
pub incomplete: bool, | ||
#[serde(default, skip_serializing_if = "Vec::is_empty")] | ||
pub log_messages: Vec<String>, | ||
pub metadata: Metadata, | ||
pub os_info: OsInfo, | ||
pub proc_info: ProcInfo, | ||
pub sig_info: SigInfo, | ||
#[serde(default, skip_serializing_if = "Vec::is_empty")] | ||
pub span_ids: Vec<Span>, | ||
pub timestamp: String, | ||
#[serde(default, skip_serializing_if = "Vec::is_empty")] | ||
pub trace_ids: Vec<Span>, | ||
pub uuid: String, | ||
} | ||
|
||
impl From<crate::crash_info::CrashInfo> for CrashInfo { | ||
fn from(value: crate::crash_info::CrashInfo) -> Self { | ||
let counters = value.counters; | ||
let data_schema_version = String::from("1.0"); | ||
let error = { | ||
let is_crash = true; | ||
let kind = ErrorKind::UnixSignal; | ||
let message = None; | ||
let source_type = SourceType::Crashtracking; | ||
let stack = value.stacktrace.into(); | ||
let threads = thread_data_from_additional_stacktraces(value.additional_stacktraces); | ||
ErrorData { | ||
is_crash, | ||
kind, | ||
message, | ||
source_type, | ||
stack, | ||
threads, | ||
} | ||
}; | ||
let files = value.files; | ||
let fingerprint = None; | ||
let incomplete = value.incomplete; | ||
let log_messages = vec![]; | ||
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 span_ids = value | ||
.span_ids | ||
.into_iter() | ||
.map(|s| Span { | ||
id: s.to_string(), | ||
thread_name: None, | ||
}) | ||
.collect(); | ||
let trace_ids = value | ||
.trace_ids | ||
.into_iter() | ||
.map(|s| Span { | ||
id: s.to_string(), | ||
thread_name: None, | ||
}) | ||
.collect(); | ||
let timestamp = value.timestamp.unwrap().to_string(); | ||
let uuid = value.uuid.to_string(); | ||
Self { | ||
counters, | ||
data_schema_version, | ||
error, | ||
files, | ||
fingerprint, | ||
incomplete, | ||
log_messages, | ||
metadata, | ||
os_info, | ||
proc_info, | ||
sig_info, | ||
span_ids, | ||
trace_ids, | ||
timestamp, | ||
uuid, | ||
} | ||
} | ||
} | ||
|
||
impl CrashInfo { | ||
/// Emit the CrashInfo as structured json in file `path`. | ||
pub fn to_file(&self, path: &Path) -> anyhow::Result<()> { | ||
let file = File::options() | ||
.create(true) | ||
.append(true) | ||
.open(path) | ||
.with_context(|| format!("Failed to create {}", path.display()))?; | ||
serde_json::to_writer_pretty(file, self) | ||
.with_context(|| format!("Failed to write json to {}", path.display()))?; | ||
Ok(()) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
#[ignore] | ||
#[test] | ||
/// Utility function to print the schema. | ||
fn print_schema() { | ||
let schema = schemars::schema_for!(CrashInfo); | ||
println!("{}", serde_json::to_string_pretty(&schema).unwrap()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
use schemars::JsonSchema; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)] | ||
pub struct OsInfo { | ||
pub architecture: String, | ||
pub bitness: String, | ||
pub os_type: String, | ||
pub version: String, | ||
} | ||
|
||
impl From<os_info::Info> for OsInfo { | ||
fn from(value: os_info::Info) -> Self { | ||
let architecture = value.architecture().unwrap_or("unknown").to_string(); | ||
let bitness = value.bitness().to_string(); | ||
let os_type = value.os_type().to_string(); | ||
let version = value.version().to_string(); | ||
Self { | ||
architecture, | ||
bitness, | ||
os_type, | ||
version, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
use schemars::JsonSchema; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)] | ||
pub struct ProcInfo { | ||
pid: u32, | ||
} | ||
|
||
impl From<crate::crash_info::ProcessInfo> for ProcInfo { | ||
fn from(value: crate::crash_info::ProcessInfo) -> Self { | ||
Self { pid: value.pid } | ||
} | ||
} |
Oops, something went wrong.