-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
feat(core): Add default behaviour for rewriteFramesIntegration
in browser
#11535
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
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,45 +1,61 @@ | ||
import type { Event, IntegrationFn, StackFrame, Stacktrace } from '@sentry/types'; | ||
import { basename, relative } from '@sentry/utils'; | ||
import type { Event, StackFrame, Stacktrace } from '@sentry/types'; | ||
import { GLOBAL_OBJ, basename, relative } from '@sentry/utils'; | ||
import { defineIntegration } from '../integration'; | ||
|
||
type StackFrameIteratee = (frame: StackFrame) => StackFrame; | ||
|
||
const INTEGRATION_NAME = 'RewriteFrames'; | ||
|
||
interface RewriteFramesOptions { | ||
/** | ||
* Root path (the beginning of the path) that will be stripped from the frames' filename. | ||
* | ||
* This option has slightly different behaviour in the browser and on servers: | ||
* - In the browser, the value you provide in `root` will be stripped from the beginning stack frames' paths (if the path started with the value). | ||
* - On the server, the root value will only replace the beginning of stack frame filepaths, when the path is absolute. If no `root` value is provided and the path is absolute, the frame will be reduced to only the filename and the provided `prefix` option. | ||
* | ||
* Browser example: | ||
* - Original frame: `'http://example.com/my/path/static/asset.js'` | ||
* - `root: 'http://example.com/my/path'` | ||
* - `assetPrefix: 'app://'` | ||
* - Resulting frame: `'app:///static/asset.js'` | ||
* | ||
* Server example: | ||
* - Original frame: `'/User/local/my/path/static/asset.js'` | ||
* - `root: '/User/local/my/path'` | ||
* - `assetPrefix: 'app://'` | ||
* - Resulting frame: `'app:///static/asset.js'` | ||
*/ | ||
root?: string; | ||
|
||
/** | ||
* A custom prefix that stack frames will be prepended with. | ||
* | ||
* Default: `'app://'` | ||
* | ||
* This option has slightly different behaviour in the browser and on servers: | ||
* - In the browser, the value you provide in `prefix` will prefix the resulting filename when the value you provided in `root` was applied. Effectively replacing whatever `root` matched in the beginning of the frame with `prefix`. | ||
* - On the server, the prefix is applied to all stackframes with absolute paths. On Windows, the drive identifier (e.g. "C://") is replaced with the prefix. | ||
*/ | ||
prefix?: string; | ||
|
||
/** | ||
* Defines an iterator that is used to iterate through all of the stack frames for modification before being sent to Sentry. | ||
* Setting this option will effectively disable both the `root` and the `prefix` options. | ||
*/ | ||
iteratee?: StackFrameIteratee; | ||
} | ||
|
||
const _rewriteFramesIntegration = ((options: RewriteFramesOptions = {}) => { | ||
/** | ||
* Rewrite event frames paths. | ||
*/ | ||
export const rewriteFramesIntegration = defineIntegration((options: RewriteFramesOptions = {}) => { | ||
const root = options.root; | ||
const prefix = options.prefix || 'app:///'; | ||
|
||
const iteratee: StackFrameIteratee = | ||
options.iteratee || | ||
((frame: StackFrame) => { | ||
if (!frame.filename) { | ||
return frame; | ||
} | ||
// Determine if this is a Windows frame by checking for a Windows-style prefix such as `C:\` | ||
const isWindowsFrame = | ||
/^[a-zA-Z]:\\/.test(frame.filename) || | ||
// or the presence of a backslash without a forward slash (which are not allowed on Windows) | ||
(frame.filename.includes('\\') && !frame.filename.includes('/')); | ||
// Check if the frame filename begins with `/` | ||
const startsWithSlash = /^\//.test(frame.filename); | ||
if (isWindowsFrame || startsWithSlash) { | ||
const filename = isWindowsFrame | ||
? frame.filename | ||
.replace(/^[a-zA-Z]:/, '') // remove Windows-style prefix | ||
.replace(/\\/g, '/') // replace all `\\` instances with `/` | ||
: frame.filename; | ||
const base = root ? relative(root, filename) : basename(filename); | ||
frame.filename = `${prefix}${base}`; | ||
} | ||
return frame; | ||
}); | ||
const isBrowser = 'window' in GLOBAL_OBJ && GLOBAL_OBJ.window !== undefined; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. l: Can we just compress this to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. typescript sadness but yeah |
||
|
||
const iteratee: StackFrameIteratee = options.iteratee || generateIteratee({ isBrowser, root, prefix }); | ||
|
||
/** Process an exception event. */ | ||
function _processExceptionsEvent(event: Event): Event { | ||
|
@@ -81,9 +97,53 @@ const _rewriteFramesIntegration = ((options: RewriteFramesOptions = {}) => { | |
return processedEvent; | ||
}, | ||
}; | ||
}) satisfies IntegrationFn; | ||
}); | ||
|
||
/** | ||
* Rewrite event frames paths. | ||
* Exported only for tests. | ||
*/ | ||
export const rewriteFramesIntegration = defineIntegration(_rewriteFramesIntegration); | ||
export function generateIteratee({ | ||
isBrowser, | ||
root, | ||
prefix, | ||
}: { | ||
isBrowser: boolean; | ||
root?: string; | ||
prefix: string; | ||
}): StackFrameIteratee { | ||
return (frame: StackFrame) => { | ||
if (!frame.filename) { | ||
return frame; | ||
} | ||
|
||
// Determine if this is a Windows frame by checking for a Windows-style prefix such as `C:\` | ||
const isWindowsFrame = | ||
/^[a-zA-Z]:\\/.test(frame.filename) || | ||
// or the presence of a backslash without a forward slash (which are not allowed on Windows) | ||
(frame.filename.includes('\\') && !frame.filename.includes('/')); | ||
|
||
// Check if the frame filename begins with `/` | ||
const startsWithSlash = /^\//.test(frame.filename); | ||
|
||
if (isBrowser) { | ||
if (root) { | ||
const oldFilename = frame.filename; | ||
if (oldFilename.indexOf(root) === 0) { | ||
frame.filename = oldFilename.replace(root, prefix); | ||
} | ||
} | ||
} else { | ||
if (isWindowsFrame || startsWithSlash) { | ||
const filename = isWindowsFrame | ||
? frame.filename | ||
.replace(/^[a-zA-Z]:/, '') // remove Windows-style prefix | ||
.replace(/\\/g, '/') // replace all `\\` instances with `/` | ||
: frame.filename; | ||
const base = root ? relative(root, filename) : basename(filename); | ||
frame.filename = `${prefix}${base}`; | ||
} | ||
} | ||
|
||
return frame; | ||
}; | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I re-shuffled the code a bit so we can test it more easily