Lambda Powertools Integration
FsCDK provides first-class integration with AWS Lambda Powertools, a suite of utilities for: - Structured logging with correlation IDs - Custom metrics without CloudWatch API overhead - Distributed tracing integration - Best practice environment variables
Powertools layers are automatically added to supported Lambda functions (Python, Node.js, Java).
Quick Start
#r "nuget: Amazon.CDK.Lib, 2.128.0"
#r "../src/bin/Release/net8.0/publish/Amazon.JSII.Runtime.dll"
#r "../src/bin/Release/net8.0/publish/Constructs.dll"
#r "../src/bin/Release/net8.0/publish/Amazon.CDK.Lib.dll"
#r "../src/bin/Release/net8.0/publish/FsCDK.dll"
open Amazon.CDK
open Amazon.CDK.AWS.Lambda
open FsCDK
let app = App()
stack "PowertoolsDemo" {
scope app
lambda "MyFunction" {
handler "app.handler"
runtime Runtime.PYTHON_3_11
code "./src"
// Powertools layer added automatically!
// Just add environment variables for configuration
environment
[ "POWERTOOLS_SERVICE_NAME", "order-service"
"POWERTOOLS_METRICS_NAMESPACE", "MyApp"
"LOG_LEVEL", "INFO" ]
}
}
That's it! The Powertools layer is automatically added, and your function is ready to use Powertools features.
Supported Runtimes
Automatic Layer Addition
FsCDK automatically adds Powertools layers for these runtimes:
Runtime |
Powertools Layer |
Status |
|---|---|---|
Python 3.8 |
AWSLambdaPowertoolsPython |
Auto-added |
Python 3.9 |
AWSLambdaPowertoolsPython |
Auto-added |
Python 3.10 |
AWSLambdaPowertoolsPython |
Auto-added |
Python 3.11 |
AWSLambdaPowertoolsPython |
Auto-added |
Python 3.12 |
AWSLambdaPowertoolsPython |
Auto-added |
Node.js 14 |
AWSLambdaPowertoolsTypeScript |
Auto-added |
Node.js 16 |
AWSLambdaPowertoolsTypeScript |
Auto-added |
Node.js 18 |
AWSLambdaPowertoolsTypeScript |
Auto-added |
Node.js 20 |
AWSLambdaPowertoolsTypeScript |
Auto-added |
Java 8 |
AWSLambdaPowertoolsJava |
Auto-added |
Java 11 |
AWSLambdaPowertoolsJava |
Auto-added |
Java 17 |
AWSLambdaPowertoolsJava |
Auto-added |
*.NET 6+* |
NuGet packages |
Manual (see below) |
Note: Currently, Powertools layers use us-east-1 region by default. The layer ARNs are regionalized and work in all AWS regions, but the ARN string currently references us-east-1. This will be improved in a future release to use the actual stack region.
.NET Special Case
.NET Lambda functions use NuGet packages instead of layers. Add these to your .csproj or .fsproj:
|
FsCDK skips layer auto-addition for .NET runtimes.
Python Example
CDK Definition
lambda "PythonOrderProcessor" {
handler "app.lambda_handler"
runtime Runtime.PYTHON_3_11
code "./python-service"
memorySize 512
timeout 30.0
environment
[ "POWERTOOLS_SERVICE_NAME", "order-processor"
"POWERTOOLS_METRICS_NAMESPACE", "ECommerceApp"
"LOG_LEVEL", "INFO"
// Optional advanced configuration
"POWERTOOLS_LOGGER_SAMPLE_RATE", "0.1" // Sample 10% of logs
"POWERTOOLS_LOGGER_LOG_EVENT", "true" // Log incoming event
"POWERTOOLS_TRACE_DISABLED", "false" ] // Enable tracing
}
Python Lambda Code
app.py:
|
SQS Event Processing with Powertools
|
Node.js/TypeScript Example
CDK Definition
lambda "NodeOrderProcessor" {
handler "index.handler"
runtime Runtime.NODEJS_20_X
code "./nodejs-service"
memorySize 512
timeout 30.0
environment
[ "POWERTOOLS_SERVICE_NAME", "order-processor"
"POWERTOOLS_METRICS_NAMESPACE", "ECommerceApp"
"LOG_LEVEL", "INFO"
// Optional configuration
"POWERTOOLS_LOGGER_SAMPLE_RATE", "0.1"
"POWERTOOLS_LOGGER_LOG_EVENT", "true" ]
}
TypeScript Lambda Code
Install dependencies:
|
index.ts:
|
Java Example
CDK Definition
lambda "JavaOrderProcessor" {
handler "com.example.OrderHandler::handleRequest"
runtime Runtime.JAVA_17
code "./java-service/target/order-service.jar"
memorySize 1024
timeout 60.0
environment
[ "POWERTOOLS_SERVICE_NAME", "order-processor"
"POWERTOOLS_METRICS_NAMESPACE", "ECommerceApp"
"POWERTOOLS_LOG_LEVEL", "INFO" ]
}
Java Lambda Code
Maven dependencies (pom.xml):
|
OrderHandler.java:
|
Environment Variables Reference
Logger Configuration
Variable |
Default |
Description |
|---|---|---|
|
- |
Service name (required) |
|
|
Logging level: DEBUG, INFO, WARNING, ERROR |
|
|
Log incoming event |
|
|
Sample rate (0.0-1.0) for debug logs |
Metrics Configuration
Variable |
Default |
Description |
|---|---|---|
|
- |
CloudWatch namespace (required) |
|
- |
Service name dimension |
Tracer Configuration
Variable |
Default |
Description |
|---|---|---|
|
|
Disable tracing |
|
|
Capture response in traces |
|
|
Capture errors in traces |
Advanced Configuration
Multiple Runtimes in One Stack
stack "MultiRuntimeStack" {
scope app
// Python function - Powertools added automatically
lambda "PythonFunction" {
handler "app.handler"
runtime Runtime.PYTHON_3_11
code "./python-service"
environment
[ "POWERTOOLS_SERVICE_NAME", "python-service"
"POWERTOOLS_METRICS_NAMESPACE", "MyApp" ]
}
// Node.js function - Powertools added automatically
lambda "NodeFunction" {
handler "index.handler"
runtime Runtime.NODEJS_20_X
code "./nodejs-service"
environment
[ "POWERTOOLS_SERVICE_NAME", "nodejs-service"
"POWERTOOLS_METRICS_NAMESPACE", "MyApp" ]
}
// .NET function - No layer added (uses NuGet)
lambda "DotNetFunction" {
handler "Assembly::Namespace.Class::Method"
runtime Runtime.DOTNET_8
code "./dotnet-service"
// No Powertools layer - handled via NuGet packages
}
}
Disabling Auto-Addition
If you need to use a custom Powertools layer version or disable it entirely:
// Note: Custom Powertools layer version must be created outside lambda builder
// Example:
// let customPowertoolsLayer =
// LayerVersion.FromLayerVersionArn(
// scope, // The CDK Stack or Construct
// "CustomPowertools",
// "arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPython:50"
// )
//
// Then use in lambda:
lambda "CustomPowertoolsFunction" {
handler "app.handler"
runtime Runtime.PYTHON_3_11
code "./src"
autoAddPowertools false // Disable auto-addition
// layers [ customPowertoolsLayer ] // Add the custom layer
}
Using with Custom Layers
Powertools layers are added alongside your custom layers:
// Note: Custom layers must be created using CDK LayerVersion directly
// Example:
// let myCustomLayer = LayerVersion(stack, "CustomLayer",
// LayerVersionProps(
// LayerVersionName = "my-utils",
// Code = Code.FromAsset("./layers/utils"),
// CompatibleRuntimes = [| Runtime.PYTHON_3_11 |]
// ))
lambda "MultiLayerFunction" {
handler "app.handler"
runtime Runtime.PYTHON_3_11
code "./src"
// layers [ myCustomLayer ] // Add custom layers here
// Powertools layer added automatically in addition to your layers
}
CloudWatch Integration
Querying Structured Logs
With Powertools JSON logging, use CloudWatch Logs Insights:
|
// Verify Powertools is enabled (default)
lambda "MyFunction" {
handler "app.handler"
runtime Runtime.PYTHON_3_11
code "./src"
autoAddPowertools true // Explicitly enable
}
```
### Import Errors in Python
**Symptom**: `ModuleNotFoundError: No module named 'aws_lambda_powertools'`
**Solution**: Layer was not added. Check runtime compatibility or verify deployment.
### Metrics Not Appearing
**Symptom**: No custom metrics in CloudWatch
**Causes**:
1. Missing `POWERTOOLS_METRICS_NAMESPACE`
2. Missing `@metrics.log_metrics()` decorator
3. Exception thrown before metrics flushed
**Solution**:
```python
# Always use decorator to ensure metrics are flushed
@metrics.log_metrics(capture_cold_start_metric=True)
def lambda_handler(event, context):
metrics.add_metric(name="MyMetric", unit=MetricUnit.Count, value=1)
# Metrics automatically flushed when handler exits
```
---
## Related Documentation
- [Lambda Production Defaults](lambda-production-defaults.html) - Overview of all production features
- [Lambda Quickstart](lambda-quickstart.html) - Basic Lambda usage
- [CloudWatch Dashboard](cloudwatch-dashboard.html) - Visualizing metrics
---
## External Resources
- [AWS Lambda Powertools Python](https://docs.powertools.aws.dev/lambda/python/)
- [AWS Lambda Powertools TypeScript](https://docs.powertools.aws.dev/lambda/typescript/)
- [AWS Lambda Powertools Java](https://docs.powertools.aws.dev/lambda/java/)
- [AWS Lambda Powertools .NET](https://docs.powertools.aws.dev/lambda/dotnet/)
---
## Summary
FsCDK's Lambda Powertools integration provides:
**Zero-configuration** - Layers added automatically
**Multi-runtime support** - Python, Node.js, Java, .NET
**Production-grade observability** - Logging, metrics, tracing
**Zero cold-start impact** - Layers don't increase startup time
**Cost-effective metrics** - No CloudWatch API calls
**Easy to override** - Use `autoAddPowertools false` if needed
**Get production-ready observability with zero extra code!**
*)
()
type App = inherit Stage new: ?props: IAppProps -> unit static member IsApp: obj: obj -> bool
--------------------
App(?props: IAppProps) : App
<summary>Creates an AWS CDK Stack construct.</summary>
<param name="name">The name of the stack.</param>
<code lang="fsharp"> stack "MyStack" { lambda myFunction bucket myBucket } </code>
<summary>Creates a Lambda function configuration.</summary>
<param name="name">The function name.</param>
<code lang="fsharp"> lambda "MyFunction" { handler "index.handler" runtime Runtime.NODEJS_18_X code "./lambda" timeout 30.0 } </code>
<summary>Sets the handler for the Lambda function.</summary>
<param name="config">The function configuration.</param>
<param name="handler">The handler name (e.g., "index.handler").</param>
<code lang="fsharp"> lambda "MyFunction" { handler "index.handler" } </code>
<summary>Sets the runtime for the Lambda function.</summary>
<param name="config">The function configuration.</param>
<param name="runtime">The Lambda runtime.</param>
<code lang="fsharp"> lambda "MyFunction" { runtime Runtime.NODEJS_18_X } </code>
type Runtime = inherit DeputyBase new: name: string * ?family: Nullable<RuntimeFamily> * ?props: ILambdaRuntimeProps -> unit member RuntimeEquals: other: Runtime -> bool member ToString: unit -> string member BundlingImage: DockerImage member Family: Nullable<RuntimeFamily> member IsVariable: bool member Name: string member SupportsCodeGuruProfiling: bool member SupportsInlineCode: bool ...
--------------------
Runtime(name: string, ?family: System.Nullable<RuntimeFamily>, ?props: ILambdaRuntimeProps) : Runtime
<summary>Sets the code source from a Code object.</summary>
<param name="config">The function configuration.</param>
<param name="path">The Code object.</param>
<code lang="fsharp"> lambda "MyFunction" { code (Code.FromBucket myBucket "lambda.zip") } </code>
<summary>Sets environment variables for the Lambda function.</summary>
<param name="config">The function configuration.</param>
<param name="env">List of key-value pairs for environment variables.</param>
<code lang="fsharp"> lambda "MyFunction" { environment [ "KEY1", "value1"; "KEY2", "value2" ] } </code>
<summary>Sets the memory allocation for the Lambda function.</summary>
<param name="config">The function configuration.</param>
<param name="mb">The memory size in megabytes.</param>
<code lang="fsharp"> lambda "MyFunction" { memory 512 } </code>
<summary>Sets the timeout for the Lambda function.</summary>
<param name="config">The function configuration.</param>
<param name="seconds">The timeout in seconds.</param>
<code lang="fsharp"> lambda "MyFunction" { timeout 30.0 } </code>
<summary> Controls automatic Lambda Powertools layer addition. Default: true (Yan Cui recommendation). Set to false to disable Powertools auto-addition. </summary>
<param name="config">The function configuration.</param>
<param name="value">True to auto-add Powertools, false to skip.</param>
<code lang="fsharp"> lambda "MyFunction" { autoAddPowertools true } </code>
FsCDK