From 5eb634416f513a22b4633e6dd23fd3e62754e79c Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Tue, 29 Apr 2025 15:57:31 -0400 Subject: [PATCH 1/9] Remove unnecessary properties --- .../Components/Pages/Metrics.razor.cs | 3 --- .../Components/Pages/Resources.razor.cs | 8 ++------ .../Components/Pages/StructuredLogs.razor.cs | 5 +---- src/Aspire.Dashboard/Components/Pages/Traces.razor.cs | 9 --------- .../Telemetry/TelemetryPropertyKeys.cs | 11 +---------- 5 files changed, 4 insertions(+), 32 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs b/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs index c4e580da60d..d9b380aeaf5 100644 --- a/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs @@ -320,11 +320,8 @@ public void Dispose() public void UpdateTelemetryProperties() { TelemetryContext.UpdateTelemetryProperties([ - new ComponentTelemetryProperty(TelemetryPropertyKeys.ApplicationInstanceId, new AspireTelemetryProperty(PageViewModel.SelectedApplication.Id?.InstanceId ?? string.Empty)), new ComponentTelemetryProperty(TelemetryPropertyKeys.MetricsApplicationIsReplica, new AspireTelemetryProperty(PageViewModel.SelectedApplication.Id?.ReplicaSetName is not null)), new ComponentTelemetryProperty(TelemetryPropertyKeys.MetricsInstrumentsCount, new AspireTelemetryProperty(PageViewModel.Instruments?.Count ?? -1)), - new ComponentTelemetryProperty(TelemetryPropertyKeys.MetricsSelectedMeter, new AspireTelemetryProperty(PageViewModel.SelectedMeter?.MeterName ?? string.Empty)), - new ComponentTelemetryProperty(TelemetryPropertyKeys.MetricsSelectedInstrument, new AspireTelemetryProperty(PageViewModel.SelectedInstrument?.Name ?? string.Empty)), new ComponentTelemetryProperty(TelemetryPropertyKeys.MetricsSelectedDuration, new AspireTelemetryProperty(PageViewModel.SelectedDuration.Id.ToString(), AspireTelemetryPropertyType.UserSetting)), new ComponentTelemetryProperty(TelemetryPropertyKeys.MetricsSelectedView, new AspireTelemetryProperty(PageViewModel.SelectedViewKind?.ToString() ?? string.Empty, AspireTelemetryPropertyType.UserSetting)) ]); diff --git a/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs b/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs index ccb2748f120..836fe67df84 100644 --- a/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs @@ -833,14 +833,10 @@ public void UpdateTelemetryProperties() { var properties = new List { - new(TelemetryPropertyKeys.ResourceView, new AspireTelemetryProperty(PageViewModel.SelectedViewKind.ToString(), AspireTelemetryPropertyType.UserSetting)) + new(TelemetryPropertyKeys.ResourceView, new AspireTelemetryProperty(PageViewModel.SelectedViewKind.ToString(), AspireTelemetryPropertyType.UserSetting)), + new(TelemetryPropertyKeys.ResourceTypes, new AspireTelemetryProperty(_resourceByName.Values.Select(r => r.ResourceType).ToList())) }; - foreach (var resourceTypeGroup in _resourceByName.Values.GroupBy(r => r.ResourceType)) - { - properties.Add(new ComponentTelemetryProperty($"{TelemetryPropertyKeys.ResourceType}.{resourceTypeGroup.Key}", new AspireTelemetryProperty(resourceTypeGroup.Count(), AspireTelemetryPropertyType.Metric))); - } - TelemetryContext.UpdateTelemetryProperties(properties.ToArray()); } } diff --git a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor.cs b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor.cs index 9b1b9c4ff73..640966b9581 100644 --- a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor.cs @@ -495,11 +495,8 @@ public class StructuredLogsPageState public void UpdateTelemetryProperties() { TelemetryContext.UpdateTelemetryProperties([ - new ComponentTelemetryProperty(TelemetryPropertyKeys.StructuredLogsSelectedApplication, new AspireTelemetryProperty(PageViewModel.SelectedApplication.Id?.ToString() ?? string.Empty)), new ComponentTelemetryProperty(TelemetryPropertyKeys.StructuredLogsSelectedLogLevel, new AspireTelemetryProperty(PageViewModel.SelectedLogLevel.Id?.ToString() ?? string.Empty, AspireTelemetryPropertyType.UserSetting)), - new ComponentTelemetryProperty(TelemetryPropertyKeys.StructuredLogsFilterCount, new AspireTelemetryProperty(ViewModel.Filters.Count.ToString(CultureInfo.InvariantCulture), AspireTelemetryPropertyType.Metric)), - new ComponentTelemetryProperty(TelemetryPropertyKeys.StructuredLogsTraceId, new AspireTelemetryProperty(TraceId ?? string.Empty)), - new ComponentTelemetryProperty(TelemetryPropertyKeys.StructuredLogsSpanId, new AspireTelemetryProperty(SpanId ?? string.Empty)) + new ComponentTelemetryProperty(TelemetryPropertyKeys.StructuredLogsFilterCount, new AspireTelemetryProperty(ViewModel.Filters.Count.ToString(CultureInfo.InvariantCulture), AspireTelemetryPropertyType.Metric)) ]); } } diff --git a/src/Aspire.Dashboard/Components/Pages/Traces.razor.cs b/src/Aspire.Dashboard/Components/Pages/Traces.razor.cs index 00d55f8f702..bb5145b2b99 100644 --- a/src/Aspire.Dashboard/Components/Pages/Traces.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/Traces.razor.cs @@ -11,7 +11,6 @@ using Aspire.Dashboard.Otlp.Model; using Aspire.Dashboard.Otlp.Storage; using Aspire.Dashboard.Resources; -using Aspire.Dashboard.Telemetry; using Aspire.Dashboard.Utils; using Microsoft.AspNetCore.Components; using Microsoft.Extensions.Options; @@ -182,7 +181,6 @@ protected override async Task OnParametersSetAsync() TracesViewModel.ApplicationKey = PageViewModel.SelectedApplication.Id?.GetApplicationKey(); UpdateSubscription(); - UpdateTelemetryProperties(); } private void UpdateApplications() @@ -385,11 +383,4 @@ public class TracesPageState // IComponentWithTelemetry impl public ComponentTelemetryContext TelemetryContext { get; } = new(DashboardUrls.TracesBasePath); - - public void UpdateTelemetryProperties() - { - TelemetryContext.UpdateTelemetryProperties([ - new ComponentTelemetryProperty(TelemetryPropertyKeys.ApplicationInstanceId, new AspireTelemetryProperty(PageViewModel.SelectedApplication.Id?.InstanceId ?? string.Empty)), - ]); - } } diff --git a/src/Aspire.Dashboard/Telemetry/TelemetryPropertyKeys.cs b/src/Aspire.Dashboard/Telemetry/TelemetryPropertyKeys.cs index 8f66832a5d4..f86758cd970 100644 --- a/src/Aspire.Dashboard/Telemetry/TelemetryPropertyKeys.cs +++ b/src/Aspire.Dashboard/Telemetry/TelemetryPropertyKeys.cs @@ -15,8 +15,6 @@ public static class TelemetryPropertyKeys public const string DashboardComponentId = AspireDashboardPropertyPrefix + "ComponentId"; public const string UserAgent = AspireDashboardPropertyPrefix + "UserAgent"; - public const string ApplicationInstanceId = AspireDashboardPropertyPrefix + "Metrics.ApplicationInstanceId"; - // ConsoleLogs properties public const string ConsoleLogsShowTimestamp = AspireDashboardPropertyPrefix + "ConsoleLogs.ShowTimestamp"; public const string ConsoleLogsApplicationName = AspireDashboardPropertyPrefix + "ConsoleLogs.ApplicationName"; @@ -24,8 +22,6 @@ public static class TelemetryPropertyKeys // Metrics properties public const string MetricsApplicationIsReplica = AspireDashboardPropertyPrefix + "Metrics.ApplicationIsReplica"; public const string MetricsInstrumentsCount = AspireDashboardPropertyPrefix + "Metrics.InstrumentsCount"; - public const string MetricsSelectedMeter = AspireDashboardPropertyPrefix + "Metrics.SelectedMeter"; - public const string MetricsSelectedInstrument = AspireDashboardPropertyPrefix + "Metrics.SelectedInstrument"; public const string MetricsSelectedDuration = AspireDashboardPropertyPrefix + "Metrics.SelectedDuration"; public const string MetricsSelectedView = AspireDashboardPropertyPrefix + "Metrics.SelectedView"; @@ -35,21 +31,16 @@ public static class TelemetryPropertyKeys public const string ExceptionStackTrace = AspireDashboardPropertyPrefix + "Exception.StackTrace"; // Resources properties + public const string ResourceTypes = AspireDashboardPropertyPrefix + "Resource.Types"; public const string ResourceType = AspireDashboardPropertyPrefix + "Resource.Type"; public const string ResourceView = AspireDashboardPropertyPrefix + "Resource.View"; // Error properties public const string ErrorRequestId = AspireDashboardPropertyPrefix + "RequestId"; - // Trace detail properties - public const string TraceDetailTraceId = AspireDashboardPropertyPrefix + "TraceDetail.TraceId"; - // Structured logs properties - public const string StructuredLogsSelectedApplication = AspireDashboardPropertyPrefix + "StructuredLogs.SelectedApplication"; public const string StructuredLogsSelectedLogLevel = AspireDashboardPropertyPrefix + "StructuredLogs.SelectedLogLevel"; public const string StructuredLogsFilterCount = AspireDashboardPropertyPrefix + "StructuredLogs.FilterCount"; - public const string StructuredLogsTraceId = AspireDashboardPropertyPrefix + "StructuredLogs.TraceId"; - public const string StructuredLogsSpanId = AspireDashboardPropertyPrefix + "StructuredLogs.SpanId"; // Command properties public const string CommandName = AspireDashboardPropertyPrefix + "Command.Name"; From 790ab081c19300aac40cdac29692d85ce2eb3517 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Tue, 29 Apr 2025 16:00:08 -0400 Subject: [PATCH 2/9] Make op id not nullable --- .../Model/DashboardCommandExecutor.cs | 11 +++++++++-- .../Telemetry/DashboardTelemetryService.cs | 8 ++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/Aspire.Dashboard/Model/DashboardCommandExecutor.cs b/src/Aspire.Dashboard/Model/DashboardCommandExecutor.cs index 3e50809357a..1c8b3d97d36 100644 --- a/src/Aspire.Dashboard/Model/DashboardCommandExecutor.cs +++ b/src/Aspire.Dashboard/Model/DashboardCommandExecutor.cs @@ -50,11 +50,18 @@ public async Task ExecuteAsync(ResourceViewModel resource, CommandViewModel comm try { await ExecuteAsyncCore(resource, command, getResourceName).ConfigureAwait(false); - telemetryService.EndOperation(operationId, TelemetryResult.Success); + + if (operationId is not null) + { + telemetryService.EndOperation(operationId, TelemetryResult.Success); + } } catch (Exception ex) { - telemetryService.EndUserTask(operationId, TelemetryResult.Failure, ex.Message); + if (operationId is not null) + { + telemetryService.EndUserTask(operationId, TelemetryResult.Failure, ex.Message); + } } finally { diff --git a/src/Aspire.Dashboard/Telemetry/DashboardTelemetryService.cs b/src/Aspire.Dashboard/Telemetry/DashboardTelemetryService.cs index 61fd6548a2d..de333cfa008 100644 --- a/src/Aspire.Dashboard/Telemetry/DashboardTelemetryService.cs +++ b/src/Aspire.Dashboard/Telemetry/DashboardTelemetryService.cs @@ -113,9 +113,9 @@ public OperationContext StartOperation(string eventName, Dictionary /// Ends a long-running operation. This will post the end event and calculate the duration. /// - public void EndOperation(OperationContextProperty? operationId, TelemetryResult result, string? errorMessage = null) + public void EndOperation(OperationContextProperty operationId, TelemetryResult result, string? errorMessage = null) { - if (SkipQueuingRequests() || operationId is null) + if (SkipQueuingRequests()) { return; } @@ -159,9 +159,9 @@ public OperationContext StartUserTask(string eventName, Dictionary /// Ends a long-running user task. This will post the end event and calculate the duration. /// - public void EndUserTask(OperationContextProperty? operationId, TelemetryResult result, string? errorMessage = null) + public void EndUserTask(OperationContextProperty operationId, TelemetryResult result, string? errorMessage = null) { - if (SkipQueuingRequests() || operationId is null) + if (SkipQueuingRequests()) { return; } From 968728cb3daa7170a060cfc80dddabd7ff2c685c Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Tue, 29 Apr 2025 16:36:22 -0400 Subject: [PATCH 3/9] Remove trace id property --- .../Components/Pages/TraceDetail.razor.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs b/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs index 74de324337f..3b55a5ce104 100644 --- a/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs @@ -8,7 +8,6 @@ using Aspire.Dashboard.Model.Otlp; using Aspire.Dashboard.Otlp.Model; using Aspire.Dashboard.Otlp.Storage; -using Aspire.Dashboard.Telemetry; using Aspire.Dashboard.Utils; using Microsoft.AspNetCore.Components; using Microsoft.FluentUI.AspNetCore.Components; @@ -177,8 +176,6 @@ protected override async Task OnParametersSetAsync() // Navigate to remove ?spanId=xxx in the URL. NavigationManager.NavigateTo(DashboardUrls.TraceDetailUrl(TraceId), new NavigationOptions { ReplaceHistoryEntry = true }); } - - UpdateTelemetryProperties(); } private void UpdateDetailViewData() @@ -337,11 +334,4 @@ public void Dispose() // IComponentWithTelemetry impl public ComponentTelemetryContext TelemetryContext { get; } = new(DashboardUrls.TracesBasePath); - - public void UpdateTelemetryProperties() - { - TelemetryContext.UpdateTelemetryProperties([ - new ComponentTelemetryProperty(TelemetryPropertyKeys.TraceDetailTraceId, new AspireTelemetryProperty(TraceId)), - ]); - } } From 7e02ee8827cf62b4d6e759f463052af4b91ea55e Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Tue, 29 Apr 2025 16:58:05 -0400 Subject: [PATCH 4/9] Set resource type and command name properties to PII --- .../Components/Controls/ResourceDetails.razor.cs | 2 +- src/Aspire.Dashboard/Components/Pages/Resources.razor.cs | 2 +- src/Aspire.Dashboard/Model/DashboardCommandExecutor.cs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Controls/ResourceDetails.razor.cs b/src/Aspire.Dashboard/Components/Controls/ResourceDetails.razor.cs index d17a44259c6..f9d0d7247e7 100644 --- a/src/Aspire.Dashboard/Components/Controls/ResourceDetails.razor.cs +++ b/src/Aspire.Dashboard/Components/Controls/ResourceDetails.razor.cs @@ -278,7 +278,7 @@ public Task OnViewRelationshipAsync(ResourceDetailRelationshipViewModel relation public void UpdateTelemetryProperties() { TelemetryContext.UpdateTelemetryProperties([ - new ComponentTelemetryProperty(TelemetryPropertyKeys.ResourceType, new AspireTelemetryProperty(Resource.ResourceType)) + new ComponentTelemetryProperty(TelemetryPropertyKeys.ResourceType, new AspireTelemetryProperty(Resource.ResourceType, AspireTelemetryPropertyType.Pii)) ]); } diff --git a/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs b/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs index 836fe67df84..876178f774e 100644 --- a/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs @@ -834,7 +834,7 @@ public void UpdateTelemetryProperties() var properties = new List { new(TelemetryPropertyKeys.ResourceView, new AspireTelemetryProperty(PageViewModel.SelectedViewKind.ToString(), AspireTelemetryPropertyType.UserSetting)), - new(TelemetryPropertyKeys.ResourceTypes, new AspireTelemetryProperty(_resourceByName.Values.Select(r => r.ResourceType).ToList())) + new(TelemetryPropertyKeys.ResourceTypes, new AspireTelemetryProperty(_resourceByName.Values.Select(r => r.ResourceType).OrderBy(t => t).ToList(), AspireTelemetryPropertyType.Pii)) }; TelemetryContext.UpdateTelemetryProperties(properties.ToArray()); diff --git a/src/Aspire.Dashboard/Model/DashboardCommandExecutor.cs b/src/Aspire.Dashboard/Model/DashboardCommandExecutor.cs index 1c8b3d97d36..544a872cbcc 100644 --- a/src/Aspire.Dashboard/Model/DashboardCommandExecutor.cs +++ b/src/Aspire.Dashboard/Model/DashboardCommandExecutor.cs @@ -41,8 +41,8 @@ public async Task ExecuteAsync(ResourceViewModel resource, CommandViewModel comm var startEvent = telemetryService.StartOperation(TelemetryEventKeys.ExecuteCommand, new Dictionary { - { TelemetryPropertyKeys.ResourceType, new AspireTelemetryProperty(resource.ResourceType) }, - { TelemetryPropertyKeys.CommandName, new AspireTelemetryProperty(command.Name) }, + { TelemetryPropertyKeys.ResourceType, new AspireTelemetryProperty(resource.ResourceType, AspireTelemetryPropertyType.Pii) }, + { TelemetryPropertyKeys.CommandName, new AspireTelemetryProperty(command.Name, AspireTelemetryPropertyType.Pii) }, }); var operationId = startEvent.Properties.FirstOrDefault(); From 0ce32dec69a72eca9f53c664316f68e6b78ee099 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Tue, 29 Apr 2025 17:13:07 -0400 Subject: [PATCH 5/9] Do not send empty string telemetry properties --- .../Components/Pages/ComponentTelemetryContext.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Aspire.Dashboard/Components/Pages/ComponentTelemetryContext.cs b/src/Aspire.Dashboard/Components/Pages/ComponentTelemetryContext.cs index 719bf16b55c..8fc2bb66be0 100644 --- a/src/Aspire.Dashboard/Components/Pages/ComponentTelemetryContext.cs +++ b/src/Aspire.Dashboard/Components/Pages/ComponentTelemetryContext.cs @@ -69,6 +69,11 @@ public bool UpdateTelemetryProperties(ReadOnlySpan m 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; From bc934c502432b37eeb672cfca81f7f83d2742311 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Tue, 29 Apr 2025 17:48:38 -0400 Subject: [PATCH 6/9] Use correct property type for instrument count --- src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs b/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs index d9b380aeaf5..5c55161c2d7 100644 --- a/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs @@ -321,7 +321,7 @@ public void UpdateTelemetryProperties() { TelemetryContext.UpdateTelemetryProperties([ new ComponentTelemetryProperty(TelemetryPropertyKeys.MetricsApplicationIsReplica, new AspireTelemetryProperty(PageViewModel.SelectedApplication.Id?.ReplicaSetName is not null)), - new ComponentTelemetryProperty(TelemetryPropertyKeys.MetricsInstrumentsCount, new AspireTelemetryProperty(PageViewModel.Instruments?.Count ?? -1)), + new ComponentTelemetryProperty(TelemetryPropertyKeys.MetricsInstrumentsCount, new AspireTelemetryProperty(PageViewModel.Instruments?.Count ?? -1, AspireTelemetryPropertyType.Metric)), new ComponentTelemetryProperty(TelemetryPropertyKeys.MetricsSelectedDuration, new AspireTelemetryProperty(PageViewModel.SelectedDuration.Id.ToString(), AspireTelemetryPropertyType.UserSetting)), new ComponentTelemetryProperty(TelemetryPropertyKeys.MetricsSelectedView, new AspireTelemetryProperty(PageViewModel.SelectedViewKind?.ToString() ?? string.Empty, AspireTelemetryPropertyType.UserSetting)) ]); From 6429bb8532a138ceaed10c51afcd11070a03f858 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Thu, 1 May 2025 05:44:19 -0400 Subject: [PATCH 7/9] Do not post custom command or resource type names --- .../Controls/ResourceDetails.razor.cs | 2 +- .../Components/Pages/Resources.razor.cs | 2 +- .../Model/DashboardCommandExecutor.cs | 4 +-- .../Telemetry/TelemetryPropertyValues.cs | 27 +++++++++++++++++++ src/Shared/Model/KnownResourceCommands.cs | 5 ++++ src/Shared/Model/KnownResourceTypes.cs | 10 +++++++ 6 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 src/Aspire.Dashboard/Telemetry/TelemetryPropertyValues.cs diff --git a/src/Aspire.Dashboard/Components/Controls/ResourceDetails.razor.cs b/src/Aspire.Dashboard/Components/Controls/ResourceDetails.razor.cs index f9d0d7247e7..d993c81ec2c 100644 --- a/src/Aspire.Dashboard/Components/Controls/ResourceDetails.razor.cs +++ b/src/Aspire.Dashboard/Components/Controls/ResourceDetails.razor.cs @@ -278,7 +278,7 @@ public Task OnViewRelationshipAsync(ResourceDetailRelationshipViewModel relation public void UpdateTelemetryProperties() { TelemetryContext.UpdateTelemetryProperties([ - new ComponentTelemetryProperty(TelemetryPropertyKeys.ResourceType, new AspireTelemetryProperty(Resource.ResourceType, AspireTelemetryPropertyType.Pii)) + new ComponentTelemetryProperty(TelemetryPropertyKeys.ResourceType, new AspireTelemetryProperty(TelemetryPropertyValues.GetResourceTypeTelemetryValue(Resource.ResourceType))) ]); } diff --git a/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs b/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs index 876178f774e..84040bfa577 100644 --- a/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs @@ -834,7 +834,7 @@ public void UpdateTelemetryProperties() var properties = new List { new(TelemetryPropertyKeys.ResourceView, new AspireTelemetryProperty(PageViewModel.SelectedViewKind.ToString(), AspireTelemetryPropertyType.UserSetting)), - new(TelemetryPropertyKeys.ResourceTypes, new AspireTelemetryProperty(_resourceByName.Values.Select(r => r.ResourceType).OrderBy(t => t).ToList(), AspireTelemetryPropertyType.Pii)) + new(TelemetryPropertyKeys.ResourceTypes, new AspireTelemetryProperty(_resourceByName.Values.Select(r => TelemetryPropertyValues.GetResourceTypeTelemetryValue(r.ResourceType)).OrderBy(t => t).ToList())) }; TelemetryContext.UpdateTelemetryProperties(properties.ToArray()); diff --git a/src/Aspire.Dashboard/Model/DashboardCommandExecutor.cs b/src/Aspire.Dashboard/Model/DashboardCommandExecutor.cs index 544a872cbcc..7a2d3c08e94 100644 --- a/src/Aspire.Dashboard/Model/DashboardCommandExecutor.cs +++ b/src/Aspire.Dashboard/Model/DashboardCommandExecutor.cs @@ -41,8 +41,8 @@ public async Task ExecuteAsync(ResourceViewModel resource, CommandViewModel comm var startEvent = telemetryService.StartOperation(TelemetryEventKeys.ExecuteCommand, new Dictionary { - { TelemetryPropertyKeys.ResourceType, new AspireTelemetryProperty(resource.ResourceType, AspireTelemetryPropertyType.Pii) }, - { TelemetryPropertyKeys.CommandName, new AspireTelemetryProperty(command.Name, AspireTelemetryPropertyType.Pii) }, + { TelemetryPropertyKeys.ResourceType, new AspireTelemetryProperty(TelemetryPropertyValues.GetResourceTypeTelemetryValue(resource.ResourceType)) }, + { TelemetryPropertyKeys.CommandName, new AspireTelemetryProperty(TelemetryPropertyValues.GetCommandNameTelemetryValue(command.Name)) }, }); var operationId = startEvent.Properties.FirstOrDefault(); diff --git a/src/Aspire.Dashboard/Telemetry/TelemetryPropertyValues.cs b/src/Aspire.Dashboard/Telemetry/TelemetryPropertyValues.cs new file mode 100644 index 00000000000..fbf6036da11 --- /dev/null +++ b/src/Aspire.Dashboard/Telemetry/TelemetryPropertyValues.cs @@ -0,0 +1,27 @@ +// 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.Model; +using Aspire.Hosting.Dashboard; + +namespace Aspire.Dashboard.Telemetry; + +public static class TelemetryPropertyValues +{ + private const string CustomResourceCommand = "custom-command"; + private const string CustomResourceType = "custom-resource-type"; + + public static string GetCommandNameTelemetryValue(string commandName) + { + return KnownResourceCommands.IsKnownCommand(commandName) + ? commandName + : CustomResourceCommand; + } + + public static string GetResourceTypeTelemetryValue(string resourceType) + { + return KnownResourceTypes.IsKnownResourceType(resourceType) + ? resourceType + : CustomResourceType; + } +} diff --git a/src/Shared/Model/KnownResourceCommands.cs b/src/Shared/Model/KnownResourceCommands.cs index af785e8905e..a6ae15d1241 100644 --- a/src/Shared/Model/KnownResourceCommands.cs +++ b/src/Shared/Model/KnownResourceCommands.cs @@ -8,4 +8,9 @@ internal static class KnownResourceCommands public const string StartCommand = "resource-start"; public const string StopCommand = "resource-stop"; public const string RestartCommand = "resource-restart"; + + public static bool IsKnownCommand(string command) + { + return command is StartCommand or StopCommand or RestartCommand; + } } diff --git a/src/Shared/Model/KnownResourceTypes.cs b/src/Shared/Model/KnownResourceTypes.cs index 09a06c22c1d..ea1939c8942 100644 --- a/src/Shared/Model/KnownResourceTypes.cs +++ b/src/Shared/Model/KnownResourceTypes.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Immutable; + namespace Aspire.Dashboard.Model; internal static class KnownResourceTypes @@ -8,4 +10,12 @@ internal static class KnownResourceTypes public const string Executable = "Executable"; public const string Project = "Project"; public const string Container = "Container"; + + // This field needs to be updated when new resource types are added. + private static readonly ImmutableArray s_builtInResources = ["Resource", "AzureAppConfigurationResource", "AzureContainerAppEnvironmentResource", "AzureApplicationInsightsResource", "AzureOpenAIDeploymentResource", "AzureOpenAIResource", "AzureCosmosDBContainerResource", "AzureCosmosDBDatabaseResource", "AzureCosmosDBEmulatorResource", "AzureCosmosDBResource", "AzureEventHubConsumerGroupResource", "AzureEventHubResource", "AzureEventHubsEmulatorResource", "AzureEventHubsResource", "AzureFunctionsProjectResource", "AzureKeyVaultResource", "AzureLogAnalyticsWorkspaceResource", "AzurePostgresFlexibleServerDatabaseResource", "AzurePostgresFlexibleServerResource", "AzurePostgresResource", "AzureRedisCacheResource", "AzureRedisResource", "AzureSearchResource", "AzureServiceBusEmulatorResource", "AzureServiceBusQueueResource", "AzureServiceBusResource", "AzureServiceBusSubscriptionResource", "AzureServiceBusTopicResource", "AzureSignalREmulatorResource", "AzureSignalRResource", "AzureSqlDatabaseResource", "AzureSqlServerResource", "AzureBlobStorageResource", "AzureQueueStorageResource", "AzureStorageEmulatorResource", "AzureStorageResource", "AzureTableStorageResource", "AzureWebPubSubHubResource", "AzureWebPubSubResource", "AppIdentityResource", "AzureBicepResource", "AzureProvisioningResource", "DockerComposeEnvironmentResource", "DockerComposeServiceResource", "ElasticsearchResource", "GarnetResource", "KafkaServerResource", "KafkaUIContainerResource", "KeycloakResource", "KubernetesEnvironmentResource", "KubernetesResource", "AttuResource", "MilvusDatabaseResource", "MilvusServerResource", "MongoDBDatabaseResource", "MongoDBServerResource", "MongoExpressContainerResource", "MySqlDatabaseResource", "MySqlServerResource", "PhpMyAdminContainerResource", "NatsServerResource", "NodeAppResource", "OracleDatabaseResource", "OracleDatabaseServerResource", "PgAdminContainerResource", "PgWebContainerResource", "PostgresDatabaseResource", "PostgresServerResource", "PythonAppResource", "PythonProjectResource", "QdrantServerResource", "RabbitMQServerResource", "RedisCommanderResource", "RedisInsightResource", "RedisResource", "SeqResource", "SqlServerDatabaseResource", "SqlServerServerResource", "ValkeyResource", "ContainerResource", "ExecutableResource", "ParameterResource", "ProjectResource", "ConnectionStringParameterResource", "ConnectionStringResource", "ExecutableContainerResource", "ProjectContainerResource"]; + + public static bool IsKnownResourceType(string resourceType) + { + return s_builtInResources.Contains(resourceType); + } } From cb390b06c55b000823c2f04d2e736707c79c420d Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Fri, 2 May 2025 10:06:30 -0700 Subject: [PATCH 8/9] Updated data structure to hashset, order resource types, remove Resource suffix from executable/project/container. ToString MetricsInstrumentsCount --- src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs | 3 ++- src/Shared/Model/KnownResourceTypes.cs | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs b/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs index 5c55161c2d7..fc81d05c09c 100644 --- a/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Globalization; using Aspire.Dashboard.Components.Controls; using Aspire.Dashboard.Components.Layout; using Aspire.Dashboard.Model; @@ -321,7 +322,7 @@ public void UpdateTelemetryProperties() { TelemetryContext.UpdateTelemetryProperties([ new ComponentTelemetryProperty(TelemetryPropertyKeys.MetricsApplicationIsReplica, new AspireTelemetryProperty(PageViewModel.SelectedApplication.Id?.ReplicaSetName is not null)), - new ComponentTelemetryProperty(TelemetryPropertyKeys.MetricsInstrumentsCount, new AspireTelemetryProperty(PageViewModel.Instruments?.Count ?? -1, AspireTelemetryPropertyType.Metric)), + new ComponentTelemetryProperty(TelemetryPropertyKeys.MetricsInstrumentsCount, new AspireTelemetryProperty((PageViewModel.Instruments?.Count ?? -1).ToString(CultureInfo.InvariantCulture), AspireTelemetryPropertyType.Metric)), new ComponentTelemetryProperty(TelemetryPropertyKeys.MetricsSelectedDuration, new AspireTelemetryProperty(PageViewModel.SelectedDuration.Id.ToString(), AspireTelemetryPropertyType.UserSetting)), new ComponentTelemetryProperty(TelemetryPropertyKeys.MetricsSelectedView, new AspireTelemetryProperty(PageViewModel.SelectedViewKind?.ToString() ?? string.Empty, AspireTelemetryPropertyType.UserSetting)) ]); diff --git a/src/Shared/Model/KnownResourceTypes.cs b/src/Shared/Model/KnownResourceTypes.cs index ea1939c8942..70fd49ca2dd 100644 --- a/src/Shared/Model/KnownResourceTypes.cs +++ b/src/Shared/Model/KnownResourceTypes.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Immutable; - namespace Aspire.Dashboard.Model; internal static class KnownResourceTypes @@ -12,7 +10,7 @@ internal static class KnownResourceTypes public const string Container = "Container"; // This field needs to be updated when new resource types are added. - private static readonly ImmutableArray s_builtInResources = ["Resource", "AzureAppConfigurationResource", "AzureContainerAppEnvironmentResource", "AzureApplicationInsightsResource", "AzureOpenAIDeploymentResource", "AzureOpenAIResource", "AzureCosmosDBContainerResource", "AzureCosmosDBDatabaseResource", "AzureCosmosDBEmulatorResource", "AzureCosmosDBResource", "AzureEventHubConsumerGroupResource", "AzureEventHubResource", "AzureEventHubsEmulatorResource", "AzureEventHubsResource", "AzureFunctionsProjectResource", "AzureKeyVaultResource", "AzureLogAnalyticsWorkspaceResource", "AzurePostgresFlexibleServerDatabaseResource", "AzurePostgresFlexibleServerResource", "AzurePostgresResource", "AzureRedisCacheResource", "AzureRedisResource", "AzureSearchResource", "AzureServiceBusEmulatorResource", "AzureServiceBusQueueResource", "AzureServiceBusResource", "AzureServiceBusSubscriptionResource", "AzureServiceBusTopicResource", "AzureSignalREmulatorResource", "AzureSignalRResource", "AzureSqlDatabaseResource", "AzureSqlServerResource", "AzureBlobStorageResource", "AzureQueueStorageResource", "AzureStorageEmulatorResource", "AzureStorageResource", "AzureTableStorageResource", "AzureWebPubSubHubResource", "AzureWebPubSubResource", "AppIdentityResource", "AzureBicepResource", "AzureProvisioningResource", "DockerComposeEnvironmentResource", "DockerComposeServiceResource", "ElasticsearchResource", "GarnetResource", "KafkaServerResource", "KafkaUIContainerResource", "KeycloakResource", "KubernetesEnvironmentResource", "KubernetesResource", "AttuResource", "MilvusDatabaseResource", "MilvusServerResource", "MongoDBDatabaseResource", "MongoDBServerResource", "MongoExpressContainerResource", "MySqlDatabaseResource", "MySqlServerResource", "PhpMyAdminContainerResource", "NatsServerResource", "NodeAppResource", "OracleDatabaseResource", "OracleDatabaseServerResource", "PgAdminContainerResource", "PgWebContainerResource", "PostgresDatabaseResource", "PostgresServerResource", "PythonAppResource", "PythonProjectResource", "QdrantServerResource", "RabbitMQServerResource", "RedisCommanderResource", "RedisInsightResource", "RedisResource", "SeqResource", "SqlServerDatabaseResource", "SqlServerServerResource", "ValkeyResource", "ContainerResource", "ExecutableResource", "ParameterResource", "ProjectResource", "ConnectionStringParameterResource", "ConnectionStringResource", "ExecutableContainerResource", "ProjectContainerResource"]; + private static readonly HashSet s_builtInResources = ["AppIdentityResource", "AttuResource", "AzureAppConfigurationResource", "AzureApplicationInsightsResource", "AzureBicepResource", "AzureBlobStorageResource", "AzureContainerAppEnvironmentResource", "AzureCosmosDBContainerResource", "AzureCosmosDBDatabaseResource", "AzureCosmosDBEmulatorResource", "AzureCosmosDBResource", "AzureEventHubConsumerGroupResource", "AzureEventHubResource", "AzureEventHubsEmulatorResource", "AzureEventHubsResource", "AzureFunctionsProjectResource", "AzureKeyVaultResource", "AzureLogAnalyticsWorkspaceResource", "AzureOpenAIDeploymentResource", "AzureOpenAIResource", "AzurePostgresFlexibleServerDatabaseResource", "AzurePostgresFlexibleServerResource", "AzurePostgresResource", "AzureProvisioningResource", "AzureQueueStorageResource", "AzureRedisCacheResource", "AzureRedisResource", "AzureSearchResource", "AzureServiceBusEmulatorResource", "AzureServiceBusQueueResource", "AzureServiceBusResource", "AzureServiceBusSubscriptionResource", "AzureServiceBusTopicResource", "AzureSignalREmulatorResource", "AzureSignalRResource", "AzureSqlDatabaseResource", "AzureSqlServerResource", "AzureStorageEmulatorResource", "AzureStorageResource", "AzureTableStorageResource", "AzureWebPubSubHubResource", "AzureWebPubSubResource", "ConnectionStringParameterResource", "ConnectionStringResource", Container, "DockerComposeEnvironmentResource", "DockerComposeServiceResource", "ElasticsearchResource", Executable, "ExecutableContainerResource", "GarnetResource", "KafkaServerResource", "KafkaUIContainerResource", "KeycloakResource", "KubernetesEnvironmentResource", "KubernetesResource", "MilvusDatabaseResource", "MilvusServerResource", "MongoDBDatabaseResource", "MongoDBServerResource", "MongoExpressContainerResource", "MySqlDatabaseResource", "MySqlServerResource", "NatsServerResource", "NodeAppResource", "OracleDatabaseResource", "OracleDatabaseServerResource", "ParameterResource", "PgAdminContainerResource", "PgWebContainerResource", "PhpMyAdminContainerResource", "PostgresDatabaseResource", "PostgresServerResource", Project, "ProjectContainerResource", "PythonAppResource", "PythonProjectResource", "QdrantServerResource", "RabbitMQServerResource", "RedisCommanderResource", "RedisInsightResource", "RedisResource", "Resource", "SeqResource", "SqlServerDatabaseResource", "SqlServerServerResource", "ValkeyResource"]; public static bool IsKnownResourceType(string resourceType) { From 83a2de6ba8f13bedb74072901556db74c9369a36 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Fri, 2 May 2025 14:39:30 -0700 Subject: [PATCH 9/9] Update privacy policy link --- src/Aspire.Dashboard/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Aspire.Dashboard/README.md b/src/Aspire.Dashboard/README.md index d90678cf5eb..608a7ba0af3 100644 --- a/src/Aspire.Dashboard/README.md +++ b/src/Aspire.Dashboard/README.md @@ -126,7 +126,7 @@ Limits are per-resource. For example, a `MaxLogCount` value of 10,000 configures ## Data collection -The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the repository. There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at https://go.microsoft.com/fwlink/?LinkID=824704. You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the repository. There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at https://go.microsoft.com/fwlink/?LinkId=521839. You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. ### Opting out of data collection