Skip to content

Initialize telemetry context in UpdateTelemetryProperties if not already initialized #9553

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -37,6 +37,9 @@ public partial class ResourceDetails : IComponentWithTelemetry, IDisposable
[Inject]
public required BrowserTimeProvider TimeProvider { get; init; }

[Inject]
public required ILogger<ResourceDetails> Logger { get; init; }

private bool IsSpecOnlyToggleDisabled => !Resource.Environment.All(i => !i.FromSpec) && !GetResourceProperties(ordered: false).Any(static vm => vm.KnownProperty is null);

// NOTE Excludes URLs as they don't expose sensitive items (and enumerating URLs is non-trivial)
@@ -159,8 +162,8 @@ protected override async Task OnAfterRenderAsync(bool firstRender)

protected override void OnInitialized()
{
(_resizeLabels, _sortLabels) = DashboardUIHelpers.CreateGridLabels(ControlStringsLoc);
TelemetryContextProvider.Initialize(TelemetryContext);
(_resizeLabels, _sortLabels) = DashboardUIHelpers.CreateGridLabels(ControlStringsLoc);
}

private IEnumerable<ResourceDetailRelationshipViewModel> GetRelationships()
@@ -279,7 +282,7 @@ public void UpdateTelemetryProperties()
{
TelemetryContext.UpdateTelemetryProperties([
new ComponentTelemetryProperty(TelemetryPropertyKeys.ResourceType, new AspireTelemetryProperty(TelemetryPropertyValues.GetResourceTypeTelemetryValue(Resource.ResourceType, Resource.SupportsDetailedTelemetry))),
]);
], Logger);
}

public void Dispose()
Original file line number Diff line number Diff line change
@@ -61,7 +61,7 @@ public void Initialize(DashboardTelemetryService telemetryService, string? brows
});
}

public bool UpdateTelemetryProperties(ReadOnlySpan<ComponentTelemetryProperty> modifiedProperties)
public bool UpdateTelemetryProperties(ReadOnlySpan<ComponentTelemetryProperty> modifiedProperties, ILogger logger)
{
// Only send updated properties if they are different from the existing ones.
var anyChange = false;
@@ -82,17 +82,18 @@ public bool UpdateTelemetryProperties(ReadOnlySpan<ComponentTelemetryProperty> m

if (anyChange)
{
PostProperties();
PostProperties(logger);
}

return anyChange;
}

private void PostProperties()
private void PostProperties(ILogger logger)
{
if (_telemetryService == null)
{
throw new InvalidOperationException("InitializeAsync has not been called.");
logger.LogWarning($"Telemetry service for '{_componentType}' is not initialized. Cannot post properties.");
return;
}

_telemetryService.PostOperation(
5 changes: 2 additions & 3 deletions src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs
Original file line number Diff line number Diff line change
@@ -126,6 +126,7 @@ private sealed class ConsoleLogsSubscription

protected override async Task OnInitializedAsync()
{
TelemetryContextProvider.Initialize(TelemetryContext);
_resourceSubscriptionToken = _resourceSubscriptionCts.Token;
_logEntries = new(Options.Value.Frontend.MaxConsoleLogCount);
_noSelection = new() { Id = null, Name = ControlsStringsLoc[nameof(ControlsStrings.LabelNone)] };
@@ -172,8 +173,6 @@ protected override async Task OnInitializedAsync()
PageViewModel.Status = Loc[nameof(Dashboard.Resources.ConsoleLogs.ConsoleLogsLogsNotYetAvailable)];
}

TelemetryContextProvider.Initialize(TelemetryContext);

async Task TrackResourceSnapshotsAsync()
{
if (!DashboardClient.IsEnabled)
@@ -750,6 +749,6 @@ public void UpdateTelemetryProperties()
{
TelemetryContext.UpdateTelemetryProperties([
new ComponentTelemetryProperty(TelemetryPropertyKeys.ConsoleLogsShowTimestamp, new AspireTelemetryProperty(_showTimestamp, AspireTelemetryPropertyType.UserSetting))
]);
], Logger);
}
}
7 changes: 5 additions & 2 deletions src/Aspire.Dashboard/Components/Pages/Error.razor.cs
Original file line number Diff line number Diff line change
@@ -9,6 +9,9 @@ namespace Aspire.Dashboard.Components.Pages;

public partial class Error : IComponentWithTelemetry, IDisposable
{
[Inject]
public required ILogger<Error> Logger { get; init; }

[CascadingParameter]
private HttpContext? HttpContext { get; set; }

@@ -17,8 +20,8 @@ public partial class Error : IComponentWithTelemetry, IDisposable

protected override void OnInitialized()
{
RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier;
TelemetryContextProvider.Initialize(TelemetryContext);
RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier;
}

[Inject]
@@ -36,7 +39,7 @@ public void UpdateTelemetryProperties()
{
TelemetryContext.UpdateTelemetryProperties([
new ComponentTelemetryProperty(TelemetryPropertyKeys.ErrorRequestId, new AspireTelemetryProperty(RequestId ?? string.Empty)),
]);
], Logger);
}

public void Dispose()
4 changes: 2 additions & 2 deletions src/Aspire.Dashboard/Components/Pages/Login.razor.cs
Original file line number Diff line number Diff line change
@@ -41,6 +41,8 @@ public partial class Login : IAsyncDisposable, IComponentWithTelemetry

protected override async Task OnInitializedAsync()
{
TelemetryContextProvider.Initialize(TelemetryContext);

// Create EditContext before awaiting. This is required to prevent an await in OnInitializedAsync
// triggering parameters being set on EditForm before EditContext is created.
// If that happens then EditForm errors that it requires an EditContext.
@@ -60,8 +62,6 @@ protected override async Task OnInitializedAsync()
return;
}
}

TelemetryContextProvider.Initialize(TelemetryContext);
}

protected override async Task OnAfterRenderAsync(bool firstRender)
6 changes: 3 additions & 3 deletions src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs
Original file line number Diff line number Diff line change
@@ -78,6 +78,8 @@ public partial class Metrics : IDisposable, IComponentWithTelemetry, IPageWithSe

protected override void OnInitialized()
{
TelemetryContextProvider.Initialize(TelemetryContext);

_durations = new List<SelectViewModel<TimeSpan>>
{
new() { Name = Loc[nameof(Dashboard.Resources.Metrics.MetricsLastOneMinute)], Id = TimeSpan.FromMinutes(1) },
@@ -109,8 +111,6 @@ protected override void OnInitialized()
UpdateApplications();
StateHasChanged();
}));

TelemetryContextProvider.Initialize(TelemetryContext);
}

protected override async Task OnParametersSetAsync()
@@ -335,6 +335,6 @@ public void UpdateTelemetryProperties()
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))
]);
], Logger);
}
}
6 changes: 4 additions & 2 deletions src/Aspire.Dashboard/Components/Pages/Resources.razor.cs
Original file line number Diff line number Diff line change
@@ -56,6 +56,8 @@ public partial class Resources : ComponentBase, IComponentWithTelemetry, IAsyncD
public required IOptionsMonitor<DashboardOptions> DashboardOptions { get; init; }
[Inject]
public required ComponentTelemetryContextProvider TelemetryContextProvider { get; init; }
[Inject]
public required ILogger<Resources> Logger { get; init; }

public string BasePath => DashboardUrls.ResourcesBasePath;
public string SessionStorageKey => BrowserStorageKeys.ResourcesPageState;
@@ -160,6 +162,7 @@ private async Task HandleSearchFilterChangedAsync()

protected override async Task OnInitializedAsync()
{
TelemetryContextProvider.Initialize(TelemetryContext);
Copy link
Preview

Copilot AI May 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Add a comment explaining why telemetry initialization is placed at the top of OnInitializedAsync, so future maintainers understand its importance before any awaits or parameter setup.

Copilot uses AI. Check for mistakes.

(_resizeLabels, _sortLabels) = DashboardUIHelpers.CreateGridLabels(ControlsStringsLoc);

_gridColumns = [
@@ -214,7 +217,6 @@ protected override async Task OnInitializedAsync()
}
});

TelemetryContextProvider.Initialize(TelemetryContext);
_isLoading = false;

async Task SubscribeResourcesAsync()
@@ -867,6 +869,6 @@ public void UpdateTelemetryProperties()
new(TelemetryPropertyKeys.ResourceTypes, new AspireTelemetryProperty(_resourceByName.Values.Select(r => TelemetryPropertyValues.GetResourceTypeTelemetryValue(r.ResourceType, r.SupportsDetailedTelemetry)).OrderBy(t => t).ToList()))
};

TelemetryContext.UpdateTelemetryProperties(properties.ToArray());
TelemetryContext.UpdateTelemetryProperties(properties.ToArray(), Logger);
}
}
5 changes: 2 additions & 3 deletions src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor.cs
Original file line number Diff line number Diff line change
@@ -148,6 +148,7 @@ private async ValueTask<GridItemsProviderResult<OtlpLogEntry>> GetData(GridItems

protected override void OnInitialized()
{
TelemetryContextProvider.Initialize(TelemetryContext);
(_resizeLabels, _sortLabels) = DashboardUIHelpers.CreateGridLabels(ControlsStringsLoc);

_gridColumns = [
@@ -203,8 +204,6 @@ protected override void OnInitialized()
UpdateApplications();
StateHasChanged();
}));

TelemetryContextProvider.Initialize(TelemetryContext);
}

protected override async Task OnParametersSetAsync()
@@ -497,6 +496,6 @@ public void UpdateTelemetryProperties()
TelemetryContext.UpdateTelemetryProperties([
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))
]);
], Logger);
}
}
4 changes: 2 additions & 2 deletions src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs
Original file line number Diff line number Diff line change
@@ -66,6 +66,8 @@ public partial class TraceDetail : ComponentBase, IComponentWithTelemetry, IDisp

protected override void OnInitialized()
{
TelemetryContextProvider.Initialize(TelemetryContext);

_gridColumns = [
new GridColumn(Name: NameColumn, DesktopWidth: "4fr", MobileWidth: "4fr"),
new GridColumn(Name: TicksColumn, DesktopWidth: "12fr", MobileWidth: "12fr"),
@@ -81,8 +83,6 @@ protected override void OnInitialized()
await InvokeAsync(_dataGrid.SafeRefreshDataAsync);
}));
}

TelemetryContextProvider.Initialize(TelemetryContext);
}

// Internal to be used in unit tests
3 changes: 1 addition & 2 deletions src/Aspire.Dashboard/Components/Pages/Traces.razor.cs
Original file line number Diff line number Diff line change
@@ -149,6 +149,7 @@ private async ValueTask<GridItemsProviderResult<OtlpTrace>> GetData(GridItemsPro

protected override void OnInitialized()
{
TelemetryContextProvider.Initialize(TelemetryContext);
(_resizeLabels, _sortLabels) = DashboardUIHelpers.CreateGridLabels(ControlsStringsLoc);

_gridColumns = [
@@ -168,8 +169,6 @@ protected override void OnInitialized()
UpdateApplications();
StateHasChanged();
}));

TelemetryContextProvider.Initialize(TelemetryContext);
}

protected override async Task OnParametersSetAsync()
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@ public async Task ComponentTelemetryContext_TelemetryEnabled_EndToEnd()
var telemetryContextProvider = new ComponentTelemetryContextProvider(telemetryService);
telemetryContextProvider.SetBrowserUserAgent("mozilla");
await telemetryService.InitializeAsync();
var logger = NullLogger<ComponentTelemetryContextTests>.Instance;

// Act & assert initialize
telemetryContextProvider.Initialize(telemetryContext);
@@ -38,18 +39,18 @@ public async Task ComponentTelemetryContext_TelemetryEnabled_EndToEnd()
OperationContext? parametersUpdateOperation;

// Act & assert update properties
telemetryContext.UpdateTelemetryProperties([new ComponentTelemetryProperty("Test", new AspireTelemetryProperty("Value"))]);
telemetryContext.UpdateTelemetryProperties([new ComponentTelemetryProperty("Test", new AspireTelemetryProperty("Value"))], logger);
Assert.Equal(3, telemetryContext.Properties.Count);
Assert.True(telemetrySender.ContextChannel.Reader.TryRead(out parametersUpdateOperation));
Assert.Equal("/telemetry/operation - $aspire/dashboard/component/paramsSet", parametersUpdateOperation.Name);
Assert.Single(parametersUpdateOperation.Properties);

// If value didn't change, we shouldn't post again
telemetryContext.UpdateTelemetryProperties([new ComponentTelemetryProperty("Test", new AspireTelemetryProperty("Value"))]);
telemetryContext.UpdateTelemetryProperties([new ComponentTelemetryProperty("Test", new AspireTelemetryProperty("Value"))], logger);
Assert.Equal(3, telemetryContext.Properties.Count);
Assert.False(telemetrySender.ContextChannel.Reader.TryRead(out parametersUpdateOperation));

telemetryContext.UpdateTelemetryProperties([new ComponentTelemetryProperty("Test", new AspireTelemetryProperty("NewValue"))]);
telemetryContext.UpdateTelemetryProperties([new ComponentTelemetryProperty("Test", new AspireTelemetryProperty("NewValue"))], logger);
Assert.Equal(3, telemetryContext.Properties.Count);
Assert.True(telemetrySender.ContextChannel.Reader.TryRead(out parametersUpdateOperation));

@@ -69,13 +70,14 @@ public async Task ComponentTelemetryContext_TelemetryDisabled_EndToEnd()
var telemetryContextProvider = new ComponentTelemetryContextProvider(telemetryService);
telemetryContextProvider.SetBrowserUserAgent("mozilla");
await telemetryService.InitializeAsync();
var logger = NullLogger<ComponentTelemetryContextTests>.Instance;

// Act & assert initialize
telemetryContextProvider.Initialize(telemetryContext);
Assert.False(telemetrySender.ContextChannel.Reader.TryRead(out _));

// Act & assert update properties
telemetryContext.UpdateTelemetryProperties([new ComponentTelemetryProperty("Test", new AspireTelemetryProperty("Value"))]);
telemetryContext.UpdateTelemetryProperties([new ComponentTelemetryProperty("Test", new AspireTelemetryProperty("Value"))], logger);
Assert.Equal(3, telemetryContext.Properties.Count);
Assert.False(telemetrySender.ContextChannel.Reader.TryRead(out _));