Sourcemaps
Raygun will automatically give you complete stack traces and error occurrence data from your minified JavaScript. We support both public and private source maps.
Minified files save space and make loading of pages faster, but sometimes make it hard for Raygun to pull out the error details and show a readable stack trace. To counteract this we need customers to upload their source maps to Raygun or make them available for us to fetch from their application, so we can do some magic to pull out the right information and show a readable stacktrace.
Some security conscious companies will not want to upload source maps to us or make them publicly accessible. For this we can support private source maps which solves this issue for them. Refer to the specific language provider documentation for more information on source maps as they are only used with certain languages and frameworks.
When dealing with minified JavaScript the information supplied in stack traces does not provide accurate line/column information to track down the source of the error. To deal with this you can utilize a source map which will provide the translation between the original JavaScript source and the minified version.
What you need
Raygun requires the following to complete the decoding process:
- Payloads sent from a valid JS provider. This includes Raygun4JS and Raygun4Node (if enabled within the JS source map center).
- Valid line/column numbers to be present in at least one line of the stack trace
- An accessible minified JavaScript file as specified in the stack trace. This is either downloaded or retrieved from the source map center to determine if there is map file present
- The map file to be correctly indicated in the minified JavaScript file using a footer comment (i.e.
//# sourceMappingURL=index.min.js.map
). Note: See the instructions below for how to work around this if the footer comment is not generated during your build. - An accessible source map file (either publicly hosted or uploaded to the source map center)
- To provide inline code snippets we also require the sources content field of the map file to be present or for the map file to point to publicly accessible unminified source JavaScript files. If neither of these are provided decoding of line numbers and variable names can still succeed but no inline code will be displayed with the stack trace
note: Sourcemaps do not support custom providers names. To use sourcemaps with a custom provider, you will need to specify an appropriate client name matching raygun4js (raygun-js
) or raygun4node (raygun-node
). See the API reference here.
Recommended minifier tooling
We recommend using UglifyJS2 to generate a source map file.
Both the minified JS and its map file should use relative pathing. Look into the -p and --source-map-root options.
Uploading JavaScript files
If you do not wish to have publicly accessible JavaScript files you can upload them directly to Raygun from the JS Source Map Center. This is within the Application Settings submenu on the main dashboard.
Within the Source Map Center you can upload files and label them with the URL they would normally be accessed from. When a JavaScript error is mapped we will use the files you uploaded instead of trying to access them from your servers.
In addition to the upload page we offer an API endpoint, the URL is displayed in the Source Map Center and is specific to each application.
The endpoint expects form data with the following fields:
file
– the JS file to be uploaded.
url
– the url the file will be mapped to.
The request must be authenticated by a user who has access to an application. Either by adding either a basic auth header using an email/password, or an External Access Token, generated on the user's settings page, which is appended as a querystring parameter (eg. "https://app.raygun.com/upload/jssymbols/MyAppId?authToken=MyExternalAuthToken"
).
We recommend creating another Raygun user with a generic email e.g. external.api@mycompany.com. Then use either the basic auth or a new external token from this user's settings as a means of authentication.
note: It may take up to 2 hours for your sourcemaps to be processed and your errors to start mapping correctly.
Here is a cURL example request using Basic Authorization:
curl
-X POST
-u email@example.com:password
-F "url=http://example.com/myjs.min.js"
-F "file=@C:\website\js\myjs.min.js"
https://app.raygun.com/upload/jssymbols/MyAppId
Here is an example using the Grunt plugin grunt_http_upload using an External Access Token:
http_upload: {
your_target: {
options: {
url: 'https://app.raygun.com/upload/jssymbols/MyAppId?authToken=MyExternalAuthToken',
method: 'POST',
data: {
url: 'http://example.com/myjs.min.js'
}
},
src: 'C:\website\js\myjs.min.js',
dest: 'file'
}
}
Here is an example using PowerShell:
$multipartContent = [System.Net.Http.MultipartFormDataContent]::new()
$stringHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data")
$stringHeader.Name = "url"
$StringContent = [System.Net.Http.StringContent]::new("https://test.raygun.io/scripts/test.min.js.map")
$StringContent.Headers.ContentDisposition = $stringHeader
$multipartContent.Add($stringContent)
$multipartFile = 'test.min.js.map'
$FileStream = [System.IO.FileStream]::new($multipartFile, [System.IO.FileMode]::Open)
$fileHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data")
$fileHeader.Name = "file"
$fileHeader.FileName = "test.min.js.map"
$fileContent = [System.Net.Http.StreamContent]::new($FileStream)
$fileContent.Headers.ContentDisposition = $fileHeader
$multipartContent.Add($fileContent)
$body = $multipartContent
$response = Invoke-RestMethod 'http://app.raygun.com/upload/jssymbols/appIdentifier?authToken=XXX' -Method 'POST' -Headers $headers -Body $body
$response | ConvertTo-Json
Private source maps setup example
To get started you will need a tool which can help produce a source map as part of producing a minified version of your JavaScript. We personally use UglifyJS and find it to be a great tool. To install it you will need Node.js installed, you can then run:
npm install uglify-js -g
This will install Uglify so that it's globally available which is what you will typically want.
To produce minified JavaScript we can simply run
uglifyjs example.js -o example.min.js
To produce minified JavaScript with a mapping file we can run
uglifyjs example.js -o example.min.js --source-map example.min.js.map
This produces the minified file "example.min.js" as well as a source map file "example.min.js.map"
If you deploy the minified file example.min.js to production but do not wish for any or some of these files to be publicly accessible you will need to upload these files to Raygun to get source mapped stacktraces.
You can do this from within Raygun by accessing the JS Source Map Center in the Application Settings sub menu.
Here you can simply select the minified, mapping and source files to upload. After uploading you can type the URL the resource is mapped to so when our source mapping process tries to retrieve the file, it uses the file you uploaded instead.
You can determine the URL to enter by looking at the map file's "file" and "sources" properties. You can then prepend the URL of the minified file on production minus the filename.
For instance, if we have a minified file example.min.js located at http://example.com/scripts/example.min.js
and we upload example.min.js, example.js and example.min.js.map to Raygun. We would assign their URLs like this:
After the files are uploaded they will be used in the source mapping processes. This is what your mapped stacktrace will look like:
Authentication key
Raygun allows you to configure an authentication key header for source map asset requests. The purpose of the header is to allow Raygun to request your privately hosted files whilst protecting them from unwanted access by adding a check to your server.
Setting up the authentication key header:
The authentication key is configured in your source maps settings in the source map centre.
Here is an example of how the header can be used, using node.js:
router.get('/scripts/:fileName.map', (req, res, next) => {
if (req.header('Raygun-SourceMap-Auth') === SourceMapCenterAuthKey) {
const mapPath = path.join(__dirname, `/scripts/${req.params.fileName}.map`);
res.sendFile(mapPath, {}, err => {
console.error(err);
next(err);
});
}
else {
res.sendStatus(404);
}
});
Using private source maps for hybrid mobile apps
With many mobile applications being written in JavaScript within containers such as Apache Cordova, using Raygun4js is an appealing way to track errors across all platforms. However, as the application is hosted on the phone instead of a website with a static URL you may find that error stacktraces contain files paths which differ across different platforms and devices. This introduces some difficulty when trying to utilize source maps which require the minified and mapping files to be uploaded and labeled with exactly the same URLs as would appear in a stacktrace.
For this reason we recommend adding a handler to the raygun4js provider to rewrite file's URLs before the error is reported back to Raygun. This means that errors will be reported from the same domains and not unique domains for every platform or device.
An example of such a handler is shown below:
//handler method
var beforeSend = function(payload) {
var stacktrace = payload.Details.Error.StackTrace;
var normalizeFilename = function(filename) {
var indexOfJsRoot = filename.indexOf("js");
return 'http://normalizedurl.com/' + filename.substring(indexOfJsRoot);
}
for(var i = 0 ; i < stacktrace.length; i++) {
var stackline = stacktrace[i];
stackline.FileName = normalizeFilename(stackline.FileName);
}
return payload;
}
//attaching the handler to the Raygun provider
Raygun.onBeforeSend(beforeSend);
This handler removes the platform and device specific paths from the URLs present in an error's stacktrace.
For instance an error occuring on an Android phone within the file
file://android_asset/www/js/myjsfile.min.js
and on an iOS device within the file
file://accounts/1234/appdata/b12b33f1-519b-4d1c-8d68-315513ecbac1/www/js/myjsfile.min.js
will both report
http://normalizedurl.com/js/myjsfile.min.js
as the URL of the file within which the error occurred.
This allows the use of a single set of sourcemaps for source mapping across all deployments.
Notes:
There could be up to a 2 hour delay before the mapping process starts utilizing any uploaded files. To reprocess any errors which occur during this time simply hit the "Re-process this error for Source Maps" button on an error instance.
Code snippet insertion is only available if there are less than 50 source files referenced in the map file.
Using Private Source Maps with Node.js apps
Raygun supports source mapping for Node.js stacktraces which include column numbers. To enable this feature simply upload your map files as per the instructions on this page and enable the processing of Node.js errors with this setting in Raygun.
Managing files in the JavaScript Source Map Center
Files in the JavaScript Source Map Center can be managed via a few API calls.
A GET request to https://app.raygun.com/jssymbols/[applicationIdentifier]
will return a JSON object listing all files within the center. eg.
curl
-X GET
-u my@email.com:mypassword
https://app.raygun.com/jssymbols/[applicationIdentifier]
Returns:
{
"Count": totalNumberOfItems,
"Items": [
{
"Url": "https://urlOfItem",
"FileName": "fileName.js",
"UploadedOn": "2016-01-01..."
},
...
]
}
A DELETE request to https://app.raygun.com/jssymbols/[applicationIdentifier]/all
will remove all files within the center. eg.
curl
-X DELETE
-u my@email.com:mypassword
https://app.raygun.com/jssymbols/[applicationIdentifier]/all
A DELETE request to https://app.raygun.com/jssymbols/[applicationIdentifier]
will remove files with the specified URLS from the center. eg.
curl
-X DELETE
-u my@email.com:mypassword
-F "url=https://example.com/js/myjs.min.map"
https://app.raygun.com/jssymbols/[applicationIdentifier]
All requests use the same authentication methods as the upload call (Basic Authentication and Token Authentication).
Associate a map file with a minified source file
If your generated minified file does not include the //# sourceMappingURL=...
pragma at the end of the script, you can upload the .map
file to the Source Map Center and set the URL to be the original minified source file URL.
For example:
- Source file:
http://example.com/dist/index.min.js
- Map file:
http://example.com/src/index.min.js.map
- Upload the map file
- Set the URL field to be the source file URL
Troubleshooting
If source mapping fails, you should see one or both of the sections below. If you don't see these sections, try clicking "Re-process this error for Source Maps":
The "minified files could not be obtained" section lists the files we were unable to locate after checking both the URL and the JS Source Map Center. Please make sure that either:
- The file is accessible at the given URL
- The file has been uploaded to the JS Source Map Center, with the URL field exactly matching what we display in the stack trace.
If the listed file is not a web address (e.g the first file in the screenshot above), just enter whatever is displayed (a file path in this case) into the "URL" field in the JS Source Map Center for that file e.g:
If you've checked that the JS Source Map Center URLs match the list of unobtained files in the stack trace, and source mapping still doesn't work, please reach out to our engineering support team via the contact page, or click "Contact Raygun" in the app.