Skip to content

Commit 06d78e5

Browse files
authored
feat: Pass scope via IPC (#13)
1 parent b9b08bf commit 06d78e5

File tree

6 files changed

+130
-16
lines changed

6 files changed

+130
-16
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,4 @@ jobs:
4242
uses: actions-rs/cargo@v1
4343
with:
4444
command: test
45+
args: --all-features

Cargo.toml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,19 @@ license = "MIT OR Apache-2.0"
55
name = "sentry-rust-minidump"
66
readme = "README.md"
77
repository = "https://github.com/timfish/sentry-rust-minidump"
8-
version = "0.6.4"
8+
version = "0.7.0"
99

1010
[dependencies]
1111
minidumper-child = "0.2"
12-
sentry = "0.31"
12+
sentry = "0.32"
1313
thiserror = "1"
14+
serde = { version = "1", features = ["derive"], optional = true }
15+
serde_json = { version = "1", optional = true }
1416

1517
[dev-dependencies]
1618
actix-rt = "2.7"
1719
sadness-generator = "0.5"
18-
sentry-test-server = {git = "https://github.com/timfish/sentry-test-server.git", rev = "134c30e"}
20+
sentry-test-server = {git = "https://github.com/timfish/sentry-test-server.git", rev = "df19c85"}
21+
22+
[features]
23+
ipc = [ "dep:serde", "dep:serde_json"]

README.md

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ your application code.
1818

1919
```toml
2020
[dependencies]
21-
sentry = "0.31"
22-
sentry-rust-minidump = "0.6"
21+
sentry = "0.32"
22+
sentry-rust-minidump = "0.7"
2323
```
2424

2525
```rust
@@ -39,3 +39,29 @@ fn main() {
3939
}
4040
}
4141
```
42+
43+
## `ipc` feature
44+
45+
By default there is no scope synchronisation from the app process to the crash
46+
reporter process. This means that native crash event will be missing
47+
breadcrumbs, user, tags or extra added to the scope in the app.
48+
49+
When the `ipc` feature is enabled, you can send scope updates to the crash
50+
reporter process:
51+
52+
```rust
53+
fn main() {
54+
let client = sentry::init("__YOUR_DSN__");
55+
56+
// Everything before here runs in both app and crash reporter processes
57+
let crash_reporter = sentry_rust_minidump::init(&client).expect("crash reported didn't start");
58+
// Everything after here runs in only the app process
59+
60+
crash_reporter.add_breadcrumb(...);
61+
crash_reporter.set_user(...);
62+
crash_reporter.set_extra(...);
63+
crash_reporter.set_tag(...);
64+
65+
// Don't drop crash_reporter or the reporter process will close!
66+
}
67+
```

examples/app.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,16 @@ fn main() {
22
let client = sentry::init("http://[email protected]:8123/12345");
33

44
// Everything before here runs in both app and crash reporter processes
5-
let _guard = sentry_rust_minidump::init(&client);
5+
let crash_handler =
6+
sentry_rust_minidump::init(&client).expect("could not initialize crash reporter");
67
// Everything after here runs in only the app process
78

9+
crash_handler.set_user(Some(sentry::User {
10+
username: Some("john_doe".into()),
11+
email: Some("[email protected]".into()),
12+
..Default::default()
13+
}));
14+
815
std::thread::sleep(std::time::Duration::from_secs(10));
916

1017
unsafe { sadness_generator::raise_segfault() };

src/lib.rs

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,76 @@
1-
pub use minidumper_child::MinidumperChild;
1+
use minidumper_child::{ClientHandle, Error, MinidumperChild};
22
use sentry::{
33
protocol::{Attachment, AttachmentType, Event, Value},
44
Level,
55
};
66

7-
pub use minidumper_child::{ClientHandle, Error};
7+
#[cfg(feature = "ipc")]
8+
use sentry::{Breadcrumb, User};
9+
10+
pub struct Handle {
11+
_handle: ClientHandle,
12+
}
13+
14+
#[cfg(feature = "ipc")]
15+
#[derive(serde::Deserialize, serde::Serialize, Debug, Clone, PartialEq)]
16+
pub enum ScopeUpdate {
17+
AddBreadcrumb(Breadcrumb),
18+
SetUser(Option<User>),
19+
SetExtra(String, Option<Value>),
20+
SetTag(String, Option<String>),
21+
}
22+
23+
#[cfg(feature = "ipc")]
24+
impl Handle {
25+
fn send_message(&self, update: &ScopeUpdate) {
26+
let buffer = serde_json::to_vec(update).expect("could not serialize scope update");
27+
self._handle.send_message(0, buffer).ok();
28+
}
29+
30+
pub fn add_breadcrumb(&self, breadcrumb: Breadcrumb) {
31+
self.send_message(&ScopeUpdate::AddBreadcrumb(breadcrumb));
32+
}
33+
34+
pub fn set_user(&self, user: Option<User>) {
35+
self.send_message(&ScopeUpdate::SetUser(user));
36+
}
37+
38+
pub fn set_extra(&self, key: String, value: Option<Value>) {
39+
self.send_message(&ScopeUpdate::SetExtra(key, value));
40+
}
41+
42+
pub fn set_tag(&self, key: String, value: Option<String>) {
43+
self.send_message(&ScopeUpdate::SetTag(key, value));
44+
}
45+
}
846

947
#[must_use = "The return value from init() should not be dropped until the program exits"]
10-
pub fn init(sentry_client: &sentry::Client) -> Result<ClientHandle, Error> {
48+
pub fn init(sentry_client: &sentry::Client) -> Result<Handle, Error> {
1149
let sentry_client = sentry_client.clone();
1250

13-
let child = MinidumperChild::new().on_minidump(move |buffer, path| {
51+
let child = MinidumperChild::new();
52+
53+
#[cfg(feature = "ipc")]
54+
let child = child.on_message(|_kind, buffer| {
55+
if let Ok(update) = serde_json::from_slice::<ScopeUpdate>(&buffer[..]) {
56+
match update {
57+
ScopeUpdate::AddBreadcrumb(b) => sentry::add_breadcrumb(b),
58+
ScopeUpdate::SetUser(u) => sentry::configure_scope(|scope| {
59+
scope.set_user(u);
60+
}),
61+
ScopeUpdate::SetExtra(k, v) => sentry::configure_scope(|scope| match v {
62+
Some(v) => scope.set_extra(&k, v),
63+
None => scope.remove_extra(&k),
64+
}),
65+
ScopeUpdate::SetTag(k, v) => match v {
66+
Some(v) => sentry::configure_scope(|scope| scope.set_tag(&k, &v)),
67+
None => sentry::configure_scope(|scope| scope.remove_tag(&k)),
68+
},
69+
}
70+
}
71+
});
72+
73+
let child = child.on_minidump(move |buffer, path| {
1474
sentry::with_scope(
1575
|scope| {
1676
// Remove event.process because this event came from the
@@ -49,5 +109,5 @@ pub fn init(sentry_client: &sentry::Client) -> Result<ClientHandle, Error> {
49109
});
50110
}
51111

52-
child.spawn()
112+
child.spawn().map(|handle| Handle { _handle: handle })
53113
}

tests/e2e.rs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,40 @@ async fn test_example_app() -> Result<(), Box<dyn Error>> {
66
let envelope_rx = sentry_test_server::server(("127.0.0.1", 8123))?;
77

88
// We need to await at some point otherwise the server doesn't seem to start
9-
actix_rt::time::sleep(Duration::from_secs(1)).await;
9+
actix_rt::time::sleep(Duration::from_secs(2)).await;
1010

1111
Command::new("cargo")
12-
.args(["run", "--example", "app"])
12+
.args(["run", "--example", "app", "--all-features"])
1313
.spawn()?
1414
.wait()?;
1515

16-
let env = envelope_rx.recv_timeout(Duration::from_secs(2))?;
16+
let env = envelope_rx.recv_timeout(Duration::from_secs(15))?;
1717

1818
if let Ok(json) = sentry_test_server::to_json_pretty(&env) {
1919
println!("{}", json);
2020
}
2121

22-
let item = env
22+
let env_item = env
23+
.items()
24+
.find(|item| matches!(item, EnvelopeItem::Event(_)))
25+
.expect("envelope should have an event");
26+
27+
let event = match env_item {
28+
EnvelopeItem::Event(event) => event.clone(),
29+
_ => unreachable!("envelope should have an event"),
30+
};
31+
32+
let user = event.user.expect("event should have a user");
33+
34+
assert_eq!(user.email, Some("[email protected]".into()));
35+
assert_eq!(user.username, Some("john_doe".into()));
36+
37+
let env_item = env
2338
.items()
2439
.find(|item| matches!(item, EnvelopeItem::Attachment(_)))
2540
.expect("envelope should have an attachment");
2641

27-
let attachment = match item {
42+
let attachment = match env_item {
2843
EnvelopeItem::Attachment(attachment) => attachment,
2944
_ => unreachable!("envelope should have an attachment"),
3045
};

0 commit comments

Comments
 (0)