From ec7e04990bcb22a267a3249a909b98e85414ffca Mon Sep 17 00:00:00 2001
From: Knut Haug <154342485+knuhau@users.noreply.github.com>
Date: Mon, 21 Oct 2024 16:19:49 +0200
Subject: [PATCH] chore(webapi): Add Opentelemetry tracing and metrics to
webapi (#1202)
## Description
Replace Application Insights tracing with Opentelemetry in the webapi
## Related Issue(s)
- #1101
## Verification
- [x] **Your** code builds clean without any errors or warnings
- [x] Manual testing done (required)
- [ ] Relevant automated test added (if you find this hard, leave it and
we'll help out)
---
.../WebApplicationBuilderExtensions.cs | 49 +++++++++++++++++++
.../Digdir.Domain.Dialogporten.WebApi.csproj | 6 ++-
.../Program.cs | 19 +++----
.../Features/V1/SwaggerSnapshotTests.cs | 2 +-
4 files changed, 63 insertions(+), 13 deletions(-)
create mode 100644 src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/WebApplicationBuilderExtensions.cs
diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/WebApplicationBuilderExtensions.cs b/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/WebApplicationBuilderExtensions.cs
new file mode 100644
index 000000000..88b734912
--- /dev/null
+++ b/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/WebApplicationBuilderExtensions.cs
@@ -0,0 +1,49 @@
+using Azure.Monitor.OpenTelemetry.AspNetCore;
+using OpenTelemetry.Trace;
+using Npgsql;
+using OpenTelemetry.Metrics;
+using OpenTelemetry.Resources;
+
+namespace Digdir.Domain.Dialogporten.WebApi.Common.Extensions;
+
+internal static class WebApplicationBuilderExtensions
+{
+ public static WebApplicationBuilder ConfigureTelemetry(this WebApplicationBuilder builder)
+ {
+ builder.Services.AddOpenTelemetry()
+ .ConfigureResource(resource => resource
+ .AddService(serviceName: builder.Environment.ApplicationName))
+ .WithTracing(tracing =>
+ {
+ if (builder.Environment.IsDevelopment())
+ {
+ tracing.SetSampler(new AlwaysOnSampler());
+ }
+
+ tracing.AddAspNetCoreInstrumentation(options =>
+ {
+ options.Filter = (httpContext) =>
+ !httpContext.Request.Path.StartsWithSegments("/health");
+ });
+
+ tracing.AddHttpClientInstrumentation();
+ tracing.AddNpgsql();
+ })
+ .WithMetrics(metrics =>
+ {
+ metrics.AddRuntimeInstrumentation();
+ });
+
+ if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("APPLICATIONINSIGHTS_CONNECTION_STRING")))
+ {
+ builder.Services.AddOpenTelemetry().UseAzureMonitor();
+ }
+ else
+ {
+ // Use Application Insights SDK for local development
+ builder.Services.AddApplicationInsightsTelemetry();
+ }
+
+ return builder;
+ }
+}
diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj b/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj
index 0154714ba..31715419d 100644
--- a/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj
+++ b/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj
@@ -8,13 +8,17 @@
+
+
+
+
@@ -25,4 +29,4 @@
-
\ No newline at end of file
+
diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs
index f6d179cba..f69497778 100644
--- a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs
+++ b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs
@@ -7,12 +7,12 @@
using Digdir.Domain.Dialogporten.Application.Common.Extensions;
using Digdir.Domain.Dialogporten.Application.Common.Extensions.OptionExtensions;
using Digdir.Domain.Dialogporten.Application.Externals.Presentation;
+using Digdir.Domain.Dialogporten.WebApi.Common.Extensions;
using Digdir.Domain.Dialogporten.Infrastructure;
using Digdir.Domain.Dialogporten.WebApi;
using Digdir.Domain.Dialogporten.WebApi.Common;
using Digdir.Domain.Dialogporten.WebApi.Common.Authentication;
using Digdir.Domain.Dialogporten.WebApi.Common.Authorization;
-using Digdir.Domain.Dialogporten.WebApi.Common.Extensions;
using Digdir.Domain.Dialogporten.WebApi.Common.Json;
using Digdir.Domain.Dialogporten.WebApi.Common.Swagger;
using Digdir.Library.Utils.AspNet;
@@ -26,18 +26,17 @@
using Microsoft.Extensions.Options;
// Using two-stage initialization to catch startup errors.
+var telemetryConfiguration = TelemetryConfiguration.CreateDefault();
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Warning()
.Enrich.FromLogContext()
.WriteTo.Console(formatProvider: CultureInfo.InvariantCulture)
- .WriteTo.ApplicationInsights(
- TelemetryConfiguration.CreateDefault(),
- TelemetryConverter.Traces)
+ .WriteTo.ApplicationInsights(telemetryConfiguration, TelemetryConverter.Traces)
.CreateBootstrapLogger();
try
{
- BuildAndRun(args);
+ BuildAndRun(args, telemetryConfiguration);
}
catch (Exception ex) when (ex is not OperationCanceledException)
{
@@ -49,7 +48,7 @@
Log.CloseAndFlush();
}
-static void BuildAndRun(string[] args)
+static void BuildAndRun(string[] args, TelemetryConfiguration telemetryConfiguration)
{
var builder = WebApplication.CreateBuilder(args);
@@ -58,9 +57,7 @@ static void BuildAndRun(string[] args)
.ReadFrom.Configuration(context.Configuration)
.ReadFrom.Services(services)
.Enrich.FromLogContext()
- .WriteTo.ApplicationInsights(
- services.GetRequiredService(),
- TelemetryConverter.Traces));
+ .WriteTo.ApplicationInsights(telemetryConfiguration, TelemetryConverter.Traces));
builder.Configuration
.AddAzureConfiguration(builder.Environment.EnvironmentName)
@@ -74,6 +71,8 @@ static void BuildAndRun(string[] args)
var thisAssembly = Assembly.GetExecutingAssembly();
+ builder.ConfigureTelemetry();
+
builder.Services
// Options setup
.ConfigureOptions()
@@ -91,7 +90,6 @@ static void BuildAndRun(string[] args)
.AddHttpContextAccessor()
.AddValidatorsFromAssembly(thisAssembly, ServiceLifetime.Transient, includeInternalTypes: true)
.AddAzureAppConfiguration()
- .AddApplicationInsightsTelemetry()
.AddEndpointsApiExplorer()
.AddFastEndpoints()
.SwaggerDocument(x =>
@@ -125,7 +123,6 @@ static void BuildAndRun(string[] args)
.JwtBearerTokenSchemas?
.Select(z => z.WellKnown)
.ToList() ?? [])
-
// Auth
.AddDialogportenAuthentication(builder.Configuration)
.AddAuthorization();
diff --git a/tests/Digdir.Domain.Dialogporten.WebApi.Integration.Tests/Features/V1/SwaggerSnapshotTests.cs b/tests/Digdir.Domain.Dialogporten.WebApi.Integration.Tests/Features/V1/SwaggerSnapshotTests.cs
index ed2d01235..187a1269d 100644
--- a/tests/Digdir.Domain.Dialogporten.WebApi.Integration.Tests/Features/V1/SwaggerSnapshotTests.cs
+++ b/tests/Digdir.Domain.Dialogporten.WebApi.Integration.Tests/Features/V1/SwaggerSnapshotTests.cs
@@ -35,7 +35,7 @@ public async Task FailIfSwaggerSnapshotDoesNotMatch()
// The order of the properties in the swagger.json file is not cross-platform deterministic.
// Running client.GetAsync("/swagger/v1/swagger.json"); on Windows and Mac will produce
// different ordering of the results (although the content is the same). So we force an
- // alphabetical ordering of the properties to make the test deterministic.
+ // alphabetical ordering of the properties to make the test deterministic.
// Ref: https://github.com/digdir/dialogporten/issues/996
var orderedSwagger = SortJson(newSwagger);