How To Easily Get Started with AWS Lambda Tracing in .NET using Powertools

By admin
Powertools for

AWS Lambda
ORG

(.NET) Tracing, is an opinionated wrapper for

AWS X-Ray .NET SDK
ORG

, aimed to reduce the overhead of performing common tracing tasks. Let’s explore how to easily get started with using the Lambda

Powertools
PERSON

Tracing library when building

AWS Lambda Functions
ORG

in .NET.


Powertools
PERSON

for

AWS Lambda
ORG

(.NET) Tracing, is an opinionated wrapper for

AWS X-Ray .NET SDK
ORG

, aimed to reduce the overhead of performing common tracing tasks.

Some of the key features that the

Powertools
PERSON

provides for tracing include attribute annotation, helper methods to easily add annotations and custom segments, capture function responses and exceptions as metadata, etc.

In this blog post, let’s explore how to easily get started with using the Lambda

Powertools
PERSON

Tracing library when building

AWS Lambda Functions
ORG

in .NET.

To see the Lambda

Powertools
PERSON

Tracing library in action, let’s

first
ORDINAL

create a Lambda Function.

Let’s use

the AWS Lambda Annotations Library
ORG

to quickly create an

API
ORG

Endpoint using

Lambda
PRODUCT

backend.

To an empty

Lambda
LOC

function project add

Amazon
ORG

.Lambda.Annotations ,

Amazon
ORG

.Lambda.

APIGatewayEvents
ORDINAL

and

AWS.Lambda
CARDINAL

.

Powertools
PERSON

.Tracing

NuGet
PRODUCT

packages.

To enable Tracing all we need to do is add the Tracing attribute to the required

Lambda
PRODUCT

function handler as shown below.

For this function to write to

AWS Cloudwatch
PERSON

and

AWS X-Ray
ORG

it needs the appropriate permissions. The AWSXRayDaemonWriteAccess and AWSLambdaBasicExecutionRole are in-built role policies that give the required permissions.

[LambdaFunction(Policies = "AWSXRayDaemonWriteAccess, AWSLambdaBasicExecutionRole")] [HttpApi(LambdaHttpMethod.Get, template: "/{cityName}")] [Tracing] public List<WeatherForecast> GetWeather(string cityName, ILambdaContext context) { return new List<WeatherForecast> { new

WeatherForecast
PRODUCT

{ CityName = cityName, Date = DateTime.

Today
DATE

, TemperatureC = Random.Shared.

Next(-10
GPE

,

50
DATE

) } }; }

The Function returns a hardcoded list of

WeatherForecast
ORG

objects for a given cityName .

Once deployed to

AWS
ORG

, make sure to enable ‘Active Tracing’ for the

Lambda
ORG

function under the ‘Monitoring and operations tools’ in the Configuration section of

the Lambda Function
ORG

.

Enable Active Tracing on

the AWS Lambda Function
ORG

deployed for it to start capturing trace information.

As you make requests to the API Gateway endpoint for the deployed

API
ORG

endpoint, it starts collecting trace information for the

API
ORG

request.

You can view the

Trace
ORG

under the Monitor → Traces section for

the AWS Lambda Function
ORG

.

X-Ray Trace information summary for

the AWS Lambda Function
ORG

in the AWS Console. It shows the Service map and also the associated traces.

You can drill into each of the

Trace
ORG

entries to see more details about the specific trace entry.

Trace detail for a Lambda Function API invocation. It shows all the segments and subsegments created from

the Lambda Function
LAW

code.

If you are new to

AWS X-Ray
ORG

, check out the video below to get started.

Additional Segments

The Tracing library allows capturing additional sub-segments for the main function call.

You can do this by annotating any of the C# Functions with the Tracing attribute like before, or explicitly using the helper method

WithSubsegment
ORG

on the Tracing class.

Below is an example function that the main

Lambda Function Handler
ORG

calls into now to generate the fake

WeatherForecast
ORG

data.

By annotating the function with the Tracing attribute, the function gets automatically traced as a sub-segment.

[Tracing] public async Task<List<WeatherForecast>> GenerateFakeDataWithDelay(string cityName) { await

Task
PRODUCT

.Delay(1000); Tracing.

WithSubsegment
ORG

( "TimeConsumingSubProcess", async _ => { await

Task
PRODUCT

.Delay(500); }); return new List<WeatherForecast> { new

WeatherForecast
PRODUCT

{ CityName = cityName, Date = DateTime.

Today
DATE

, TemperatureC = Random.Shared.

Next(-10
GPE

,

50
DATE

) } }; }

You can see the new sub-segments for the new traces in

the AWS Console
LOC

as shown below.

AWS Lambda Function trace showing additional sub-segments logged using the Tracing attribute and also the helper method.

Annotations and

Metadata
ORG

AWS X-Ray allows the recording of additional information about requests, the environment, or the application with annotations and metadata.

Annotations and

Metadata
ORG

are attached to the segment or sub-segment and are both key-value pairs.

Annotations are indexed for use with filter expressions while

Metadata
ORG

are not indexed and cannot be used in the filter expressions.

The Tracing class from the

Powertools
PERSON

Tracing library exposes

two
CARDINAL

methods,

AddAnnotation
ORG

and

AddMetadata
ORG

to add annotations and metadata to the trace segment.

Tracing.AddAnnotation("City", cityName); Tracing.

AddMetadata("Count
ORG

", results.Count);

Annotations and

Metadata
ORG

are shown under the corresponding segment detail in the AWS Console as key-value pairs, as shown in the screenshot below.

Annotations and

Metadata
ORG

are shown as key-value pairs under the corresponding segment detail in

the AWS Console
LOC

.


Instrumenting Other AWS Services
ORG

Often when building

Lambda Functions
ORG

we integrate with other

AWS Services
ORG

, like DynamoDB,

SQS
ORG

,

SNS
ORG

, Secrets Manager, etc. In these cases, you use the appropriate .NET

Nuget
ORG

packages to talk to these services.

You can instrument all calls made using the

AWS
ORG

SDK for .NET clients by calling the RegisterForAllServices method on the Tracing class. Ensure to make this call before the .NET client is instantiated.

The below code shows how to register the DynamoDB client to be captured into the

Trace
ORG

information.

public Function() { Tracing.RegisterForAllServices(); dynamoDbContext = new DynamoDBContext(new AmazonDynamoDBClient()); }

In the Function constructor, before creating the

DynamoDBContext
ORG

instance, call the RegisterForAllServices helper function.

The actual

Lambda
PRODUCT

function code now uses the

DynamoDBContext
ORG

to retrieve Weather forecast data for a given city name.

[

LambdaFunction(Role
PRODUCT

= "@WeatherApiLambdaExecutionRole")] [HttpApi(LambdaHttpMethod.Get, template: "/{cityName}")] [Tracing(Namespace = "

GetWeather
WORK_OF_ART

")] public async Task<List<WeatherForecast>> GetWeather(string cityName, ILambdaContext context) { Tracing.AddAnnotation("City", cityName); var results = await dynamoDbContext.

QueryAsync
PERSON

<WeatherForecast>(cityName).GetRemainingAsync(); Tracing.

AddMetadata("Count
ORG

", results.Count); return results; }

You can see the calls to DynamoDB in the trace information as shown below in the screenshot.

AWS X-Ray Trace information showing calls to DynamoDB and the information related to it.

Similarly, you can show the trace information to any external

AWS Services
ORG

and also other HTTP client calls that you make from your application.

This makes it very easy to keep track of tracing information to external dependencies.