using System.Diagnostics.Metrics; using System.Net; using System.Text; using ItWorx.KnowledgeHub.Application.Operations; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.Extensions.DependencyInjection; using OpenTelemetry; using OpenTelemetry.Exporter; using OpenTelemetry.Metrics; namespace ItWorx.KnowledgeHub.IntegrationTests.Operations; public sealed class OtlpExportTests { [Fact] public async Task Platform_metrics_are_exported_over_real_OTLP_HTTP_without_private_labels() { var received = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var builder = WebApplication.CreateSlimBuilder(); builder.WebHost.ConfigureKestrel(server => server.Listen(IPAddress.Loopback, 0)); await using var collector = builder.Build(); collector.MapPost("/v1/metrics", async context => { using var body = new MemoryStream(); await context.Request.Body.CopyToAsync(body); received.TrySetResult(body.ToArray()); context.Response.ContentType = "application/x-protobuf"; context.Response.StatusCode = 200; }); await collector.StartAsync(); var address = collector.Services.GetRequiredService() .Features.Get()!.Addresses.Single(); using var metrics = new PlatformMetrics(); using var provider = Sdk.CreateMeterProviderBuilder().AddMeter("ItWorx.KnowledgeHub.Platform") .AddOtlpExporter(options => { options.Endpoint = new Uri(new Uri(address), "/v1/metrics"); options.Protocol = OtlpExportProtocol.HttpProtobuf; }).Build(); metrics.Record("private-document-title", "secret-token", .125, 2); metrics.SetQueueState(2, 1, 0, 90); metrics.SetOperationalAges(30, 60, 120); Assert.True(provider.ForceFlush(10_000)); var payload = Encoding.UTF8.GetString(await received.Task.WaitAsync(TimeSpan.FromSeconds(10))); Assert.Contains("platform_operations_total", payload, StringComparison.Ordinal); Assert.Contains("platform_evidence_age_seconds", payload, StringComparison.Ordinal); Assert.DoesNotContain("private-document-title", payload, StringComparison.Ordinal); Assert.DoesNotContain("secret-token", payload, StringComparison.Ordinal); await collector.StopAsync(); } }