Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Allow for selecting frame in sourcemaps explain #1293

Merged
merged 1 commit into from Jul 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
47 changes: 31 additions & 16 deletions src/commands/sourcemaps/explain.rs
Expand Up @@ -24,6 +24,13 @@ pub fn make_command(command: Command) -> Command {
.required(true)
.help("ID of an event to be explained."),
)
.arg(
Arg::new("frame")
.long("frame")
.default_value("0")
.value_parser(clap::value_parser!(usize))
.help("Position of the frame that should be used for source map resolution."),
)
.arg(
Arg::new("force")
.long("force")
Expand Down Expand Up @@ -82,28 +89,34 @@ fn extract_in_app_frames(stacktrace: &Stacktrace) -> Vec<&Frame> {
.collect()
}

fn extract_top_frame(stacktrace: &Stacktrace) -> Result<&Frame> {
let in_app_frames = extract_in_app_frames(stacktrace);
fn extract_nth_frame(stacktrace: &Stacktrace, position: usize) -> Result<&Frame> {
let mut in_app_frames = extract_in_app_frames(stacktrace);

if in_app_frames.is_empty() {
bail!("Event exception stacktrace has no in_app frames");
}

let top_frame = in_app_frames.last().unwrap();
let abs_path = top_frame
// Frames are in bottom-up order.
in_app_frames.reverse();

let frame = in_app_frames
.get(position)
.ok_or_else(|| format_err!("Selected frame ({}) is missing.", position))?;

let abs_path = frame
.abs_path
.as_ref()
.ok_or_else(|| format_err!("Top frame is missing an abs_path"))?;
.ok_or_else(|| format_err!("Selected frame ({}) is missing an abs_path", position))?;

if let Ok(abs_path) = Url::parse(abs_path) {
if Path::new(abs_path.path()).extension().is_none() {
bail!("Top frame of event exception originates from the <script> tag, its not possible to resolve source maps");
bail!("Selected frame ({}) of event exception originates from the <script> tag, its not possible to resolve source maps", position);
}
} else {
bail!("Event exception stacktrace top frame has incorrect abs_path (valid url is required). Found {}", abs_path);
bail!("Event exception stacktrace selected frame ({}) has incorrect abs_path (valid url is required). Found {}", position, abs_path);
}

Ok(top_frame)
Ok(frame)
}

fn fetch_release_artifacts(org: &str, project: &str, release: &str) -> Result<Vec<Artifact>> {
Expand Down Expand Up @@ -363,21 +376,23 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
})?;
success("Event has a valid stacktrace present");

let mut frame = extract_top_frame(stacktrace).map_err(|err| {
error(err);
QuietExit(1)
})?;
let mut frame = extract_nth_frame(stacktrace, *matches.get_one::<usize>("frame").unwrap())
.map_err(|err| {
error(err);
QuietExit(1)
})?;

if exception.raw_stacktrace.is_some() {
if matches.is_present("force") {
warning(
"Exception is already source mapped, however 'force' flag was used. Moving along.",
);
let raw_stacktrace = exception.raw_stacktrace.as_ref().unwrap();
frame = extract_top_frame(raw_stacktrace).map_err(|err| {
error(err);
QuietExit(1)
})?;
frame = extract_nth_frame(raw_stacktrace, *matches.get_one::<usize>("frame").unwrap())
.map_err(|err| {
error(err);
QuietExit(1)
})?;
} else {
warning("Exception is already source mapped and first resolved frame points to:\n");
if let Some(frame) = extract_in_app_frames(stacktrace)
Expand Down
Expand Up @@ -5,6 +5,6 @@ $ sentry-cli sourcemaps explain 43a57a55cd5a4207ac520c03e1dee1b4
✔ Event has release name: ytho-test
✔ Event has a valid exception present
✔ Event has a valid stacktrace present
✖ Event exception stacktrace top frame has incorrect abs_path (valid url is required). Found okboomer
✖ Event exception stacktrace selected frame (0) has incorrect abs_path (valid url is required). Found okboomer

```
Expand Up @@ -5,6 +5,6 @@ $ sentry-cli sourcemaps explain 43a57a55cd5a4207ac520c03e1dee1b4
✔ Event has release name: ytho-test
✔ Event has a valid exception present
✔ Event has a valid stacktrace present
Top frame is missing an abs_path
Selected frame (0) is missing an abs_path

```
Expand Up @@ -5,6 +5,6 @@ $ sentry-cli sourcemaps explain 43a57a55cd5a4207ac520c03e1dee1b4
✔ Event has release name: ytho-test
✔ Event has a valid exception present
✔ Event has a valid stacktrace present
Top frame of event exception originates from the <script> tag, its not possible to resolve source maps
Selected frame (0) of event exception originates from the <script> tag, its not possible to resolve source maps

```
Expand Up @@ -14,6 +14,8 @@ OPTIONS:
--auth-token <AUTH_TOKEN> Use the given Sentry auth token.
-f, --force Force full validation flow, even when event is already source
mapped.
--frame <frame> Position of the frame that should be used for source map
resolution. [default: 0]
-h, --help Print help information
--header <KEY:VALUE> Custom headers that should be attached to all requests
in key:value format.
Expand Down
@@ -0,0 +1,10 @@
```
$ sentry-cli sourcemaps explain 43a57a55cd5a4207ac520c03e1dee1b4 --frame 42
? failed
✔ Fetched data for event: 43a57a55cd5a4207ac520c03e1dee1b4
✔ Event has release name: ytho-test
✔ Event has a valid exception present
✔ Event has a valid stacktrace present
✖ Selected frame (42) is missing.

```
@@ -0,0 +1,10 @@
```
$ sentry-cli sourcemaps explain 43a57a55cd5a4207ac520c03e1dee1b4 --frame 2
? failed
✔ Fetched data for event: 43a57a55cd5a4207ac520c03e1dee1b4
✔ Event has release name: ytho-test
✔ Event has a valid exception present
✔ Event has a valid stacktrace present
✖ Event exception stacktrace selected frame (2) has incorrect abs_path (valid url is required). Found wrongabspath

```
@@ -0,0 +1,51 @@
{
"event_id": "43a57a55cd5a4207ac520c03e1dee1b4",
"project": 5334254,
"release": "ytho-test",
"dist": null,
"exception": {
"values": [
{
"type": "Error",
"value": "whoops",
"stacktrace": {
"frames": [
{
"filename": "/dist/bundle.min.js",
"abs_path": "wrongabspath",
"lineno": 1,
"colno": 456,
"context_line": "{snip} tps://5b0e5845265a472ba9c269bbfa0c8388@o333688.ingest.sentry.io/5334254\",release:\"ytho-test\"}),function(t){throw new Error(\"whoops\")}()})();",
"post_context": [
"//# sourceMappingURL=bundle.min.js.map"
],
"in_app": true
},
{
"filename": "/dist/bundle.min.js",
"abs_path": "http://localhost:5000/dist/bundle.min.js",
"lineno": 1,
"colno": 452,
"context_line": "{snip} tps://5b0e5845265a472ba9c269bbfa0c8388@o333688.ingest.sentry.io/5334254\",release:\"ytho-test\"}),function(t){throw new Error(\"whoops\")}()})();",
"post_context": [
"//# sourceMappingURL=bundle.min.js.map"
],
"in_app": true
},
{
"filename": "/dist/bundle.min.js",
"abs_path": "http://localhost:5000/dist/bundle.min.js",
"lineno": 1,
"colno": 432,
"context_line": "{snip} tps://5b0e5845265a472ba9c269bbfa0c8388@o333688.ingest.sentry.io/5334254\",release:\"ytho-test\"}),function(t){throw new Error(\"whoops\")}()})();",
"post_context": [
"//# sourceMappingURL=bundle.min.js.map"
],
"in_app": true
}
]
}
}
]
}
}
26 changes: 26 additions & 0 deletions tests/integration/sourcemaps/explain.rs
Expand Up @@ -385,3 +385,29 @@ fn command_sourcemaps_explain_print_sourcemap() {

register_test("sourcemaps/sourcemaps-explain-print-sourcemap.trycmd");
}

#[test]
fn command_sourcemaps_explain_select_frame() {
let _event = mock_endpoint(
EndpointOptions::new(
"GET",
"/api/0/projects/wat-org/wat-project/events/43a57a55cd5a4207ac520c03e1dee1b4/json/",
200,
)
.with_response_file("sourcemaps/get-event-select-frame.json"),
);
register_test("sourcemaps/sourcemaps-explain-select-frame.trycmd");
}

#[test]
fn command_sourcemaps_explain_select_frame_out_of_range() {
let _event = mock_endpoint(
EndpointOptions::new(
"GET",
"/api/0/projects/wat-org/wat-project/events/43a57a55cd5a4207ac520c03e1dee1b4/json/",
200,
)
.with_response_file("sourcemaps/get-event-select-frame.json"),
);
register_test("sourcemaps/sourcemaps-explain-select-frame-out-of-range.trycmd");
}