I have been doing web app error tracking and debugging wrong all these years

Protecting the source maps and improving web app debugging experience in production

Today my day started with an email of an exception report originating from the frontend of the GO2CINEMA:

ReferenceError

The email is produced by sentry.io and it includes additional information, such as the request URL, user’s IP, browser information, request time, etc.

Disclaimer: As I think of what I am going to write next, this starts to sound more and more as a sentry.io ad. I have no affiliate with sentry.io other than that I am their customer.

Unfortunately, the stack trace itself references the minimized code. This is because the error happened in the production environment where the code is minimized and source maps have not been published due to IP considerations. Nothing unusual.

The usual route to identify the problem is therefore to spin-up the development environment and find a way to replicate the error with the little information thats available. Thats what I have been doing all these years. That said, errors in production are not that common (the secret sauce is a lot of unit and integration tests) and I was not bothered enough to seek for a better solution.

This time was different. I couldn’t replicate the issue and I was in no mood to go through the obscure stack trace. Surely there must be a better way.

Well, there is.

Securing access to the source maps

The most simple solution is to upload the source maps to the production and restrict access using token authentication, e.g.

app.get(/\.js\.map/, (req, res, next) => {
if (req.headers['x-source-map-access-token'] !== 'secret-value') {
res
.status(401)
.send('Authentication access token is required to access the source map.');
return;
}
next();
});

At the very least, now if you encounter the error in production, you are able to inject the required header to your browser request and analyse the error stack trace in production.

This is good, but it does not solve the problem of error reporting.

The rest of the article is sentry.io specific.

Providing source maps to Sentry.io service

Sentry.io is an open-source error tracking agent/ service that works server-side and in browser. I am using sentry.io for all the key Node.js services – it does the job. More recently, I enabled it on the GO2CINEMA website. However, as I started to get the error messages about the frontend the lack of the source maps became a big issue. Turns out that sentry.io thought about it.

Sentry.io documents two ways to share source maps with the agent. First, is what I already presented – using x-sentry-token header to grant access just to the sentry.io agent. It works. However, there is even a better way – you can upload source maps to sentry.io in your CI/CD pipeline. This is what I have opted in. I simply generate a RELEASE_ID that is passed to the docker image and used to initialise the Raven client.

# The CD pipeline generates a RELEASE_ID
- apt-get update -y && apt-get install -y python-pip && pip install python-ulid && export RELEASE_ID=$(python -c 'from ulid import ULID; print ULID.new().str')
- docker build --cache-from $CONTAINER_IMAGE:latest --build-arg RELEASE_ID=$RELEASE_ID -t $CONTAINER_IMAGE:$BUILD_TAG -t $CONTAINER_IMAGE:latest .
# Which is then picked up in the Dockerfile
ARG RELEASE_ID
ENV RELEASE_ID $RELEASE_ID
# Which is then picked up by the web app
import Raven from 'raven-js';
Raven.config(DSN, {
release: process.env.RELEASE_ID
});

As a final step in the CI/CD, you need to use the sentry-cli tool to upload the source files with the source map and associate them with the release ID.

Now every time Raven records an error, this error is associated with the release ID and you get a clear error report.

This got me thinking — what else I am missing out.

Going all-in Sentry.io with React, Redux and redux-saga integration

There is nothing specific about Sentry.io service to React, Redux or redux-saga. However, Sentry.io provides a clear documentation of how to integrate with React. Nevertheless, Sentry.io concept of breadcrumbs is amazing companion if you are using Redux.

You see, every Redux action is effectively a breadcrumb and there is a community created middleware (raven-for-redux) that logs the latest actions and include them with every error report as a breadcrumb trail. In practice, this allows to recreate the exact state of the application before the error occurred.

Remember that earlier list error? I couldn’t find where it originates until after I activated the breadcrumb collection. With the breadcrumbs – it was easy-peasy.

Breadcrumbs for the subject list error

Not only I know every action up to the error, I know what user interacted just before the error occurred.

Next time a user buys a cinema ticket and there is an error, I will have a clear view of how user got to that point. Oh, and as if that were not enough – sentry.io provides a way for user to provide additional feedback in case of an error which can be used to follow up with the customer by the support team.

End of the ad.

What else I have been missing out in the world of the web app error reporting, monitoring and profiling?