Skip to content

Commit 5cfacc8

Browse files
authored
feat(minidump): Parse Chromium stability report from minidumps (#4837)
- Ref getsentry/sentry#89156 This PR: - Updates the `minidump` crate to the latest version which supports parsing the stability report stream - Adds a `StabilityReportContext` context type with conversions from the minidump types - If there is a `crashpad` annotations stream, we also check for the stability report stream - If a stability report stream is found, it's added to the context as `chromium_stability_report`. - Some memory values in the report are in 4K blocks so these are multiplied by 4096 so that all values are in bytes
1 parent 4fe14fe commit 5cfacc8

File tree

9 files changed

+348
-10
lines changed

9 files changed

+348
-10
lines changed

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
## Unreleased
44

55
**Features**:
6-
76
- Add configuration to allow high cardinality tags in metrics. ([#4805](https://github.com/getsentry/relay/pull/4805))
87
- Make client sdk mandatory for profile sample v2. ([#4853](https://github.com/getsentry/relay/pull/4853))
8+
- Parse Chromium stability report from minidumps into context ([#4837](https://github.com/getsentry/relay/pull/4837))
99

1010
**Internal**:
1111

@@ -24,7 +24,7 @@
2424
**Features**:
2525

2626
- Implements a minimum sample rate dynamic sampling rule. ([#4801](https://github.com/getsentry/relay/pull/4801))
27-
- Convert NEL reports into logs. ([#4813](https://github.com/getsentry/relay/pull/4813)
27+
- Convert NEL reports into logs. ([#4813](https://github.com/getsentry/relay/pull/4813))
2828
- Add parsing for _Nintendo Switch_ to populate `os.name="Nintendo OS"`. ([#4821](https://github.com/getsentry/relay/pull/4821))
2929

3030
**Internal**:

Cargo.lock

Lines changed: 22 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ maxminddb = "0.24.0"
136136
md5 = "0.7.0"
137137
memchr = "2.7.4"
138138
mime = "0.3.17"
139-
minidump = "0.22.2"
139+
minidump = "0.26.0"
140140
multer = "3.1.0"
141141
num-traits = "0.2.19"
142142
num_cpus = "1.13.1"

relay-event-schema/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ chrono = { workspace = true, features = ["clock"] }
1818
cookie = { workspace = true, features = ["percent-encode"] }
1919
debugid = { workspace = true, features = ["serde"] }
2020
enumset = { workspace = true }
21+
minidump = { workspace = true }
2122
opentelemetry-proto = { workspace = true, features = ["gen-tonic", "trace"] }
2223
relay-common = { workspace = true }
2324
relay-base-schema = { workspace = true }
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
use relay_protocol::{Annotated, Array, Empty, FromValue, IntoValue};
2+
3+
use crate::processor::ProcessValue;
4+
5+
/// Some stability report fields are measured in 4K pages which we convert to bytes.
6+
fn bytes_from_4k_pages(value: u32) -> u64 {
7+
(value as u64) * 4096
8+
}
9+
10+
/// The state of a process.
11+
#[derive(Clone, Debug, Default, PartialEq, Empty, FromValue, IntoValue, ProcessValue)]
12+
pub struct ProcessStateContext {
13+
/// The identifier of the process.
14+
pub process_id: Annotated<u64>,
15+
/// Process memory state
16+
pub memory_state: Annotated<process_state::MemoryStateContext>,
17+
/// Process file system state
18+
pub file_system_state: Annotated<process_state::FileSystemStateContext>,
19+
}
20+
21+
/// Nested message and enum types in `ProcessState`.
22+
pub mod process_state {
23+
use super::*;
24+
25+
/// Records the state of process memory at the time of crash.
26+
/// Next id: 6
27+
#[derive(Clone, Debug, Default, PartialEq, Empty, FromValue, IntoValue, ProcessValue)]
28+
pub struct MemoryStateContext {
29+
pub windows_memory: Annotated<memory_state::WindowsMemoryContext>,
30+
}
31+
/// Nested message and enum types in `MemoryState`.
32+
pub mod memory_state {
33+
use super::*;
34+
35+
#[derive(Clone, Debug, Default, PartialEq, Empty, FromValue, IntoValue, ProcessValue)]
36+
pub struct WindowsMemoryContext {
37+
/// The private byte usage of the process.
38+
pub process_private_usage: Annotated<u64>,
39+
/// The peak working set usage of the process.
40+
pub process_peak_workingset_size: Annotated<u64>,
41+
/// The peak pagefile usage of the process.
42+
pub process_peak_pagefile_usage: Annotated<u64>,
43+
/// The allocation request that caused OOM bytes.
44+
pub process_allocation_attempt: Annotated<u64>,
45+
}
46+
}
47+
/// Records the state of the file system at the time of crash.
48+
#[derive(Clone, Debug, Default, PartialEq, Empty, FromValue, IntoValue, ProcessValue)]
49+
pub struct FileSystemStateContext {
50+
/// The state of the file system for POSIX systems.
51+
pub posix_file_system_state: Annotated<file_system_state::PosixFileSystemStateContext>,
52+
/// The state of the file system for Windows systems.
53+
pub windows_file_system_state: Annotated<file_system_state::WindowsFileSystemStateContext>,
54+
}
55+
/// Nested message and enum types in `FileSystemState`.
56+
pub mod file_system_state {
57+
use super::*;
58+
59+
#[derive(Clone, Debug, Default, PartialEq, Empty, FromValue, IntoValue, ProcessValue)]
60+
pub struct PosixFileSystemStateContext {
61+
/// The number of open file descriptors in the crashing process.
62+
pub open_file_descriptors: Annotated<u64>,
63+
}
64+
#[derive(Clone, Debug, Default, PartialEq, Empty, FromValue, IntoValue, ProcessValue)]
65+
pub struct WindowsFileSystemStateContext {
66+
/// The number of open handles in the process.
67+
pub process_handle_count: Annotated<u64>,
68+
}
69+
}
70+
}
71+
/// Records the state of system memory at the time of crash.
72+
#[derive(Clone, Debug, Default, PartialEq, Empty, FromValue, IntoValue, ProcessValue)]
73+
pub struct SystemMemoryStateContext {
74+
pub windows_memory: Annotated<system_memory_state::WindowsMemoryContext>,
75+
}
76+
/// Nested message and enum types in `SystemMemoryState`.
77+
pub mod system_memory_state {
78+
use super::*;
79+
80+
#[derive(Clone, Debug, Default, PartialEq, Empty, FromValue, IntoValue, ProcessValue)]
81+
82+
pub struct WindowsMemoryContext {
83+
/// The system commit limit.
84+
pub system_commit_limit: Annotated<u64>,
85+
/// The amount of system commit remaining.
86+
pub system_commit_remaining: Annotated<u64>,
87+
/// The current number of open handles.
88+
pub system_handle_count: Annotated<u64>,
89+
}
90+
}
91+
92+
/// A stability report contains information pertaining to the execution of a
93+
/// single logical instance of a "chrome browser". It is comprised of information
94+
/// about the system state and about the chrome browser's processes.
95+
96+
#[derive(Clone, Debug, Default, PartialEq, Empty, FromValue, IntoValue, ProcessValue)]
97+
pub struct StabilityReportContext {
98+
/// State pertaining to Chrome's processes.
99+
pub process_states: Annotated<Array<ProcessStateContext>>,
100+
/// System-wide resource usage.
101+
pub system_memory_state: Annotated<SystemMemoryStateContext>,
102+
}
103+
104+
impl super::DefaultContext for StabilityReportContext {
105+
fn default_key() -> &'static str {
106+
"chromium_stability_report"
107+
}
108+
109+
fn from_context(context: super::Context) -> Option<Self> {
110+
match context {
111+
super::Context::ChromiumStabilityReport(c) => Some(*c),
112+
_ => None,
113+
}
114+
}
115+
116+
fn cast(context: &super::Context) -> Option<&Self> {
117+
match context {
118+
super::Context::ChromiumStabilityReport(c) => Some(c),
119+
_ => None,
120+
}
121+
}
122+
123+
fn cast_mut(context: &mut super::Context) -> Option<&mut Self> {
124+
match context {
125+
super::Context::ChromiumStabilityReport(c) => Some(c),
126+
_ => None,
127+
}
128+
}
129+
130+
fn into_context(self) -> super::Context {
131+
super::Context::ChromiumStabilityReport(Box::new(self))
132+
}
133+
}
134+
135+
// From implementations for converting from minidump types
136+
impl From<minidump::StabilityReport> for StabilityReportContext {
137+
fn from(report: minidump::StabilityReport) -> Self {
138+
Self {
139+
process_states: Annotated::from(
140+
report
141+
.process_states
142+
.into_iter()
143+
.map(|ps| Annotated::from(ProcessStateContext::from(ps)))
144+
.collect::<Vec<_>>(),
145+
),
146+
system_memory_state: report.system_memory_state.map(Into::into).into(),
147+
}
148+
}
149+
}
150+
151+
impl From<minidump::ProcessState> for ProcessStateContext {
152+
fn from(state: minidump::ProcessState) -> Self {
153+
Self {
154+
process_id: state.process_id.map(|id| id as u64).into(),
155+
memory_state: state.memory_state.map(Into::into).into(),
156+
file_system_state: state.file_system_state.map(Into::into).into(),
157+
}
158+
}
159+
}
160+
161+
impl From<minidump::SystemMemoryState> for SystemMemoryStateContext {
162+
fn from(state: minidump::SystemMemoryState) -> Self {
163+
Self {
164+
windows_memory: state.windows_memory.map(Into::into).into(),
165+
}
166+
}
167+
}
168+
169+
impl From<minidump::system_memory_state::WindowsMemory>
170+
for system_memory_state::WindowsMemoryContext
171+
{
172+
fn from(memory: minidump::system_memory_state::WindowsMemory) -> Self {
173+
Self {
174+
system_commit_limit: memory.system_commit_limit.map(bytes_from_4k_pages).into(),
175+
system_commit_remaining: memory
176+
.system_commit_remaining
177+
.map(bytes_from_4k_pages)
178+
.into(),
179+
system_handle_count: memory.system_handle_count.map(|v| v as u64).into(),
180+
}
181+
}
182+
}
183+
184+
impl From<minidump::process_state::MemoryState> for process_state::MemoryStateContext {
185+
fn from(state: minidump::process_state::MemoryState) -> Self {
186+
Self {
187+
windows_memory: state.windows_memory.map(Into::into).into(),
188+
}
189+
}
190+
}
191+
192+
impl From<minidump::process_state::memory_state::WindowsMemory>
193+
for process_state::memory_state::WindowsMemoryContext
194+
{
195+
fn from(memory: minidump::process_state::memory_state::WindowsMemory) -> Self {
196+
Self {
197+
process_private_usage: memory.process_private_usage.map(bytes_from_4k_pages).into(),
198+
process_peak_workingset_size: memory
199+
.process_peak_workingset_size
200+
.map(bytes_from_4k_pages)
201+
.into(),
202+
process_peak_pagefile_usage: memory
203+
.process_peak_pagefile_usage
204+
.map(bytes_from_4k_pages)
205+
.into(),
206+
process_allocation_attempt: memory.process_allocation_attempt.map(|v| v as u64).into(),
207+
}
208+
}
209+
}
210+
211+
impl From<minidump::process_state::FileSystemState> for process_state::FileSystemStateContext {
212+
fn from(state: minidump::process_state::FileSystemState) -> Self {
213+
Self {
214+
posix_file_system_state: state.posix_file_system_state.map(Into::into).into(),
215+
windows_file_system_state: state.windows_file_system_state.map(Into::into).into(),
216+
}
217+
}
218+
}
219+
220+
impl From<minidump::process_state::file_system_state::PosixFileSystemState>
221+
for process_state::file_system_state::PosixFileSystemStateContext
222+
{
223+
fn from(state: minidump::process_state::file_system_state::PosixFileSystemState) -> Self {
224+
Self {
225+
open_file_descriptors: state.open_file_descriptors.map(|v| v as u64).into(),
226+
}
227+
}
228+
}
229+
230+
impl From<minidump::process_state::file_system_state::WindowsFileSystemState>
231+
for process_state::file_system_state::WindowsFileSystemStateContext
232+
{
233+
fn from(state: minidump::process_state::file_system_state::WindowsFileSystemState) -> Self {
234+
Self {
235+
process_handle_count: state.process_handle_count.map(|v| v as u64).into(),
236+
}
237+
}
238+
}

relay-event-schema/src/protocol/contexts/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod app;
22
mod browser;
3+
mod chromium_stability_report;
34
mod cloud_resource;
45
mod device;
56
mod flags;
@@ -20,6 +21,7 @@ mod trace;
2021
mod user_report_v2;
2122
pub use app::*;
2223
pub use browser::*;
24+
pub use chromium_stability_report::*;
2325
pub use cloud_resource::*;
2426
pub use device::*;
2527
pub use gpu::*;
@@ -98,6 +100,8 @@ pub enum Context {
98100
Spring(Box<SpringContext>),
99101
/// OTA Updates information.
100102
OTAUpdates(Box<OTAUpdatesContext>),
103+
/// Chromium Stability Report from minidump.
104+
ChromiumStabilityReport(Box<StabilityReportContext>),
101105
/// Additional arbitrary fields for forwards compatibility.
102106
#[metastructure(fallback_variant)]
103107
Other(#[metastructure(pii = "true")] Object<Value>),

0 commit comments

Comments
 (0)