feat(aspire): resource-diagnostics helpers + retained log buffer (#6343)#6350
Merged
Conversation
Add first-class post-mortem diagnostics to AspireFixture<T> so consumers stop hand-rolling ResourceLoggerService.WatchAsync — which races to "(no logs available)" when a resource has already exited. New public API: - GetResourceLogsAsync(name, maxLines): most-recent lines from the retained buffer when enabled (reliable even after exit/dispose), else a best-effort live WatchAsync read. Both paths now return raw Content. - GetResourceSnapshot(name) -> new ResourceSnapshot record (name, state, exit code, start/stop timestamps, health). - DumpResourceDiagnosticsAsync(): one report per waited-on resource (state, decoded exit code, health, deps, last-N logs); non-throwing. New opt-in options: RetainResourceLogs + ResourceLogBufferCapacity (default 500). The bounded per-resource buffer (BoundedLogBuffer) subscribes before StartAsync via a single background pump shared with live forwarding, and is kept alive past teardown for post-mortem reads. On startup failure, when ForwardResourceLogs is on, the fixture self-documents by dumping consolidated diagnostics to the progress log (covers failure paths that don't build their own), always rethrowing the original exception. Pure (no-Docker) tests cover the buffer's rolling/cap semantics and the helpers' graceful behavior on an un-initialized fixture.
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 48 |
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
Contributor
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. |
This was referenced Jul 1, 2026
This was referenced Jul 2, 2026
Open
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #6343.
Problem
Consumers who want a resource's logs on failure hand-roll
ResourceLoggerService.WatchAsync(...). That pattern is racy: fetch logs only after a startup failure (e.g. in acatch) and a resource that has already exited returns "(no logs available)" — the backlog is gone.What this adds
New public API on
AspireFixture<T>:Retained log buffer (opt-in): new
AspireFixtureOptions.RetainResourceLogs+ResourceLogBufferCapacity(default 500 lines/resource). A bounded per-resource ring buffer (BoundedLogBuffer) subscribes beforeStartAsyncvia a single background pump shared with live forwarding, and is kept alive past teardown so post-mortem reads are reliable even for an exited/disposed resource. Scoped by the existingResourceLogNames.When retention is off, the helpers fall back to a best-effort live
WatchAsyncread (degraded — may race to empty). Both paths return raw log content.Self-documenting failed boot: when
ForwardResourceLogsis on (the "same opt-in as log forwarding" the issue calls for), a failedInitializeAsyncemits a consolidated diagnostics dump to the progress log — covering even the failure paths that don't build their own diagnostics. The dump never masks the original exception (always rethrows).Acceptance criteria
GetResourceLogsAsyncreturns buffered lines even for an exited resource (no "(no logs available)" race) when retention is enabled.DumpResourceDiagnosticsAsyncproduces a single string with per-resource state + decoded exit code + last-N logs.Design notes
#6341forwarding pump +SelectResourceLogNamesselection; reuses the#6342DiagnoseResource/DescribeState/FormatExitCode/FindAwaitersrendering.Tests
Pure (no-Docker) tests for
BoundedLogBufferrolling/cap semantics and the helpers' graceful behavior on an un-initialized fixture.TUnit.Aspire.Corebuilds net8/9/10; all pure Aspire tests green. Buffer-backed and snapshot-reading paths of a running app are exercised by the existing Docker-backed integration tests.Reviewer notes
A self-review pass caught and fixed two issues before submission: the
WatchAsyncfallback inGetResourceLogsAsyncnow guardsObjectDisposedException(keeps the helper non-throwing under a concurrent teardown), and the buffer vs. fallback paths now return identically-formatted (raw) lines.🤖 Generated with Claude Code