Debug Your Python Functions Locally


Editor’s Note: This post was originally published in January 2019 and has been updated in October 2020.

Debugging can quickly become a problem in serverless applications. As someone who benefits greatly from step-by-step debugging, I had some difficulty debugging Lambda functions efficiently. I’d get lost in the logs and found myself retrying endless permutations of parameters over and over again. Then I discovered the AWS Serverless Application Model (SAM). This Command-Line Interface (CLI) tool lets you debug your AWS Lambda functions the traditional way, providing step-by-step debugging at the per-line level.

With this new set of tools under my belt, I was able to successfully debug my Python Lambda functions locally. However, I still found myself struggling to find issues with code running in production configurations, that is, detecting and debugging failures in their native production environment. In a similar epiphany moment, we, as a team at Thundra, thought that there could be a better way of debugging AWS Lambda functions from within their native environment. That’s why we decided to build the real-time debugging for AWS Lambda functions. Thundra’s live debugging lets you tie into Lambda code running in production and debug issues at their source.

Below, I’ll cover both methods of debugging Python Lambda functions. I’ll start with a walk-through of my previous method for debugging Python functions locally with AWS SAM CLI and then explore how I was able to move to the next level with Thundra live debugging.

Debugging Lambda Functions Locally in VS Code

In order to debug these functions locally, you’ll need to install the AWS SAM CLI, which will receive most of the local testing commands we use. Let’s walk through the process step by step.

Step 1: Add a Visual Studio Code Launch Configuration

First, we need to add a launch configuration to VS Code so that we can attach the debugger to the simulated AWS runtime environment in which our functions will run. You can use the following launch configuration as a base for building your own:

{   "version": "0.2.0",   "configurations": [       {          "name": "SAM CLI Python Hello World",          "type": "python",          "request": "attach",          "port": 5890,          "host": "localhost",          "pathMappings": [              {                  "localRoot": "${workspaceFolder}",                  "remoteRoot": "/var/task"              }          ]      }  ]} 

Step 2: Install the Python Tools for Visual Studio Debug (PTVSD) Package

With our build configuration ready to go, we’ll next want to move on to the means of testing your application. If you haven’t already, install the PTVSD server into your Lambda application. You can do so by using the following command in the root directory of your Lambda application:

pip install ptvsd -t .

Step 3: Add PTVSD Code

Next, we need to invoke PTVSD so that we can connect our IDE to the running code we wish to test. To do this, add the following lines of code to the file that contains your Lambda handler:

Now that we’ve configured the debugger’s attach point, we need to add a breakpoint where we want PTVSD to stop. This should take place in your code after PTVSD is initialized:

Step 4: Invoke Your Function with the AWS SAM CLI

With everything configured, it’s time to invoke our function. We’ll use the AWS SAM CLI, as it allows us to troubleshoot locally without a deploy. Start by specifying the port that you want to connect to. You do this by specifying -d or --debug-port as arguments to the SAM CLI. Furthermore, by using the -e option, you can also specify the path of the JSON file containing a sample event, which can be provided as input to your function.

Putting everything together, we get the following command that we can use to invoke Lambda functions locally:

sam local invoke -e event.json -d 5890

When you run this command, the AWS SAM CLI sets up the environment and waits for the VS Code debugger to be attached.

Step 5: Start Debugger and Connect to PTVSD

Now we’re ready to debug! Start the debugging tool in VS Code (F5 in macOS and Windows). VS Code will then attempt to connect to the port specified in the launch configuration file. Once the IDE has connected to the simulated PTVSD run, the function will continue executing and, eventually, hit our first breakpoint.

We now have a good old step-by-step debugger waiting for us at the breakpoint we specified! You can now step into function calls, step over them, watch variables, and more—just like when we debug regular applications!

Voila! The above displays that we successfully configured VS Code and AWS SAM CLI to allow you to locally debug your Python Lambda functions. There is, however, one important point remaining, namely that when you deploy your Lambda function, you need to make sure that you have removed or commented out the following lines in your application:

ptvsd.enable_attach(address=('', 5890), 

The reason for this is that when you call ptvsd.wait_for_attach(), your Lambda function execution waits on that line and does not proceed further. Leaving this line of code in your program would cause your function’s execution to stop at that line, eventually resulting in a timeout as Lambda’s execution time thresholds are exceeded.

Live Debugging of Lambda with Thundra

Once you’ve finished local debugging, you’ll want to see your function running on AWS hardware to let you see how your function actually operates with various third-party libraries and AWS services. While the approach we followed above allows you to make good progress as you develop, at some point you’ll need the ability to troubleshoot code in its production environment.

Luckily, Thundra offers live debugging, a feature that lets you debug your functions in the AWS production environment. Below is a step-by-step guide for enabling live debugging of your AWS Lambda functions with Thundra.

Step 1: Install the Thundra Lambda Layer for Your Function

The first step to debugging your functions online is to set up Thundra’s Lambda layer for your function. The Thundra Lambda layer includes your libraries and functionality, tying your application together with its dedicated Thundra dashboard. Modify your template.yml file to use the Thundra Lambda layer as detailed in our documentation.

Step 2: Define the Online Debugging Environment Variable

Once you’ve built your Lambda function on top of Thundra’s Lambda layer, you’ll next need to enable the live debugging functionality. Use the environment variable thundra_agent_lambda_debugger_auth_token to enable this. This environment variable accepts an authentication token that you pull from Thundra’s console, and when this flag is active, the function defining this variable will be started in debug mode.

Step 3: Connect Your IDE to the Debugging Environment

To connect your IDE to a running Lambda function, Thundra uses the concept of named sessions. These named sessions tie your Lambda functions to your local IDE’s execution environment. You can manage this complexity effectively using the Thundra VSCode plugin. This gives you handy tools to modify your Thundra configuration, start a remote debugging session with or without a name, and more.

Step 4: Live Debugging Achieved

At this point, you have all of the tools you need to debug your production Python functions in a local development environment. The Thundra VS Code plugin will automatically connect to the function secured with the debugger auth token you specify, and you’ll be able to troubleshoot your functions live from within VS Code as they execute on the AWS Lambda infrastructure.

Wrapping Up: Two Choices for Debugging Lambda

We’ve presented two different ways of debugging your Lambda functions: locally using PTVSD and remotely using Thundra’s Online Debugging. While PTVSD does a lot to allow us to troubleshoot Lambda functions in the process of execution, it will fall short if you need to work with any production resources or if you are attempting to troubleshoot a production-specific failure.

With the use of Thundra’s Online Debugging, you can move past the shortcomings of a local-only debugging environment and get to the core of an issue quickly, efficiently, and in a way that a local environment simply cannot replicate.

*** This is a Security Bloggers Network syndicated blog from Thundra blog authored by Hamit Burak Emre. Read the original post at: