Skip to content

Commit 007fb9a

Browse files
feature(#6): this commit introduces correlation support to the project, improving observability and tracing
1 parent bbe0fd6 commit 007fb9a

7 files changed

Lines changed: 67 additions & 0 deletions

File tree

Boundaries/Comanda.Payments/Source/Comanda.Payments.WebApi/Constants/Headers.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,10 @@
33
public static class Headers
44
{
55
public const string Credential = "X-Credential";
6+
public const string Location = "Location";
7+
public const string Link = "Link";
8+
public const string Pagination = "X-Pagination";
9+
public const string Authorization = "Authorization";
10+
public const string Idempotency = "Idempotency-Key";
11+
public const string Correlation = "Correlation";
612
}

Boundaries/Comanda.Payments/Source/Comanda.Payments.WebApi/Extensions/HttpClientsExtension.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ public static void AddHttpClients(this IServiceCollection services, ISettings se
88
// register transient lifetime interceptors here
99
// https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/httpclient-parameters-handlers
1010
services.AddTransient<CredentialInterceptor>();
11+
services.AddTransient<CorrelationInterceptor>();
1112

1213
var paymentClient = services.AddHttpClient<IAbacatePayClient, AbacatePayClient>(client =>
1314
{
@@ -16,5 +17,6 @@ public static void AddHttpClients(this IServiceCollection services, ISettings se
1617
});
1718

1819
paymentClient.AddHttpMessageHandler<CredentialInterceptor>();
20+
paymentClient.AddHttpMessageHandler<CorrelationInterceptor>();
1921
}
2022
}

Boundaries/Comanda.Payments/Source/Comanda.Payments.WebApi/Extensions/HttpPipelineExtension.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public static void UseHttpPipeline(this IApplicationBuilder app)
1313
app.UseAuthentication();
1414
app.UseAuthorization();
1515

16+
app.UseCorrelationMiddleware();
1617
app.UseEndpoints(endpoints =>
1718
{
1819
endpoints.MapControllers();
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace Comanda.Payments.WebApi.Interceptors;
2+
3+
public sealed class CorrelationInterceptor(IHttpContextAccessor accessor) : DelegatingHandler
4+
{
5+
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
6+
{
7+
var correlation = accessor.HttpContext?.Items[Headers.Correlation]?.ToString();
8+
9+
if (!string.IsNullOrWhiteSpace(correlation))
10+
{
11+
request.Headers.Remove(Headers.Correlation);
12+
request.Headers.Add(Headers.Correlation, correlation);
13+
}
14+
15+
return await base.SendAsync(request, cancellationToken);
16+
}
17+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
namespace Comanda.Payments.WebApi.Middlewares;
2+
3+
public sealed class CorrelationMiddleware(RequestDelegate next)
4+
{
5+
public async Task InvokeAsync(HttpContext context)
6+
{
7+
var correlationId = context.Request.Headers[Headers.Correlation].FirstOrDefault();
8+
9+
if (string.IsNullOrWhiteSpace(correlationId))
10+
correlationId = context.TraceIdentifier;
11+
12+
context.Items[Headers.Correlation] = correlationId;
13+
context.Response.Headers[Headers.Correlation] = correlationId;
14+
15+
/* enriches the logging scope with the current correlation identifier, ensuring all logs within this request pipeline share the same identifier */
16+
/* more details: https://microsoft.github.io/code-with-engineering-playbook/observability/correlation-id/ */
17+
18+
using (LogContext.PushProperty(Headers.Correlation, correlationId))
19+
using (SentrySdk.PushScope())
20+
{
21+
SentrySdk.ConfigureScope(scope =>
22+
{
23+
scope.SetTag("correlation_id", correlationId);
24+
});
25+
26+
await next(context);
27+
}
28+
}
29+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace Comanda.Payments.WebApi.Middlewares;
2+
3+
[ExcludeFromCodeCoverage(Justification = "contains only dependency injection")]
4+
public static class CorrelationMiddlewareExtension
5+
{
6+
public static IApplicationBuilder UseCorrelationMiddleware(this IApplicationBuilder app)
7+
{
8+
return app.UseMiddleware<CorrelationMiddleware>();
9+
}
10+
}

Boundaries/Comanda.Payments/Source/Comanda.Payments.WebApi/Usings.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
global using Comanda.Payments.WebApi.Constants;
99
global using Comanda.Payments.WebApi.Interceptors;
1010
global using Comanda.Payments.WebApi.Extensions;
11+
global using Comanda.Payments.WebApi.Middlewares;
1112
global using Comanda.Payments.Domain.Errors;
1213

1314
global using Comanda.Payments.Application.Payloads.Traceability;
@@ -25,4 +26,5 @@
2526

2627
global using Scalar.AspNetCore;
2728
global using Serilog;
29+
global using Serilog.Context;
2830
global using FluentValidation.AspNetCore;

0 commit comments

Comments
 (0)