AWS X-Ray recommends using AWS Distro for OpenTelemetry (ADOT) to instrument your application instead of this X-Ray SDK due to its wider range of features and instrumentations. See the AWS X-Ray docs on Working with .NET for more help with choosing between ADOT and X-Ray SDK.
If you want additional features when tracing your .NET applications, please open an issue on the OpenTelemetry .NET Instrumentation repository.
The AWS X-Ray SDK for .NET and .NET Core (.netstandard 2.0 and above) is in the form of Nuget packages. You can install the packages from Nuget gallery or from Visual Studio editor. Search AWSXRayRecorder*
to see various middlewares available.
Use the following community resources for getting help with the SDK. We use the GitHub issues for tracking bugs and feature requests.
- Ask a question in the AWS X-Ray Forum.
- Open a support ticket with AWS Support.
- If you think you may have found a bug, open an issue.
If you encounter a bug with the AWS X-Ray SDK for .NET/.NET Core, we want to hear about it. Before opening a new issue, search the existing issues to see if others are also experiencing the issue. Include platform (.NET/ .NET Core). In addition, include the repro case when appropriate.
The GitHub issues are intended for bug reports and feature requests. For help and questions about using the AWS X-Ray SDK for .NET and .NET Core, use the resources listed in the Getting Help section. Keeping the list of open issues lean helps us respond in a timely manner.
The developer guide provides in-depth guidance about using the AWS X-Ray service. Following API reference documentation provides guidance for using the SDK and module-level documentation.
- The API Reference for .NET
- The API Reference for .NET Core
- AWS X-Ray SDK Documentation for .NET SDK
- Sample Apps
- Configuration
- ASP.NET Core Framework
- ASP.NET Framework
- Trace AWS SDK request
- Trace out-going HTTP requests
- Trace Query to SQL Server
- Trace SQL Query through Entity Framework
- Multithreaded Execution
- Trace custom methods
- Creating custom Segment/Subsegment
- Adding metadata/annotations
- AWS Lambda support (.NET Core)
- ASP.NET Core on AWS Lambda
- Logging
- Enabling X-Ray on Elastic Beanstalk
- Enabling X-Ray on AWS Lambda
You can configure X-Ray in the appsettings
of your App.config
or Web.config
file.
<configuration>
<appSettings>
<add key="DisableXRayTracing" value="false"/>
<add key="AWSXRayPlugins" value="EC2Plugin, ECSPlugin, ElasticBeanstalkPlugin"/>
<add key="SamplingRuleManifest" value="JSONs\DefaultSamplingRules.json"/>
<add key="AwsServiceHandlerManifest" value="JSONs\AWSRequestInfo.json"/>
<add key="UseRuntimeErrors" value="true"/>
<add key="CollectSqlQueries" value="false"/>
</appSettings>
</configuration>
Following are the steps to configure your .NET Core project with X-Ray.
a) In appsettings.json
file, configure items under XRay
key
{
"XRay": {
"DisableXRayTracing": "false",
"SamplingRuleManifest": "SamplingRules.json",
"AWSXRayPlugins": "EC2Plugin, ECSPlugin, ElasticBeanstalkPlugin",
"AwsServiceHandlerManifest": "JSONs\AWSRequestInfo.json",
"UseRuntimeErrors":"true",
"CollectSqlQueries":"false"
}
}
b) Register IConfiguration
instance with X-Ray:
using Amazon.XRay.Recorder.Core;
AWSXRayRecorder.InitializeInstance(configuration); // pass IConfiguration object that reads appsettings.json file
Note:
- You should configure this before initialization of
AWSXRayRecorder
instance and using any AWS X-Ray methods. - If you manually need to configure
IConfiguration
object refer: Link - For more information on configuration, please refer : Link
Alternatively, you can also set up the AWSXRayRecorder
instance programmatically by using the AWSXRayRecorderBuilder
class instead of a configuration file.
For initializing an AWSXRayRecorder instance with default configurations, simply do the following.
using Amazon.XRay.Recorder.Core;
AWSXRayRecorder recorder = new AWSXRayRecorderBuilder().Build();
AWSXRayRecorder.InitializeInstance(recorder: recorder);
The following code initializes an AWSXRayRecorder
instance with a custom IStreamingStrategy
and a custom ISamplingStrategy
.
using Amazon.XRay.Recorder.Core;
AWSXRayRecorder recorder = new AWSXRayRecorderBuilder().WithStreamingStrategy(new CustomStreamingStrategy()).WithSamplingStrategy(CustomSamplingStrategy()).Build();
AWSXRayRecorder.InitializeInstance(recorder: recorder);
Note:
CustomStreamingStrategy
andCustomSamplingStrategy
must implementIStreamingStrategy
andISamplingStrategy
before being used to build therecorder
.recorder
must be instantiated usingAWSXRayRecorder.InitializeInstance(recorder: recorder)
before being used in the program.
ASP.NET Core Framework (.NET Core) : Nuget
You can instrument X-Ray for your ASP.NET Core
App in the Configure()
method of Startup.cs
file of your project.
Note :
- For .Net Core 2.1 and above, use
app.UseXRay()
middleware before any other middleware to trace incoming requests. For .Net Core 2.0 place theapp.UseXRay()
middleware after theapp.UseExceptionHandler("/Error")
in order to catch exceptions. You would be able to see any runtime exception with its stack trace, however, the status code might show 200 due to a known limitation of the ExceptionHandler middleware in .Net Core 2.0. - You need to install
AWSXRayRecorder.Handlers.AspNetCore
nuget package. This package adds extension methods to theIApplicationBuilder
to make it easy to register AWS X-Ray to the ASP.NET Core HTTP pipeline.
A) With default configuration:
- For .Net Core 2.1 and above:
using Microsoft.AspNetCore.Builder;
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseXRay("SampleApp"); // name of the app
app.UseExceptionHandler("/Error");
app.UseStaticFiles(); // rest of the middlewares
app.UseMVC();
}
- For .Net Core 2.0:
using Microsoft.AspNetCore.Builder;
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseExceptionHandler("/Error");
app.UseXRay("SampleApp"); // name of the app
app.UseStaticFiles(); // rest of the middlewares
app.UseMVC();
}
B) With custom X-Ray configuration
using Microsoft.AspNetCore.Builder;
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseExceptionHandler("/Error");
app.UseXRay("SampleApp",configuration); // IConfiguration object is not required if you have used "AWSXRayRecorder.InitializeInstance(configuration)" method
app.UseStaticFiles(); // rest of the middlewares
app.UseMVC();
}
Instead of name you can also pass SegmentNamingStrategy
in the above two ways. Please refer: Link
ASP.NET Framework (.NET) : Nuget
HTTP Message handler for ASP.NET framework
Register your application with X-Ray in the Init()
method of Global.asax file
using Amazon.XRay.Recorder.Handlers.AspNet;
public class MvcApplication : System.Web.HttpApplication
{
public override void Init()
{
base.Init();
AWSXRayASPNET.RegisterXRay(this, "ASPNETTest"); // default name of the web app
}
}
At the start of each Http request, a segment
is created and stored in the context
(Key : AWSXRayASPNET.XRayEntity) of HttpApplication
instance. If users write their custom error handler for ASP.NET framework, they can access segment
for the current request by following way :
<%@ Import Namespace="Amazon.XRay.Recorder.Handlers.AspNet" %>
<%@ Import Namespace="Amazon.XRay.Recorder.Core.Internal.Entities" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
var context = System.Web.HttpContext.Current.ApplicationInstance.Context;
var segment = (Segment) context.Items[AWSXRayASPNET.XRayEntity]; // get segment from the context
segment.AddMetadata("Error","404");
}
</script>
Trace AWS SDK request (.NET and .NET Core) : Nuget
using Amazon.XRay.Recorder.Handlers.AwsSdk;
AWSSDKHandler.RegisterXRayForAllServices(); //place this before any instantiation of AmazonServiceClient
AmazonDynamoDBClient client = new AmazonDynamoDBClient(RegionEndpoint.USWest2); // AmazonDynamoDBClient is automatically registered with X-Ray
Methods of AWSSDKHandler
class:
AWSSDKHandler.RegisterXRayForAllServices(); // all instances of AmazonServiceClient created after this line are registered
AWSSDKHandler.RegisterXRay<IAmazonDynamoDB>(); // Registers specific type of AmazonServiceClient : All instances of IAmazonDynamoDB created after this line are registered
AWSSDKHandler.RegisterXRayManifest(String path); // To configure custom AWS Service Manifest file. This is optional, if you have followed "Configuration" section
Trace out-going HTTP requests (.NET and .NET Core) : Nuget
An extension method GetResponseTraced()
is provided to trace GetResponse()
in System.Net.HttpWebRequest
class. If you want to trace the out-going HTTP request, call the GetResponseTraced()
instead of GetResponse()
. The extension method will generate a trace subsegment, inject the trace header to the out-going HTTP request header and collect trace information.
using Amazon.XRay.Recorder.Handlers.System.Net;
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(URL); // enter desired url
// Any other configuration to the request
request.GetResponseTraced();
An extension method GetAsyncResponseTraced()
is provided to trace GetResponseAsync()
in System.Net.HttpWebRequest
class. If you want to trace the out-going HTTP request, call the GetAsyncResponseTraced()
instead of GetResponseAsync()
. The extension method will generate a trace subsegment, inject the trace header to the out-going HTTP request header and collect trace information.
using Amazon.XRay.Recorder.Handlers.System.Net;
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(URL); // enter desired url
// Any other configuration to the request
request.GetAsyncResponseTraced();
A handler derived from DelegatingHandler
is provided to trace the HttpMessageHandler.SendAsync
method
using Amazon.XRay.Recorder.Handlers.System.Net;
var httpClient = new HttpClient(new HttpClientXRayTracingHandler(new HttpClientHandler()));
// Any other configuration to the client
httpClient.GetAsync(URL);
The Amazon.XRay.Recorder.Handlers.System.Net
package includes a delegate that can be used to trace outbound requests without the need to specifically wrap outbound requests from that class.
Register the HttpClientXRayTracingHandler
as a middleware for your http client.
services.AddHttpClient<IFooClient, FooClient>()
.AddHttpMessageHandler<HttpClientXRayTracingHandler>();
or
services.AddHttpClient("foo")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientXRayTracingHandler(new HttpClientHandler());
});
Use the above client factory to create clients with outgoing requests traced.
var client = _clientFactory.CreateClient("foo");
var request = new HttpRequestMessage(HttpMethod.Get, "https://www.foobar.com");
var response = await client.SendAsync(request);
Trace Query to SQL Server (.NET and .NET Core) : Nuget
The SDK provides a wrapper class for System.Data.SqlClient.SqlCommand
. The wrapper class can be used interchangable with SqlCommand
class. By replacing instance of SqlCommand
to TraceableSqlCommand
, synchronized/asynchronized method will automatically generate subsegment for the SQL query.
Following examples illustrate the use of TraceableSqlCommand
to automatically trace SQL Server queries using Synchronous/Asynchronous methods:
using Amazon.XRay.Recorder.Handlers.SqlServer;
using (var connection = new SqlConnection("fake connection string"))
using (var command = new TraceableSqlCommand("SELECT * FROM products", connection))
{
command.ExecuteNonQuery();
}
using Amazon.XRay.Recorder.Handlers.SqlServer;
using (var connection = new SqlConnection(ConnectionString))
{
var command = new TraceableSqlCommand("SELECT * FROM Products FOR XML AUTO, ELEMENTS", connection);
command.Connection.Open();
await command.ExecuteXmlReaderAsync();
}
You can also opt in to capture the SqlCommand.CommandText
as part of the subsegment created for your SQL query. The collected SqlCommand.CommandText
will appear as sanitized_query
in the subsegment JSON. By default, this feature is disabled due to security reasons. If you want to enable this feature, it can be done in two ways. First, by setting the CollectSqlQueries
to true
in the global configuration for your application as follows:
<configuration>
<appSettings>
<add key="CollectSqlQueries" value="true">
</appSettings>
</configuration>
{
"XRay": {
"CollectSqlQueries":"true"
}
}
This will enable X-Ray to collect all the sql queries made to SQL Server by your application.
Secondly, you can set the collectSqlQueries
parameter in the TraceableSqlCommand
instance as true
to collect the SQL query text for SQL Server query calls made using this instance. If you set this parameter as false
, it will disable the CollectSqlQuery feature for this TraceableSqlCommand
instance.
using Amazon.XRay.Recorder.Handlers.SqlServer;
using (var connection = new SqlConnection("fake connection string"))
using (var command = new TraceableSqlCommand("SELECT * FROM products", connection, collectSqlQueries: true))
{
command.ExecuteNonQuery();
}
NOTE:
- You should not enable either of these properties if you are including sensitive information as clear text in your SQL queries.
- Parameterized values will appear in their tokenized form and will not be expanded.
- The value of
collectSqlQueries
in theTraceableSqlCommand
instance overrides the value set in the global configuration using theCollectSqlQueries
property.
Trace SQL Query through Entity Framework (.NET and .NET Core) : Nuget
AWS XRay SDK for .NET Core provides interceptor for tracing SQL query through Entity Framework Core (>=3.0).
For how to start with Entity Framework Core in an ASP.NET Core web app, please take reference to Link
NOTE:
- You need to install
AWSXRayRecorder.Handlers.EntityFramework
nuget package. This package adds extension methods to theDbContextOptionsBuilder
to make it easy to register AWS X-Ray interceptor. - Not all database provider support Entity Framework Core 3.0 and above, please make sure that you are using the Nuget package with a compatible version (EF Core >= 3.0).
Known Limitation (as of 12-03-2020): If you're using another DbCommandInterceptor
implementation along with the AddXRayInterceptor
in the DbContext
, it may not work as expected and you may see a "EntityNotAvailableException" from the XRay EFCore interceptor. This is due to AsyncLocal
not being able to maintain context across the ReaderExecutingAsync
and ReaderExecutedAsync
methods. Ref here for more details on the issue.
In order to trace SQL query, you can register your DbContext
with AddXRayInterceptor()
accordingly in the ConfigureServices
method in startup.cs
file.
For instance, when dealing with MySql server using Nuget: Pomelo.EntityFrameworkCore.MySql (V 3.1.1).
using Microsoft.EntityFrameworkCore;
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<your_DbContext>(options => options.UseMySql(your_connectionString).AddXRayInterceptor());
}
Alternatively, you can register AddXRayInterceptor()
in the Onconfiguring
method in your DbContext
class. Below we are using Nuget: Microsoft.EntityFrameworkCore.Sqlite (V 3.1.2)
using Microsoft.EntityFrameworkCore;
public class your_DbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlite(your_connectionString).AddXRayInterceptor();
}
The connection string can be either hard coded or configured from appsettings.json
file.
AWS XRay SDK for .NET provides interceptor for tracing SQL query through Entity Framework 6 (>= 6.2.0).
For how to start with Entity Framework 6 in an ASP.NET web app, please take reference to link.
For instrumentation, you will need to install AWSXRayRecorder.Handlers.EntityFramework
nuget package and call AWSXRayEntityFramework6.AddXRayInterceptor()
in your code. Make sure to call it only once to avoid duplicate tracing.
For instance, you can call AddXRayInterceptor()
in the Application_Start
method of Global.asax file.
using Amazon.XRay.Recorder.Handlers.EntityFramework;
protected void Application_Start()
{
AWSXRayEntityFramework6.AddXRayInterceptor();
}
Or you can call it in the DbConfiguration
class if there is one in your application to configure execution policy.
using Amazon.XRay.Recorder.Handlers.EntityFramework;
public class YourDbConfiguration : DbConfiguration
{
public YourDbConfiguration()
{
AWSXRayEntityFramework6.AddXRayInterceptor();
}
}
You can also opt in to capture the DbCommand.CommandText
as part of the subsegment created for your SQL query. The collected DbCommand.CommandText
will appear as sanitized_query
in the subsegment JSON. By default, this feature is disabled due to security reasons.
If you want to enable this feature, it can be done in two ways. First, by setting the CollectSqlQueries
to true in the appsettings.json
file as follows:
{
"XRay": {
"CollectSqlQueries":"true"
}
}
Secondly, you can set the collectSqlQueries
parameter in the AddXRayInterceptor()
as true to collect the SQL query text. If you set this parameter as false, it will disable the collectSqlQueries
feature for this AddXRayInterceptor()
. Opting in AddXRayInterceptor()
has the highest execution priority, which will override the configuration item in appsettings.json
mentioned above.
using Microsoft.EntityFrameworkCore;
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<your_DbContext>(options => options.UseMySql(your_connectionString).AddXRayInterceptor(true));
}
Or
using Microsoft.EntityFrameworkCore;
public class your_DbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlite(your_connectionString).AddXRayInterceptor(true);
}
You can enable tracing SQL query text for EF 6 interceptor in the Web.config
file.
<configuration>
<appSettings>
<add key="CollectSqlQueries" value="true"/>
</appSettings>
</configuration>
You can also pass true to AddXRayInterceptor()
to collect SQL query text, otherwise pass false to disable. Opting in AddXRayInterceptor()
has the highest execution priority, which will override the configuration item in Web.config
mentioned above.
using Amazon.XRay.Recorder.Handlers.EntityFramework;
AWSXRayEntityFramework6.AddXRayInterceptor(true);
Multithreaded Execution (.NET and .NET Core) : Nuget
In multithreaded execution, X-Ray context from current to its child thread is automatically set.
using Amazon.XRay.Recorder.Core;
private static void TestMultiThreaded()
{
int numThreads = 3;
AWSXRayRecorder.Instance.BeginSegment("MainThread");
Thread[] t= new Thread[numThreads];
for(int i = 0; i < numThreads; i++)
{
t[i] = new Thread(()=>MakeHttpRequest(i));
t[i].Start();
}
for (int i = 0; i < numThreads; i++)
{
t[i].Join();
}
AWSXRayRecorder.Instance.EndSegment();
}
private static void MakeHttpRequest(int i)
{
AWSXRayRecorder.Instance.TraceMethodAsync("Thread "+i, CreateRequestAsync<HttpResponseMessage>).Wait();
}
private static async Task<HttpResponseMessage> CreateRequestAsync <TResult>()
{
var request = new HttpClient();
var result = await request.GetAsync(URL); // Enter desired url
return result;
}
Note:
- Context used to save traces in .NET : CallContext
- Context used to save traces in .NET Core : AsyncLocal
It may be useful to further decorate portions of an application for which performance is critical. Generating subsegments around these hot spots will help in understanding their impact on application performance.
using Amazon.XRay.Recorder.Core;
AWSXRayRecorder.Instance.TraceMethod("custom method", () => DoSomething(arg1, arg2, arg3));
using Amazon.XRay.Recorder.Core;
var response = await AWSXRayRecorder.Instance.TraceMethodAsync("AddProduct", () => AddProduct<Document>(product));
private async Task<Document> AddProduct <TResult>(Product product)
{
var document = new Document();
document["Id"] = product.Id;
document["Name"] = product.Name;
document["Price"] = product.Price;
return await LazyTable.Value.PutItemAsync(document);
}
using Amazon.XRay.Recorder.Core;
AWSXRayRecorder.Instance.BeginSegment("segment name"); // generates `TraceId` for you
try
{
DoSometing();
// can create custom subsegments
}
catch (Exception e)
{
AWSXRayRecorder.Instance.AddException(e);
}
finally
{
AWSXRayRecorder.Instance.EndSegment();
}
If you want to pass custom TraceId
:
using Amazon.XRay.Recorder.Core;
String traceId = TraceId.NewId(); // This function is present in : Amazon.XRay.Recorder.Core.Internal.Entities
AWSXRayRecorder.Instance.BeginSegment("segment name",traceId); // custom traceId used while creating segment
try
{
DoSometing();
// can create custom subsegments
}
catch (Exception e)
{
AWSXRayRecorder.Instance.AddException(e);
}
finally
{
AWSXRayRecorder.Instance.EndSegment();
}
Note: This should only be used after BeginSegment()
method.
using Amazon.XRay.Recorder.Core;
AWSXRayRecorder.Instance.BeginSubsegment("subsegment name");
try
{
DoSometing();
}
catch (Exception e)
{
AWSXRayRecorder.Instance.AddException(e);
}
finally
{
AWSXRayRecorder.Instance.EndSubsegment();
}
using Amazon.XRay.Recorder.Core;
AWSXRayRecorder.Instance.AddAnnotation("mykey", "my value");
AWSXRayRecorder.Instance.AddMetadata("my key", "my value");
The AWS Lambda execution environment by default creates a Segment
before each Lambda function invocation and sends it to the X-Ray service. AWS X-Ray .NET/Core SDK will make sure there will be a FacadeSegment
inside the lambda context so that you can instrument your application successfully through subsegments only. Subsegments
generated inside a Lambda function are attached to this FacadeSegment
and only subsegments are streamed by the SDK. In addition to the custom subsegments, the middlewares would generate subsegments for outgoing HTTP calls, SQL queries, and AWS SDK calls within the lambda function the same way they do in a normal application.
Note: You can only create and close Subsegment
inside a lambda function. Segment
cannot be created inside the lambda function. All operations on Segment
will throw an UnsupportedOperationException
exception.
public string FunctionHandler(string input, ILambdaContext context)
{
AWSXRayRecorder recorder = new AWSXRayRecorder();
recorder.BeginSubsegment("UpperCase");
recorder.BeginSubsegment("Inner 1");
String result = input?.ToUpper();
recorder.EndSubsegment();
recorder.BeginSubsegment("Inner 2");
recorder.EndSubsegment();
recorder.EndSubsegment();
return result;
}
We support instrumenting ASP.NET Core web app on Lambda. Please follow the steps of ASP.NET Core instrumentation.
The AWS X-Ray .NET SDK share the same logging mechanism as AWS .NET SDK. If the application had already configured logging for AWS .NET SDK, it should just work for AWS X-Ray .NET SDK.
The recommended way to configure an application is to use the element in the project’s App.config
or Web.config
file.
<configuration>
<configSections>
<section name="aws" type="Amazon.AWSSection, AWSSDK.Core"/>
</configSections>
<aws>
<logging logTo="Log4Net"/>
</aws>
</configuration>
Other ways to configure logging is to edit the element in the App.config
or Web.config
file, and set property values in the AWSConfig
class. Refer to the following page for more details and example : Link
The AWS X-Ray .NET SDK share the same logging mechanism as AWS .NET SDK. To configure logging for .NET Core application, pass one of these options to the AWSXRayRecorder.RegisterLogger
method.
Following is the way to configure log4net
with X-Ray SDK:
using Amazon;
using Amazon.XRay.Recorder.Core;
class Program
{
static Program()
{
AWSXRayRecorder.RegisterLogger(LoggingOptions.Log4Net); // Log4Net instance should already be configured before this point
}
}
log4net.config example:
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="FileAppender" type="log4net.Appender.FileAppender,log4net">
<file value="c:\logs\sdk-log.txt" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %level %logger - %message%newline" />
</layout>
</appender>
<logger name="Amazon">
<level value="DEBUG" />
<appender-ref ref="FileAppender" />
</logger>
</log4net>
Note: For log4net
configuration, refer : Link
The AWS X-Ray SDK for .NET and .NET Core is licensed under the Apache 2.0 License. See LICENSE and NOTICE.txt for more information.