Debugging Production JavaScript

Eric Elliott
Sep 5, 2016 · 9 min read

by Todd H. Gardner

Image for post
Image for post

Editor’s Note: The hardest bugs to fix are the bugs you never see. You may not see them, but perhaps thousands, even millions of your users do see them every day, in the middle of workflows that are critical to their success with your app.

There are lots of solutions designed to fix this problem, but few error tracking services provide as much context and clarity for JavaScript errors as TrackJS. Flux & Redux users in particular will appreciate TrackJS context features.

Once in a while we find products or services that we highly recommend and invite the company behind them to participate in a sponsored post. I’m pleased to bring you this sponsored post for TrackJS by Todd H. Gardner.

I enjoyed reading it, and learned a thing or two. I think you will, too.

The web can be a hostile place and our JavaScript apps will inevitably break for some users. Browser changes, invasive plugins, unstable networks, or just plain bugs — something is going to go wrong. When it does, we need to be ready. We need to know what went wrong and how to fix it or our users just won’t come back.

JavaScript Error Monitoring from TrackJS is a great option to get visibility into your production environment fast. Teams at Microsoft, Twitter, StackOverflow, and Atlassian use TrackJS to quickly identify and triage user bugs. In this article, we’ll look at the basics of monitoring our JavaScript apps and how to start debugging with the errors reported. Then we’ll take a look at the most common causes of errors that occur and how to identify them.

Logging Our First Error

If you haven’t already, grab a free trial account of TrackJS and it will show you an installation snippet that looks something like this:

This doesn’t have to be in the `<head>`, but it should probably be the first script on the page. Otherwise, any errors that happen before we can capture it would never get reported! There is also an NPM package so that you could bundle their script with the rest of your app.

If you’d prefer to do-it-yourself without TrackJS, you should start with attaching to `window.onerror`. This global function hook is supported by all browsers (really, all of them) as is notified when the browser hits an unhandled error in any JavaScript on the page.

Posting an error with jQuery.ajax()

Newer browsers will give you an instance of `Error` with a stack trace, but many older browsers will only provide message, file, and line. Error monitoring libraries like TrackJS can improve error collection by injecting listeners more places where errors are likely to occur.

Now that we’ve got something listening to our app for errors, let’s make sure it’s working. Open up your browser console and try something like this:

You should see an error being sent off in your Network debugger, and if you’re using TrackJS it should pop into your Recent error list.

Image for post
Image for post

You may be wondering why we needed to put a `setTimeout()` in our example. Most browser debuggers create a sandbox around their console to prevent errors from leaking into the page. However, in our case, that’s exactly what we’re trying to do! The `setTimeout()` allows us to inject our error into the page to be executed on the next event loop cycle.

The Anatomy of an Error

Wait, what about the stack? Strangely enough, an error stack trace is a non-standard property! Internet Explorer older than 10 and Safari older than 6 do not even include it. Even for new browsers, the structure and syntax of the stack trace is different.

TrackJS will automatically normalize the structure of your stack traces. If you are building something yourself, you should take a look at StackTrace JS, which can help give you similar capability.

Network Errors

Unfortunately, there is not a standard way to describe a network error. TrackJS records network errors as the METHOD and URL of the network request, as well as the status code of the response. To protect sensitive data, it does not capture request or response bodies or headers. If you are customizing your own tools, you may want to consider capturing this depending on the context of your application

Tip: Since TrackJS records messages passed into the console, you could add your own request and response bodies and headers by writing them out into the console.

Console Errors

TrackJS will automatically record messages passed into `console.error`. If you want to do this, or add additional context to things passed into the console, you can wrap the console functions.

Enhancing Error Context

Image for post
Image for post

Telemetry are all the things that your application is doing before an error happens. Things like changing state, issuing network requests, or responding to user actions. The TrackJS agent is recording this telemetry so that it can present a timeline of activity leading up to a problem. It’s a really great way to visualize how an error occurred.

If you are using an architectural pattern like Flux, this can be a really powerful way to visualize state transitions leading up to an error.

Image for post
Image for post

Getting Past `Script Error`

Script Error Sucks. There is no context. No clues. No indication of how your users are impacted. We need to get it out of the way fast to understand our real problems.

The most compatible way to handle Script Error is to load scripts from the same origin as the page. You may lose some performance benefits of a CDN and multiplexed loading, so may want to consider doing this temporarily or for only a fraction of your traffic. For example, you could have 10% of your traffic load scripts from the same origin and use this traffic for error monitoring.

For a more thorough discussion and the causes and other solutions, check out the TrackJS Blog on Script Error.

Identifying and Fixing Errors

Generalized Error Causes

Browser Compatibility Error

Symptoms: Low cardinality of browsers affected. If there is a small number of browsers reporting the error, and you have not specifically tested the application with the browsers.

Debug With: Use developer tooling provided by the browser reporting errors to debug compatibility. If the browser does not provide developer tooling, you can always fallback to `console` and `alert`.

User Configuration Error

Symptoms: Errors originate from unrecognizable sources not part of your original application.

Debug With: Expand your error context to record the contents of the document and scripts as part of error capture. Compare these with the expected application to determine if they have been manipulated.

Network Resilience Errors

At the 2016 Google I/O conference, Ilya Grigorik shared metrics that 1%-10% of network requests may fail from a mobile device due to connectivity or processing constraints.

Symptoms: Reports of `TypeError` and `ReferenceError` may indicate that foundational interfaces are not available. For example, `$ is not defined`. These can arise if the scripts that provide these foundations fail to load.

Debug With: Check the load and presence of assets with error reports. Explore how your application loads if key assets are removed. If possible, construct reasonable fallbacks and safety check for types before using them. Progressive Enhancement is still the best path.

Integration Errors

Symptoms: Errors that begin reporting as of a specific date and time that does not correspond to your own release schedule. When integrating with third parties, note that their changes can impact the experiences of your customers.

Debug With: This should be debuggable with standard developer tools, like the Chrome Developer Tools, run in your application.

Logical Application Errors

Symptoms: Various

Debug: Record customized context about your application to better understand the current state and timing.

Go Forth and Build Better Apps!

If you want some more information and demos of debugging JavaScript errors, check out my talk from NDC Oslo on JavaScript Forensics and how to triage some specific bugs with Chrome Developer Tools.

It’s amazing how much better our apps can be with a little feedback from our production environments. Usually there are only a handful of subtle problems keeping applications from being great. I’d love to help make yours great and crush a few bugs. Grab a free 30 days of TrackJS and let’s build a better web.

Todd H. Gardner is a JavaScript developer and the co-founder of TrackJS JavaScript Error Monitoring, where he promotes improving the quality and maintainability of JavaScript web applications. When he’s not nerding-out at a tech-conference, you can find him sampling the latest restaurants and bars in Minneapolis, Minnesota.

JavaScript Scene

JavaScript, software leadership, software development, and…

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store