Skip to content

Commit 3ed0aae

Browse files
ncipollinaclaude
andauthored
feat: configurable OTEL layer with architecture and version support (BREAKING) (#26)
BREAKING CHANGES: - OpenTelemetry layer is now disabled by default (was enabled by default) - Added new required properties: Architecture and OtelLayerVersion Features: - Add Architecture property with default "amd64" (supports arm64) - Add OtelLayerVersion property with default "0-117-0" (latest version) - Support configurable OTEL layer ARN format with architecture and version - Update all tests to reflect new defaults - Update testing helpers and builders with new properties Documentation: - Update CLAUDE.md, README.md, and docs/constructs/lambda-function.md - Add migration guide and breaking change warnings - Add examples showing new OTEL configuration Version: - Bump version to 2.0.0-beta for breaking changes - Update CDK dependency to 2.209.1 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Claude <noreply@anthropic.com>
1 parent d0baecc commit 3ed0aae

11 files changed

Lines changed: 96 additions & 20 deletions

File tree

CLAUDE.md

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ dotnet add test/LayeredCraft.Cdk.Constructs.Tests/ package PackageName
4545
**LambdaFunctionConstruct** (`src/LayeredCraft.Cdk.Constructs/LambdaFunctionConstruct.cs`)
4646
- Main CDK construct that creates Lambda functions with comprehensive configuration
4747
- Automatically creates IAM roles and policies with CloudWatch Logs permissions
48-
- Supports OpenTelemetry layer integration via AWS managed layer
48+
- Supports configurable OpenTelemetry layer integration via AWS managed layer (disabled by default)
49+
- Configurable OTEL layer version and architecture (amd64/arm64)
4950
- Supports AWS Lambda SnapStart for improved cold start performance
5051
- Creates function versions and aliases for deployment management
5152
- Handles Lambda permissions for multiple targets (function, version, alias)
@@ -82,13 +83,32 @@ dotnet add test/LayeredCraft.Cdk.Constructs.Tests/ package PackageName
8283
1. **Construct Pattern**: Uses AWS CDK construct pattern for reusable infrastructure components
8384
2. **Interface + Record Pattern**: Props classes use both interface and record for flexibility and immutability
8485
3. **Multi-Target Permissions**: Automatically applies permissions to function, version, and alias
85-
4. **OpenTelemetry Integration**: Built-in support for AWS OTEL collector layer
86+
4. **OpenTelemetry Integration**: Configurable support for AWS OTEL collector layer with version and architecture options
8687
5. **Versioning Strategy**: Creates new versions on every deployment with "live" alias
8788

8889
### Target Frameworks
8990
- .NET 8.0 and .NET 9.0
9091
- Uses AWS CDK v2 (Amazon.CDK.Lib 2.203.1)
9192

93+
### OpenTelemetry Configuration (v2.0.0+)
94+
Starting with version 2.0.0, the OpenTelemetry layer configuration has been updated:
95+
96+
- **Default Behavior**: OTEL layer is now **disabled by default** (breaking change from v1.x)
97+
- **Architecture Support**: Configurable architecture via `Architecture` property (default: "amd64")
98+
- **Version Control**: Configurable OTEL layer version via `OtelLayerVersion` property (default: "0-117-0")
99+
- **Layer ARN Format**: `arn:aws:lambda:{region}:901920570463:layer:aws-otel-collector-{architecture}-ver-{version}:1`
100+
101+
To enable OTEL layer in v2.0.0+:
102+
```csharp
103+
var props = new LambdaFunctionConstructProps
104+
{
105+
// ... other properties
106+
IncludeOtelLayer = true, // Explicitly enable
107+
Architecture = "arm64", // Optional: change architecture
108+
OtelLayerVersion = "0-117-0" // Optional: specify version
109+
};
110+
```
111+
92112
## Testing Framework
93113

94114
### Test Structure
@@ -179,7 +199,7 @@ The library includes comprehensive testing helpers for consumers:
179199

180200
### AWS CDK Patterns
181201
- Uses `PROVIDED_AL2023` runtime for Lambda functions (supports custom runtimes)
182-
- Hardcoded OpenTelemetry layer ARN for us-east-1 region
202+
- Configurable OpenTelemetry layer version and architecture (defaults to version 0-117-0, amd64 architecture)
183203
- Default memory: 1024MB, timeout: 6 seconds, log retention: 2 weeks
184204
- Uses `RemovalPolicy.RETAIN` for Lambda versions to prevent deletion
185205

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project>
22
<PropertyGroup>
3-
<VersionPrefix>1.0.1</VersionPrefix>
3+
<VersionPrefix>2.0.0-beta</VersionPrefix>
44
<!-- SPDX license identifier for MIT -->
55
<PackageLicenseExpression>MIT</PackageLicenseExpression>
66

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ A comprehensive library of reusable AWS CDK constructs for .NET projects, design
1111

1212
## Features
1313

14-
- **🚀 Lambda Functions**: Comprehensive Lambda construct with OpenTelemetry support, IAM management, and environment configuration
14+
- **🚀 Lambda Functions**: Comprehensive Lambda construct with configurable OpenTelemetry support, IAM management, and environment configuration
1515
- **🌐 Static Sites**: Complete static website hosting with S3, CloudFront, SSL certificates, and Route53 DNS management
1616
- **📊 DynamoDB Tables**: Full-featured DynamoDB construct with streams, TTL, and global secondary indexes
1717
- **🧪 Testing Helpers**: Extensive testing utilities with fluent assertions and builders
@@ -45,6 +45,8 @@ public class MyStack : Stack
4545
RoleName = "my-api-role",
4646
PolicyName = "my-api-policy",
4747
GenerateUrl = true, // Creates Function URL for HTTP access
48+
IncludeOtelLayer = true, // Enable OpenTelemetry (disabled by default in v2.0+)
49+
Architecture = "arm64", // Optional: specify architecture (default: amd64)
4850
EnvironmentVariables = new Dictionary<string, string>
4951
{
5052
{ "ENVIRONMENT", "production" },

docs/constructs/lambda-function.md

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Lambda Function Construct
22

3-
The `LambdaFunctionConstruct` provides a comprehensive, production-ready Lambda function with integrated OpenTelemetry support, IAM management, and environment configuration.
3+
The `LambdaFunctionConstruct` provides a comprehensive, production-ready Lambda function with configurable OpenTelemetry support, IAM management, and environment configuration.
44

55
## :rocket: Features
66

7-
- **:chart_with_upwards_trend: OpenTelemetry Integration**: Built-in AWS OpenTelemetry collector layer
7+
- **:chart_with_upwards_trend: OpenTelemetry Integration**: Configurable AWS OpenTelemetry collector layer with version and architecture support
88
- **:shield: IAM Management**: Automatic role and policy creation with CloudWatch Logs permissions
99
- **:gear: Environment Configuration**: Easy environment variable management
1010
- **:link: Function URLs**: Optional HTTP endpoint generation
@@ -29,7 +29,8 @@ public class MyStack : Stack
2929
FunctionSuffix = "prod",
3030
AssetPath = "./lambda-deployment.zip",
3131
RoleName = "my-api-role",
32-
PolicyName = "my-api-policy"
32+
PolicyName = "my-api-policy",
33+
IncludeOtelLayer = true // Enable OpenTelemetry (disabled by default in v2.0+)
3334
});
3435
}
3536
}
@@ -55,7 +56,9 @@ public class MyStack : Stack
5556
| `TimeoutInSeconds` | `double` | `6` | Function timeout in seconds |
5657
| `PolicyStatements` | `PolicyStatement[]` | `[]` | Additional IAM policy statements |
5758
| `EnvironmentVariables` | `IDictionary<string, string>` | `{}` | Environment variables |
58-
| `IncludeOtelLayer` | `bool` | `true` | Enable OpenTelemetry layer |
59+
| `IncludeOtelLayer` | `bool` | `false` | Enable OpenTelemetry layer |
60+
| `OtelLayerVersion` | `string` | `"0-117-0"` | OpenTelemetry layer version |
61+
| `Architecture` | `string` | `"amd64"` | Lambda architecture (amd64/arm64) |
5962
| `Permissions` | `List<LambdaPermission>` | `[]` | Lambda invocation permissions |
6063
| `EnableSnapStart` | `bool` | `false` | Enable SnapStart for improved cold starts |
6164
| `GenerateUrl` | `bool` | `false` | Generate Function URL for HTTP access |
@@ -142,6 +145,25 @@ var lambda = new LambdaFunctionConstruct(this, "MyLambda", new LambdaFunctionCon
142145
});
143146
```
144147

148+
### Lambda with OpenTelemetry Configuration
149+
150+
```csharp
151+
var lambda = new LambdaFunctionConstruct(this, "MyLambda", new LambdaFunctionConstructProps
152+
{
153+
FunctionName = "my-api",
154+
FunctionSuffix = "prod",
155+
AssetPath = "./lambda-deployment.zip",
156+
RoleName = "my-api-role",
157+
PolicyName = "my-api-policy",
158+
IncludeOtelLayer = true, // Enable OpenTelemetry layer
159+
Architecture = "arm64", // Use ARM64 architecture
160+
OtelLayerVersion = "0-117-0" // Specify OTEL layer version
161+
});
162+
```
163+
164+
!!! warning "Breaking Change in v2.0.0"
165+
Starting with version 2.0.0, the OpenTelemetry layer is **disabled by default**. You must explicitly set `IncludeOtelLayer = true` to enable it. This change allows for better control over observability costs and layer dependencies.
166+
145167
## Public Properties
146168

147169
### LambdaFunction
@@ -175,9 +197,9 @@ The Lambda functions use the following runtime configuration:
175197
!!! info "Runtime Details"
176198
- **Runtime**: `PROVIDED_AL2023` (Amazon Linux 2023)
177199
- **Handler**: `bootstrap` (for custom runtimes)
178-
- **Architecture**: x86_64
200+
- **Architecture**: Configurable (amd64/arm64, default: amd64)
179201
- **Log Retention**: 2 weeks
180-
- **OpenTelemetry Layer**: AWS managed layer (us-east-1 region)
202+
- **OpenTelemetry Layer**: Configurable AWS managed layer (disabled by default in v2.0+)
181203

182204
## IAM Permissions
183205

src/LayeredCraft.Cdk.Constructs/LambdaFunctionConstruct.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public LambdaFunctionConstruct(Construct scope, string id, ILambdaFunctionConstr
8989
if (props.IncludeOtelLayer)
9090
{
9191
LambdaFunction.AddLayers(LayerVersion.FromLayerVersionArn(this, "OTELLambdaLayer",
92-
$"arn:aws:lambda:{region}:901920570463:layer:aws-otel-collector-amd64-ver-0-102-1:1"));
92+
$"arn:aws:lambda:{region}:901920570463:layer:aws-otel-collector-{props.Architecture}-ver-{props.OtelLayerVersion}:1"));
9393
}
9494

9595
// ✅ Create a new version on every deployment

src/LayeredCraft.Cdk.Constructs/LayeredCraft.Cdk.Constructs.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
</PropertyGroup>
1616

1717
<ItemGroup>
18-
<PackageReference Include="Amazon.CDK.Lib" Version="2.206.0" />
18+
<PackageReference Include="Amazon.CDK.Lib" Version="2.209.1" />
1919
</ItemGroup>
2020
<ItemGroup>
2121
<None Include="..\..\docs\assets\icon.png" Pack="true" PackagePath="" Visible="False" />

src/LayeredCraft.Cdk.Constructs/Models/LambdaFunctionConstructProps.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ public interface ILambdaFunctionConstructProps
1414
PolicyStatement[] PolicyStatements { get; set; }
1515
IDictionary<string, string> EnvironmentVariables { get; set; }
1616
bool IncludeOtelLayer { get; set; }
17+
string OtelLayerVersion { get; set; }
18+
string Architecture { get; set; }
1719
List<LambdaPermission> Permissions { get; set; }
1820
bool EnableSnapStart { get; set; }
1921
bool GenerateUrl { get; set; }
@@ -29,8 +31,10 @@ public sealed record LambdaFunctionConstructProps : ILambdaFunctionConstructProp
2931
public double TimeoutInSeconds { get; set; } = 6;
3032
public PolicyStatement[] PolicyStatements { get; set; } = [];
3133
public IDictionary<string, string> EnvironmentVariables { get; set; } = new Dictionary<string, string>();
32-
public bool IncludeOtelLayer { get; set; } = true;
34+
public bool IncludeOtelLayer { get; set; } = false;
35+
public string OtelLayerVersion { get; set; } = "0-117-0";
36+
public string Architecture { get; set; } = "amd64";
3337
public List<LambdaPermission> Permissions { get; set; } = [];
34-
public bool EnableSnapStart { get; set; } = false;
35-
public bool GenerateUrl { get; set; } = false;
38+
public bool EnableSnapStart { get; set; }
39+
public bool GenerateUrl { get; set; }
3640
}

src/LayeredCraft.Cdk.Constructs/Testing/LambdaFunctionConstructPropsBuilder.cs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ public class LambdaFunctionConstructPropsBuilder
1818
private double _timeoutInSeconds = 6;
1919
private readonly List<PolicyStatement> _policyStatements = new();
2020
private readonly Dictionary<string, string> _environmentVariables = new();
21-
private bool _includeOtelLayer = true;
21+
private bool _includeOtelLayer = false;
22+
private string _otelLayerVersion = "0-117-0";
23+
private string _architecture = "amd64";
2224
private readonly List<LambdaPermission> _permissions = new();
2325
private bool _enableSnapStart = false;
2426
private bool _generateUrl = false;
@@ -89,6 +91,28 @@ public LambdaFunctionConstructPropsBuilder WithOtelEnabled(bool enabled = true)
8991
return this;
9092
}
9193

94+
/// <summary>
95+
/// Sets the OpenTelemetry layer version.
96+
/// </summary>
97+
/// <param name="version">The OTEL layer version (e.g., "0-117-0")</param>
98+
/// <returns>The builder instance for method chaining</returns>
99+
public LambdaFunctionConstructPropsBuilder WithOtelLayerVersion(string version)
100+
{
101+
_otelLayerVersion = version;
102+
return this;
103+
}
104+
105+
/// <summary>
106+
/// Sets the Lambda function architecture.
107+
/// </summary>
108+
/// <param name="architecture">The architecture (e.g., "amd64", "arm64")</param>
109+
/// <returns>The builder instance for method chaining</returns>
110+
public LambdaFunctionConstructPropsBuilder WithArchitecture(string architecture)
111+
{
112+
_architecture = architecture;
113+
return this;
114+
}
115+
92116
/// <summary>
93117
/// Adds DynamoDB access permissions for the specified table.
94118
/// </summary>
@@ -273,6 +297,8 @@ public LambdaFunctionConstructProps Build()
273297
PolicyStatements = [.. _policyStatements],
274298
EnvironmentVariables = _environmentVariables,
275299
IncludeOtelLayer = _includeOtelLayer,
300+
OtelLayerVersion = _otelLayerVersion,
301+
Architecture = _architecture,
276302
Permissions = _permissions,
277303
EnableSnapStart = _enableSnapStart,
278304
GenerateUrl = _generateUrl

test/LayeredCraft.Cdk.Constructs.Tests/LambdaFunctionConstructTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ public void Construct_ShouldIncludeOtelLayerWhenEnabled(LambdaFunctionConstructP
155155
template.HasResourceProperties("AWS::Lambda::Function", Match.ObjectLike(new Dictionary<string, object>
156156
{
157157
{ "TracingConfig", new Dictionary<string, object> { { "Mode", "Active" } } },
158-
{ "Layers", new object[] { Match.StringLikeRegexp(".*aws-otel-collector.*") } }
158+
{ "Layers", new object[] { Match.StringLikeRegexp(".*aws-otel-collector-amd64-ver-0-117-0.*") } }
159159
}));
160160
}
161161

test/LayeredCraft.Cdk.Constructs.Tests/TestKit/Attributes/LambdaFunctionConstructAutoDataAttribute.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace LayeredCraft.Cdk.Constructs.Tests.TestKit.Attributes;
55

6-
public class LambdaFunctionConstructAutoDataAttribute(bool includeOtelLayer = true, bool includePermissions = true, bool generateUrl = false) : AutoDataAttribute(() => CreateFixture(includeOtelLayer, includePermissions, generateUrl))
6+
public class LambdaFunctionConstructAutoDataAttribute(bool includeOtelLayer = false, bool includePermissions = true, bool generateUrl = false) : AutoDataAttribute(() => CreateFixture(includeOtelLayer, includePermissions, generateUrl))
77
{
88
private static IFixture CreateFixture(bool includeOtelLayer, bool includePermissions, bool generateUrl)
99
{

0 commit comments

Comments
 (0)