AWS Lambda Powertools for .NET: Complete Observability Guide

Observability in serverless is challenging. Lambda functions execute in ephemeral environments, making traditional APM tools ineffective. AWS Lambda Powertools for .NET provides structured logging, distributed tracing, and custom metrics out of the box—implementing AWS Well-Architected best practices without boilerplate. This guide covers installation, configuration, and production patterns for each Powertools utility.

The Observability Challenge in Serverless

Traditional observability relies on agents running alongside your application. In Lambda, you cannot install agents. The execution environment is recycled. Logs must be structured for CloudWatch Logs Insights queries. Traces must integrate with AWS X-Ray. Metrics must flow to CloudWatch Metrics.

Lambda Powertools solves this with three core utilities:

flowchart TB
    subgraph Powertools ["Lambda Powertools"]
        Logger["Logger (Structured Logging)"]
        Tracer["Tracer (X-Ray Integration)"]
        Metrics["Metrics (CloudWatch EMF)"]
    end
    
    Logger --> CWLogs["CloudWatch Logs"]
    Tracer --> XRay["AWS X-Ray"]
    Metrics --> CWMetrics["CloudWatch Metrics"]
    
    style Logger fill:#E1F5FE,stroke:#0277BD
    style Tracer fill:#C8E6C9,stroke:#2E7D32
    style Metrics fill:#FFF3E0,stroke:#E65100

Installation

dotnet add package AWS.Lambda.Powertools.Logging
dotnet add package AWS.Lambda.Powertools.Tracing
dotnet add package AWS.Lambda.Powertools.Metrics

Structured Logging

The Logging utility outputs JSON-structured logs that CloudWatch Logs Insights can query efficiently.

using AWS.Lambda.Powertools.Logging;

public class OrderFunction
{
    [Logging(LogEvent = true, Service = "OrderService")]
    public async Task<APIGatewayProxyResponse> Handler(
        APIGatewayProxyRequest request, 
        ILambdaContext context)
    {
        // Add custom keys to all subsequent logs
        Logger.AppendKey("orderId", "12345");
        Logger.AppendKey("customerId", "C-789");
        
        Logger.LogInformation("Processing order");
        
        try
        {
            var result = await ProcessOrderAsync();
            Logger.LogInformation("Order processed successfully", new { 
                Total = result.Total, 
                ItemCount = result.Items.Count 
            });
            
            return new APIGatewayProxyResponse { StatusCode = 200 };
        }
        catch (Exception ex)
        {
            Logger.LogError(ex, "Order processing failed");
            throw;
        }
    }
}

Log Output

{
  "level": "Information",
  "message": "Processing order",
  "timestamp": "2022-06-02T10:30:00.000Z",
  "service": "OrderService",
  "cold_start": true,
  "function_name": "OrderFunction",
  "function_memory_size": 1024,
  "function_arn": "arn:aws:lambda:...",
  "function_request_id": "abc-123",
  "orderId": "12345",
  "customerId": "C-789"
}

Querying in CloudWatch Logs Insights

fields @timestamp, message, orderId, customerId
| filter service = "OrderService" and level = "Error"
| sort @timestamp desc
| limit 100

Distributed Tracing

The Tracing utility integrates with AWS X-Ray, capturing subsegments for method calls, HTTP requests, and AWS SDK operations.

using AWS.Lambda.Powertools.Tracing;

public class OrderFunction
{
    private readonly IOrderRepository _repository;
    private readonly IPaymentService _paymentService;
    
    [Tracing(CaptureMode = TracingCaptureMode.ResponseAndError)]
    public async Task<APIGatewayProxyResponse> Handler(
        APIGatewayProxyRequest request, 
        ILambdaContext context)
    {
        var order = await ValidateOrderAsync(request);
        var payment = await ProcessPaymentAsync(order);
        await SaveOrderAsync(order);
        
        return new APIGatewayProxyResponse { StatusCode = 200 };
    }
    
    [Tracing(SegmentName = "ValidateOrder")]
    private async Task<Order> ValidateOrderAsync(APIGatewayProxyRequest request)
    {
        // Custom subsegment created automatically
        Tracing.AddAnnotation("OrderType", "Standard");
        Tracing.AddMetadata("RawPayload", request.Body);
        
        return JsonSerializer.Deserialize<Order>(request.Body);
    }
    
    [Tracing(SegmentName = "ProcessPayment")]
    private async Task<PaymentResult> ProcessPaymentAsync(Order order)
    {
        // HTTP calls to external services are automatically traced
        return await _paymentService.ChargeAsync(order.Total);
    }
}

Custom Metrics

The Metrics utility uses CloudWatch Embedded Metric Format (EMF) to publish high-cardinality metrics without API calls.

using AWS.Lambda.Powertools.Metrics;

public class OrderFunction
{
    [Metrics(Namespace = "Ecommerce", Service = "OrderService")]
    public async Task<APIGatewayProxyResponse> Handler(
        APIGatewayProxyRequest request, 
        ILambdaContext context)
    {
        var stopwatch = Stopwatch.StartNew();
        
        try
        {
            var order = await ProcessOrderAsync();
            
            // Record custom metrics
            Metrics.AddMetric("OrdersProcessed", 1, MetricUnit.Count);
            Metrics.AddMetric("OrderTotal", order.Total, MetricUnit.None);
            Metrics.AddDimension("Region", order.ShippingRegion);
            Metrics.AddDimension("CustomerTier", order.CustomerTier);
            
            return new APIGatewayProxyResponse { StatusCode = 200 };
        }
        catch (Exception ex)
        {
            Metrics.AddMetric("OrdersFailed", 1, MetricUnit.Count);
            throw;
        }
        finally
        {
            Metrics.AddMetric("ProcessingTime", stopwatch.ElapsedMilliseconds, MetricUnit.Milliseconds);
        }
    }
}

Environment Configuration

# SAM template
Globals:
  Function:
    Environment:
      Variables:
        POWERTOOLS_SERVICE_NAME: OrderService
        POWERTOOLS_METRICS_NAMESPACE: Ecommerce
        POWERTOOLS_LOG_LEVEL: Information
        POWERTOOLS_TRACER_CAPTURE_RESPONSE: true
        POWERTOOLS_TRACER_CAPTURE_ERROR: true

Key Takeaways

  • Install all three Powertools packages for comprehensive observability
  • Logger outputs structured JSON for CloudWatch Logs Insights
  • Tracer integrates with X-Ray automatically
  • Metrics uses EMF for zero-latency metric publishing
  • Configure via environment variables for consistency
  • Use decorators/attributes for clean, declarative instrumentation

References


Discover more from C4: Container, Code, Cloud & Context

Subscribe to get the latest posts sent to your email.

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.