Painless AWS Chalice Application Debug

Alex Gelman
CyberArk Engineering
5 min readFeb 16, 2020
Photo by Per Lööv on Unsplash

When you’re developing serverless applications using Function-as-a-Service services like AWS lambda, there comes a time when you need to troubleshoot your application. Doing so in a cloud environment can prove difficult since you cannot simply attach a debugger to your code running in the cloud.

You may have tried to debug your serverless functions by adding print statements, but I’m going to show you how it’s possible to run and debug local serverless functions written using AWS’s Chalice micro-framework.

Additionally you’ll see how to create integration tests that run your code locally, while integrating with cloud resources. This approach will save you time and money, since you won’t need to re-upload your functions on every change.

Getting Started with a Chalice Application

AWS Chalice is a Python micro-framework, designed to provide developers with a familiar flask-like experience when developing serverless applications.

Before we can get started, you’ll need the following prerequisites:

Let’s start with a simple Chalice application that will allow us to show how we can troubleshoot it locally:

  • Open a terminal and navigate to the folder you’d like to create the project in.
  • Run the command:
    chalice new-project
    The on-screen prompt will ask you for a project name, enter troubleshooting-chalice as the project name.
    You should see a new directory with the name troubleshooting-chalice, navigate into the new directory
Figure 1 — Creating a new project using Chalice CLI
  • Create a new python 3.7.5 virtual environment by running
    pipenv --python 3.7.5
  • Activate the virtual environment by running
    pipenv shell
  • Now install chalice in the virtual environment by running
    pipenv install chalice
  • Open the directory in PyCharm, you should see the following file structure:
Figure 2- Basic Chalice project structure

The file app.py contains a simple hello world lambda function.
The .chalice directory contains configurations of the way the application is deployed in AWS.

Open the app.py file and look at the index method

@app.route('/')
Def index():
return{'hello':'world'}

This method represents a Hello World Lambda function that will be triggered via API gateway calls to the base route ‘/’

Now that you have a simple application, let’s see how you can debug and test it locally before deploying to AWS.

Debugging Locally

You can start the application locally by running the command chalice local, this will start a local web server running your application.
Use Postman to invoke the API locally by sending an HTTP GET request to the address http://localhost:8000/.

Figure 3 — Using Postman to execute the hello world function

You should see the response containing ‘hello world’.

The local server supports hot reload, whenever you make changes to the code and save the file the server will reload to serve the latest code.
To attach a debugger, you need to stop it from automatically reloading code changes.

Stop the running server by pressing ctrl+c in the terminal window to stop the process.
Next, restart the server without the hot reload feature by running the command:
chalice local — no-autoreload
Now back in PyCharm go to the Run menu and choose the option Attach to Process….
A new menu will open, the menu lists all python processes.
Select the chalice local process to attach a debugger to it.

Figure 4 — PyCharm attach to process menu

Now place a breakpoint in the index() method.
Invoke the API again using Postman.
The execution will stop at the breakpoint, you’ll be able to inspect the local variables, step through the code, etc.
The debugging experience is just like when debugging any other local application.

Figure 5 — Debugger breaks at the hello world function

You’ve seen how to manually debug and test your lambda function, however, for real production code you’ll probably want to write automated integration tests.

Adding Integration Tests

Writing automated integration tests enables you to test your application in a consistent and reproducible way.
Your serverless application can run locally, while using other resources such as S3 buckets or DynamoDB database running on AWS. All without having to deploy the Lambda code to AWS.
This works best as part of a CI/CD pipeline, which can validate that your code works before actually publishing it to AWS.

To get started with integration tests, add pytest to your project as a dev dependency.
pipenv install --dev pytest
Now add a tests folder and an integration tests file, your project structure should look like this:

Figure 6 — Project structure with integration tests

Chalice exposes the local API gateway as a class that you can initialize in your test fixture.
Add the following code to the integration test file:

@pytest.fixture
def api():
return LocalGateway(app.app,Config())

Now let’s add an integration test that calls our Hello World function:

def test_get_hello_world(api):
response = api.handle_request(method='GET', path='/',
headers={}, body=None)
print(response)
assert response['statusCode'] == HTTPStatus.OK
response = json.loads(response['body'])
assert response['hello'] == 'world'

Running the test invokes your Lambda functions via a simulated API gateway. Using PyCharm, it’s possible to debug the execution just like we would debug any other test suite.

The example here is a simple Hello World. In the real world your function may be more complex and call other AWS services, such as DynamoDB.
When running locally, the Lambda will still call out to the external services using your local AWS credentials.
You’ve seen how to troubleshoot Lambda functions when using AWS Chalice, both in manual and automated testing.

Running and testing serverless functions locally should save you time and money since you don’t need to re-upload your functions on every change. Additionally local invocations are always free.
Hopefully it will aid you in your serverless development.

You can find the complete code example at the following repository: https://github.com/alexgelman/troubleshooting-chalice-demo

--

--

Alex Gelman
CyberArk Engineering

Principal software architect @CyberArk and full stack tech geek