Correlation Between HTTP Requests (W3C)
The Arcus.WebApi.Logging
library provides a way to add correlation between HTTP requests.
🚩 This page describes W3C Trace-Context correlation, see this page for information on the (deprecated) Hierarchical HTTP correlation.
How This Works​
This diagram shows an example of a user interacting with service A that calls another service B.
Three kind of correlation ID's are used to create the relationship:
- Transaction ID: this ID is the one constant in the diagram. This ID is used to describe the entire transaction, from begin to end. All telemetry will be tracked under this ID.
- Operation ID: this ID describes a single operation within the transaction. This ID is used within a service to link all telemetry correctly together.
- Operation Parent ID: this ID is create the parent/child link across services. When service A calls service B, then service A is the so called 'parent' of service B.
The following list shows each step in the diagram:
- The initial call in this example doesn't contain any correlation headers. This can be seen as a first interaction call to a service.
- Upon receiving at service A, the application will generate new correlation information. This correlation info will be used when telemetry is tracked on the service.
- When a call is made to service B, the transaction ID is sent but also the operation parent ID in the form of a W3C structure:
00-transactionId-parentId-00
. - The
def
part of this ID, describes the new parent ID for service B (when service B calls service C, then it will use a different parent ID) - Service B responds to service A with the same information as the call to service B.
- The user receives both the transaction ID and operation ID in their final response.
💡 This correlation is based on the traceparent
HTTP request/response header.
Additional configuration is available to tweak this functionality.
⚡ Automatic dependency tracking​
When choosing for the W3C HTTP correlation format, Arcus and Microsoft technology works seemingly together. When a HTTP request is received on a service that uses the Arcus W3C HTTP correlation, all remote dependencies managed my Microsoft (HTTP, ServiceBus, EventHubs...) are tracked automatically, without additional configuration.
Installation​
This feature requires to install our NuGet package:
PM > Install-Package Arcus.WebApi.Logging
Usage​
To fully benefit from the Arcus' HTTP correlation functionality, both sending and receiving HTTP endpoints should be configured. These three things need to be added on both sides:
- Adding HTTP correlation to application services with
services.AddHttpCorrelation()
. - Adding HTTP correlation to application middleware with
app.UseHttpCorrelation()
andapp.UseRequestTracking()
(more info on request tracking). - Adding HTTP correlation enricher to Serilog configuration with
Enrich.WithHttpCorrelationInfo(app.Services)
(more info).
using Microsoft.AspNetCore.Builder;
using Serilog;
using Serilog.Configuration;
WebApplication builder = WebApplication.CreateBuilder();
builder.Services.AddHttpCorrelation();
builder.Services.AddHttpClient("from-service-a-to-service-b");
builder.Host.UseSerilog((context, serviceProvider, config) =>
{
config.Enrich.WithHttpCorrelationInfo(serviceProvider)
.WriteTo.Console()
.CreateLogger();
});
WebApplication app = builder.Build();
app.UseHttpCorrelation();
// âš Because the correlation is based on <span>ASP.NET</span> Core middleware, it's recommended to place it before the `.UseRouting` call.
app.UseRouting();
app.UseRequestTracking();
âš¡ The
UseRequestTracking
extension will make sure that the incoming HTTP request will be tracked as a 'request' in Application Insights (if configured). For more information on HTTP request tracking, see our dedicated feature documentation page;
âš¡ As an additional feature, we provide an extension to use the HTTP correlation directly in a Serilog configuration as an enricher. This adds the correlation information of the current request to the log event as a log property called
TransactionId
,OperationId
, andOperationParentId
. Example
TransactionId
:4b1c0c8d608f57db7bd0b13c88ef865e
OperationId
:4a3c1c8d
OperationParentId
:4c6893cc6c6cad10
âš¡ To use HTTP correlation in Azure Functions, see this dedicated page, as the configuration on the receiving side is slightly different.
Configuration​
The HTTP correlation can be configured with different options to work for your needs.
Configuring HTTP correlation services​
The HTTP correlation is available throughout the application via the registered IHttpCorrelationInfoAccessor
. This HTTP correlation accessor is both used in sending/receiving functionality.
Some extra options are available to alter the functionality of the correlation:
using Microsoft.AspNetCore.Builder;
WebApplicationBuilder builder = WebApplication.CreateBuilder();
builder.Services.AddHttpCorrelation(options =>
{
// Configuration on the transaction ID (`X-Transaction-ID`) response header.
// ---------------------------------------------------------------------------------
// Whether to include the transaction ID in the response (default: true).
options.Transaction.IncludeInResponse = true;
// The header will be set in the HTTP response (default: X-Transaction-ID).
options.Transaction.HeaderName = "X-Transaction-ID";
// Configuration on the operation ID (`X-Operation-Id`) response header.
// ----------------------------------------------------------------
// Whether to include the operation ID in the response (default: true).
options.Operation.IncludeInResponse = true;
// The header that will contain the operation ID in the HTTP response (default: X-Operation-Id).
options.Operation.HeaderName = "X-MyOperation-Id";
});
Dependency injection​
To use the HTTP correlation in your application code, you can use a dedicated marker interface called IHttpCorrelationInfoAccessor
.
This will help you with accessing and setting the HTTP correlation.
Note that the correlation is a scoped dependency, so will be the same instance across the HTTP request.
using Microsoft.AspNetCore.Mvc;
using Arcus.WebApi.Logging.Core.Correlation;
[ApiController]
[Route("api/v1/order")]
public class OrderController : ControllerBase
{
private readonly IHttpCorrelationInfoAccessor _accessor;
public OrderController(IHttpCorrelationInfoAccessor accessor)
{
_accessor = accessor;
}
[HttpPost]
public IActionResult Post([FromBody] Order order)
{
CorrelationInfo correlation = _accessor.GetCorrelationInfo();
_accessor.SetCorrelationInfo(correlation);
}
}