Add minimum span duration filtering#17299
Conversation
Add dashboard trace-detail filtering for spans shorter than a configured duration, expose the same minDurationMs filter through telemetry APIs, and add CLI --min-duration support for spans and traces. Co-authored-by: Copilot <[email protected]>
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 17299Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 17299" |
There was a problem hiding this comment.
Pull request overview
Adds a minimum span duration filter across the Dashboard telemetry APIs, Dashboard trace detail UI, and Aspire CLI telemetry commands so very short spans can be hidden to reduce trace noise.
Changes:
- Adds
minDurationMsquery support to dashboard telemetry endpoints (spans, traces, trace detail) and applies filtering inTelemetryApiService. - Adds a “Minimum duration (ms)” filter control to the Trace Detail page and filters spans client-side in the grid.
- Adds
--min-duration/--min-duration-msto CLIotel spans/otel traces, plus test coverage and localization resources.
Show a summary per file
| File | Description |
|---|---|
| tests/Aspire.Dashboard.Tests/TelemetryApiServiceTests.cs | Adds unit tests for minimum-duration filtering behavior in telemetry APIs. |
| tests/Aspire.Dashboard.Tests/DashboardUrlsTests.cs | Verifies minDurationMs is appended to telemetry API URLs. |
| tests/Aspire.Dashboard.Components.Tests/Shared/FluentUISetupHelpers.cs | Updates Fluent UI JS interop test setup for text/number fields. |
| tests/Aspire.Dashboard.Components.Tests/Pages/TraceDetailsTests.cs | Adds component test for minimum-duration filtering in trace details grid. |
| tests/Aspire.Cli.Tests/Commands/TelemetryTracesCommandTests.cs | Tests CLI traces command includes minDurationMs in requests. |
| tests/Aspire.Cli.Tests/Commands/TelemetrySpansCommandTests.cs | Tests CLI spans command includes minDurationMs in requests. |
| src/Shared/DashboardUrls.cs | Adds optional minDurationMs query parameter to telemetry URL builders. |
| src/Aspire.Dashboard/DashboardEndpointsBuilder.cs | Wires minDurationMs from query string into telemetry API service calls. |
| src/Aspire.Dashboard/Api/TelemetryApiService.cs | Implements minimum-duration filtering for spans/traces/trace detail + follow streaming. |
| src/Aspire.Dashboard/Components/Pages/TraceDetail.razor | Adds minimum-duration input control (desktop + mobile toolbars). |
| src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs | Applies minimum-duration filter when computing visible span view models. |
| src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.css | Styles the new minimum-duration filter UI. |
| src/Aspire.Dashboard/Resources/TraceDetail.resx | Adds localized strings for the new UI label/placeholder/title. |
| src/Aspire.Dashboard/Resources/TraceDetail.Designer.cs | Generated accessors for new TraceDetail resource strings. |
| src/Aspire.Dashboard/Resources/xlf/TraceDetail.cs.xlf | Localization entries for new TraceDetail strings (cs). |
| src/Aspire.Dashboard/Resources/xlf/TraceDetail.de.xlf | Localization entries for new TraceDetail strings (de). |
| src/Aspire.Dashboard/Resources/xlf/TraceDetail.es.xlf | Localization entries for new TraceDetail strings (es). |
| src/Aspire.Dashboard/Resources/xlf/TraceDetail.fr.xlf | Localization entries for new TraceDetail strings (fr). |
| src/Aspire.Dashboard/Resources/xlf/TraceDetail.it.xlf | Localization entries for new TraceDetail strings (it). |
| src/Aspire.Dashboard/Resources/xlf/TraceDetail.ja.xlf | Localization entries for new TraceDetail strings (ja). |
| src/Aspire.Dashboard/Resources/xlf/TraceDetail.ko.xlf | Localization entries for new TraceDetail strings (ko). |
| src/Aspire.Dashboard/Resources/xlf/TraceDetail.pl.xlf | Localization entries for new TraceDetail strings (pl). |
| src/Aspire.Dashboard/Resources/xlf/TraceDetail.pt-BR.xlf | Localization entries for new TraceDetail strings (pt-BR). |
| src/Aspire.Dashboard/Resources/xlf/TraceDetail.ru.xlf | Localization entries for new TraceDetail strings (ru). |
| src/Aspire.Dashboard/Resources/xlf/TraceDetail.tr.xlf | Localization entries for new TraceDetail strings (tr). |
| src/Aspire.Dashboard/Resources/xlf/TraceDetail.zh-Hans.xlf | Localization entries for new TraceDetail strings (zh-Hans). |
| src/Aspire.Dashboard/Resources/xlf/TraceDetail.zh-Hant.xlf | Localization entries for new TraceDetail strings (zh-Hant). |
| src/Aspire.Cli/Commands/TelemetryCommandHelpers.cs | Introduces the shared --min-duration/--min-duration-ms option definition. |
| src/Aspire.Cli/Commands/TelemetrySpansCommand.cs | Passes minimum duration through to spans API URL. |
| src/Aspire.Cli/Commands/TelemetryTracesCommand.cs | Passes minimum duration through to traces/trace detail API URLs. |
| src/Aspire.Cli/Resources/TelemetryCommandStrings.resx | Adds description string for the new CLI option. |
| src/Aspire.Cli/Resources/TelemetryCommandStrings.Designer.cs | Generated accessor for the new CLI option description. |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.cs.xlf | Localization entry for new CLI option description (cs). |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.de.xlf | Localization entry for new CLI option description (de). |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.es.xlf | Localization entry for new CLI option description (es). |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.fr.xlf | Localization entry for new CLI option description (fr). |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.it.xlf | Localization entry for new CLI option description (it). |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.ja.xlf | Localization entry for new CLI option description (ja). |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.ko.xlf | Localization entry for new CLI option description (ko). |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.pl.xlf | Localization entry for new CLI option description (pl). |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.pt-BR.xlf | Localization entry for new CLI option description (pt-BR). |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.ru.xlf | Localization entry for new CLI option description (ru). |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.tr.xlf | Localization entry for new CLI option description (tr). |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.zh-Hans.xlf | Localization entry for new CLI option description (zh-Hans). |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.zh-Hant.xlf | Localization entry for new CLI option description (zh-Hant). |
Copilot's findings
Files not reviewed (2)
- src/Aspire.Cli/Resources/TelemetryCommandStrings.Designer.cs: Language not supported
- src/Aspire.Dashboard/Resources/TraceDetail.Designer.cs: Language not supported
Comments suppressed due to low confidence (2)
src/Aspire.Cli/Commands/TelemetrySpansCommand.cs:101
- --min-duration accepts negative/NaN/Infinity values and they’ll be silently treated as “no duration filter” by the dashboard API (since minDurationMs <= 0 or non-finite becomes null). This makes the CLI option misleading. Add validation similar to --limit (e.g., require a finite value >= 0, or reject < 0/non-finite with an InvalidCommand exit and a clear error message).
var traceId = parseResult.GetValue(s_traceIdOption);
var hasError = parseResult.GetValue(s_hasErrorOption);
var dashboardUrl = parseResult.GetValue(s_dashboardUrlOption);
var apiKey = parseResult.GetValue(s_apiKeyOption);
var search = parseResult.GetValue(s_searchOption);
var minimumDuration = parseResult.GetValue(s_minimumDurationOption);
// Validate --limit value
if (limit.HasValue && limit.Value < 1)
{
return CommandResult.Failure(CliExitCodes.InvalidCommand, TelemetryCommandStrings.LimitMustBePositive);
}
src/Aspire.Cli/Commands/TelemetryTracesCommand.cs:99
- --min-duration accepts negative/NaN/Infinity values and they’ll be silently treated as “no duration filter” by the dashboard API (minDurationMs <= 0 or non-finite becomes null). This makes the CLI option misleading. Add validation similar to --limit (e.g., require a finite value >= 0, or reject < 0/non-finite with an InvalidCommand exit and a clear error message).
var format = parseResult.GetValue(s_formatOption);
var limit = parseResult.GetValue(s_limitOption);
var traceId = parseResult.GetValue(s_traceIdOption);
var hasError = parseResult.GetValue(s_hasErrorOption);
var dashboardUrl = parseResult.GetValue(s_dashboardUrlOption);
var apiKey = parseResult.GetValue(s_apiKeyOption);
var search = parseResult.GetValue(s_searchOption);
var minimumDuration = parseResult.GetValue(s_minimumDurationOption);
// Validate --limit value
if (limit.HasValue && limit.Value < 1)
{
return CommandResult.Failure(CliExitCodes.InvalidCommand, TelemetryCommandStrings.LimitMustBePositive);
}
- Files reviewed: 43/45 changed files
- Comments generated: 2
# Conflicts: # src/Aspire.Dashboard/Components/Pages/TraceDetail.razor # src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.css
Co-authored-by: Copilot <[email protected]>
|
Fixed values don’t cut it (though we can be smart about calculating a scale). I think it needs to be possible to enter a value. I am too worried about horizontal space as it doesn’t scale well for general filters |
Co-authored-by: Copilot <[email protected]>
|
Acknowledged. I addressed the performance issue from the inline thread and pushed the fix. |
PR Testing ReportPR Information
CLI Version Verification
Changes AnalyzedThe PR adds minimum span duration filtering to CLI telemetry commands and dashboard trace-detail views/APIs, including:
Test Scenarios ExecutedScenario 1: Dogfood CLI install and option discoveryObjective: Verify the PR dogfood artifact is available, matches the PR head, and exposes the new CLI options. Result: Passed Evidence:
Scenario 2: Fresh starter app restore/build with PR packagesObjective: Verify a new Aspire starter app can be created and built using the PR package channel. Steps:
Result: Passed Evidence:
Scenario 3: CLI duration filter query propagation with mock dashboard APIObjective: Verify the PR CLI sends the expected Steps:
Result: Passed Captured requests: Scenario 4: Live AppHost telemetry filteringObjective: Exercise the filter against a running starter AppHost and dashboard. Result: Inconclusive Observation: A starter AppHost launched successfully, but the live telemetry run was not reliable in this agent environment: one attempt produced empty telemetry arrays, and a later follow-up could not reconnect to the dashboard after startup. I did not count this as a PR failure because the controlled dashboard API scenario verified the CLI request behavior added by this PR. Summary
Overall ResultPassed for the validated CLI/package scenarios. I did not find a PR-specific failure in the executed coverage. |
Co-authored-by: Copilot <[email protected]>
|
Re-running the failed jobs in the CI workflow for this pull request because 1 job was identified as retry-safe transient failures in the CI run attempt.
|
|
❓ CLI E2E Tests unknown — 95 passed, 0 failed, 5 unknown (commit View all recordings
📹 Recordings uploaded automatically from CI run #26204401078 |

Description
Adds minimum span duration filtering so performance profiling can hide very short spans that add noise to trace analysis.
Users can filter spans by duration in three places:
Duration (ms)from the existing filter dialog. Numeric duration fields use numeric input and comparison operators (>=,>,<=,<) instead of the string combobox operators.minDurationMsto span and trace endpoints.--min-durationor--min-duration-mstoaspire telemetry spansandaspire telemetry traces.The Trace Detail duration filter is intentionally scoped to the trace detail page. It is applied after the context-preserving text/type/structured filters, so duration filtering removes short spans even when another filter makes related spans visible for context.
User-facing usage
Dashboard Trace Detail:
Duration (ms).>=.50.Dashboard telemetry API:
CLI:
Command help:
Validation
dotnet test --project tests/Aspire.Dashboard.Tests/Aspire.Dashboard.Tests.csproj --no-launch-profile -- --filter-class "*.TelemetryApiServiceTests" --filter-class "*.DashboardUrlsTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"dotnet test --project tests/Aspire.Cli.Tests/Aspire.Cli.Tests.csproj --no-launch-profile -- --filter-class "*.TelemetrySpansCommandTests" --filter-class "*.TelemetryTracesCommandTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"dotnet test --project tests/Aspire.Dashboard.Components.Tests/Aspire.Dashboard.Components.Tests.csproj --no-launch-profile -- --filter-class "*.FilterDialogTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"dotnet test --project tests/Aspire.Dashboard.Components.Tests/Aspire.Dashboard.Components.Tests.csproj --no-launch-profile -- --filter-class "*.TraceDetailsTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"dotnet test --project tests/Aspire.Dashboard.Tests/Aspire.Dashboard.Tests.csproj --no-launch-profile -- --filter-method "*.RoundTripDurationFilter_UsesInvariantValue" --filter-method "*.GetTraces_KnownFilters" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"otel spans --min-duration 50otel traces --trace-id <trace-id> --min-duration 50dotnet build /t:UpdateXlf src/Aspire.Dashboard/Aspire.Dashboard.csprojgit diff --checkFixes # (issue)
Checklist
<remarks />and<code />elements on your triple slash comments?