Skip to content

Improve PauseResumeButton_TogglePauseResume_LogsPausedAndResumed logging #9031

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 4 commits into from
May 1, 2025
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
15 changes: 1 addition & 14 deletions src/Aspire.Dashboard/Components/Controls/LogViewer.razor
Original file line number Diff line number Diff line change
@@ -22,24 +22,11 @@
return;
}

var text = pause.EndTime is null
? string.Format(
CultureInfo.CurrentCulture,
Loc[nameof(ConsoleLogs.ConsoleLogsPauseActive)],
FormatHelpers.FormatTimeWithOptionalDate(TimeProvider, pause.StartTime, MillisecondsDisplay.Truncated),
pause.FilteredCount)
: string.Format(
CultureInfo.CurrentCulture,
Loc[nameof(ConsoleLogs.ConsoleLogsPauseDetails)],
FormatHelpers.FormatTimeWithOptionalDate(TimeProvider, pause.StartTime, MillisecondsDisplay.Truncated),
FormatHelpers.FormatTimeWithOptionalDate(TimeProvider, pause.EndTime.Value, MillisecondsDisplay.Truncated),
pause.FilteredCount);

<div class="log-line-row-container">
<div class="log-line-row console-line-row">
<div class="log-line-area" role="log">
<span class="log-line-number"></span>
<span class="log-content log-pause">@text</span>
<span class="log-content log-pause">@pause.GetDisplayText(Loc, TimeProvider)</span>
</div>
</div>
</div>
27 changes: 27 additions & 0 deletions src/Shared/ConsoleLogs/LogPauseViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Globalization;
using Aspire.Dashboard.Model;
using Aspire.Dashboard.Utils;
using Microsoft.Extensions.Localization;

namespace Aspire.Hosting.ConsoleLogs;

#if ASPIRE_DASHBOARD
@@ -14,4 +19,26 @@ internal sealed class LogPauseViewModel
public int FilteredCount { get; set; }

public bool Contains(DateTime timestamp) => timestamp >= StartTime && (EndTime is null || timestamp < EndTime);

#if ASPIRE_DASHBOARD
public string GetDisplayText(IStringLocalizer<Aspire.Dashboard.Resources.ConsoleLogs> loc, BrowserTimeProvider timeProvider)
{
var pause = this;

var text = pause.EndTime is null
? string.Format(
CultureInfo.CurrentCulture,
loc[nameof(Aspire.Dashboard.Resources.ConsoleLogs.ConsoleLogsPauseActive)],
FormatHelpers.FormatTimeWithOptionalDate(timeProvider, pause.StartTime, MillisecondsDisplay.Truncated),
pause.FilteredCount)
: string.Format(
CultureInfo.CurrentCulture,
loc[nameof(Aspire.Dashboard.Resources.ConsoleLogs.ConsoleLogsPauseDetails)],
FormatHelpers.FormatTimeWithOptionalDate(timeProvider, pause.StartTime, MillisecondsDisplay.Truncated),
FormatHelpers.FormatTimeWithOptionalDate(timeProvider, pause.EndTime.Value, MillisecondsDisplay.Truncated),
pause.FilteredCount);

return text;
}
#endif
}
33 changes: 24 additions & 9 deletions tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs
Original file line number Diff line number Diff line change
@@ -15,7 +15,6 @@
using Aspire.Dashboard.Utils;
using Aspire.Hosting.ConsoleLogs;
using Aspire.Tests.Shared.DashboardModel;
using Aspire.TestUtilities;
using Bunit;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.InternalTesting;
@@ -413,7 +412,6 @@ public async Task ExecuteCommand_DelayExecuting_IsExecutingReturnsTrueWhileRunni
}

[Fact]
[QuarantinedTest("https://github.com/dotnet/aspire/issues/8931")]
public void PauseResumeButton_TogglePauseResume_LogsPausedAndResumed()
{
// Arrange
@@ -432,6 +430,8 @@ public void PauseResumeButton_TogglePauseResume_LogsPausedAndResumed()
var timeProvider = Services.GetRequiredService<BrowserTimeProvider>();
var loc = Services.GetRequiredService<IStringLocalizer<Resources.ConsoleLogs>>();
var dimensionManager = Services.GetRequiredService<DimensionManager>();
var logger = Services.GetRequiredService<ILogger<ConsoleLogsTests>>();
var browserTimeProvider = Services.GetRequiredService<BrowserTimeProvider>();
var viewport = new ViewportInformation(IsDesktop: true, IsUltraLowHeight: false, IsUltraLowWidth: false);
dimensionManager.InvokeOnViewportInformationChanged(viewport);

@@ -447,11 +447,11 @@ public void PauseResumeButton_TogglePauseResume_LogsPausedAndResumed()
// Assert initial state
cut.WaitForState(() => instance.PageViewModel.SelectedResource == testResource);

// Pause logs
logger.LogInformation("Pause logs.");
var pauseResumeButton = cut.FindComponent<PauseIncomingDataSwitch>();
pauseResumeButton.Find("fluent-button").Click();

// A pause line should be visible
logger.LogInformation("Wait for pause log.");
var pauseConsoleLogLine = cut.WaitForElement(".log-pause");

// Add a new log while paused and assert that the log viewer shows that 1 log was filtered
@@ -461,6 +461,7 @@ public void PauseResumeButton_TogglePauseResume_LogsPausedAndResumed()
consoleLogsChannel.Writer.TryWrite([new ResourceLogLine(2, pauseContent, IsErrorMessage: false)]);
consoleLogsChannel.Writer.TryWrite([new ResourceLogLine(3, pauseContent, IsErrorMessage: false)]);

logger.LogInformation("Assert that the last log is the pause log.");
cut.WaitForAssertion(() => Assert.Equal(
string.Format(
loc[Resources.ConsoleLogs.ConsoleLogsPauseActive],
@@ -469,18 +470,23 @@ public void PauseResumeButton_TogglePauseResume_LogsPausedAndResumed()
3),
pauseConsoleLogLine.TextContent));

// Resume and write a new log, check that
logger.LogInformation("Resume logs.");
// Check that
// - the pause line has been replaced with pause details
// - the log viewer shows the new log
// - the log viewer does not show the discarded log
pauseResumeButton.Find("fluent-button").Click();
cut.WaitForAssertion(() => Assert.False(Services.GetRequiredService<PauseManager>().ConsoleLogsPaused));

logger.LogInformation("Write a new log.");
var resumeContent = $"{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ss.fffK} Log after resume";
consoleLogsChannel.Writer.TryWrite([new ResourceLogLine(4, resumeContent, IsErrorMessage: false)]);

logger.LogInformation("Assert that pause log has expected content.");
cut.WaitForAssertion(() =>
{
PrintCurrentLogEntries(cut.Instance._logEntries);

var pauseEntry = Assert.Single(cut.Instance._logEntries.GetEntries(), e => e.Type == LogEntryType.Pause);
var pause = pauseEntry.Pause;
Assert.NotNull(pause);
@@ -494,18 +500,27 @@ public void PauseResumeButton_TogglePauseResume_LogsPausedAndResumed()
pauseConsoleLogLine.TextContent);
});

logger.LogInformation("Assert that log entries discarded aren't in log viewer and log entries that should be logged are in log viewer.");
cut.WaitForAssertion(() =>
{
var logViewer = cut.FindComponent<LogViewer>();
foreach (var logEntry in logViewer.Instance.LogEntries!.GetEntries())
{
_testOutputHelper.WriteLine(logEntry.RawContent ?? "no content");
}
PrintCurrentLogEntries(logViewer.Instance.LogEntries!);

var newLog = Assert.Single(logViewer.Instance.LogEntries!.GetEntries(), e => e.RawContent == resumeContent);
// We discarded one log while paused, so the new log should be line 3, skipping one
Assert.Equal(4, newLog.LineNumber);
Assert.DoesNotContain(pauseContent, logViewer.Instance.LogEntries!.GetEntries().Select(e => e.RawContent));
});

void PrintCurrentLogEntries(LogEntries logEntries)
{
logger.LogInformation($"Log entries count: {logEntries.EntriesCount}");

foreach (var logEntry in logEntries.GetEntries())
{
logger.LogInformation($"Log line. Type = {logEntry.Type}, Raw content = {logEntry.RawContent ?? "no content"}, Pause content: {logEntry.Pause?.GetDisplayText(loc, browserTimeProvider) ?? "n/a"}");
}
}
}

private void SetupConsoleLogsServices(TestDashboardClient? dashboardClient = null, TestTimeProvider? timeProvider = null)