using System.Diagnostics.Metrics; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using OpenTelemetry; using OpenTelemetry.Metrics; using OpenTelemetry.Resources; using ZB.MOM.WW.Telemetry; namespace ZB.MOM.WW.Telemetry.Tests; public sealed class AddZbTelemetryTests { [Fact] public void AddZbTelemetry_ExportsAppMeter_WithSharedResource() { // 1.15.x note: AddInMemoryExporter moved out of the core OpenTelemetry assembly into a // separate OpenTelemetry.Exporter.InMemory package (not referenced here). We attach a // BaseExporter directly instead — it both collects metric names and exposes the // MeterProvider Resource via ParentProvider.GetResource(). var capture = new CapturingMetricExporter(); var builder = WebApplication.CreateBuilder(); builder.AddZbTelemetry(o => { o.ServiceName = "t"; o.SiteId = "site-test"; o.NodeRole = "central"; o.Meters = ["Test.Meter"]; }); // Compose a capturing reader onto the pipeline AddZbTelemetry already registered. builder.Services.ConfigureOpenTelemetryMeterProvider(b => b.AddReader(new PeriodicExportingMetricReader(capture) { TemporalityPreference = MetricReaderTemporalityPreference.Cumulative, })); // Create the meter + instrument BEFORE the provider is built so the MeterProvider's // listener subscribes to it during construction. using var meter = new Meter("Test.Meter"); var counter = meter.CreateCounter("test.events.count"); using var app = builder.Build(); var meterProvider = app.Services.GetRequiredService(); counter.Add(1); meterProvider.ForceFlush(); // The app's meter was registered and its instrument was collected through the pipeline. Assert.Contains("test.events.count", capture.MetricNames); // The exported metric carries the shared Resource (identical to ZbResource.Build). Assert.NotNull(capture.CapturedResource); var attrs = capture.CapturedResource!.Attributes.ToDictionary(a => a.Key, a => a.Value); Assert.Equal("t", attrs["service.name"]); Assert.Equal("ZB.MOM.WW", attrs["service.namespace"]); Assert.Equal("site-test", attrs["site.id"]); Assert.Equal("central", attrs["node.role"]); Assert.Equal(Environment.MachineName, attrs["host.name"]); } /// /// Collects exported metric names and captures the MeterProvider Resource on first export so /// the test can assert the pipeline wired both the app meter and the shared Resource. /// private sealed class CapturingMetricExporter : BaseExporter { public List MetricNames { get; } = []; public Resource? CapturedResource { get; private set; } public override ExportResult Export(in Batch batch) { CapturedResource ??= ParentProvider?.GetResource(); foreach (var metric in batch) { MetricNames.Add(metric.Name); } return ExportResult.Success; } } }