Capturing Client Side JS Errors on AWS

Donnie - 04 Apr 2012

I saw a post go by on Hacker News this morning discussing capturing and reporting on client side errors. We have been doing this for a long time and I wanted to share our approach.


Quick background, we have two major types of javascript that our customers and partners may use: analytics tags and ad tags. Both tags are javascript and share the same error capture code.

Another quick note is that we run on Amazon Web Services so this approach is based on some of these services including S3, CloudFront and EMR.


Our client side JS is compiled from Coffeescript. I've created a couple of gists to show you what the error logging code looks like in Coffeescript.

# Simple error log that uses pixels with a query string to send error information
class ErrorLog
  @log: (context, error_data, loggers...) ->
    logger.log(context, error_data) for logger in loggers
class BaseLogger
  @map_error_data: (error_data, seperator, func = (val) -> val) ->
    ("#{k}=#{func(v)}" for k, v of error_data).join(seperator)
class PixelLogger extends BaseLogger
  @http_host: "http://YOUR_HTTP_HOST"
  @https_host: "https://YOUR_HTTPS_HOST"
  @set_pixel_path: (pixel_path) ->
    @pixel_path = pixel_path
  @log: (context, error_data) ->
    log_path = if == "https:" then @https_host else @http_host
    msg = @map_error_data(error_data, "&", encodeURIComponent)
    pixel = new Image(1,1)
    pixel.src = "#{log_path}/#{@pixel_path}?#{msg}"
class ConsoleLogger extends BaseLogger
  @log: (context, error_data) ->
    msg = @map_error_data(error_data, ", ")
    console.log(msg) if console? && console.log?
# used for local testing 
class LocalLogger extends BaseLogger
  @errors: []
  @log: (context, error_data) ->
class AdTagErrorLog 
  @log : (context, error)->
    error_data = {
      tag_type:   "ad_tags",
      ref:        context.doc.referrer,
      error:      error
    ErrorLog.log(context, error_data, PixelLogger)
    if( == true) = LocalLogger
      ErrorLog.log(context, error_data, ConsoleLogger, LocalLogger)
#... snipped for brevity
  context = new Context(document, window)
  new AdTags(context).execute()
catch e
  AdTagErrorLog.log(new Context(document, window), e)


The example shows our ad tags trying to execute surrounded by a try/catch that captures the error and eventually results in loading an image appending the relevant error metadata.

AWS Details

The image that is loaded actually lives on CloudFront. The CloudFront distribution is setup with logging which means that requests are logged and delivered to a specified S3 bucket (usually within 24 hours). Every day we run an EMR job against the CloudFront request logs that generates a report summarizing the errors. And that is it. Pretty simple and this approach has worked for us.

Pre-emptive "this isn't perfect" response

Some of you may be thinking, "you may not get all requests!". CloudFront logs are not supposed to be used for 100% accurate reporting (although nothing is really 100%). In our case, we don't need to capture all errors rather we are looking for directional information.

comments powered by Disqus