Skip to content

Conversation

@adamint
Copy link
Member

@adamint adamint commented Mar 19, 2025

Description

Adds a pause/resume button to those 4 pages to the left of the clear signals button.
image

For console logs, an entry appears when a pause is active noting how many logs have been filtered out for that resource.
image

If, after a pause has ended, one or more logs were filtered, text appears in the console log noting the dates of the pause and how many logs were filtered. These lines are filtered out when downloading logs. Additionally, line numbers increment by the # of filtered logs, as can be seen in the screenshot below.
image

For metrics, the X axis of a visible graph stays consistent during a pause.

Fixes #7610

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No
  • Does the change require an update in our Aspire docs?

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds a pause/resume feature across dashboard pages (console logs, structured logs, traces, and metrics) by introducing a reusable PauseResumeButton component and updating data retrieval logic to honor a paused timestamp.

  • Added a PauseResumeButton component with binding for a paused timestamp.
  • Updated LogViewer, ChartContainer, TracesViewModel, and StructuredLogsViewModel to filter data based on the paused timestamp.
  • Modified multiple page components to integrate the pause functionality with the new component and corresponding event callbacks.

Reviewed Changes

Copilot reviewed 30 out of 33 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor.cs New component to toggle pause/resume state.
src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs Updated to use a filtered data method based on PausedAt.
src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor.cs Modified to skip data refresh when paused.
src/Aspire.Dashboard/Model/Otlp/TelemetryFilter.cs Extended filtering to apply a timestamp condition on spans.
src/Aspire.Dashboard/Model/TracesViewModel.cs and StructuredLogsViewModel.cs Adjusted data retrieval methods to accept an optional paused timestamp.
Various page components (Metrics, ConsoleLogs, StructuredLogs, Traces) Integrated PauseResumeButton and updated callbacks to support pause/resume behavior.
Files not reviewed (3)
  • src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs: Language not supported
  • src/Aspire.Dashboard/Resources/ControlsStrings.resx: Language not supported
  • src/Aspire.Dashboard/Resources/xlf/ControlsStrings.cs.xlf: Language not supported
Comments suppressed due to low confidence (3)

src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs:94

  • Consider storing the result of logEntries.GetEntries() in a local variable to avoid calling it twice. This would improve clarity and guarantee consistency of the retrieved log entries before applying the filter.
return PausedAt is null ? logEntries.GetEntries() : logEntries.GetEntries().Where(logEntry => logEntry.Timestamp is { } timestamp && timestamp <= PausedAt).ToList();

src/Aspire.Dashboard/Model/Otlp/TelemetryFilter.cs:135

  • Verify that using 'OtlpLogEntry.TimeStamp' as the field for filtering spans is intentional. If spans should be filtered based on a different timestamp property (e.g. StartTime), update the field name accordingly.
nameof(OtlpLogEntry.TimeStamp) => ApplyTimeStamp(),

src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor.cs:94

  • [nitpick] Document the rationale for skipping updates when PausedAt is set. A brief comment would clarify that data refresh is intentionally paused to prevent unnecessary API calls while the view is paused.
if (_instrument == null || PausedAt is not null)

@adamint adamint self-assigned this Mar 19, 2025
@JamesNK
Copy link
Member

JamesNK commented Mar 20, 2025

There is a design decision that needs to be made here that I mentioned on the issue: whether the pause happens in the UI, or collecting telemetry. That needs to be figured out first.

@JamesNK
Copy link
Member

JamesNK commented Mar 24, 2025

There should have been some logs inbetween these pauses. But I believe there is a 10,000 log limit so they were filtered out. I think that limit is on the server and it would require extra API calls to do filtering there.

However, the row number starts at 1. It should take into account previous logs, and logs filtered out.

Sometimes the line number is updated to skip values, other times it isn't:

image

@adamint
Copy link
Member Author

adamint commented Mar 25, 2025

There should have been some logs inbetween these pauses. But I believe there is a 10,000 log limit so they were filtered out. I think that limit is on the server and it would require extra API calls to do filtering there.
However, the row number starts at 1. It should take into account previous logs, and logs filtered out.

Sometimes the line number is updated to skip values, other times it isn't:

image

Hmm, I'm not able to reproduce this?

@JamesNK
Copy link
Member

JamesNK commented Mar 26, 2025

Please try again and keep testing. There are definitely bugs here. Use the stress playground and the actions that add many logs.

Another example:
image


if (foundRange is not null && foundRange.FilteredLogsByApplication.GetValueOrDefault(application)?.Contains(entry) is not true)
{
ImmutableInterlocked.Update(
Copy link
Member

@JamesNK JamesNK Mar 26, 2025

Choose a reason for hiding this comment

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

Every filtered log is going to recreate a constantly growing immutable has set? What happens if there are thousands of log entries being filtered very quickly?

@JamesNK
Copy link
Member

JamesNK commented Mar 26, 2025

I didn't take a close look at the console pausing logic until now. I think the way counts are calculated and stored needs to be rewritten. We can't hold onto all the log entries in memory until the user unpauses. All memory could be consumed.

@JamesNK
Copy link
Member

JamesNK commented Mar 26, 2025

LogEntry.CreatePause(pauseStart)

When a pause log entry is created it have some kind of pause view model, and it's associated with the range and has a count. When something is filtered out, the count on the pause view model is incremented.

Keep the logic needed for this page (the counts) on this page. Don't put it into global state.

@JamesNK
Copy link
Member

JamesNK commented Mar 26, 2025

I think line number of pause log entries also need to be rethought.

  • I think pause log entry line number should always be zero.
  • Code that looks to get the line number should skip pause log entries.
  • A pause entry could be added first. So logic that checks whether a log entry is added first (and use the initial base number) needs to also consider whether there are earlier pause entries.


var logEntry = logParser.CreateLogEntry(content, isErrorOutput);
if (timestampFilterDate is null || logEntry.Timestamp is null || logEntry.Timestamp > timestampFilterDate)
if (logEntry.Timestamp is not null && _logEntries.GetPauseEntries().Select(e => e.Pause).Cast<LogPauseViewModel>().FirstOrDefault(pause => pause.Contains(logEntry.Timestamp.Value)) is { } pause)
Copy link
Member Author

Choose a reason for hiding this comment

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

If the user refreshes the page, may add several prior pauses to log entries. Each needs to be checked. I added a list of pause entries to LogEntries to speed up this call

@JamesNK JamesNK enabled auto-merge (squash) March 29, 2025 00:28
@JamesNK
Copy link
Member

JamesNK commented Mar 29, 2025

I think it's much better.

I fixed a bug when you remove log entries while a pause is active. I noticed a race condition bug on log entries so added locks around modifying it. Also did some minor clean up.

@JamesNK JamesNK merged commit 5109843 into dotnet:main Mar 29, 2025
172 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Apr 28, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Pause/resume button on console logs, structured logs, traces and metrics

2 participants