| File: Components\Pages\ComponentTelemetryContext.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.Dashboard.Telemetry; namespace Aspire.Dashboard.Components.Pages; public sealed class ComponentTelemetryContextProvider { private readonly DashboardTelemetryService _telemetryService; private string? _browserUserAgent; public ComponentTelemetryContextProvider(DashboardTelemetryService telemetryService) { _telemetryService = telemetryService; } public void SetBrowserUserAgent(string? userAgent) { _browserUserAgent = userAgent; } public void Initialize(ComponentTelemetryContext context) { context.Initialize(_telemetryService, _browserUserAgent); } } public enum ComponentType { Page, Control } public sealed class ComponentTelemetryContext : IDisposable { private DashboardTelemetryService? _telemetryService; private OperationContext? _initializeCorrelation; private readonly string _componentId; private readonly ComponentType _type; private bool _disposed; public ComponentTelemetryContext(ComponentType type, string componentId) { _componentId = componentId; _type = type; } // Internal for testing internal Dictionary<string, AspireTelemetryProperty> Properties { get; } = []; public void Initialize(DashboardTelemetryService telemetryService, string? browserUserAgent) { _telemetryService = telemetryService; Properties[TelemetryPropertyKeys.DashboardComponentId] = new AspireTelemetryProperty(_componentId); Properties[TelemetryPropertyKeys.DashboardComponentType] = new AspireTelemetryProperty(_type.ToString()); if (browserUserAgent != null) { Properties[TelemetryPropertyKeys.UserAgent] = new AspireTelemetryProperty(browserUserAgent); } _initializeCorrelation = telemetryService.PostUserTask( TelemetryEventKeys.ComponentInitialize, TelemetryResult.Success, properties: CreateInitializeAndDisposeProperties()); } public bool UpdateTelemetryProperties(ReadOnlySpan<ComponentTelemetryProperty> modifiedProperties, ILogger logger) { // Only send updated properties if they are different from the existing ones. var anyChange = false; foreach (var (name, value) in modifiedProperties) { if (value.Value is string s && string.IsNullOrEmpty(s)) { continue; } if (!Properties.TryGetValue(name, out var existingValue) || !existingValue.Value.Equals(value.Value)) { Properties[name] = value; anyChange = true; } } if (anyChange) { PostProperties(logger); } return anyChange; } private void PostProperties(ILogger logger) { if (_telemetryService == null) { logger.LogWarning("Telemetry service for '{ComponentType}' is not initialized. Cannot post properties.", _componentId); return; } _telemetryService.PostOperation( TelemetryEventKeys.ParametersSet, TelemetryResult.Success, properties: Properties, correlatedWith: _initializeCorrelation?.Properties); } private Dictionary<string, AspireTelemetryProperty> CreateInitializeAndDisposeProperties() { return new Dictionary<string, AspireTelemetryProperty> { // Component properties { TelemetryPropertyKeys.DashboardComponentId, new AspireTelemetryProperty(_componentId) }, { TelemetryPropertyKeys.DashboardComponentType, new AspireTelemetryProperty(_type.ToString()) }, }; } public void Dispose() { if (!_disposed) { _telemetryService?.PostOperation( TelemetryEventKeys.ComponentDispose, TelemetryResult.Success, properties: CreateInitializeAndDisposeProperties(), correlatedWith: _initializeCorrelation?.Properties); _disposed = true; } } }