From f9b7af64550be1320acc84d60184e8c8ce873b94 Mon Sep 17 00:00:00 2001 From: Ariel Costas Guerrero Date: Sun, 25 Jan 2026 21:05:33 +0100 Subject: feat: Add OpenTelemetry instrumentation and configuration for enhanced telemetry tracking --- src/Enmarcha.Backend/Program.cs | 111 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) (limited to 'src/Enmarcha.Backend/Program.cs') diff --git a/src/Enmarcha.Backend/Program.cs b/src/Enmarcha.Backend/Program.cs index a13abec..8599a5c 100644 --- a/src/Enmarcha.Backend/Program.cs +++ b/src/Enmarcha.Backend/Program.cs @@ -1,14 +1,113 @@ using System.Text.Json.Serialization; +using Enmarcha.Backend; using Enmarcha.Backend.Configuration; using Enmarcha.Backend.Services; using Enmarcha.Backend.Services.Geocoding; using Enmarcha.Backend.Services.Processors; using Enmarcha.Backend.Services.Providers; +using Microsoft.AspNetCore.WebUtilities; +using OpenTelemetry.Logs; +using OpenTelemetry.Resources; +using OpenTelemetry.Trace; var builder = WebApplication.CreateBuilder(args); builder.Services.Configure(builder.Configuration.GetSection("App")); +var appConfig = builder.Configuration.GetSection("App").Get(); +var otelConfig = appConfig?.OpenTelemetry; + +builder.Logging.AddOpenTelemetry(options => +{ + options.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("Enmarcha.Backend")); + options.IncludeFormattedMessage = true; + options.IncludeScopes = true; + + if (otelConfig?.Endpoint != null) + { + options.AddOtlpExporter(exporterOptions => + { + exporterOptions.Endpoint = new Uri(otelConfig.Endpoint); + exporterOptions.Headers = otelConfig.Headers; + }); + } + +#if DEBUG + options.AddOtlpExporter(exporterOptions => + { + exporterOptions.Endpoint = new Uri("http://localhost:17011"); + }); +#endif +}); + +builder.Services.AddOpenTelemetry() + .WithTracing(tracing => + { + tracing + .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("Enmarcha.Backend")) + .AddSource(Telemetry.Source.Name) + .AddAspNetCoreInstrumentation() + .AddHttpClientInstrumentation(options => + { + options.EnrichWithHttpRequestMessage = (activity, req) => + { + var host = req.RequestUri?.Host; + if (host == null) return; + + // Set default peer service to host + activity.SetTag("peer.service", host); + activity.SetTag("server.address", host); + + if (host == "api.geoapify.com") + { + activity.SetTag("peer.service", "Geoapify"); + var query = QueryHelpers.ParseQuery(req.RequestUri!.Query); + if (query.ContainsKey("apiKey")) + { + var uriBuilder = new UriBuilder(req.RequestUri); + var newQuery = query.ToDictionary(x => x.Key, x => x.Value.ToString()); + newQuery["apiKey"] = "REDACTED"; + uriBuilder.Query = string.Join("&", newQuery.Select(x => $"{x.Key}={x.Value}")); + activity.SetTag("http.url", uriBuilder.ToString()); + } + } + else if (host.Contains("tussa.org")) + { + activity.SetTag("peer.service", "TUSSA"); + } + else if (host.Contains("itranvias.com")) + { + activity.SetTag("peer.service", "Tranvías Coruña"); + } + else if (host.Contains("vigo.org")) + { + activity.SetTag("peer.service", "Vitrasa"); + } + else if (appConfig?.OpenTripPlannerBaseUrl != null && req.RequestUri!.ToString().StartsWith(appConfig.OpenTripPlannerBaseUrl)) + { + activity.SetTag("peer.service", "OpenTripPlanner"); + } + }; + }) + .SetSampler(new TraceIdRatioBasedSampler(0.75)); + + if (otelConfig?.Endpoint != null) + { + tracing.AddOtlpExporter(exporterOptions => + { + exporterOptions.Endpoint = new Uri(otelConfig.Endpoint); + exporterOptions.Headers = otelConfig.Headers; + }); + } + +#if DEBUG + tracing.AddOtlpExporter(exporterOptions => + { + exporterOptions.Endpoint = new Uri("http://localhost:17011"); + }); +#endif + }); + builder.Services .AddControllers() .AddJsonOptions(options => @@ -40,9 +139,21 @@ builder.Services.AddScoped(); // builder.Services.AddKeyedScoped("Nominatim"); builder.Services.AddHttpClient(); builder.Services.AddHttpClient(); +builder.Services.AddHttpClient(); +builder.Services.AddHttpClient(); +builder.Services.AddHttpClient(); var app = builder.Build(); +app.Use(async (context, next) => +{ + if (context.Request.Headers.TryGetValue("X-Session-Id", out var sessionId)) + { + System.Diagnostics.Activity.Current?.SetTag("session.id", sessionId.ToString()); + } + await next(); +}); + app.MapControllers(); app.Run(); -- cgit v1.3