| File: Telemetry\DashboardTelemetryManager.cs | Web Access |
| Project: src\src\Aspire.Dashboard\Aspire.Dashboard.csproj (Aspire.Dashboard) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Shared; using Aspire.Shared.Telemetry; using OpenTelemetry.Resources; namespace Aspire.Dashboard.Telemetry; /// <summary> /// Owns the dashboard's Azure Monitor reported trace and usage-log providers. /// </summary> internal sealed class DashboardTelemetryManager : IHostedService, IAsyncDisposable { private const string ApplicationInsightsConnectionString = "InstrumentationKey=3be364e3-d9eb-436a-983e-0a681d5af691;IngestionEndpoint=https://centralus-2.in.applicationinsights.azure.com/;LiveEndpoint=https://centralus.livediagnostics.monitor.azure.com/;ApplicationId=83cb9aa6-6ebc-4c33-b434-8d348004bde1"; private readonly Lock _lock = new(); private readonly DashboardTelemetryConfiguration _configuration; private readonly ILogger<DashboardTelemetryManager> _logger; private readonly DashboardTelemetryService _telemetry; private readonly Func<ResourceBuilder, string, AzureMonitorTelemetryProvider> _createProvider; private AzureMonitorTelemetryProvider? _provider; private bool _initialized; private bool _disposed; private Task? _shutdownTask; public DashboardTelemetryManager( DashboardTelemetryConfiguration configuration, ILogger<DashboardTelemetryManager> logger, DashboardTelemetryService telemetry) { _configuration = configuration; _logger = logger; _telemetry = telemetry; _createProvider = (resource, storageDirectory) => AzureMonitorTelemetryProvider.Create( new ServiceCollection(), resource, DashboardTelemetryService.ReportedActivitySourceName, DashboardTelemetryService.EventLogCategoryName, ApplicationInsightsConnectionString, storageDirectory); } internal DashboardTelemetryManager( DashboardTelemetryConfiguration configuration, ILogger<DashboardTelemetryManager> logger, DashboardTelemetryService telemetry, Func<ResourceBuilder, string, AzureMonitorTelemetryProvider> createProvider) : this(configuration, logger, telemetry) { _createProvider = createProvider; } internal bool IsInitialized { get { lock (_lock) { return _initialized && !_disposed; } } } /// <summary> /// Creates the reported providers once, before dashboard usage can be recorded. /// </summary> internal void Initialize() { lock (_lock) { ObjectDisposedException.ThrowIf(_disposed, this); if (_initialized) { return; } if (!_configuration.ReportedTelemetryEnabled) { _initialized = true; _logger.LogDebug("Dashboard product telemetry is disabled."); return; } AzureMonitorTelemetryProvider? provider = null; try { var storageDirectory = AspireTelemetryExporter.GetTelemetryStoragePath("dashboard"); var resource = CreateResourceBuilder(); provider = _createProvider(resource, storageDirectory); _telemetry.SetEventLogger(provider.EventLogger); _provider = provider; _initialized = true; } catch (Exception ex) { provider?.Dispose(); // Product telemetry is optional; exporter or storage failures must not // prevent users from starting the dashboard. _logger.LogWarning(ex, "Failed to initialize dashboard product telemetry. The dashboard will continue without product export."); } } } /// <inheritdoc /> public Task StartAsync(CancellationToken cancellationToken) { Initialize(); return Task.CompletedTask; } /// <inheritdoc /> public Task StopAsync(CancellationToken cancellationToken) => ShutdownAsync(); /// <inheritdoc /> public ValueTask DisposeAsync() => new(ShutdownAsync()); private Task ShutdownAsync() { lock (_lock) { if (_shutdownTask is not null) { return _shutdownTask; } _disposed = true; var provider = _provider; _provider = null; _telemetry.SetEventLogger(null); _shutdownTask = FlushProviderAsync(provider); return _shutdownTask; } } private async Task FlushProviderAsync(AzureMonitorTelemetryProvider? provider) { using (provider) { if (provider is not null && !await provider.ShutdownAsync(timeoutMilliseconds: 5000).ConfigureAwait(false)) { _logger.LogWarning("Timed out flushing dashboard product telemetry."); } } } private static ResourceBuilder CreateResourceBuilder() => ResourceBuilder.CreateEmpty().AddService( serviceName: "aspire-dashboard", serviceVersion: AssemblyVersionHelper.GetInformationalVersion(typeof(DashboardWebApplication).Assembly)); }