🐋 AWS CDK 101 - 🦋 SAM local to test and debug lambda function
Tags: typescript, aws, serverless, awscdk
Published: 2022-09-18 08:57:24

🔰  Beginners new to AWS CDK, please do look at my previous articles one by one in this series.

If in case missed my previous article, do find it with the below links.

🔁 🔗 [Dev Post aws-cdk-101-send-message-across-accounts-using-sns-topic-and-sqs](https://devpost.hashnode.dev/aws-cdk-101-send-message-across-accounts-using-sns-topic-and-sqs)

🔁 🔗 [dev to aws-cdk-101-send-message-across-accounts-using-sns-topic-and-sqs-h2i](https://dev.to/aws-builders/aws-cdk-101-send-message-across-accounts-using-sns-topic-and-sqs-h2i)

Also, we have started to develop an open source project which we would be using to play around with refracting the architecture as well as learn CDK stuff at the same time we will provide something useful for our community. Find more about this discussed in the article below.

![arch](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/msrbf94oefdrnu29a5db.jpeg)

🔁 Original project post at 🔗 [Dev Post aws-cdk-101-projects-cdk-stackresourcedrift-events-forwarded-to-cool-slack-posts-event-forwarder](https://devpost.hashnode.dev/aws-cdk-101-projects-cdk-stackresourcedrift-events-forwarded-to-cool-slack-posts-event-forwarder)

🔁 Reposted project post at 🔗 [dev to aws-cdk-101-projects-cdk-stackresourcedrift-events-forwarded-to-cool-slack-posts-event-forwarder-1m0m](https://dev.to/aws-builders/aws-cdk-101-projects-cdk-stackresourcedrift-events-forwarded-to-cool-slack-posts-event-forwarder-1m0m)

[event-forwarder Github repo](https://github.com/aravindvcyber/event-forwarder/)

## Integration testing lambda :dango:

Earlier in our article, we have seen how to use Eventbridge and SNS to forward over messages to remote stacks as well. Now let us make one more addition to our stack by setting up local integration testing of the lambda using sam local.

We need to get this since after performing numerous iterations with cdk deploy and validating the cloud watch logs, i wanted to find something which i could leverage to be capable of find the bugs prior to release. 

## Sam local :clown_face:

Using Sam local will be able to set up sam local docker to test our lambda processor, though someone of you may not find it useful. But you may be making changes to the code in repeated iterations. Now and then you may need to hot-swap or force deploy the changes and based on the assets it will unnecessarily lead to the below scenarios if you are not interested with

* you could also check in your test events rather than using in lambda console.
* you can try to run the lambda in a similar environment (like arm64) and runtime (different node versions) even if you don't have that locally
* Inspect the environment information and debug log traces for lambda container
* Monitor the system usage and audit the memory composition of the layers used
* This can also help you use pull remote layers and bind with local layers to simulate it.
* temporarily your network could be offline and you could not test.
* increase asset file/zip uploads
* KMS keys used for cross-account deploy buckets
* need to commit for the pipeline to deploy event for minor changes
* more importantly you may need to wait for the deployment/pipeline to complete

To start with we will be first discussing how to set up sam local.

## SAM CLI Installation :robot:

For this, we need to install sam cli

[Installing the AWS SAM CLI on Linux](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install-linux.html)
[Installing the AWS SAM CLI on Windows](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install-windows.html)
[Installing the AWS SAM CLI on macOS](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install-mac.html)

I prefer the homebrew option if you have that installed already.

```sh
brew tap aws/tap
brew install aws-sam-cli
sam --version
```

## Json output format :eyes:

For better formatting, I use to have `| jq .` towards the end of certain npm run scripts. If you need this u need to install check out the below link 
[jq download](https://stedolan.github.io/jq/download/)

Again I do it with homebrew

```sh
brew install jq
```

## Add the below launch configuration :bone:

In vscode, you can also add the below launch config to the launch configurations in the file `.vscode/launch.json`. This will enable the js map link to the source as well so that we could follow the code in vscode with js map errors in debug console.

```json
 {
    "name": "Attach to SAM CLI",
    "type": "node",
    "request": "attach",
    "address": "localhost",
    "port": 9999,
    "localRoot": "${workspaceRoot}/dist/lambda/stack-event-processor",
    "remoteRoot": "/var/task",
    "protocol": "inspector",
    "stopOnEntry": false
}
```


If you don't like to use js debugging when using typescript with webpack you can add the below to your launch config attach configuration `sourceMapPathOverrides` as discussed above.

```json
{
"sourceMapPathOverrides": {
    "meteor://💻ap{workspaceFolder}/*",
    "webpack:///./{workspaceFolder}/node_*",
    "webpack://?:{workspaceFolder}/*"
}
```


## Define the stack template in the package config :chicken:

Here I have defined a random stack template name for the remote stack `npm_package_config_remoteTemplate` since it has generated stack id `./cdk.out/RemoteEventRouterStack-ap-south-1-456.template.json`. 
You can update it to the correct one as per your synth.

```json
  "config": {
    "stackName": "EventForwarderStack",
    "cfnTemplateProcessor": "./cdk.out/EventForwarderStack.template.json",
    "remoteTemplate": "./cdk.out/RemoteEventRouterStack-ap-south-1-456.template.json"
  },
```

## Sample Events :hatched_chick:

I have placed sample events in the events folder to run the function. This can grow based on needs. Here a dummy cloudformation event is stringified inside the body of the dummy sqs event payload.

`events`

## Detecting sam local setup locally :owl:

You can add the below code into the handler to choice the right flow and use sam local seamlessly.

```ts
const handle = async function (event: SQSEvent) {

  if(process.env.AWS_SAM_LOCAL) {
    logger.info("running with sam local:", { event });
  }
```

> Note since we are using webpack to bundle to the dist folder we will using this our local and we could not link to typescript, so we have place a similar break point in the js file to linkable by the debugger


Else add add the `sourceMapPathOverrides` property to the launch config as discussed above for webpack.

### How to run :peacock:

As already advised the config and the AWS named profile and package config has to be updated as per your preference and then you can run the below scripts.


### Build script with sam template :turtle:

```json
{
    "sam:b:1": "sam build --docker-network cloud -t $npm_package_config_cfnTemplateProcessor --profile av --region ap-south-1 ",
    "sam:b:2": "sam build --docker-network cloud -t $npm_package_config_remoteTemplate --profile av-s --region ap-south-1 ",
}
```

### Run scripts for testing :ant:

> Note for testing you have to provide the event payload in the below format as follows.

Directly invoking the function when the sam template is already validated

`npm run t:1:func1 -- --event=events/event_stack_delete_complete.json`

or always build with sam before testing

`npm run t:1:1 -- --event=events/event_stack_delete_complete.json`

![response in t 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t95il1s2d8gp0o6dxhz7.png)

```json
{
    "sam:i": "sam local invoke $npm_config_fname --docker-network cloud -e $npm_config_event | jq .",
    "t:1:func1": "npm run sam:i --fname=stackEventProcessor",
    "t:1:func2": "npm run sam:i --fname=failedMessageLogger",
    "t:2:func1": "npm run sam:i --fname=failedMessageAggregator",
    "t:1:1": "npm run sam:b:1 && npm run t:1:func1",
    "t:1:2": "npm run sam:b:1 && npm run t:1:func2",
    "t:2:1": "npm run sam:b:2 && npm run t:2:func1"
}
```

### run scripts for debugging :cherry_blossom:

> Note for debugging you have to provide the event payload in the below format as follows.

> `--log-file logs/sam-debug-logs.txt ` is used to move the cloudwatch logs to my current folder you may remove that if you prefer. Also when the log file is enabled you won't get the web socket link for debugging and you only get the below notification. Once you find it you can switch to vscode to attach to SAM CLI process using our config defined above.

![interrupt handler ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/353v29wgx88w10atqeet.png)



> `--debug` option is used to capture more verbose environment-related insights and trace beyond your function logic, feel free to remove it if you don't need them

In these scripts, you may additionally find that we are synthesizing and building before debugging to make sure the latest code changes are into sam local.

`npm run d:1:func1 -- --event=events/event_stack_delete_complete.json`

```json
{
    
    "sam:i:debug": "sam local invoke $npm_config_fname --docker-network cloud -d 9999 -e $npm_config_event  --log-file logs/sam-debug-logs.txt --debug | jq .",
    "d:1:func1": "npm run cdk:synth:all && npm run sam:b:1 && npm run sam:i:debug --fname=stackEventProcessor",
    "d:1:func2": "npm run cdk:synth:all && npm run sam:b:1 && npm run sam:i:debug --fname=failedMessageLogger",
    "d:2:func2": "npm run cdk:synth:all && npm run sam:b:2 && npm run sam:i:debug --fname=failedMessageAggregator",
    
}
```

## Debugging in vscode :rose:

![logs and vscode](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4jnvww25pl37voim91zx.png)

As discussed earlier we made a break point in the js file under the dist folder to catch via the debugger.

![debug in vscode set breakpoint](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jovncf6f3df2pb1buqrf.png)

## Inspect Docker container while debugging :bouquet:

Understand system processes and usage

![Understand system processes and usage](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bhr5suw7tf1o2idjf8bi.png)

memory requirements of layers

![memory requirements of layers](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lmd6m7as80cf5swggh0k.png)


lambda container environment variables

![sam local env 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ikelkmew60fcpzpy8gfm.png)


![sam local env 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sjywkvqi8g72b2szpa7j.png)


## Conclusion :fountain:

This will be extremely useful when you repeatedly iterate and make code changes to the processor and you could use the test event to test it swiftly. Watch out for our next article on local dynamodb setup and integration.

We will be talking about more similar engineering concepts as we refactor and refine the event forwarder project. Keep following for similar posts on engineering with IaC primarily using AWS CDK and Serverless.

Also, feel free to contribute to the progress of the below solution with your comments, and issues, maybe you can also do a pr if you feel it can help our community.

[event-forwarder Github repo](https://github.com/aravindvcyber/event-forwarder/)

![arch](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/msrbf94oefdrnu29a5db.jpeg)

🔁 Original project post at 🔗 [Dev Post aws-cdk-101-projects-cdk-stackresourcedrift-events-forwarded-to-cool-slack-posts-event-forwarder](https://devpost.hashnode.dev/aws-cdk-101-projects-cdk-stackresourcedrift-events-forwarded-to-cool-slack-posts-event-forwarder)

🔁 Reposted project post at 🔗 [dev to aws-cdk-101-projects-cdk-stackresourcedrift-events-forwarded-to-cool-slack-posts-event-forwarder-1m0m](https://dev.to/aws-builders/aws-cdk-101-projects-cdk-stackresourcedrift-events-forwarded-to-cool-slack-posts-event-forwarder-1m0m)

⏭ We have our next article in serverless and IaC, do check out

https://dev.to/aws-builders/aws-cdk-101-dynamodb-local-setup-and-integrating-with-sam-invoke-527f

🎉 Thanks for supporting! 🙏

Would be great if you like to [☕ Buy Me a Coffee](https://www.buymeacoffee.com/AravindVCyber), to help boost my efforts 😍.

<a href="https://www.buymeacoffee.com/AravindVCyber"><img src="https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=&slug=AravindVCyber&button_colour=BD5FFF&font_colour=ffffff&font_family=Cookie&outline_colour=000000&coffee_colour=FFDD00" /></a>

<a href='https://ko-fi.com/X8X0CITDJ' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://cdn.ko-fi.com/cdn/kofi4.png?v=3' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>

🔁 Original post at 🔗 [Dev Post aws-cdk-101-sam-local-to-test-and-debug-lambda-function](https://devpost.hashnode.dev/aws-cdk-101-sam-local-to-test-and-debug-lambda-function)

🔁 Reposted at 🔗 [dev to @aravindvcyber aws-cdk-101-sam-local-to-test-and-debug-lambda-function-1afj](https://dev.to/aws-builders/aws-cdk-101-sam-local-to-test-and-debug-lambda-function-1afj)