Add TelemetryRepository.GetSpans, move text search into repository, and add SearchTextParser#17482
Add TelemetryRepository.GetSpans, move text search into repository, and add SearchTextParser#17482JamesNK wants to merge 7 commits into
Conversation
- Remove minDuration option from CLI spans/traces commands and dashboard API - Add GetSpansRequest/GetSpansResponse types for repository-level span querying - Add TelemetryRepository.GetSpans with filtering by resource, traceId, hasError, duration, text fragments, and telemetry filters - Refactor TelemetryApiService.GetSpans to delegate filtering to the repository - Move GetSpans tests from TelemetryApiServiceTests to TraceTests - Add comprehensive GetSpans repository tests including pagination and shortened trace ID matching
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 17482Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 17482" |
There was a problem hiding this comment.
Pull request overview
This PR refactors telemetry span querying to support span-level filtering at the repository layer (TelemetryRepository.GetSpans), removes the unused minDuration parameter/option across CLI + dashboard endpoints, and introduces a shared SearchTextParser to support structured key:value-style search qualifiers.
Changes:
- Removed
minDuration/minDurationMsfrom CLI commands, dashboard API endpoints, and shared URL builders. - Added
TelemetryRepository.GetSpans(+ request/response types) and updatedTelemetryApiService.GetSpansto delegate filtering to the repository. - Added shared
SearchTextParserand expanded test coverage for span querying + search parsing.
Reviewed changes
Copilot reviewed 34 out of 35 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Aspire.Dashboard.Tests/TelemetryRepositoryTests/TraceTests.cs | Adds repository-level GetSpans tests (resource/traceId/hasError/duration/text/pagination). |
| tests/Aspire.Dashboard.Tests/TelemetryApiServiceTests.cs | Removes/moves span-specific tests; updates trace tests to reflect minDuration removal and duration filtering via search. |
| tests/Aspire.Dashboard.Tests/DashboardUrlsTests.cs | Updates URL tests to remove minDurationMs expectations. |
| tests/Aspire.Cli.Tests/Utils/SearchTextParserTests.cs | Adds comprehensive unit tests for structured search parsing + matching. |
| tests/Aspire.Cli.Tests/Commands/TelemetryTracesCommandTests.cs | Updates CLI tests to use --search "duration:>=..." instead of --min-duration and asserts exact URLs. |
| tests/Aspire.Cli.Tests/Commands/TelemetrySpansCommandTests.cs | Updates CLI tests to assert exact URLs and use duration filtering via --search. |
| src/Shared/SearchTextParser.cs | Introduces shared parser/matcher for text fragments + qualifiers (incl. negation and comparisons). |
| src/Shared/DashboardUrls.cs | Removes minDurationMs from telemetry URL builders. |
| src/Aspire.Dashboard/Otlp/Storage/TelemetryRepository.cs | Adds repository GetSpans implementation and span text-fragment matching. |
| src/Aspire.Dashboard/Otlp/Storage/GetSpansResponse.cs | Adds response type for repository GetSpans. |
| src/Aspire.Dashboard/Otlp/Storage/GetSpansRequest.cs | Adds request type for repository GetSpans. |
| src/Aspire.Dashboard/DashboardEndpointsBuilder.cs | Removes minDurationMs query param from telemetry endpoints and updates service calls. |
| src/Aspire.Dashboard/Aspire.Dashboard.csproj | Links shared SearchTextParser.cs into the dashboard project. |
| src/Aspire.Dashboard/Api/TelemetryApiService.cs | Refactors spans/traces/logs search handling: parses qualifiers into TelemetryFilters and applies text fragments separately. |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.zh-Hant.xlf | Removes min-duration option string. |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.zh-Hans.xlf | Removes min-duration option string. |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.tr.xlf | Removes min-duration option string. |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.ru.xlf | Removes min-duration option string. |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.pt-BR.xlf | Removes min-duration option string. |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.pl.xlf | Removes min-duration option string. |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.ko.xlf | Removes min-duration option string. |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.ja.xlf | Removes min-duration option string. |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.it.xlf | Removes min-duration option string. |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.fr.xlf | Removes min-duration option string. |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.es.xlf | Removes min-duration option string. |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.de.xlf | Removes min-duration option string. |
| src/Aspire.Cli/Resources/xlf/TelemetryCommandStrings.cs.xlf | Removes min-duration option string. |
| src/Aspire.Cli/Resources/TelemetryCommandStrings.resx | Removes min-duration option description. |
| src/Aspire.Cli/Resources/TelemetryCommandStrings.Designer.cs | Removes generated accessor for min-duration option description. |
| src/Aspire.Cli/Mcp/Tools/ListConsoleLogsTool.cs | Switches MCP console log search to structured qualifier parsing/matching. |
| src/Aspire.Cli/Commands/TelemetryTracesCommand.cs | Removes --min-duration option and stops appending minDurationMs to URLs. |
| src/Aspire.Cli/Commands/TelemetrySpansCommand.cs | Removes --min-duration option and stops appending minDurationMs to URLs. |
| src/Aspire.Cli/Commands/TelemetryCommandHelpers.cs | Removes creation of --min-duration option. |
| src/Aspire.Cli/Commands/LogsCommand.cs | Switches CLI log search to structured qualifier parsing/matching. |
| src/Aspire.Cli/Aspire.Cli.csproj | Links shared SearchTextParser.cs into the CLI project. |
Files not reviewed (1)
- src/Aspire.Cli/Resources/TelemetryCommandStrings.Designer.cs: Language not supported
…earch - Add TextFragments to GetTracesRequest and GetLogsContext so text matching is performed inside TelemetryRepository instead of post-query in TelemetryApiService. - Rename FilterText to TraceNameFilterText to clarify it only matches trace.FullName (used by dashboard UI). - Simplify LogsCommand and ListConsoleLogsTool search to treat all input as free-text fragments (no qualifier parsing) since console logs have no structured attributes. - Add tests for multi-word search and qualifier-as-freetext behavior.
The MatchesFilter overloads and their private helpers (QualifierMatches, AttributeMatches, CompareNumeric, StringMatchesQualifier) had no product callers — only test references. Remove them and their tests. Add test for quoted qualifier syntax treated as text fragment.
- Add WatchSpansRequest and WatchLogsRequest to encapsulate watcher filters - WatchSpansAsync/WatchLogsAsync now accept request objects with ResourceKey, Filters, TextFragments (and TraceId/HasError for spans) - WatchSpansAsync uses GetSpans for initial snapshot instead of GetTraces - Extract shared MatchesSpanCriteria for both GetSpans and PushSpansToWatchers - Remove dead MatchesLogTextFragments/MatchesSpanTextFragments from TelemetryApiService - TelemetryApiService constructs request objects and delegates filtering to repository
Replace the ReadOnlySpan<string> overload that allocated a List<string> per call with a generic delegate version that passes state directly, eliminating per-call allocations in hot paths like span/log filtering. All callers updated to use the new API: - TelemetryRepository: passes span/log/trace state directly - LogsCommand: passes tuple of (content, prefix, stripped) - ListConsoleLogsTool: passes tuple of (content, prefix, stripped) - Tests: updated to exercise the delegate API
|
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.
|
|
Do we need to update the skill and help text so agents can effectively use these filters? |
- Refactor TelemetryRepository to support filtered GetSpans/GetLogs queries - Remove watcher-based filtering in favor of direct repository filtering - Fix SearchTextParser to handle empty input without throwing - Add LogsCommand_FollowWithSearch_FiltersExistingAndStreamedLogs test - Add TelemetryRepository filtering tests for logs, traces, and spans - Update monitoring.md with --search filtering documentation
|
How do you combine free text with filters? |
GetSpans returns spans grouped by trace, not globally sorted by time. When traces have overlapping time ranges, the initial snapshot was yielded out of chronological order. Add .OrderBy(s => s.StartTime) to restore the global sort guarantee for streaming clients. Add test covering multi-span traces with interleaved timestamps.
Check out monitoring.md. If you can understand it, then hopefully so will agents 😄 |
|
Well I did and I just had more questions so I asked my agent: Main ambiguities
--search "severity:error \"connection failed\""The outer shell quotes are not part of the query; the parser receives: That is fine, but the docs could confuse users into thinking quotes are part of the search language. More importantly, this example implies quoted phrases are free-text fragments, but it does not say whether this is valid: If structured qualifiers can take quoted values, that should be explicit.
Any token with Questions to resolve:
Recommendation: only known keys and
This is clear if Can negation apply to free-text fragments, quoted phrases, and quoted qualifier values, or only structured qualifiers?
Ambiguities:
Recommendation: explicitly define duration comparison grammar and units.
“Multiple words are AND’d” is clear for positives, but mixed queries need formal semantics: Likely intended meaning: Say that explicitly.
For structured qualifiers, does
Same for: This matters a lot. Severity and kind probably want exact enum matching; message/resource may want substring matching.
For logs: Does this match event name, event body, event ID, structured log event attributes, or OpenTelemetry log event fields? “event” needs a definition.
The heading says: But examples use
If quoted phrases exist, define escaping: On Windows especially, backslashes and quotes can become confusing across shell parsing and search-language parsing.
For console logs: The text says only free-text is supported, so this would search literally for Recommendation: call this out directly, or consider rejecting qualifier-looking syntax in console logs with “structured filters are only supported for Suggested clarificationsA compact grammar would remove most ambiguity: Then define:
Biggest decision to make: should unknown |
|
Good questions from the agent. Here are answers to each: 1. Quoted qualifier values — Yes, 2. Unknown 3. Negation scope — Negation ( 4. Comparison syntax — No whitespace allowed between key, colon, and operator ( 5. AND semantics with negation — Correct: 6. Field matching semantics — All qualifier matching uses case-insensitive substring ( 7. 8. Trace/span commands — 9. Escaping — No escape sequences inside quoted phrases. A backslash is literal. You cannot embed a literal double-quote inside a quoted phrase currently. This is a known limitation — for the use cases we have, attribute values rarely contain quotes. 10. Console vs structured search — This is intentional and called out in monitoring.md: "Only free-text is supported (no structured qualifiers)" for Re: the first question about updating the skill — yes, I already updated |
|
❓ CLI E2E Tests unknown — 107 passed, 0 failed, 2 unknown (commit View all recordings
📹 Recordings uploaded automatically from CI run #26435048028 |
Summary
Adds a
GetSpansmethod toTelemetryRepository, moves text-fragment matching from the API service layer into the repository, introduces a sharedSearchTextParserfor structured search queries, and simplifies CLI log search to treat all input as free-text.Changes
New:
TelemetryRepository.GetSpansGetSpansRequest/GetSpansResponsemodels and aGetSpansmethod onTelemetryRepositorythat supports filtering by resource, trace ID, error status, attribute filters, and text fragments.minDurationoption (was unused).Move text-fragment search into
TelemetryRepositoryGetTracesRequestandGetLogsContextnow accept optionalTextFragmentsarrays.TelemetryApiService, improving consistency and enabling the repository to skip non-matching items earlier.GetTracesRequest.TraceNameFilterText(renamed fromFilterText) remains for the dashboard UI's trace-name-only filter (matchestrace.FullName).New:
SearchTextParser(shared)A shared parser for search queries supporting free-text fragments, field qualifiers, attribute qualifiers, negation, and comparison operators.
Search syntax
word"quoted phrase"field:valuefield:"value with spaces"@attr:value-field:value/-@attr:valuefield:>N/field:>=N/field:<N/field:<=NAll terms are AND'd: every fragment and qualifier must independently match.
Available field qualifiers
Spans / Traces:
nameresourcescopesourcestatuskindtrace-idtraceidspan-idspanidduration>,>=,<,<=)Structured Logs:
severitylevelresourcescopecategorymessagemsgtrace-idtraceidspan-idspanideventConsole Logs (CLI):
All search text is treated as free-text fragments (no field qualifiers). Console logs have no structured attributes — search matches against log content and resource name.
Text fragment matching candidates
When text fragments are used (plain words without qualifiers), they match against:
Simplify CLI log search
LogsCommand.MatchesSearchandListConsoleLogsToolnow useSearchTextParser.ParseFragments+MatchesAllFragmentsinstead of the full qualifier-awareMatchesFilter. Since console logs have no structured attributes, all search input (includingkey:value-like text) is treated as plain free-text fragments.Tests
SearchTextParserTests— comprehensive tests for parsing and matchingTelemetryApiServiceTests— attribute filter tests for spans, traces, and logsTraceTests—TextFragmentsmatching in repository for tracesLogsCommandTests— multi-word search, qualifier-as-freetext behaviorListConsoleLogsToolTests— multi-word search, qualifier-as-freetext behavior