Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
bump: patch
type: fix
---

Fix matching on backtrace paths containing spaces.

When using `matchBacktracePaths`, when a backtrace line path contains a space, it will now match correctly against the whole path.
56 changes: 56 additions & 0 deletions packages/javascript/src/__tests__/span.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,35 @@ describe("Span", () => {
})
})

it("cleans Chrome-style backtraces with spaces in the path", () => {
const error = new Error("test error")
error.stack = [
"Error: test error",
" at Foo (http://localhost:8080/assets with space/app/bundle.js:13:10)",
" at Bar (http://localhost:8080/assets with space/app/bundle.js:17:10)",
" at track (http://thirdparty.app/script.js:1:530)",
" at http://localhost:8080/assets with space/app/bundle.js:21:10"
].join("\n")

span.setError(error)
span.cleanBacktracePath(
[new RegExp("/assets with space/(app/.*)$")].map(toBacktraceMatcher)
)

const backtrace = span.serialize().error.backtrace
expect(backtrace).toEqual([
"Error: test error",
" at Foo (app/bundle.js:13:10)",
" at Bar (app/bundle.js:17:10)",
" at track (http://thirdparty.app/script.js:1:530)",
" at app/bundle.js:21:10"
])

expect(span.serialize().environment).toMatchObject({
backtrace_paths_matched: "3"
})
})

it("cleans Safari/FF-style backtraces", () => {
const error = new Error("test error")
error.stack = [
Expand Down Expand Up @@ -116,6 +145,33 @@ describe("Span", () => {
})
})

it("cleans Safari/FF-style backtraces with spaces in the path", () => {
const error = new Error("test error")
error.stack = [
"Foo@http://localhost:8080/assets with space/app/bundle.js:13:10",
"Bar@http://localhost:8080/assets with space/app/bundle.js:17:10",
"track@http://thirdparty.app/script.js:1:530",
"@http://localhost:8080/assets with space/app/bundle.js:21:10"
].join("\n")

span.setError(error)
span.cleanBacktracePath(
[new RegExp("/assets with space/(app/.*)$")].map(toBacktraceMatcher)
)

const backtrace = span.serialize().error.backtrace
expect(backtrace).toEqual([
"Foo@app/bundle.js:13:10",
"Bar@app/bundle.js:17:10",
"track@http://thirdparty.app/script.js:1:530",
"@app/bundle.js:21:10"
])

expect(span.serialize().environment).toMatchObject({
backtrace_paths_matched: "3"
})
})

it("concatenates all match groups", () => {
const error = new Error("test error")
error.stack = [
Expand Down
24 changes: 15 additions & 9 deletions packages/javascript/src/span.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,15 +186,22 @@ function extractPath(backtraceLine: string): string | undefined {
// A Chrome backtrace line always contains `at` near the beginning,
// preceded by space characters and followed by one space.
const IS_CHROME = /^\s*at\s/

// In a Chrome backtrace line, the path (if it is available)
// is located, usually within parentheses, after the "@" towards the
// end of the line, along with the line number and column number,
// separated by colons. We check for those to reject clear non-paths.
const CHROME_PATH = /at(?:\s.*)?\s\(?(.*):\d*:\d*\)?$/i
// is located after the "at" towards the end of the line, along with
// the line number and column number, separated by colons.
// When the function name is available, the path is enclosed in
// parentheses. When there is no function name, the path comes
// immediately after the "at".
// We check for the line and column numbers to reject clear non-paths.
const CHROME_PATH_WITH_FUNCTION_NAME = /^\s*at(?:\s[^\(]+)?\s\((.*):\d+:\d+\)$/
const CHROME_PATH_WITHOUT_FUNCTION_NAME = /^\s*at\s(.*):\d+:\d+$/

if (backtraceLine.match(IS_CHROME)) {
const match = backtraceLine.match(CHROME_PATH)
return match ? match[1] : undefined
return (
backtraceLine.match(CHROME_PATH_WITH_FUNCTION_NAME)?.[1] ??
backtraceLine.match(CHROME_PATH_WITHOUT_FUNCTION_NAME)?.[1]
)
}

// A Safari or Firefox backtrace line always contains `@` after the first
Expand All @@ -205,10 +212,9 @@ function extractPath(backtraceLine: string): string | undefined {
// is located after the "@" at the towards end of the line, followed by
// the line number and column number, separated by colons. We check for
// those to reject clear non-paths.
const SAFARI_FF_PATH = /@\s?(.*):\d*:\d*$/i
const SAFARI_FF_PATH = /^.*@\s?(.*):\d+:\d+$/

if (backtraceLine.match(IS_SAFARI_FF)) {
const match = backtraceLine.match(SAFARI_FF_PATH)
return match ? match[1] : undefined
return backtraceLine.match(SAFARI_FF_PATH)?.[1]
}
}
Loading