Skip to content

Commit 627ca3a

Browse files
committed
Add Python debugging sample
1 parent 51e121e commit 627ca3a

File tree

18 files changed

+650
-0
lines changed

18 files changed

+650
-0
lines changed
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
# Lambda function response
2+
response.json
3+
4+
# Created by https://www.toptal.com/developers/gitignore/api/python,sam
5+
# Edit at https://www.toptal.com/developers/gitignore?templates=python,sam
6+
7+
### Python ###
8+
# Byte-compiled / optimized / DLL files
9+
__pycache__/
10+
*.py[cod]
11+
*$py.class
12+
13+
# C extensions
14+
*.so
15+
16+
# Distribution / packaging
17+
.Python
18+
build/
19+
develop-eggs/
20+
dist/
21+
downloads/
22+
eggs/
23+
.eggs/
24+
lib/
25+
lib64/
26+
parts/
27+
sdist/
28+
var/
29+
wheels/
30+
share/python-wheels/
31+
*.egg-info/
32+
.installed.cfg
33+
*.egg
34+
MANIFEST
35+
36+
# PyInstaller
37+
# Usually these files are written by a python script from a template
38+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
39+
*.manifest
40+
*.spec
41+
42+
# Installer logs
43+
pip-log.txt
44+
pip-delete-this-directory.txt
45+
46+
# Unit test / coverage reports
47+
htmlcov/
48+
.tox/
49+
.nox/
50+
.coverage
51+
.coverage.*
52+
.cache
53+
nosetests.xml
54+
coverage.xml
55+
*.cover
56+
*.py,cover
57+
.hypothesis/
58+
.pytest_cache/
59+
cover/
60+
61+
# Translations
62+
*.mo
63+
*.pot
64+
65+
# Django stuff:
66+
*.log
67+
local_settings.py
68+
db.sqlite3
69+
db.sqlite3-journal
70+
71+
# Flask stuff:
72+
instance/
73+
.webassets-cache
74+
75+
# Scrapy stuff:
76+
.scrapy
77+
78+
# Sphinx documentation
79+
docs/_build/
80+
81+
# PyBuilder
82+
.pybuilder/
83+
target/
84+
85+
# Jupyter Notebook
86+
.ipynb_checkpoints
87+
88+
# IPython
89+
profile_default/
90+
ipython_config.py
91+
92+
# pyenv
93+
# For a library or package, you might want to ignore these files since the code is
94+
# intended to run in multiple environments; otherwise, check them in:
95+
# .python-version
96+
97+
# pipenv
98+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
99+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
100+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
101+
# install all needed dependencies.
102+
#Pipfile.lock
103+
104+
# poetry
105+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
106+
# This is especially recommended for binary packages to ensure reproducibility, and is more
107+
# commonly ignored for libraries.
108+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
109+
#poetry.lock
110+
111+
# pdm
112+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113+
#pdm.lock
114+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
115+
# in version control.
116+
# https://pdm.fming.dev/#use-with-ide
117+
.pdm.toml
118+
119+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
120+
__pypackages__/
121+
122+
# Celery stuff
123+
celerybeat-schedule
124+
celerybeat.pid
125+
126+
# SageMath parsed files
127+
*.sage.py
128+
129+
# Environments
130+
.env
131+
.venv
132+
env/
133+
venv/
134+
ENV/
135+
env.bak/
136+
venv.bak/
137+
138+
# Spyder project settings
139+
.spyderproject
140+
.spyproject
141+
142+
# Rope project settings
143+
.ropeproject
144+
145+
# mkdocs documentation
146+
/site
147+
148+
# mypy
149+
.mypy_cache/
150+
.dmypy.json
151+
dmypy.json
152+
153+
# Pyre type checker
154+
.pyre/
155+
156+
# pytype static type analyzer
157+
.pytype/
158+
159+
# Cython debug symbols
160+
cython_debug/
161+
162+
# PyCharm
163+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
164+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
165+
# and can be added to the global gitignore or merged into this file. For a more nuclear
166+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
167+
#.idea/
168+
169+
### Python Patch ###
170+
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
171+
poetry.toml
172+
173+
# ruff
174+
.ruff_cache/
175+
176+
# LSP config files
177+
pyrightconfig.json
178+
179+
### SAM ###
180+
# Ignore build directories for the AWS Serverless Application Model (SAM)
181+
# Info: https://aws.amazon.com/serverless/sam/
182+
# Docs: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-reference.html
183+
184+
**/.aws-sam
185+
186+
# End of https://www.toptal.com/developers/gitignore/api/python,sam
187+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"version": "0.2.0",
3+
"configurations": [
4+
{
5+
"name": "Python: Remote Attach",
6+
"type": "debugpy",
7+
"request": "attach",
8+
"connect": {
9+
"host": "localhost",
10+
"port": 8050
11+
},
12+
"pathMappings": [
13+
{
14+
"localRoot": "${workspaceFolder}/hello_world",
15+
"remoteRoot": "."
16+
}
17+
]
18+
}
19+
]
20+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
.PHONY: usage install build build-docker build-local build-sam wait deploy deploy-aws deploy-sam invoke clean start stop ready test-ci
2+
3+
AWS_ENDPOINT_URL ?= http://localhost.localstack.cloud:4566
4+
AWS ?= AWS_ENDPOINT_URL=$(AWS_ENDPOINT_URL) \
5+
AWS_ACCESS_KEY_ID=test \
6+
AWS_SECRET_ACCESS_KEY=test \
7+
AWS_DEFAULT_REGION=us-east-1 \
8+
aws
9+
SAM ?= AWS_ENDPOINT_URL=$(AWS_ENDPOINT_URL) \
10+
AWS_ACCESS_KEY_ID=test \
11+
AWS_SECRET_ACCESS_KEY=test \
12+
AWS_DEFAULT_REGION=us-east-1 \
13+
sam
14+
FUNCTION_NAME ?= HelloWorldFunctionPython
15+
16+
# Changing architecture (arm64 or x86_64) requires rebuilding the Java package in Docker
17+
ARCH ?= x86_64
18+
DOCKER_PLATFORM ?= linux/$(ARCH)
19+
IMAGE ?= public.ecr.aws/sam/build-python3.13:latest-$(ARCH)
20+
21+
all: usage
22+
23+
usage: ## Show this help
24+
@fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##//'
25+
26+
# TODO: figure out how to install the AWS CLI v2 in CI
27+
install: ## Install CLI dependencies
28+
@which aws || pip install awscli
29+
30+
build: build-local ## Build the Lambda function (default local)
31+
32+
# TODO: package dependencies in requirements.txt
33+
# TODO: run tests before build
34+
build-docker: ## Build the Lambda function zip in Docker
35+
docker run --platform $(DOCKER_PLATFORM) --rm -v "$$(pwd)/hello_world:/app" $(IMAGE) bash -c "cd /app && zip -r hello_world_python.zip ."
36+
37+
# TODO: package dependencies in requirements.txt
38+
# TODO: run tests before build
39+
build-local: ## Build the Lambda function zip locally (JDK required)
40+
cd hello_world && zip -r hello_world_python.zip .
41+
42+
build-sam: ## Build the Lambda function via AWS SAM
43+
$(SAM) build --use-container
44+
45+
wait: ## Wait until the Lambda function becomes ready to invoke
46+
$(AWS) lambda wait function-active-v2 --function-name $(FUNCTION_NAME)
47+
48+
deploy: deploy-aws ## Deploy the Lambda function (default AWS CLI)
49+
50+
deploy-aws: ## Deploy the Lambda function via AWS CLI
51+
$(AWS) lambda create-function \
52+
--function-name $(FUNCTION_NAME) \
53+
--runtime python3.13 \
54+
--role arn:aws:iam::000000000000:role/lambda-role \
55+
--handler app.lambda_handler \
56+
--zip-file fileb://hello_world/hello_world_python.zip \
57+
--timeout 2
58+
59+
deploy-sam: ## Deploy the Lambda function via AWS SAM CLI
60+
$(SAM) deploy
61+
62+
invoke: ## Invoke the Lambda function and show logs
63+
AWS_MAX_ATTEMPTS=1 $(AWS) lambda invoke --function-name $(FUNCTION_NAME) \
64+
--payload file://events/event.json \
65+
--cli-connect-timeout 3600 \
66+
--cli-read-timeout 3600 \
67+
--log-type Tail \
68+
response.json | jq .LogResult -r | base64 -d && cat response.json | jq -r .result
69+
70+
# TODO: avoid having the built zip file in the source directory
71+
clean: ## Clean the build directory
72+
rm -rf hello_world/hello_world_python.zip
73+
74+
start: ## Start LocalStack
75+
IMAGE_NAME=localstack/localstack-pro \
76+
LOCALSTACK_AUTH_TOKEN=${LOCALSTACK_AUTH_TOKEN} \
77+
LOCALSTACK_LAMBDA_DEBUG_MODE=1 \
78+
LOCALSTACK_LAMBDA_DEBUG_MODE_CONFIG_PATH=/tmp/lambda_debug_mode_config.yaml \
79+
localstack start --detached --volume ${PWD}/lambda_debug_mode_config.yaml:/tmp/lambda_debug_mode_config.yaml
80+
81+
stop: ## Stop LocalStack
82+
localstack stop
83+
84+
ready: ## Wait until LocalStack is running
85+
@echo Waiting on the LocalStack container...
86+
@localstack wait -t 30 && echo LocalStack is ready to use! || (echo Gave up waiting on LocalStack, exiting. && exit 1)
87+
88+
test-ci:
89+
make start install ready deploy wait invoke; return_code=`echo $$?`;\
90+
echo "Interactive debugging not tested in CI"; exit $$return_code;
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Debug your Python Lambda Function
2+
3+
This Hello World Lambda function written in Python demonstrates how to use interactive breakpoint-debugging using LocalStack [Lambda Remote Debugging](https://docs.localstack.cloud/aws/tooling/lambda-tools/remote-debugging/).
4+
LocalStack automatically configures debugging and adjusts relevant timeouts.
5+
6+
We recommend the one-click setup using the AWS Toolkit for VS Code unless your advanced scenario requires Lambda Debug Mode (Preview).
7+
8+
> [!NOTE]
9+
> Check out our blog post [Developing with LocalStack using the AWS Toolkit for VS Code](#TODO-update-link)
10+
11+
## Prerequisites
12+
13+
* [Docker](https://www.docker.com/)
14+
* [VS Code](https://code.visualstudio.com/)
15+
* [LocalStack Toolkit for VS Code](https://marketplace.visualstudio.com/items?itemName=localstack.localstack) ≥ 1.2 installs [LocalStack](https://docs.localstack.cloud/aws/getting-started/installation/) ≥ 4.8
16+
* [AWS Toolkit for VS Code](https://marketplace.visualstudio.com/items?itemName=AmazonWebServices.aws-toolkit-vscode) ≥ 3.74
17+
* `make`
18+
* [AWS CLI v2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) or [AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html)
19+
20+
## Starting Up
21+
22+
1. Execute the VS Code command "LocalStack: Run Setup Wizard" using the LocalStack Toolkit
23+
2. Start LocalStack by clicking on the LocalStack Toolkit status bar
24+
25+
## Deploying
26+
27+
1. Run `make build`
28+
2. Run `make deploy`
29+
30+
## Debugging
31+
32+
1. Open the **Remote invoke configuration** in the AWS Toolkit
33+
1. Open the AWS Toolkit extension
34+
2. Expand the AWS Explorer and Lambda node
35+
3. Navigate to the function you want to debug, then choose the Invoke remotely icon ▶️ from the context menu
36+
2. Select the **Remote debugging** check box to display the remote debugging properties
37+
3. Specify the Local Root Path to your local handler file.
38+
4. Set a breakpoint in your handler file by clicking in the gutter-margin
39+
5. Click the **Remote invoke** button to invoke the Lambda function
40+
41+
## Lambda Debug Mode (Preview, Pro)
42+
43+
### Starting Up
44+
45+
1. Start LocalStack with the following configuration:
46+
47+
```sh
48+
LOCALSTACK_IMAGE_NAME=localstack/localstack-pro \
49+
LOCALSTACK_LAMBDA_DEBUG_MODE=1 \
50+
LOCALSTACK_LAMBDA_DEBUG_MODE_CONFIG_PATH=/tmp/lambda_debug_mode_config.yaml \
51+
localstack start --volume $PWD/lambda_debug_mode_config.yaml:/tmp/lambda_debug_mode_config.yaml
52+
```
53+
54+
* `IMAGE_NAME=localstack/localstack-pro` ensures the Pro image is started
55+
* `LOCALSTACK_LAMBDA_DEBUG_MODE=1` adjusts timeouts
56+
* `LOCALSTACK_LAMBDA_DEBUG_MODE_CONFIG_PATH=/tmp/lambda_debug_mode_config.yaml` points to the config file for Lambda debug mode allowing for advanced configuration. It maps the Lambda function `arn:aws:lambda:us-east-1:000000000000:function:function-one` to port `8050`.
57+
* `--volume $PWD/lambda_debug_mode_config.yaml:/tmp/lambda_debug_mode_config.yaml` maps the Lambda debug configuration from the host into the LocalStack Docker container for hot-reloading configuration updates.
58+
59+
### Deploying
60+
61+
1. Run `make build` to build the Lambda ZIP package
62+
2. Run `make deploy` to deploy the Lambda function
63+
64+
### Debugging
65+
66+
1. Open the sample folder in VS Code to auto-detect `.vscode/launch.json`
67+
2. Set a breakpoint in the handler file `HelloWorldFunction/app.py` by clicking in the gutter-margin
68+
3. Open the **Run and Debug** view in VS Code
69+
4. Run the **Python: Remote Attach** task
70+
5. Run `make invoke` to invoke the Lambda function
71+
72+
## Troubleshooting
73+
74+
* Concurrent invokes are currently rejected with a `ResourceConflictException`.
75+
Upvote [this GitHub issue](https://github.com/localstack/localstack/issues/8522) if this affects you.
76+
77+
## License
78+
79+
The code in this sample is available under the Apache 2.0 license.

lambda-debugging-sam-python/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)