Skip to main content
Marcel Krčah

Tracking AWS Lambda errors with Sentry (and CloudFormation)

Published on , in , ,

I enjoy working with Sentry for error tracking: I have a real-time overview of errors, I set up various alerts, and I use it in both backend and frontend systems. Now, how to setup Sentry for AWS Lambda that is provisioned by AWS CloudFormation?

There are currently two ways to do it: wrapping up the Lambda handler or using AWS Lambda layers. I focus on the Lambda handler here.

Step 1: Wrapping up handler #

Following the Sentry docs on integrating with AWS Lambda, this step was straightforward. Here's an example of a wrapped Node handler:

  1. Install Sentry lib:

    npm install --save @sentry/serverless
  2. Wrap the Lambda handler:

    const Sentry = require("@sentry/serverless")
    
    Sentry.AWSLambda.init({
      dsn: "<Your Sentry DSN>",
      // ...
    })
    
    exports.handler = Sentry.AWSLambda.wrapHandler(async (event, context) => {
      // Your handler code
    })

In the current version of the library (6.2.3), I had to tweak the setup a bit to make it work with WebPack and Typescript.

Step 2: Setting up CloudFormation #

Now, Sentry supports monitoring errors per environment, such as dev, acceptance, or production. I like that because I have more control over errors in different environments. The environment is set up in the Lambda itself:

Sentry.AWSLambda.init({
  dsn: "<Your Sentry DSN>",
  environemnt: "acceptnace", // <--- here we supply the lambda environment
})

Now, how to supply the lambda environment using CloudFormation? It turns out, this can be achieved with parameters.

(In the steps below, I also use AWS Parameter Store to fetch the Sentry DSN instead of having the DSN hardcoded in the Sentry init):

  1. Setup the Cloudformation template: add an environment parameter and Sentry DSN parameter

    # content of template.yml
    AWSTemplateFormatVersion: '2010-09-09'
    Transform: AWS::Serverless-2016-10-31
    
    Parameters:
      # here we define that the CloudFormation stack accepts environment parameter
      LambdaEnvironment:
         Type: String
         AllowedValues:
           - dev
           - acc
           - prod
    
      # here we fetch the sentry URL from SSM Parameter store
      SentryDSN:
         Type: AWS::SSM::Parameter::Value<String>
         Default: '/<your-path-to-sentry-dsn-ssm-parameter>'
    
    Resources:
    	ExampleLambda:
             Type: AWS::Serverless::Function
             Properties:
               Environment:
                 # here we supply sentry dsn & lambda environment to lambda
                 Variables:
                   SENTRY_DSN: !Ref SentryDSN
                   LAMBDA_ENVIRONMENT: !Ref LambdaEnvironment
             Policies:
                 # we need to allow reads from SSM parameter store
                - SSMParameterReadPolicy:
                  ParameterName: '/<your-path-to-sentry-dsn-ssm-parameter>'
             #CodeUri, Events, etc...
  2. In Lambda, read from the env vars instead:

    Sentry.AWSLambda.init({
      dsn: process.env.SENTRY_DSN,
      environemnt: process.env.LAMBDA_ENVIRONMENT,
    })
  3. When deploying the CloudFormation stack in a CI pipeline, supply --parameter-overrides argument to aws cloudformation deploy:

    aws cloudformation deploy --template-file template.yml  \
    	--parameter-overrides "LAMBDA_ENVIRONMENT=acc" \
    	# ... other args & options ...

This should be it 🎉.

Sidenote on AWS Lambda logs & CLI #

Speaking of errors, it turns out one can tail aws logs via a CLI using aws logs. Plus, there's no need to specify the log stream, which is handy:

#  print all log groups
aws logs describe-log-groups

# tail logs for lambda example-lambda since 1 day ago
aws logs tail /aws/lambda/example-lambda --since 1d --follow |

I like to combine aws logs with grep context lines to search for errors with the surrounding context:

# show all ERROR log messages. For each ERROR msg, show 10 preceding messages
aws logs tail /aws/lambda/example-name --since 1d | grep -B 10 'ERROR'

This blog is written by Marcel Krcah, an independent consultant for product-oriented software engineering. If you like what you read, sign up for my newsletter