Skip to content

Commit 51783cb

Browse files
committed
Match on the entire backtrace path line
On the `SAFARI_FF_PATH` regular expressions, match the whole line from beginning to end, repeating the matching at the beginning of the line that is done by the `IS_SAFARI_FF` regular expression. Split the `CHROME_PATH` regular expression into two variants of it, with and without a function name. When the function name is present, the path appears in parenthesis, making it easier to delimit it. Attempt to match the version where the path is in parenthesis first, then the version where the path stands alone. On both variants, like with `SAFARI_FF_PATH`, match the whole line from beginning to end. This fixes a bug where the regular expressions would only match the last space-separated segment of a path containing spaces.
1 parent e84cfe9 commit 51783cb

File tree

3 files changed

+79
-9
lines changed

3 files changed

+79
-9
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
bump: patch
3+
type: fix
4+
---
5+
6+
Fix matching on backtrace paths containing spaces.
7+
8+
When using `matchBacktracePaths`, when a backtrace line path contains a space, it will now match correctly against the whole path.

packages/javascript/src/__tests__/span.test.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,35 @@ describe("Span", () => {
8989
})
9090
})
9191

92+
it("cleans Chrome-style backtraces with spaces in the path", () => {
93+
const error = new Error("test error")
94+
error.stack = [
95+
"Error: test error",
96+
" at Foo (http://localhost:8080/assets with space/app/bundle.js:13:10)",
97+
" at Bar (http://localhost:8080/assets with space/app/bundle.js:17:10)",
98+
" at track (http://thirdparty.app/script.js:1:530)",
99+
" at http://localhost:8080/assets with space/app/bundle.js:21:10"
100+
].join("\n")
101+
102+
span.setError(error)
103+
span.cleanBacktracePath(
104+
[new RegExp("/assets with space/(app/.*)$")].map(toBacktraceMatcher)
105+
)
106+
107+
const backtrace = span.serialize().error.backtrace
108+
expect(backtrace).toEqual([
109+
"Error: test error",
110+
" at Foo (app/bundle.js:13:10)",
111+
" at Bar (app/bundle.js:17:10)",
112+
" at track (http://thirdparty.app/script.js:1:530)",
113+
" at app/bundle.js:21:10"
114+
])
115+
116+
expect(span.serialize().environment).toMatchObject({
117+
backtrace_paths_matched: "3"
118+
})
119+
})
120+
92121
it("cleans Safari/FF-style backtraces", () => {
93122
const error = new Error("test error")
94123
error.stack = [
@@ -116,6 +145,33 @@ describe("Span", () => {
116145
})
117146
})
118147

148+
it("cleans Safari/FF-style backtraces with spaces in the path", () => {
149+
const error = new Error("test error")
150+
error.stack = [
151+
"Foo@http://localhost:8080/assets with space/app/bundle.js:13:10",
152+
"Bar@http://localhost:8080/assets with space/app/bundle.js:17:10",
153+
"track@http://thirdparty.app/script.js:1:530",
154+
"@http://localhost:8080/assets with space/app/bundle.js:21:10"
155+
].join("\n")
156+
157+
span.setError(error)
158+
span.cleanBacktracePath(
159+
[new RegExp("/assets with space/(app/.*)$")].map(toBacktraceMatcher)
160+
)
161+
162+
const backtrace = span.serialize().error.backtrace
163+
expect(backtrace).toEqual([
164+
"Foo@app/bundle.js:13:10",
165+
"Bar@app/bundle.js:17:10",
166+
"track@http://thirdparty.app/script.js:1:530",
167+
"@app/bundle.js:21:10"
168+
])
169+
170+
expect(span.serialize().environment).toMatchObject({
171+
backtrace_paths_matched: "3"
172+
})
173+
})
174+
119175
it("concatenates all match groups", () => {
120176
const error = new Error("test error")
121177
error.stack = [

packages/javascript/src/span.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -186,15 +186,22 @@ function extractPath(backtraceLine: string): string | undefined {
186186
// A Chrome backtrace line always contains `at` near the beginning,
187187
// preceded by space characters and followed by one space.
188188
const IS_CHROME = /^\s*at\s/
189+
189190
// In a Chrome backtrace line, the path (if it is available)
190-
// is located, usually within parentheses, after the "@" towards the
191-
// end of the line, along with the line number and column number,
192-
// separated by colons. We check for those to reject clear non-paths.
193-
const CHROME_PATH = /at(?:\s.*)?\s\(?(.*):\d*:\d*\)?$/i
191+
// is located after the "at" towards the end of the line, along with
192+
// the line number and column number, separated by colons.
193+
// When the function name is available, the path is enclosed in
194+
// parentheses. When there is no function name, the path comes
195+
// immediately after the "at".
196+
// We check for the line and column numbers to reject clear non-paths.
197+
const CHROME_PATH_WITH_FUNCTION_NAME = /^\s*at(?:\s[^\(]+)?\s\((.*):\d+:\d+\)$/
198+
const CHROME_PATH_WITHOUT_FUNCTION_NAME = /^\s*at\s(.*):\d+:\d+$/
194199

195200
if (backtraceLine.match(IS_CHROME)) {
196-
const match = backtraceLine.match(CHROME_PATH)
197-
return match ? match[1] : undefined
201+
return (
202+
backtraceLine.match(CHROME_PATH_WITH_FUNCTION_NAME)?.[1] ??
203+
backtraceLine.match(CHROME_PATH_WITHOUT_FUNCTION_NAME)?.[1]
204+
)
198205
}
199206

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

210217
if (backtraceLine.match(IS_SAFARI_FF)) {
211-
const match = backtraceLine.match(SAFARI_FF_PATH)
212-
return match ? match[1] : undefined
218+
return backtraceLine.match(SAFARI_FF_PATH)?.[1]
213219
}
214220
}

0 commit comments

Comments
 (0)