Debug AWS Lambda Functions with Gebug

Moshe Beladev
3 min readJan 20, 2021

--

Debugging your Golang Lambda locally can be really annoying. You have great tools on your machine but you don’t always get the most out of them.

I experienced with Serverless Application Model (sam local) and it was actually really nice but was not there yet, at least for Go.

Some elementary features like auto-build and live code updates were missing and the development experience was not as smooth and fast as I wished it would be.

Quote from `sam local start-api` documentation:

If you’re using an interpreted language, local changes are available immediately in the Docker container on every invoke. For more compiled languages or projects that require complex packing support, we recommend that you run your own building solution, and point AWS SAM to the directory or file that contains the build artifacts.

So we will embrace their suggestion and build our own complex packing support. Fortunately, with Gebug it won’t be complex at all.

Gebug is an open-source tool that makes debugging of Dockerized Go applications super easy by enabling Debugger and Hot-Reload features. Check it out: https://github.com/moshebe/gebug

How it’s done

(If you don’t mind how it works behind the scenes, just jump to the setup instructions, no hard feelings)

AWS released a very interesting project called AWS Lambda Runtime Interface Emulator (a.k.a aws-lambda-rie) which is basically a proxy for the Lambda’s runtime.

Think about it, you are able to invoke your function using an HTTP trigger locally but you didn’t set up either a web-server to handle the request or a parser to translate the payload into JSON and structs that fit into the Lambda Runtime API.
You guessed right, aws-lambda-rie is a tiny web-server that handles the invocation stuff for us.
Be aware that it does not presume to simulate a full Lambda environment but only the invocation part, which for most of the common debugging scenarios that’s all you need. Thus, you won’t find orchestration, security, or authentication simulations here.

In order to install the tool in your local development Docker image you can start by downloading the binary from here:
https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie

We will add a Gebug pre-run-command that will download the binary, enable execution, and put it in the right place:

pre_run_commands:
- curl -sLo /tmp/aws-lambda-rie https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie && mv /tmp/aws-lambda-rie /usr/local/bin/aws-lambda-rie && chmod +x /usr/local/bin/aws-lambda-rie

on a real AWS Lambda environment, our Lambda binary will be placed at /var/task so we will set the following configurations as well:

build_command: go build -o /var/task/main
output_binary: /usr/local/bin/aws-lambda-rie /var/task/main

Setup Instructions

Ok, I don’t want to waste your time anymore so I’ll just share with you the complete Gebug configurations:

.gebug/config.yaml

name: lambdagebug
output_binary: /usr/local/bin/aws-lambda-rie /var/task/main
build_command: go build -o /var/task/main
build_dir: /src
run_command: '{{.output_binary}}'
runtime_image: golang:1.15.2
debugger_enabled: false
debugger_port: 0
expose_ports:
- 8080:8080
networks: []
environment: []
pre_run_commands:
- curl -sLo /tmp/aws-lambda-rie https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie && mv /tmp/aws-lambda-rie /usr/local/bin/aws-lambda-rie && chmod +x /usr/local/bin/aws-lambda-rie

I used a really simple hello-world Lambda just for the demo:

main.go

package mainimport (
"fmt"
"context"
"github.com/aws/aws-lambda-go/lambda"
)
type Event struct {
Name string `json:"name"`
}
func HandleRequest(ctx context.Context, event Event) (string, error) {
return fmt.Sprintf("Hello %s", event.Name), nil
}
func main() {
lambda.Start(HandleRequest)
}

Now, just simply run gebug start and you can start accessing your Lambda locally using a simple HTTP endpoint.

curl -XPOST "http://localhost:8080/2015-03-31/functions/function/invocations" -d '{}'

Demo

Seeing is believing. Watch a short demo to feel how simple it is to get your local Lambda debugging environment to become really awesome:

Live code update of Go Lambda Function

--

--