| File: Extensions.cs | Web Access |
| Project: src\playground\BlazorHosted\BlazorHosted.ClientServiceDefaults\BlazorHosted.ClientServiceDefaults.csproj (BlazorHosted.ClientServiceDefaults) |
using Microsoft.AspNetCore.Components.Infrastructure; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using Microsoft.Extensions.DependencyInjection; using OpenTelemetry.Logs; using OpenTelemetry.Metrics; using OpenTelemetry.Resources; using OpenTelemetry.Trace; namespace Microsoft.Extensions.Hosting; public static class BlazorClientExtensions { public static WebAssemblyHostBuilder AddBlazorClientServiceDefaults(this WebAssemblyHostBuilder builder) { ComponentsMetricsServiceCollectionExtensions.AddComponentsMetrics(builder.Services); ComponentsMetricsServiceCollectionExtensions.AddComponentsTracing(builder.Services); builder.ConfigureBlazorClientOpenTelemetry(); builder.Services.AddServiceDiscovery(); builder.Services.ConfigureHttpClientDefaults(http => { http.AddServiceDiscovery(); }); return builder; } private static WebAssemblyHostBuilder ConfigureBlazorClientOpenTelemetry(this WebAssemblyHostBuilder builder) { // Without an OTLP path base, there's nowhere to export telemetry in WASM. var otlpPathBase = builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]; if (string.IsNullOrEmpty(otlpPathBase)) { return builder; } var serviceName = builder.Configuration["OTEL_SERVICE_NAME"]!; // Resolve the OTLP path against the page's origin so telemetry goes through // the same origin the user navigated to, avoiding cross-origin issues. var baseAddress = new Uri(builder.HostEnvironment.BaseAddress); var otlpEndpoint = new Uri(baseAddress, $"{otlpPathBase}/"); builder.Services.AddOpenTelemetry() // Use a fixed instanceId so all browser tabs report as a single service instance // in the dashboard rather than spawning separate entries per tab. .ConfigureResource(r => r.AddService(serviceName, serviceInstanceId: serviceName)) .WithLogging(logging => { logging.AddOtlpExporter(o => o.Endpoint = new Uri(otlpEndpoint, "v1/logs")); }, options => { options.IncludeFormattedMessage = true; options.IncludeScopes = true; }) .WithMetrics(metrics => { metrics.AddMeter("Microsoft.AspNetCore.Components"); metrics.AddMeter("Microsoft.AspNetCore.Components.Lifecycle"); metrics.AddHttpClientInstrumentation(); metrics.AddOtlpExporter(o => o.Endpoint = new Uri(otlpEndpoint, "v1/metrics")); }) .WithTracing(tracing => { tracing.AddSource("Microsoft.AspNetCore.Components") .AddHttpClientInstrumentation(); tracing.AddOtlpExporter(o => o.Endpoint = new Uri(otlpEndpoint, "v1/traces")); }); return builder; } }