Skip to content

Releases: aws-powertools/powertools-lambda-dotnet

3.2.1

20 Mar 14:10
88ad045

Choose a tag to compare

Summary

In this release we added a new Lambda Metadata utility that provides access to the Lambda Metadata Endpoint (LMDS), allowing you to retrieve execution environment metadata like Availability Zone ID. The metadata is automatically cached for the sandbox lifetime with thread-safe access and native AOT support.

What's New

✨ Lambda Metadata Utility

| Docs

Added a new AWS.Lambda.Powertools.Metadata package that provides access to Lambda execution environment metadata from the Lambda Metadata Endpoint (LMDS). The utility exposes a simple static API with automatic caching for the sandbox lifetime, thread-safe concurrent access, and native AOT compatibility via source-generated JSON serialization.

Install:

dotnet add package AWS.Lambda.Powertools.Metadata

Basic usage:

using AWS.Lambda.Powertools.Metadata;

public class Function
{
    public string Handler(object input, ILambdaContext context)
    {
        var azId = LambdaMetadata.AvailabilityZoneId;
        return $"Running in AZ: {azId}";
    }
}

Multi-AZ routing:

using AWS.Lambda.Powertools.Metadata;

public class Function
{
    public async Task<string> Handler(OrderRequest request, ILambdaContext context)
    {
        var endpoint = LambdaMetadata.AvailabilityZoneId switch
        {
            "use1-az1" => "https://service-az1.internal",
            "use1-az2" => "https://service-az2.internal",
            _ => "https://service.internal"
        };

        return await ProcessOrder(request, endpoint);
    }
}

With Powertools Logging:

using AWS.Lambda.Powertools.Logging;
using AWS.Lambda.Powertools.Metadata;

public class Function
{
    public Function()
    {
        Logger.AppendKey("az_id", LambdaMetadata.AvailabilityZoneId);
    }

    [Logging]
    public string Handler(object input, ILambdaContext context)
    {
        Logger.LogInformation("Processing request");
        return "Success";
    }
}

Error handling:

try
{
    var azId = LambdaMetadata.AvailabilityZoneId;
}
catch (LambdaMetadataException ex)
{
    Console.WriteLine($"Failed to get metadata: {ex.Message}");

    if (ex.StatusCode != -1)
        Console.WriteLine($"HTTP Status: {ex.StatusCode}");
}

Changes

🌟New features and non-breaking changes

  • feat(metadata): add Lambda Metadata utility for retrieving execution environment metadata (#1157) by @hjgraca

📜 Documentation updates

  • feat(metadata): add Lambda Metadata utility for retrieving execution environment metadata (#1157) by @hjgraca

🔧 Maintenance

This release was made possible by the following contributors:

@hjgraca

3.2.0

12 Mar 14:42
c4492d7

Choose a tag to compare

Summary

In this release we added new logging features including ExtraKeys for temporary key management within scopes, an Enabled property for LogBuffering configuration, and TenantId support for Lambda Tenant Isolation observability. We also fixed a stdout file descriptor leak in the logging utility and an idempotency key collision issue when using multiple idempotent methods.

Thank you @jihed-garaouch for your first contribution ⭐

What's New

✨ ExtraKeys for Logger

| Docs

Added ExtraKeys() method to Logger for temporary key management within scopes. Keys are automatically cleaned up when the scope exits, with full support for async/await boundaries using AsyncLocal-based scope storage. Supports multiple overloads: Dictionary, params tuples, and nested scopes.

Dictionary syntax:

using (Logger.ExtraKeys(new Dictionary<string, object> { {"orderId", "123"} }))
{
    Logger.LogInformation("Processing order"); // includes orderId
}
// orderId is automatically removed

Tuple syntax:

using (Logger.ExtraKeys(("orderId", "123"), ("customerId", "456")))
{
    Logger.LogInformation("Processing"); // includes orderId and customerId
}

✨ LogBuffering Enabled Property

| Docs

Added Enabled property to LogBufferingOptions to explicitly control log buffering activation. This allows configuring log buffering through property assignment instead of requiring constructor parameters.

var builder = new LoggerConfiguration();
builder.LogBuffering.Enabled = true;
builder.LogBuffering.BufferAtLogLevel = LogLevel.Debug;

✨ TenantId Support

Added TenantId from ILambdaContext to the default logger properties to support AWS Lambda Tenant Isolation observability. When using Lambda Tenant Isolation, the TenantId is automatically captured and included in your structured log output.

{
    "Level": "Information",
    "Message": "Processing request",
    "TenantId": "tenant-abc-123",
    ...
}

🐛 Stdout File Descriptor Leak Fix

Fixed a file descriptor leak in ConsoleWrapper where OverrideLambdaLogger() was creating a new StreamWriter(Console.OpenStandardOutput()) on every log write, leaking one pipe file descriptor per call. Under sustained load in warm Lambda containers this exhausted the 1024 FD limit and crashed the function with "Too many open files". The stdout stream is now opened once and reused.

🐛 Idempotency Key Collision Fix

Fixed an issue where multiple idempotent methods with the same key would share the same idempotency record. The persistence store now uses AsyncLocal for the full function name, correctly isolating keys per method.

// Before: both methods would generate the same idempotency key
// After: each method generates a unique key based on the full function name

[Idempotent]
public Task<Response> MethodA(string key) { ... }

[Idempotent]
public Task<Response> MethodB(string key) { ... }

Changes

🌟New features and non-breaking changes

📜 Documentation updates

  • chore(deps): bump markdown from 3.7 to 3.8.1 in /docs (#1144) by @dependabot[bot]
  • chore(deps): bump squidfunk/mkdocs-material from 3bba0a9 to 8f41b60 in /docs (#1141) by @dependabot[bot]
  • feat(logging): add ExtraKeys to logger (#1128) by @hjgraca
  • feat(logging): add Enabled property to LogBuffering configuration (#1125) by @hjgraca

🐛 Bug and hot fixes

  • fix(logging): prevent stdout file descriptor leak in ConsoleWrapper (#1148) by @hjgraca
  • fix(idempotency): ensure unique idempotency keys for multiple methods with same key (#1124) by @hjgraca

🔧 Maintenance

This release was made possible by the following contributors:

@dependabot[bot], @dreamorosi, @hjgraca, @jihed-garaouch and dependabot[bot]

3.1.0

06 Jan 12:45
e99abe4

Choose a tag to compare

Summary

In this release we are excited to announce support for AWS Lambda Managed Instanced across all Powertools utilities, along with .Net 10 support, and a new typed batch decorator.

Thank you @fuguiKz for your first documentation contribution ⭐

What's New

🚀 Lambda Managed Instances Support

This release introduces full thread safety across all Powertools utilities, enabling seamless support for AWS Lambda Managed Instances.

What are Lambda Managed Instances?

Lambda Managed Instances runs your functions on fully-managed EC2 instances in your account, supporting multi-concurrent invocations where a single execution environment processes multiple requests simultaneously. This improves resource utilization for IO-heavy workloads but requires thread-safe code.

🔒 Thread Safety Improvements

To fully support Lambda Managed Instances, we've implemented thread safety across all utilities:

  • Logging - Per-thread scope storage using ConcurrentDictionary ensures log context isolation between concurrent requests (#1078, #1099)
  • Tracing - Async context preservation with thread-safe segment management (#1082)
  • Metrics - Concurrent collections and isolation prevent metric bleed between requests (#1080)
  • Idempotency - AsyncLocal context and thread-safe configuration for reliable idempotency checks (#1084)
  • Parameters - Immutable cache objects, atomic cache updates with AddOrUpdate, and Interlocked operations for thread-safe parameter retrieval (#1098)

✨ New Features

  • Batch Typed Decorator - New type safe decorator for batch processing, providing new interfaces that accept and serialize automatically your custom types. (#1034)
public class Product
    {
        public int Id { get; set; }
        public string? Name { get; set; }
        public decimal Price { get; set; }
    }

    public class TypedSqsRecordHandler : ITypedRecordHandler<Product> // (1)!
    {
        public async Task<RecordHandlerResult> HandleAsync(Product product, CancellationToken cancellationToken)
        {
             /*
             * Your business logic with automatic deserialization.
             * If an exception is thrown, the item will be marked as a partial batch item failure.
             */

             Logger.LogInformation($"Processing product {product.Id} - {product.Name} (${product.Price})");

             if (product.Id == 4) // (2)!
             {
                 throw new ArgumentException("Error on id 4");
             }

             return await Task.FromResult(RecordHandlerResult.None); // (3)!
         }

    }

    [BatchProcessor(TypedRecordHandler = typeof(TypedSqsRecordHandler))]
    public BatchItemFailuresResponse HandlerUsingTypedAttribute(SQSEvent _)
    {
        return TypedSqsBatchProcessor.Result.BatchItemFailuresResponse; // (4)!
    }

🎯 .NET 10 Support

  • Added .NET 10.0 as a supported target framework (#1105)
  • Removed .NET 6.0 support (end of life) (#1106)

Changes

🌟New features and non-breaking changes

  • feat(logging): thread safety with ConcurrentDictionary for scope storage (#1099) by @hjgraca
  • feat: batch typed decorator (#1034) by @hjgraca
  • feat(idempotency): enhance thread safety with AsyncLocal context and thread-safe configuration (#1084) by @hjgraca
  • feat(tracing): thread safety and async context preservation in Powertools Tracing (#1082) by @hjgraca
  • feat(metrics): thread safety with concurrent collections and isolation for metrics (#1080) by @hjgraca
  • feat(logging): implement thread-safe logging with per-thread scope storage (#1078) by @hjgraca

📜 Documentation updates

  • chore: Fix examples projects to include projectreferences (#1110) by @hjgraca
  • docs: extract batch processing snippets (#1104) by @fuguiKz
  • chore(deps): bump squidfunk/mkdocs-material from 980e11f to 3bba0a9 in /docs (#1107) by @dependabot[bot]
  • chore: update .NET runtime support to 10.0 and remove 6.0 (#1106) by @hjgraca
  • feat: batch typed decorator (#1034) by @hjgraca
  • chore(deps): bump squidfunk/mkdocs-material from f5c556a to 980e11f in /docs (#1057) by @dependabot[bot]

🔧 Maintenance

This release was made possible by the following contributors:

@dependabot[bot], @dreamorosi, @fuguiKz, @hjgraca and dependabot[bot]

v3.0.2

05 Nov 10:40
184575d

Choose a tag to compare

Summary

In this release we fixed a bug that caused correlation ids not to be captured due to case sensitive string matching. We also added a new API to get the correlation id from the Logging utility

Changes

Correlation ID extraction improvements

Enhanced the CaptureCorrelationId method to try multiple strategies for extracting the correlation ID: first by exact (case-sensitive) match, then by output case transformation, and finally by case-insensitive search. This makes correlation ID retrieval more reliable across various event shapes.

Public API enhancements

| Docs

  • Added a static CorrelationId property to the Logger class, allowing easy access to the current correlation ID from log context.
  • Introduced a new GetCorrelationId extension method for ILogger, providing a convenient way to access the correlation ID from any logger instance.

Bugs

🔧 Maintenance

This release was made possible by the following contributors:

@dependabot[bot], @hjgraca and dependabot[bot]

v3.0.1

21 Oct 09:53
958d519

Choose a tag to compare

Summary

In this release we fix two bugs introduced in the last release.

  • AspectInjector dependency that was causing build issues in large projects
  • Tracing utility regression introduced when we added a new way to create subsegments.

📜 Announcement: You can now find our documentation on the official AWS documentation domain at [docs.aws.amazon.com/powertools/dotnet](https://docs.aws.amazon.com/powertools/dotnet/).

Thanks @nCubed for reporting the AspectInjector issue

Changes

🐛 Bug and hot fixes

  • fix: tracing subsegment when using fluent api Tracing.WithSubsegment (#1032) by @hjgraca
  • chore: downgrade AspectInjector to version 2.8.1 (#1040) by @hjgraca

📜 Documentation updates

  • chore(deps): bump squidfunk/mkdocs-material from 00f9276 to f5c556a in /docs (#1041) by @dependabot[bot]
  • chore: add aws docs javascript bootstrap (#1016) by @hjgraca

🔧 Maintenance

This release was made possible by the following contributors:

@ConnorKirk, @dependabot[bot], @hjgraca, dependabot[bot] and github-actions[bot]

v3.0.0

07 Oct 14:25
cfa4560

Choose a tag to compare

Summary

We're excited to announce a major release with new features and important updates:

  • Strongly-typed batch processor with automatic deserialization for SQS, Kinesis, and DynamoDB events
  • Enhanced tracing with improved metadata error handling
  • Bug fix for logging sampling rate

This major version bump reflects significant breaking changes as we update our supported runtimes and dependencies.

Breaking Changes

⚠️ Important: Please review these breaking changes before upgrading:

Migration guide to v3

  • Removed support for .NET 6 - We now require .NET 8 or later
  • AWS SDK v3 no longer supported - We have migrated to AWS SDK v4
  • Version alignment - All Powertools for AWS Lambda utilities will maintain version parity going forward

New Features

Strongly-Typed Batch Processor

📖 Documentation | Migration Guide

Process batch events with type safety and automatic deserialization.

What's New:

  • ITypedRecordHandler<T> and ITypedRecordHandlerWithContext<T> interfaces for strongly-typed processing
  • Specialized processors: TypedSqsBatchProcessor, TypedKinesisEventBatchProcessor, TypedDynamoDbStreamBatchProcessor
  • Automatic JSON deserialization from event records to your types
  • Optional ILambdaContext injection for timeout handling and request tracking

Example Usage:

Simple typed handler:

public class OrderHandler : ITypedRecordHandler<Order>
{
    public async Task<RecordHandlerResult> HandleAsync(Order order, CancellationToken cancellationToken)
    {
        // Direct access to strongly-typed object - no manual deserialization!
        await ProcessOrder(order);
        return RecordHandlerResult.Successful;
    }
}

With Lambda context support (docs):

public class ProductHandlerWithContext : ITypedRecordHandlerWithContext<Product>
{
    public async Task<RecordHandlerResult> HandleAsync(Product product, ILambdaContext context, CancellationToken cancellationToken)
    {
        Logger.LogInformation($"Processing product {product.Id} in request {context.AwsRequestId}");
        Logger.LogInformation($"Remaining time: {context.RemainingTime.TotalSeconds}s");

        // Use context for timeout handling
        if (context.RemainingTime.TotalSeconds < 5)
        {
            Logger.LogWarning("Low remaining time, processing quickly");
        }

        return RecordHandlerResult.Successful;
    }
}

Contributors

Thank you @dcabib for your contributions to this release! ⭐

Changes

🐞 Bug fixes

  • fix(logging): Fix sampling when log level is above Debug #980 @dcabib

📜 Documentation updates

  • chore: remove dotnet6 from docs and add migration guides for v2 and v3 (#1021) by @hjgraca
  • chore(deps): bump squidfunk/mkdocs-material from 86d21da to 00f9276 in /docs (#1013) by @dependabot[bot]
  • chore: Tracing sanitize metadata (#1011) by @hjgraca
  • chore(deps): bump squidfunk/mkdocs-material from 209b62d to 86d21da in /docs (#996) by @dependabot[bot]

🔧 Maintenance

This release was made possible by the following contributors:

@dependabot[bot], @hjgraca and dependabot[bot]

1.60.1

25 Sep 09:53
1fe8ede

Choose a tag to compare

Summary

In this release, we resolved thread safety issues in the Metrics utility that were causing exceptions when multiple threads attempted to collect metrics simultaneously.

Thanks @lachriz-aws for reporting and helping investigate this issue! 🙏

🐛 Bug and hot fixes
fix: concurrency issues in Metrics (#1001) by @hjgraca

1.60.0

09 Sep 10:02
bace4b7

Choose a tag to compare

Summary

This release introduces a new feature for the Idempotency utility that allows developers to manipulate the returned data from idempotent operations, providing greater flexibility and control over the response handling process.

Congratulations @Diogobitten for your first contribution ⭐

Manipulating idempotent responses

Docs

Now you can set up a response hook in the Idempotency configuration to modify the returned data when an operation is idempotent. The hook function is called with the current deserialized response object and the Idempotency DataRecord, allowing you to add custom logic or modify the response as needed.

Idempotency.Config()
    .WithConfig(IdempotencyOptions.Builder()
        .WithEventKeyJmesPath("powertools_json(body).address")
        .WithResponseHook((responseData, dataRecord) => {
            if (responseData is APIGatewayProxyResponse proxyResponse)
            {
                proxyResponse.Headers ??= new Dictionary<string, string>();
                proxyResponse.Headers["x-idempotency-response"] = "true";
                proxyResponse.Headers["x-idempotency-expiration"] = dataRecord.ExpiryTimestamp.ToString();
                return proxyResponse;
            }
            return responseData;
        })
        .Build())
    .WithPersistenceStore(DynamoDBPersistenceStore.Builder()
        .WithTableName(Environment.GetEnvironmentVariable("IDEMPOTENCY_TABLE"))
        .Build())
    .Configure();

Changes

🌟New features and non-breaking changes

  • feat: Add support for response hooks in idempotency utility (#968) by @hjgraca

📜 Documentation updates

  • chore: Remove reference customer section from documentation (#982) by @hjgraca
  • chore: Update copyright information in mkdocs.yml (#976) by @hjgraca
  • feat: Add support for response hooks in idempotency utility (#968) by @hjgraca

🔧 Maintenance

  • chore: Update version for release (#986) by @hjgraca
  • chore: Remove reference customer section from documentation (#982) by @hjgraca
  • chore: Update copyright information in mkdocs.yml (#976) by @hjgraca
  • chore(deps): bump brace-expansion in /examples/Event Handler/BedrockAgentFunction/infra (#973) by @dependabot[bot]
  • chore(deps): bump codecov/codecov-action from 5.4.3 to 5.5.0 (#967) by @dependabot[bot]
  • chore(gitignore): add .kiro, .claude, .amazonq to prevent deletion (#971) by @Diogobitten

This release was made possible by the following contributors:

@Diogobitten, @dependabot[bot], @dreamorosi, @hjgraca and dependabot[bot]

1.54

26 Aug 11:30
0d3043e

Choose a tag to compare

Summary

In this release we fix a bug in the Logging utility where requests containing duplicate HTTP headers (such as multiple Content-Type headers) cause an unhandled exception. When duplicate headers are present, the last header is taken.

Thank you @SamuelGuine for reporting the issue

Logging 2.0.2

Changes

📜 Documentation updates

  • chore(deps): bump squidfunk/mkdocs-material from bb7b015 to 1a4e939 in /docs (#964) by @dependabot[bot]
  • chore(deps): bump squidfunk/mkdocs-material from 0bfdba4 to bb7b015 in /docs (#947) by @dependabot[bot]

🐛 Bug and hot fixes

  • fix: handle duplicate keys in logger state to prevent ArgumentException (#961) by @hjgraca

🔧 Maintenance

This release was made possible by the following contributors:

@dependabot[bot], @hjgraca, @leandrodamascena and dependabot[bot]

1.53

29 Jul 11:38
26ecdc0

Choose a tag to compare

Summary

In this release we improved our Idempotency utility and storage layer is now faster and cheaper by leveraging conditional writes. We also made important changes to the Logger and Metrics utility.

Special thanks to @j-d-ha for reporting logging issues and @sdangol for their first contribution to the project.

Logging

Docs

We've enhanced the AddPowertoolsLogger method with improved service registration and added automatic ILogger interface registration. A new ClearExistingProviders option is now available to prevent multiple logger providers.

builder.Logging.AddPowertoolsLogger(config =>
{
    config.Service = "TestService";
    config.LoggerOutputCase = LoggerOutputCase.PascalCase;
}, clearExistingProviders: true);

Metrics

Docs

Before this release, if you published invalid metrics they could fail silently, leading to data loss. Now Lambda will raise an exception if the following constraints do not hold:

  • Metric Name: Validated according to CloudWatch constraints
  • Metric Value: Validated for numeric values
  • Metric Unit: Validated for allowed units
  • Metric Resolution: Validated for allowed resolutions
  • Dimension Name: Both Dimension name and value are validated for non empty, non-null values.

Idempotency

Docs

Several months ago AWS introduced support for ReturnValuesOnConditionCheckFailure, a feature designed to streamline conditional write operations and reducing costs in Amazon DynamoDB. With this enhancement, Powertools for AWS Lambda now optimistically attempts to write items to DynamoDB. If the item already exists, it seamlessly returns it without requiring an additional operation.

Changes

🌟New features and non-breaking changes

  • feat(metrics): Added runtime validation for the metric name (#943) by @sdangol
  • feat: add support for ReturnValuesOnConditionCheckFailure in Idempotency (#930) by @hjgraca

📜 Documentation updates

  • chore: Add automatic registration of standard logging services and ILogger (#938) by @hjgraca

🔧 Maintenance

  • chore: Update version.json for release 1.53 (#945) by @hjgraca
  • chore(deps): bump github/codeql-action from 3.29.3 to 3.29.4 (#941) by @dependabot[bot]
  • chore(deps): bump aws-powertools/actions from 29979bc5339bf54f76a11ac36ff67701986bb0f0 to 7d2401cbbb232594bde7285bc5b8c0c78dcbe6e2 (#942) by @dependabot[bot]
  • chore(deps): bump github/codeql-action from 3.29.2 to 3.29.3 (#939) by @dependabot[bot]
  • chore: Add automatic registration of standard logging services and ILogger (#938) by @hjgraca
  • chore: Console output overrides lambda console out (#936) by @hjgraca
  • chore: Add missing PTENV to user agent (#927) by @hjgraca

This release was made possible by the following contributors:

@dependabot[bot], @hjgraca, @sdangol, @swopnildangol and dependabot[bot]