Skip to content

Commit

Permalink
feat: Added support for raw stacktraces and improved thread interface
Browse files Browse the repository at this point in the history
  • Loading branch information
mitsuhiko committed Mar 25, 2018
1 parent 1581f1b commit 87f2948
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 10 deletions.
47 changes: 46 additions & 1 deletion src/protocol/v7.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ pub struct Stacktrace {
#[serde(untagged)]
pub enum ThreadId {
/// Integer representation for the thread id
Int(i64),
Int(u64),
/// String representation for the thread id
String(String),
}
Expand All @@ -180,6 +180,36 @@ impl Default for ThreadId {
}
}

impl<'a> From<&'a str> for ThreadId {
fn from(id: &'a str) -> ThreadId {
ThreadId::String(id.to_string())
}
}

impl From<String> for ThreadId {
fn from(id: String) -> ThreadId {
ThreadId::String(id)
}
}

impl From<i64> for ThreadId {
fn from(id: i64) -> ThreadId {
ThreadId::Int(id as u64)
}
}

impl From<u32> for ThreadId {
fn from(id: u32) -> ThreadId {
ThreadId::Int(id as u64)
}
}

impl From<u16> for ThreadId {
fn from(id: u16) -> ThreadId {
ThreadId::Int(id as u64)
}
}

impl fmt::Display for ThreadId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Expand Down Expand Up @@ -229,21 +259,33 @@ impl Into<u64> for Addr {
}
}

fn is_false(value: &bool) -> bool {
*value == false
}

/// Represents a single thread.
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
#[serde(default)]
pub struct Thread {
/// The optional ID of the thread (usually an integer)
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<ThreadId>,
/// The optional name of the thread.
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
/// If the thread suspended or crashed a stacktrace can be
/// attached here.
#[serde(skip_serializing_if = "Option::is_none")]
pub stacktrace: Option<Stacktrace>,
/// Optional raw stacktrace.
#[serde(skip_serializing_if = "Option::is_none")]
pub raw_stacktrace: Option<Stacktrace>,
/// indicates a crashed thread
#[serde(skip_serializing_if = "is_false")]
pub crashed: bool,
/// indicates that the thread was not suspended when the
/// event was created.
#[serde(skip_serializing_if = "is_false")]
pub current: bool,
}

Expand All @@ -263,6 +305,9 @@ pub struct Exception {
/// Optionally the stacktrace.
#[serde(skip_serializing_if = "Option::is_none")]
pub stacktrace: Option<Stacktrace>,
/// An optional raw stacktrace.
#[serde(skip_serializing_if = "Option::is_none")]
pub raw_stacktrace: Option<Stacktrace>,
}

/// Represents the level of severity of an event or breadcrumb
Expand Down
76 changes: 67 additions & 9 deletions tests/test_protocol_v7.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,46 @@ fn test_template_info() {
);
}

#[test]
fn test_threads() {
let event = v7::Event {
threads: vec![
v7::Thread {
id: Some("#1".into()),
name: Some("Awesome Thread".into()),
..Default::default()
}
],
..Default::default()
};

assert_roundtrip(&event);
assert_eq!(
serde_json::to_string(&event).unwrap(),
"{\"threads\":{\"values\":[{\"id\":\"#1\",\"name\":\"Awesome Thread\"}]}}"
);

let event = v7::Event {
threads: vec![
v7::Thread {
id: Some(42u32.into()),
name: Some("Awesome Thread".into()),
crashed: true,
current: true,
..Default::default()
}
],
..Default::default()
};

assert_roundtrip(&event);
assert_eq!(
serde_json::to_string(&event).unwrap(),
"{\"threads\":{\"values\":[{\"id\":42,\"name\":\"Awesome Thread\",\
\"crashed\":true,\"current\":true}]}}"
);
}

#[test]
fn test_request() {
let event = v7::Event {
Expand Down Expand Up @@ -494,6 +534,7 @@ fn test_minimal_exception_stacktrace() {
],
..Default::default()
}),
raw_stacktrace: None,
}],
..Default::default()
};
Expand Down Expand Up @@ -541,6 +582,7 @@ fn test_slightly_larger_exception_stacktrace() {
],
..Default::default()
}),
raw_stacktrace: None,
}],
..Default::default()
};
Expand Down Expand Up @@ -597,22 +639,38 @@ fn test_full_exception_stacktrace() {
],
frames_omitted: Some((1, 2)),
}),
raw_stacktrace: Some(v7::Stacktrace {
frames: vec![
v7::Frame {
function: Some("main".into()),
instruction_info: v7::InstructionInfo {
image_addr: Some(v7::Addr(0)),
instruction_addr: Some(v7::Addr(0)),
symbol_addr: Some(v7::Addr(0)),
},
..Default::default()
},
],
frames_omitted: Some((1, 2)),
}),
}],
..Default::default()
};

assert_roundtrip(&event);
assert_eq!(
serde_json::to_string(&event).unwrap(),
"{\"exception\":{\"values\":[{\"type\":\"DivisionByZero\",\
\"value\":\"integer division or modulo by zero\",\"module\":\
\"x\",\"stacktrace\":{\"frames\":[{\"function\":\"main\",\"symbol\":\
\"main\",\"module\":\"hello\",\"package\":\"hello.whl\",\"filename\":\
\"hello.py\",\"abs_path\":\"/app/hello.py\",\"lineno\":7,\"\
colno\":42,\"pre_context\":[\"foo\",\"bar\"],\"context_line\":\
\"hey hey hey\",\"post_context\":[\"foo\",\"bar\"],\"in_app\":true,\
\"vars\":{\"var\":\"value\"},\"image_addr\":\"0x0\",\"instruction_addr\":\"0x0\",\
\"symbol_addr\":\"0x0\"}],\"frames_omitted\":[1,2]}}]}}"
"{\"exception\":{\"values\":[{\"type\":\"DivisionByZero\",\"value\":\
\"integer division or modulo by zero\",\"module\":\"x\",\"stacktrace\":\
{\"frames\":[{\"function\":\"main\",\"symbol\":\"main\",\"module\":\
\"hello\",\"package\":\"hello.whl\",\"filename\":\"hello.py\",\"abs_path\"\
:\"/app/hello.py\",\"lineno\":7,\"colno\":42,\"pre_context\":[\"foo\",\"\
bar\"],\"context_line\":\"hey hey hey\",\"post_context\":[\"foo\",\"bar\"]\
,\"in_app\":true,\"vars\":{\"var\":\"value\"},\"image_addr\":\"0x0\",\
\"instruction_addr\":\"0x0\",\"symbol_addr\":\"0x0\"}],\"frames_omitted\":\
[1,2]},\"raw_stacktrace\":{\"frames\":[{\"function\":\"main\",\
\"image_addr\":\"0x0\",\"instruction_addr\":\"0x0\",\"symbol_addr\":\"0x0\"}\
],\"frames_omitted\":[1,2]}}]}}"
);
}

Expand Down

0 comments on commit 87f2948

Please sign in to comment.