From 13fc5e737f74f5a248af9ca16511bea3bc4bafab Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Wed, 19 Mar 2025 13:19:11 -0400 Subject: [PATCH 01/35] Add pause/resume button --- .../Controls/PauseResumeButton.razor | 16 +++++++++++++ .../Controls/PauseResumeButton.razor.cs | 24 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor create mode 100644 src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor.cs diff --git a/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor b/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor new file mode 100644 index 00000000000..1a3fee88c9e --- /dev/null +++ b/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor @@ -0,0 +1,16 @@ +@using Aspire.Dashboard.Resources +@inject IStringLocalizer Loc + + + @if (IsPaused) + { + + } + else + { + + } + diff --git a/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor.cs b/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor.cs new file mode 100644 index 00000000000..1db6c71726a --- /dev/null +++ b/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.AspNetCore.Components; + +namespace Aspire.Dashboard.Components.Controls; + +public partial class PauseResumeButton : ComponentBase +{ + [Parameter] + public bool IsPaused { get; set; } + + [Parameter] + public bool Disabled { get; set; } + + [Parameter, EditorRequired] + public required Func OnTogglePauseAsync { get; set; } + + private async Task OnTogglePauseCoreAsync() + { + IsPaused = !IsPaused; + await OnTogglePauseAsync(IsPaused); + } +} + From 78b42e86e19381f687a262c47675edcce9190f80 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Wed, 19 Mar 2025 13:28:31 -0400 Subject: [PATCH 02/35] Allow pause/resume inside console logs --- .../Components/Controls/LogViewer.razor | 4 ++-- .../Components/Controls/LogViewer.razor.cs | 17 +++++++++++++++++ .../Components/Controls/PauseResumeButton.razor | 8 ++++++-- .../Controls/PauseResumeButton.razor.cs | 12 ++++++------ .../Components/Pages/ConsoleLogs.razor | 8 +++++++- .../Components/Pages/ConsoleLogs.razor.cs | 2 ++ .../Resources/ControlsStrings.Designer.cs | 12 ++++++++++++ .../Resources/ControlsStrings.resx | 6 ++++++ .../Resources/xlf/ControlsStrings.cs.xlf | 10 ++++++++++ .../Resources/xlf/ControlsStrings.de.xlf | 10 ++++++++++ .../Resources/xlf/ControlsStrings.es.xlf | 10 ++++++++++ .../Resources/xlf/ControlsStrings.fr.xlf | 10 ++++++++++ .../Resources/xlf/ControlsStrings.it.xlf | 10 ++++++++++ .../Resources/xlf/ControlsStrings.ja.xlf | 10 ++++++++++ .../Resources/xlf/ControlsStrings.ko.xlf | 10 ++++++++++ .../Resources/xlf/ControlsStrings.pl.xlf | 10 ++++++++++ .../Resources/xlf/ControlsStrings.pt-BR.xlf | 10 ++++++++++ .../Resources/xlf/ControlsStrings.ru.xlf | 10 ++++++++++ .../Resources/xlf/ControlsStrings.tr.xlf | 10 ++++++++++ .../Resources/xlf/ControlsStrings.zh-Hans.xlf | 10 ++++++++++ .../Resources/xlf/ControlsStrings.zh-Hant.xlf | 10 ++++++++++ 21 files changed, 188 insertions(+), 11 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor index 0680366ef51..e5bc657f776 100644 --- a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor +++ b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor @@ -8,9 +8,9 @@
- @if (LogEntries is {} logEntries) + @if (GetEntries() is { } entries) { - +
diff --git a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs index fcc9a94167c..1c8b1acce57 100644 --- a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs +++ b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs @@ -36,6 +36,9 @@ public sealed partial class LogViewer [Parameter] public bool IsTimestampUtc { get; set; } + [Parameter] + public DateTime? FilterTimestamp { get; set; } + protected override void OnParametersSet() { if (_logEntries != LogEntries) @@ -81,6 +84,20 @@ private string GetDisplayTimestamp(DateTimeOffset timestamp) : TimeProvider.ToLocal(timestamp).ToString(KnownFormats.ConsoleLogsUITimestampLocalFormat, CultureInfo.InvariantCulture); } + private ICollection? GetEntries() + { + if (LogEntries is not { } logEntries) + { + return null; + } + + return FilterTimestamp is null + ? logEntries.GetEntries() + : logEntries.GetEntries() + .Where(logEntry => logEntry.Timestamp is { } timestamp && timestamp <= FilterTimestamp) + .ToList(); + } + public ValueTask DisposeAsync() { Logger.LogDebug("Disposing log viewer."); diff --git a/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor b/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor index 1a3fee88c9e..523a2ec858f 100644 --- a/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor +++ b/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor @@ -1,11 +1,15 @@ @using Aspire.Dashboard.Resources @inject IStringLocalizer Loc +@{ + var isPaused = PausedAt is not null; +} + - @if (IsPaused) + @if (isPaused) { } diff --git a/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor.cs b/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor.cs index 1db6c71726a..be21d5e60b5 100644 --- a/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor.cs +++ b/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor.cs @@ -7,18 +7,18 @@ namespace Aspire.Dashboard.Components.Controls; public partial class PauseResumeButton : ComponentBase { [Parameter] - public bool IsPaused { get; set; } + public DateTime? PausedAt { get; set; } [Parameter] - public bool Disabled { get; set; } + public EventCallback PausedAtChanged { get; set; } - [Parameter, EditorRequired] - public required Func OnTogglePauseAsync { get; set; } + [Parameter] + public bool Disabled { get; set; } private async Task OnTogglePauseCoreAsync() { - IsPaused = !IsPaused; - await OnTogglePauseAsync(IsPaused); + PausedAt = PausedAt == null ? DateTime.UtcNow : null; + await PausedAtChanged.InvokeAsync(PausedAt); } } diff --git a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor index e0ca2f3f807..3e1a55c09b9 100644 --- a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor +++ b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor @@ -29,6 +29,8 @@ + + @foreach (var command in _highlightedCommands) { - +
diff --git a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs index 45070adc293..7031812ac5d 100644 --- a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs @@ -104,6 +104,7 @@ private sealed class ConsoleLogsSubscription public ConsoleLogsViewModel PageViewModel { get; set; } = null!; private IDisposable? _consoleLogsFiltersChangedSubscription; private ConsoleLogsFilters _consoleLogFilters = new(); + private DateTime? _pausedAt; public string BasePath => DashboardUrls.ConsoleLogBasePath; public string SessionStorageKey => BrowserStorageKeys.ConsoleLogsPageState; @@ -510,6 +511,7 @@ private void LoadLogs(ConsoleLogsSubscription newConsoleLogsSubscription) private async Task HandleSelectedOptionChangedAsync() { PageViewModel.SelectedResource = PageViewModel.SelectedOption?.Id?.InstanceId is null ? null : _resourceByName[PageViewModel.SelectedOption.Id.InstanceId]; + _pausedAt = null; await this.AfterViewModelChangedAsync(_contentLayout, waitToApplyMobileChange: false); } diff --git a/src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs b/src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs index 3daa4c873ed..23dc25347c8 100644 --- a/src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs +++ b/src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs @@ -710,5 +710,17 @@ public static string ChartContainerOverflowLink { return ResourceManager.GetString("ChartContainerOverflowLink", resourceCulture); } } + + public static string PauseButtonTitle { + get { + return ResourceManager.GetString("PauseButtonTitle", resourceCulture); + } + } + + public static string ResumeButtonTitle { + get { + return ResourceManager.GetString("ResumeButtonTitle", resourceCulture); + } + } } } diff --git a/src/Aspire.Dashboard/Resources/ControlsStrings.resx b/src/Aspire.Dashboard/Resources/ControlsStrings.resx index f238c878ec8..9a8898d03cd 100644 --- a/src/Aspire.Dashboard/Resources/ControlsStrings.resx +++ b/src/Aspire.Dashboard/Resources/ControlsStrings.resx @@ -463,4 +463,10 @@ For more information, see <a href="{0}" target="_blank">OpenTelemetry specification cardinality limits</a>. OpenTelemetry is the name of the standard. + + Pause incoming data + + + Resume incoming data + diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.cs.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.cs.xlf index af35103e922..ebd7f7a7697 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.cs.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.cs.xlf @@ -302,6 +302,11 @@ Panel nástrojů stránky + + Pause incoming data + Pause incoming data + + Count Počet @@ -387,6 +392,11 @@ Prostředek + + Resume incoming data + Resume incoming data + + Select an application Vybrat aplikaci diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.de.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.de.xlf index 6622875982a..7cd7b0a881b 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.de.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.de.xlf @@ -302,6 +302,11 @@ Seitensymbolleiste + + Pause incoming data + Pause incoming data + + Count Anzahl @@ -387,6 +392,11 @@ Ressource + + Resume incoming data + Resume incoming data + + Select an application Anwendung auswählen diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.es.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.es.xlf index ce93d6f52e5..fd59c84aa25 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.es.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.es.xlf @@ -302,6 +302,11 @@ Barra de herramientas de página + + Pause incoming data + Pause incoming data + + Count Recuento @@ -387,6 +392,11 @@ Recurso + + Resume incoming data + Resume incoming data + + Select an application Seleccionar una aplicación diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.fr.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.fr.xlf index aecc8ef66d4..794327dbb20 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.fr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.fr.xlf @@ -302,6 +302,11 @@ Barre d’outils de la page + + Pause incoming data + Pause incoming data + + Count Nombre @@ -387,6 +392,11 @@ Ressource + + Resume incoming data + Resume incoming data + + Select an application Sélectionner une application diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.it.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.it.xlf index c7894a9c8e7..3145362b13f 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.it.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.it.xlf @@ -302,6 +302,11 @@ Barra degli strumenti della pagina + + Pause incoming data + Pause incoming data + + Count Numero @@ -387,6 +392,11 @@ Risorsa + + Resume incoming data + Resume incoming data + + Select an application Seleziona un'applicazione diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ja.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ja.xlf index 463893297c3..06e45ae9c47 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ja.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ja.xlf @@ -302,6 +302,11 @@ ページ ツール バー + + Pause incoming data + Pause incoming data + + Count カウント @@ -387,6 +392,11 @@ リソース + + Resume incoming data + Resume incoming data + + Select an application アプリケーションを選択する diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ko.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ko.xlf index 3262d4962ec..ea9af5882bd 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ko.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ko.xlf @@ -302,6 +302,11 @@ 페이지 도구 모음 + + Pause incoming data + Pause incoming data + + Count 개수 @@ -387,6 +392,11 @@ 리소스 + + Resume incoming data + Resume incoming data + + Select an application 애플리케이션 선택 diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pl.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pl.xlf index 45016077ce9..5797cd87eb0 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pl.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pl.xlf @@ -302,6 +302,11 @@ Pasek narzędzi strony + + Pause incoming data + Pause incoming data + + Count Liczba @@ -387,6 +392,11 @@ Zasób + + Resume incoming data + Resume incoming data + + Select an application Wybierz aplikację diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pt-BR.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pt-BR.xlf index f1535d54726..d386b8de82f 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pt-BR.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pt-BR.xlf @@ -302,6 +302,11 @@ Barra de ferramentas de página + + Pause incoming data + Pause incoming data + + Count Número @@ -387,6 +392,11 @@ Recurso + + Resume incoming data + Resume incoming data + + Select an application Selecionar um aplicativo diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ru.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ru.xlf index dd857a7ac5d..ec1cf6cb21d 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ru.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ru.xlf @@ -302,6 +302,11 @@ Панель инструментов страницы + + Pause incoming data + Pause incoming data + + Count Количество @@ -387,6 +392,11 @@ Ресурс + + Resume incoming data + Resume incoming data + + Select an application Выберите приложение diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.tr.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.tr.xlf index f211305f45d..8b458cce4b2 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.tr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.tr.xlf @@ -302,6 +302,11 @@ Sayfa araç çubuğu + + Pause incoming data + Pause incoming data + + Count Sayı @@ -387,6 +392,11 @@ Kaynak + + Resume incoming data + Resume incoming data + + Select an application Uygulama seçin diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hans.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hans.xlf index ae73903cecf..67ba0d68bda 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hans.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hans.xlf @@ -302,6 +302,11 @@ 页面工具栏 + + Pause incoming data + Pause incoming data + + Count 计数 @@ -387,6 +392,11 @@ 资源 + + Resume incoming data + Resume incoming data + + Select an application 选择应用程序 diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hant.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hant.xlf index 52a67a6834f..7b86333cf5f 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hant.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hant.xlf @@ -302,6 +302,11 @@ 頁面工具列 + + Pause incoming data + Pause incoming data + + Count 計數 @@ -387,6 +392,11 @@ 資源 + + Resume incoming data + Resume incoming data + + Select an application 選取應用程式 From d1bb54886372925d829c902c92c894d542742074 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Wed, 19 Mar 2025 13:54:32 -0400 Subject: [PATCH 03/35] Add pause/resume button to structured logs --- .../Components/Pages/StructuredLogs.razor | 2 ++ .../Components/Pages/StructuredLogs.razor.cs | 9 ++++++++- src/Aspire.Dashboard/Model/StructuredLogsViewModel.cs | 8 +++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor index 2c129c76319..908747a5e7a 100644 --- a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor +++ b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor @@ -40,6 +40,8 @@ + + _dataGrid = null!; private GridColumnManager _manager = null!; private IList _gridColumns = null!; + private DateTime? _pausedAt; private ColumnResizeLabels _resizeLabels = ColumnResizeLabels.Default; private ColumnSortLabels _sortLabels = ColumnSortLabels.Default; @@ -111,7 +112,7 @@ private async ValueTask> GetData(GridItems ViewModel.StartIndex = request.StartIndex; ViewModel.Count = request.Count ?? DashboardUIHelpers.DefaultDataGridResultCount; - var logs = ViewModel.GetLogs(); + var logs = ViewModel.GetLogs(_pausedAt); if (logs.IsFull && !TelemetryRepository.HasDisplayedMaxLogLimitMessage) { @@ -349,6 +350,12 @@ private string GetRowClass(OtlpLogEntry entry) } } + private Task OnPausedAtChangedAsync(DateTime? newPausedAt) + { + _pausedAt = newPausedAt; + return InvokeAsync(_dataGrid.SafeRefreshDataAsync); + } + protected override async Task OnAfterRenderAsync(bool firstRender) { if (_applicationChanged) diff --git a/src/Aspire.Dashboard/Model/StructuredLogsViewModel.cs b/src/Aspire.Dashboard/Model/StructuredLogsViewModel.cs index 7eaf5c8a784..ad352d9e9f7 100644 --- a/src/Aspire.Dashboard/Model/StructuredLogsViewModel.cs +++ b/src/Aspire.Dashboard/Model/StructuredLogsViewModel.cs @@ -1,6 +1,7 @@ // 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.Otlp; using Aspire.Dashboard.Otlp.Model; using Aspire.Dashboard.Otlp.Storage; @@ -74,7 +75,7 @@ private void SetValue(ref T field, T value) _logs = null; } - public PagedResult GetLogs() + public PagedResult GetLogs(DateTime? _pausedAt) { var logs = _logs; if (logs == null) @@ -90,6 +91,11 @@ public PagedResult GetLogs() filters.Add(new TelemetryFilter { Field = nameof(OtlpLogEntry.Severity), Condition = FilterCondition.GreaterThanOrEqual, Value = _logLevel.Value.ToString() }); } + if (_pausedAt is not null) + { + filters.Add(new TelemetryFilter { Field = nameof(OtlpLogEntry.TimeStamp), Condition = FilterCondition.LessThanOrEqual, Value = _pausedAt.Value.ToString(CultureInfo.InvariantCulture) }); + } + logs = _telemetryRepository.GetLogs(new GetLogsContext { ApplicationKey = ApplicationKey, From 290d1294963ba8f55ef43e04807c720b45d4ce90 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Wed, 19 Mar 2025 14:11:49 -0400 Subject: [PATCH 04/35] Add pause/resume button to traces, allow applying timestamp filter to traces (start time) --- .../Components/Pages/Traces.razor | 2 ++ .../Components/Pages/Traces.razor.cs | 9 +++++++- .../Model/Otlp/TelemetryFilter.cs | 22 ++++++++++++++++--- .../Model/StructuredLogsViewModel.cs | 6 ++--- src/Aspire.Dashboard/Model/TracesViewModel.cs | 8 ++++++- 5 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Pages/Traces.razor b/src/Aspire.Dashboard/Components/Pages/Traces.razor index 2c76c270189..0dcc40e5ad5 100644 --- a/src/Aspire.Dashboard/Components/Pages/Traces.razor +++ b/src/Aspire.Dashboard/Components/Pages/Traces.razor @@ -39,6 +39,8 @@ + + _dataGrid = null!; private GridColumnManager _manager = null!; + private DateTime? _pausedAt; private ColumnResizeLabels _resizeLabels = ColumnResizeLabels.Default; private ColumnSortLabels _sortLabels = ColumnSortLabels.Default; @@ -115,7 +116,7 @@ private async ValueTask> GetData(GridItemsPro { TracesViewModel.StartIndex = request.StartIndex; TracesViewModel.Count = request.Count ?? DashboardUIHelpers.DefaultDataGridResultCount; - var traces = TracesViewModel.GetTraces(); + var traces = TracesViewModel.GetTraces(_pausedAt); if (traces.IsFull && !TelemetryRepository.HasDisplayedMaxTraceLimitMessage) { @@ -343,6 +344,12 @@ private Task ClearTraces(ApplicationKey? key) return Task.CompletedTask; } + private Task OnPausedAtChangedAsync(DateTime? newPausedAt) + { + _pausedAt = newPausedAt; + return InvokeAsync(_dataGrid.SafeRefreshDataAsync); + } + public class TracesPageViewModel { public required SelectViewModel SelectedApplication { get; set; } diff --git a/src/Aspire.Dashboard/Model/Otlp/TelemetryFilter.cs b/src/Aspire.Dashboard/Model/Otlp/TelemetryFilter.cs index 326f033aa1b..597492d2e85 100644 --- a/src/Aspire.Dashboard/Model/Otlp/TelemetryFilter.cs +++ b/src/Aspire.Dashboard/Model/Otlp/TelemetryFilter.cs @@ -130,9 +130,25 @@ public IEnumerable Apply(IEnumerable input) public bool Apply(OtlpSpan span) { - var fieldValue = OtlpSpan.GetFieldValue(span, Field); - var func = ConditionToFuncString(Condition); - return func(fieldValue, Value); + return Field switch + { + nameof(OtlpLogEntry.TimeStamp) => ApplyTimeStamp(), + _ => ApplyField() + }; + + bool ApplyTimeStamp() + { + var date = DateTime.Parse(Value, CultureInfo.InvariantCulture); + var func = ConditionToFuncDate(Condition); + return func(span.StartTime, date); + } + + bool ApplyField() + { + var fieldValue = OtlpSpan.GetFieldValue(span, Field); + var func = ConditionToFuncString(Condition); + return func(fieldValue, Value); + } } public bool Equals(TelemetryFilter? other) diff --git a/src/Aspire.Dashboard/Model/StructuredLogsViewModel.cs b/src/Aspire.Dashboard/Model/StructuredLogsViewModel.cs index ad352d9e9f7..e29e21fb5a6 100644 --- a/src/Aspire.Dashboard/Model/StructuredLogsViewModel.cs +++ b/src/Aspire.Dashboard/Model/StructuredLogsViewModel.cs @@ -75,7 +75,7 @@ private void SetValue(ref T field, T value) _logs = null; } - public PagedResult GetLogs(DateTime? _pausedAt) + public PagedResult GetLogs(DateTime? pausedAt) { var logs = _logs; if (logs == null) @@ -91,9 +91,9 @@ public PagedResult GetLogs(DateTime? _pausedAt) filters.Add(new TelemetryFilter { Field = nameof(OtlpLogEntry.Severity), Condition = FilterCondition.GreaterThanOrEqual, Value = _logLevel.Value.ToString() }); } - if (_pausedAt is not null) + if (pausedAt is not null) { - filters.Add(new TelemetryFilter { Field = nameof(OtlpLogEntry.TimeStamp), Condition = FilterCondition.LessThanOrEqual, Value = _pausedAt.Value.ToString(CultureInfo.InvariantCulture) }); + filters.Add(new TelemetryFilter { Field = nameof(OtlpLogEntry.TimeStamp), Condition = FilterCondition.LessThanOrEqual, Value = pausedAt.Value.ToString(CultureInfo.InvariantCulture) }); } logs = _telemetryRepository.GetLogs(new GetLogsContext diff --git a/src/Aspire.Dashboard/Model/TracesViewModel.cs b/src/Aspire.Dashboard/Model/TracesViewModel.cs index b9b7f7eb8c8..ab6dfdd2f0d 100644 --- a/src/Aspire.Dashboard/Model/TracesViewModel.cs +++ b/src/Aspire.Dashboard/Model/TracesViewModel.cs @@ -1,6 +1,7 @@ // 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.Otlp; using Aspire.Dashboard.Otlp.Model; using Aspire.Dashboard.Otlp.Storage; @@ -72,13 +73,18 @@ private void SetValue(ref T field, T value) _traces = null; } - public PagedResult GetTraces() + public PagedResult GetTraces(DateTime? pausedAt) { var traces = _traces; if (traces == null) { var filters = Filters.ToList(); + if (pausedAt is not null) + { + filters.Add(new TelemetryFilter { Field = nameof(OtlpLogEntry.TimeStamp), Condition = FilterCondition.LessThanOrEqual, Value = pausedAt.Value.ToString(CultureInfo.InvariantCulture) }); + } + var result = _telemetryRepository.GetTraces(new GetTracesRequest { ApplicationKey = ApplicationKey, From 813d2117415edc183ab0060cba07a453659bf8f6 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Wed, 19 Mar 2025 14:32:35 -0400 Subject: [PATCH 05/35] Add pause/resume to metrics --- .../Components/Controls/Chart/ChartContainer.razor | 11 ----------- .../Controls/Chart/ChartContainer.razor.cs | 14 +++++++++++++- .../Components/Pages/Metrics.razor | 10 ++++++++-- .../Components/Pages/Metrics.razor.cs | 7 +++++++ 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor b/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor index c9567da79b2..ab7236c3c10 100644 --- a/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor +++ b/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor @@ -53,14 +53,3 @@ else
} - -@code { - [Parameter, EditorRequired] - public required Metrics.MetricViewKind ActiveView { get; set; } - - [Parameter, EditorRequired] - public required Func OnViewChangedAsync { get; set; } - - [Parameter] - public required List Applications { get; set; } -} diff --git a/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor.cs b/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor.cs index 5a97c3d63ff..af5a592cf23 100644 --- a/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor.cs +++ b/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor.cs @@ -34,6 +34,18 @@ public partial class ChartContainer : ComponentBase, IAsyncDisposable [Parameter, EditorRequired] public required TimeSpan Duration { get; set; } + [Parameter, EditorRequired] + public required Pages.Metrics.MetricViewKind ActiveView { get; set; } + + [Parameter, EditorRequired] + public required Func OnViewChangedAsync { get; set; } + + [Parameter, EditorRequired] + public required List Applications { get; set; } + + [Parameter, EditorRequired] + public required DateTime? PausedAt { get; set; } + [Inject] public required TelemetryRepository TelemetryRepository { get; init; } @@ -79,7 +91,7 @@ private async Task UpdateDataAsync() while (await timer!.WaitForNextTickAsync()) { _instrument = GetInstrument(); - if (_instrument == null) + if (_instrument == null || PausedAt is not null) { continue; } diff --git a/src/Aspire.Dashboard/Components/Pages/Metrics.razor b/src/Aspire.Dashboard/Components/Pages/Metrics.razor index bddb1c6146c..f4caf83600d 100644 --- a/src/Aspire.Dashboard/Components/Pages/Metrics.razor +++ b/src/Aspire.Dashboard/Components/Pages/Metrics.razor @@ -51,6 +51,11 @@ + + @if (!ViewportInformation.IsDesktop) { @@ -98,7 +103,7 @@
- @if (PageViewModel.SelectedApplication.Id?.ReplicaSetName != null && PageViewModel.SelectedMeter != null && PageViewModel.SelectedInstrument != null) + @if (PageViewModel.SelectedApplication.Id?.ReplicaSetName != null && PageViewModel is { SelectedMeter: not null, SelectedInstrument: not null }) { + Applications="@_applications" + PausedAt="@_pausedAt" /> } else if (PageViewModel.SelectedMeter != null) { diff --git a/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs b/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs index c03ad79a644..fabc5312d67 100644 --- a/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs @@ -21,6 +21,7 @@ public partial class Metrics : IDisposable, IPageWithSessionAndUrlState _applications = default!; private List> _applicationViewModels = default!; @@ -297,6 +298,12 @@ private void UpdateSubscription() } } + private Task OnPausedAtChangedAsync(DateTime? newPausedAt) + { + _pausedAt = newPausedAt; + return Task.CompletedTask; + } + public void Dispose() { _applicationsSubscription?.Dispose(); From 876be0356d327f33d652bac6ec2a50d68c497e4c Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Wed, 19 Mar 2025 14:33:32 -0400 Subject: [PATCH 06/35] don't resume when switching console log apps --- src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs index 7031812ac5d..954c19fbc6f 100644 --- a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs @@ -511,7 +511,6 @@ private void LoadLogs(ConsoleLogsSubscription newConsoleLogsSubscription) private async Task HandleSelectedOptionChangedAsync() { PageViewModel.SelectedResource = PageViewModel.SelectedOption?.Id?.InstanceId is null ? null : _resourceByName[PageViewModel.SelectedOption.Id.InstanceId]; - _pausedAt = null; await this.AfterViewModelChangedAsync(_contentLayout, waitToApplyMobileChange: false); } From d1530b1ead4047457741a78e083dd4a62d453dc7 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Wed, 19 Mar 2025 14:54:37 -0400 Subject: [PATCH 07/35] Add unit test for console log pause/resume --- .../Components/Controls/LogViewer.razor.cs | 6 +- .../Components/Pages/ConsoleLogs.razor | 2 +- .../Components/Pages/ConsoleLogs.razor.cs | 2 +- .../Pages/ConsoleLogsTests.cs | 56 +++++++++++++++++++ 4 files changed, 61 insertions(+), 5 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs index 1c8b1acce57..82c875fb67c 100644 --- a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs +++ b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs @@ -37,7 +37,7 @@ public sealed partial class LogViewer public bool IsTimestampUtc { get; set; } [Parameter] - public DateTime? FilterTimestamp { get; set; } + public DateTime? PausedAt { get; set; } protected override void OnParametersSet() { @@ -91,10 +91,10 @@ private string GetDisplayTimestamp(DateTimeOffset timestamp) return null; } - return FilterTimestamp is null + return PausedAt is null ? logEntries.GetEntries() : logEntries.GetEntries() - .Where(logEntry => logEntry.Timestamp is { } timestamp && timestamp <= FilterTimestamp) + .Where(logEntry => logEntry.Timestamp is { } timestamp && timestamp <= PausedAt) .ToList(); } diff --git a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor index 3e1a55c09b9..8f62cfa4e82 100644 --- a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor +++ b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor @@ -88,7 +88,7 @@ LogEntries="@_logEntries" ShowTimestamp="@_showTimestamp" IsTimestampUtc="@_isTimestampUtc" - FilterTimestamp="@_pausedAt" /> + PausedAt="@_pausedAt" />
diff --git a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs index 954c19fbc6f..c3850192193 100644 --- a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs @@ -104,7 +104,7 @@ private sealed class ConsoleLogsSubscription public ConsoleLogsViewModel PageViewModel { get; set; } = null!; private IDisposable? _consoleLogsFiltersChangedSubscription; private ConsoleLogsFilters _consoleLogFilters = new(); - private DateTime? _pausedAt; + internal DateTime? _pausedAt; public string BasePath => DashboardUrls.ConsoleLogBasePath; public string SessionStorageKey => BrowserStorageKeys.ConsoleLogsPageState; diff --git a/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs b/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs index 260bb0d3c66..82df0ba2a95 100644 --- a/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs +++ b/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs @@ -344,6 +344,62 @@ public void MenuButtons_SelectedResourceChanged_ButtonsUpdated() }); } + [Fact] + public void PauseResumeButton_TogglePauseResume_LogsPausedAndResumed() + { + // Arrange + var testResource = ModelTestHelpers.CreateResource(appName: "test-resource", state: KnownResourceState.Running); + var consoleLogsChannel = Channel.CreateUnbounded>(); + var resourceChannel = Channel.CreateUnbounded>(); + var dashboardClient = new TestDashboardClient( + isEnabled: true, + consoleLogsChannelProvider: name => consoleLogsChannel, + resourceChannelProvider: () => resourceChannel, + initialResources: [testResource]); + + SetupConsoleLogsServices(dashboardClient); + + var dimensionManager = Services.GetRequiredService(); + var viewport = new ViewportInformation(IsDesktop: true, IsUltraLowHeight: false, IsUltraLowWidth: false); + dimensionManager.InvokeOnViewportInformationChanged(viewport); + + // Act + var cut = RenderComponent(builder => + { + builder.Add(p => p.ResourceName, "test-resource"); + builder.Add(p => p.ViewportInformation, viewport); + }); + + var instance = cut.Instance; + var logger = Services.GetRequiredService>(); + var loc = Services.GetRequiredService>(); + + // Assert initial state + cut.WaitForState(() => instance.PageViewModel.SelectedResource == testResource); + cut.WaitForAssertion(() => Assert.Null(instance._pausedAt)); + + // Pause logs + var pauseResumeButton = cut.FindComponent(); + pauseResumeButton.Find("fluent-button").Click(); + + // Assert paused state + cut.WaitForState(() => instance._pausedAt.HasValue); + + // Add a new log while paused + consoleLogsChannel.Writer.TryWrite([new ResourceLogLine(1, "Log while paused", IsErrorMessage: false)]); + + // Ensure the new log does not show up when paused + cut.WaitForAssertion(() => Assert.DoesNotContain("Log while paused", instance._logEntries.GetEntries().Select(e => e.RawContent))); + + // Resume logs + pauseResumeButton.Find("fluent-button").Click(); + + // Assert resumed state + cut.WaitForState(() => !instance._pausedAt.HasValue); + cut.WaitForAssertion(() => Assert.Contains("Log while paused", instance._logEntries.GetEntries().Select(e => e.RawContent))); + Assert.Equal(loc[nameof(Resources.ConsoleLogs.ConsoleLogsWatchingLogs)], instance.PageViewModel.Status); + } + private void SetupConsoleLogsServices(TestDashboardClient? dashboardClient = null, TestTimeProvider? timeProvider = null) { var version = typeof(FluentMain).Assembly.GetName().Version!; From a2ab30a383c99254bee8b8f1ed5d00c20989779d Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Wed, 19 Mar 2025 15:09:03 -0400 Subject: [PATCH 08/35] Fix added test --- .../Components/Controls/LogViewer.razor.cs | 2 +- .../Pages/ConsoleLogsTests.cs | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs index 82c875fb67c..5f457cc7a05 100644 --- a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs +++ b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs @@ -84,7 +84,7 @@ private string GetDisplayTimestamp(DateTimeOffset timestamp) : TimeProvider.ToLocal(timestamp).ToString(KnownFormats.ConsoleLogsUITimestampLocalFormat, CultureInfo.InvariantCulture); } - private ICollection? GetEntries() + internal ICollection? GetEntries() { if (LogEntries is not { } logEntries) { diff --git a/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs b/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs index 82df0ba2a95..f06c4bf87c2 100644 --- a/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs +++ b/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs @@ -371,7 +371,6 @@ public void PauseResumeButton_TogglePauseResume_LogsPausedAndResumed() }); var instance = cut.Instance; - var logger = Services.GetRequiredService>(); var loc = Services.GetRequiredService>(); // Assert initial state @@ -388,15 +387,24 @@ public void PauseResumeButton_TogglePauseResume_LogsPausedAndResumed() // Add a new log while paused consoleLogsChannel.Writer.TryWrite([new ResourceLogLine(1, "Log while paused", IsErrorMessage: false)]); + cut.WaitForAssertion(() => Assert.Contains("Log while paused", instance._logEntries.GetEntries().Select(e => e.RawContent))); + + var logViewer = cut.FindComponent(); + logViewer.SetParametersAndRender(p => + { + p.Add(m => m.LogEntries, instance._logEntries); + p.Add(m => m.PausedAt, instance._pausedAt); + }); + // Ensure the new log does not show up when paused - cut.WaitForAssertion(() => Assert.DoesNotContain("Log while paused", instance._logEntries.GetEntries().Select(e => e.RawContent))); + cut.WaitForAssertion(() => Assert.DoesNotContain("Log while paused", logViewer.Instance.GetEntries()!.Select(e => e.RawContent))); // Resume logs pauseResumeButton.Find("fluent-button").Click(); // Assert resumed state cut.WaitForState(() => !instance._pausedAt.HasValue); - cut.WaitForAssertion(() => Assert.Contains("Log while paused", instance._logEntries.GetEntries().Select(e => e.RawContent))); + cut.WaitForAssertion(() => Assert.Contains("Log while paused", logViewer.Instance.GetEntries()!.Select(e => e.RawContent))); Assert.Equal(loc[nameof(Resources.ConsoleLogs.ConsoleLogsWatchingLogs)], instance.PageViewModel.Status); } From 54b64d835e361aeafdf83144eaeb6ebabaf004b0 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Wed, 19 Mar 2025 15:11:01 -0400 Subject: [PATCH 09/35] slightly improve test --- .../Pages/ConsoleLogsTests.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs b/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs index f06c4bf87c2..ad55ecd3e7b 100644 --- a/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs +++ b/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs @@ -387,16 +387,11 @@ public void PauseResumeButton_TogglePauseResume_LogsPausedAndResumed() // Add a new log while paused consoleLogsChannel.Writer.TryWrite([new ResourceLogLine(1, "Log while paused", IsErrorMessage: false)]); - cut.WaitForAssertion(() => Assert.Contains("Log while paused", instance._logEntries.GetEntries().Select(e => e.RawContent))); - var logViewer = cut.FindComponent(); - logViewer.SetParametersAndRender(p => - { - p.Add(m => m.LogEntries, instance._logEntries); - p.Add(m => m.PausedAt, instance._pausedAt); - }); - // Ensure the new log does not show up when paused + // Ensure the new log does not show up in visible entries when paused + // but is still in the log entries + cut.WaitForAssertion(() => Assert.Contains("Log while paused", logViewer.Instance.LogEntries!.GetEntries().Select(e => e.RawContent))); cut.WaitForAssertion(() => Assert.DoesNotContain("Log while paused", logViewer.Instance.GetEntries()!.Select(e => e.RawContent))); // Resume logs From 85051b5bfaaa0a9ba77c3061ac47e70a5aaca25e Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Thu, 20 Mar 2025 13:25:37 -0400 Subject: [PATCH 10/35] Use singleton --- .../Controls/Chart/ChartContainer.razor.cs | 8 ++--- .../Components/Controls/LogViewer.razor | 4 +-- .../Components/Controls/LogViewer.razor.cs | 14 --------- .../Controls/PauseResumeButton.razor | 10 ++----- .../Controls/PauseResumeButton.razor.cs | 8 ++--- .../Components/Pages/ConsoleLogs.razor | 7 +++-- .../Components/Pages/ConsoleLogs.razor.cs | 29 ++++++++++++++++--- .../Components/Pages/Metrics.razor | 6 ++-- .../Components/Pages/Metrics.razor.cs | 10 ++----- .../Components/Pages/StructuredLogs.razor | 2 +- .../Components/Pages/StructuredLogs.razor.cs | 12 +++----- .../Components/Pages/Traces.razor | 2 +- .../Components/Pages/Traces.razor.cs | 12 +++----- .../DashboardWebApplication.cs | 2 ++ .../Model/Otlp/TelemetryFilter.cs | 22 ++------------ src/Aspire.Dashboard/Model/PauseManager.cs | 25 ++++++++++++++++ .../Model/StructuredLogsViewModel.cs | 8 +---- src/Aspire.Dashboard/Model/TracesViewModel.cs | 8 +---- .../Otlp/Storage/TelemetryRepository.cs | 20 ++++++++++++- 19 files changed, 108 insertions(+), 101 deletions(-) create mode 100644 src/Aspire.Dashboard/Model/PauseManager.cs diff --git a/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor.cs b/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor.cs index af5a592cf23..75bdfbbdbd9 100644 --- a/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor.cs +++ b/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor.cs @@ -43,9 +43,6 @@ public partial class ChartContainer : ComponentBase, IAsyncDisposable [Parameter, EditorRequired] public required List Applications { get; set; } - [Parameter, EditorRequired] - public required DateTime? PausedAt { get; set; } - [Inject] public required TelemetryRepository TelemetryRepository { get; init; } @@ -55,6 +52,9 @@ public partial class ChartContainer : ComponentBase, IAsyncDisposable [Inject] public required ThemeManager ThemeManager { get; init; } + [Inject] + public required PauseManager PauseManager { get; init; } + public ImmutableList DimensionFilters { get; set; } = []; public string? PreviousMeterName { get; set; } public string? PreviousInstrumentName { get; set; } @@ -91,7 +91,7 @@ private async Task UpdateDataAsync() while (await timer!.WaitForNextTickAsync()) { _instrument = GetInstrument(); - if (_instrument == null || PausedAt is not null) + if (_instrument == null || PauseManager.MetricsPaused) { continue; } diff --git a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor index e5bc657f776..62200f55cd8 100644 --- a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor +++ b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor @@ -8,9 +8,9 @@
- @if (GetEntries() is { } entries) + @if (LogEntries is { } logEntries) { - +
diff --git a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs index 5f457cc7a05..8de2fcc470a 100644 --- a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs +++ b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs @@ -84,20 +84,6 @@ private string GetDisplayTimestamp(DateTimeOffset timestamp) : TimeProvider.ToLocal(timestamp).ToString(KnownFormats.ConsoleLogsUITimestampLocalFormat, CultureInfo.InvariantCulture); } - internal ICollection? GetEntries() - { - if (LogEntries is not { } logEntries) - { - return null; - } - - return PausedAt is null - ? logEntries.GetEntries() - : logEntries.GetEntries() - .Where(logEntry => logEntry.Timestamp is { } timestamp && timestamp <= PausedAt) - .ToList(); - } - public ValueTask DisposeAsync() { Logger.LogDebug("Disposing log viewer."); diff --git a/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor b/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor index 523a2ec858f..5cb4f403e19 100644 --- a/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor +++ b/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor @@ -1,17 +1,13 @@ @using Aspire.Dashboard.Resources @inject IStringLocalizer Loc -@{ - var isPaused = PausedAt is not null; -} - - @if (isPaused) + @if (IsPaused) { - + } else { diff --git a/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor.cs b/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor.cs index be21d5e60b5..7c0c95443ae 100644 --- a/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor.cs +++ b/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor.cs @@ -7,18 +7,18 @@ namespace Aspire.Dashboard.Components.Controls; public partial class PauseResumeButton : ComponentBase { [Parameter] - public DateTime? PausedAt { get; set; } + public bool IsPaused { get; set; } [Parameter] - public EventCallback PausedAtChanged { get; set; } + public EventCallback IsPausedChanged { get; set; } [Parameter] public bool Disabled { get; set; } private async Task OnTogglePauseCoreAsync() { - PausedAt = PausedAt == null ? DateTime.UtcNow : null; - await PausedAtChanged.InvokeAsync(PausedAt); + IsPaused = !IsPaused; + await IsPausedChanged.InvokeAsync(IsPaused); } } diff --git a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor index 8f62cfa4e82..95c3f467d91 100644 --- a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor +++ b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor @@ -29,7 +29,9 @@ - + @foreach (var command in _highlightedCommands) { @@ -87,8 +89,7 @@ + IsTimestampUtc="@_isTimestampUtc" />
diff --git a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs index c3850192193..3beb5b895f6 100644 --- a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs @@ -77,6 +77,9 @@ private sealed class ConsoleLogsSubscription [Inject] public required BrowserTimeProvider TimeProvider { get; init; } + [Inject] + public required PauseManager PauseManager { get; init; } + [CascadingParameter] public required ViewportInformation ViewportInformation { get; init; } @@ -104,7 +107,6 @@ private sealed class ConsoleLogsSubscription public ConsoleLogsViewModel PageViewModel { get; set; } = null!; private IDisposable? _consoleLogsFiltersChangedSubscription; private ConsoleLogsFilters _consoleLogFilters = new(); - internal DateTime? _pausedAt; public string BasePath => DashboardUrls.ConsoleLogBasePath; public string SessionStorageKey => BrowserStorageKeys.ConsoleLogsPageState; @@ -481,11 +483,15 @@ private void LoadLogs(ConsoleLogsSubscription newConsoleLogsSubscription) } var logEntry = logParser.CreateLogEntry(content, isErrorOutput); - if (timestampFilterDate is null || logEntry.Timestamp is null || logEntry.Timestamp > timestampFilterDate) + if (logEntry.Timestamp is not null && + ((timestampFilterDate is not null && !(logEntry.Timestamp > timestampFilterDate)) + || PauseManager.ConsoleLogsPausedRanges.Any(range => range.IsOverlapping(logEntry.Timestamp.Value)))) { - // Only add entries that are not ignored, or if they are null as we cannot know when they happened. - _logEntries.InsertSorted(logEntry); + continue; } + + // Only add entries that are not ignored, or if they are null as we cannot know when they happened. + _logEntries.InsertSorted(logEntry); } await InvokeAsync(StateHasChanged); @@ -601,6 +607,21 @@ private async Task ClearConsoleLogs(ApplicationKey? key) await ConsoleLogsManager.UpdateFiltersAsync(_consoleLogFilters); } + private Task IsPausedChangedAsync(bool isPaused) + { + PauseManager.ConsoleLogsPaused = isPaused; + if (isPaused) + { + PauseManager.ConsoleLogsPausedRanges.Add(new DateTimeRange(start: DateTime.UtcNow, end: null)); + } + else + { + PauseManager.ConsoleLogsPausedRanges.Last().End = DateTime.UtcNow; + } + + return Task.CompletedTask; + } + public async ValueTask DisposeAsync() { _consoleLogsFiltersChangedSubscription?.Dispose(); diff --git a/src/Aspire.Dashboard/Components/Pages/Metrics.razor b/src/Aspire.Dashboard/Components/Pages/Metrics.razor index f4caf83600d..7e5329582c9 100644 --- a/src/Aspire.Dashboard/Components/Pages/Metrics.razor +++ b/src/Aspire.Dashboard/Components/Pages/Metrics.razor @@ -52,8 +52,7 @@ HandleClearSignal="ClearMetrics" /> @if (!ViewportInformation.IsDesktop) @@ -112,8 +111,7 @@ Duration="PageViewModel.SelectedDuration.Id" ActiveView="@(PageViewModel.SelectedViewKind ?? Metrics.MetricViewKind.Graph)" OnViewChangedAsync="@OnViewChangedAsync" - Applications="@_applications" - PausedAt="@_pausedAt" /> + Applications="@_applications" /> } else if (PageViewModel.SelectedMeter != null) { diff --git a/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs b/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs index fabc5312d67..c7462f3ed23 100644 --- a/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs @@ -21,7 +21,6 @@ public partial class Metrics : IDisposable, IPageWithSessionAndUrlState _applications = default!; private List> _applicationViewModels = default!; @@ -63,6 +62,9 @@ public partial class Metrics : IDisposable, IPageWithSessionAndUrlState Logger { get; init; } + [Inject] + public required PauseManager PauseManager { get; init; } + [CascadingParameter] public required ViewportInformation ViewportInformation { get; init; } @@ -298,12 +300,6 @@ private void UpdateSubscription() } } - private Task OnPausedAtChangedAsync(DateTime? newPausedAt) - { - _pausedAt = newPausedAt; - return Task.CompletedTask; - } - public void Dispose() { _applicationsSubscription?.Dispose(); diff --git a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor index 908747a5e7a..c00db59ec28 100644 --- a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor +++ b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor @@ -40,7 +40,7 @@ - + _dataGrid = null!; private GridColumnManager _manager = null!; private IList _gridColumns = null!; - private DateTime? _pausedAt; private ColumnResizeLabels _resizeLabels = ColumnResizeLabels.Default; private ColumnSortLabels _sortLabels = ColumnSortLabels.Default; @@ -83,6 +82,9 @@ public partial class StructuredLogs : IPageWithSessionAndUrlState> GetData(GridItems ViewModel.StartIndex = request.StartIndex; ViewModel.Count = request.Count ?? DashboardUIHelpers.DefaultDataGridResultCount; - var logs = ViewModel.GetLogs(_pausedAt); + var logs = ViewModel.GetLogs(); if (logs.IsFull && !TelemetryRepository.HasDisplayedMaxLogLimitMessage) { @@ -350,12 +352,6 @@ private string GetRowClass(OtlpLogEntry entry) } } - private Task OnPausedAtChangedAsync(DateTime? newPausedAt) - { - _pausedAt = newPausedAt; - return InvokeAsync(_dataGrid.SafeRefreshDataAsync); - } - protected override async Task OnAfterRenderAsync(bool firstRender) { if (_applicationChanged) diff --git a/src/Aspire.Dashboard/Components/Pages/Traces.razor b/src/Aspire.Dashboard/Components/Pages/Traces.razor index 0dcc40e5ad5..955293bd427 100644 --- a/src/Aspire.Dashboard/Components/Pages/Traces.razor +++ b/src/Aspire.Dashboard/Components/Pages/Traces.razor @@ -39,7 +39,7 @@ - + _dataGrid = null!; private GridColumnManager _manager = null!; - private DateTime? _pausedAt; private ColumnResizeLabels _resizeLabels = ColumnResizeLabels.Default; private ColumnSortLabels _sortLabels = ColumnSortLabels.Default; @@ -82,6 +81,9 @@ public partial class Traces : IPageWithSessionAndUrlState> GetData(GridItemsPro { TracesViewModel.StartIndex = request.StartIndex; TracesViewModel.Count = request.Count ?? DashboardUIHelpers.DefaultDataGridResultCount; - var traces = TracesViewModel.GetTraces(_pausedAt); + var traces = TracesViewModel.GetTraces(); if (traces.IsFull && !TelemetryRepository.HasDisplayedMaxTraceLimitMessage) { @@ -344,12 +346,6 @@ private Task ClearTraces(ApplicationKey? key) return Task.CompletedTask; } - private Task OnPausedAtChangedAsync(DateTime? newPausedAt) - { - _pausedAt = newPausedAt; - return InvokeAsync(_dataGrid.SafeRefreshDataAsync); - } - public class TracesPageViewModel { public required SelectViewModel SelectedApplication { get; set; } diff --git a/src/Aspire.Dashboard/DashboardWebApplication.cs b/src/Aspire.Dashboard/DashboardWebApplication.cs index 9a28043a224..0bb1c01bae9 100644 --- a/src/Aspire.Dashboard/DashboardWebApplication.cs +++ b/src/Aspire.Dashboard/DashboardWebApplication.cs @@ -230,6 +230,8 @@ public DashboardWebApplication( builder.Services.TryAddSingleton(); builder.Services.TryAddScoped(); + builder.Services.AddSingleton(); + // OTLP services. builder.Services.AddGrpc(); builder.Services.AddSingleton(); diff --git a/src/Aspire.Dashboard/Model/Otlp/TelemetryFilter.cs b/src/Aspire.Dashboard/Model/Otlp/TelemetryFilter.cs index 597492d2e85..326f033aa1b 100644 --- a/src/Aspire.Dashboard/Model/Otlp/TelemetryFilter.cs +++ b/src/Aspire.Dashboard/Model/Otlp/TelemetryFilter.cs @@ -130,25 +130,9 @@ public IEnumerable Apply(IEnumerable input) public bool Apply(OtlpSpan span) { - return Field switch - { - nameof(OtlpLogEntry.TimeStamp) => ApplyTimeStamp(), - _ => ApplyField() - }; - - bool ApplyTimeStamp() - { - var date = DateTime.Parse(Value, CultureInfo.InvariantCulture); - var func = ConditionToFuncDate(Condition); - return func(span.StartTime, date); - } - - bool ApplyField() - { - var fieldValue = OtlpSpan.GetFieldValue(span, Field); - var func = ConditionToFuncString(Condition); - return func(fieldValue, Value); - } + var fieldValue = OtlpSpan.GetFieldValue(span, Field); + var func = ConditionToFuncString(Condition); + return func(fieldValue, Value); } public bool Equals(TelemetryFilter? other) diff --git a/src/Aspire.Dashboard/Model/PauseManager.cs b/src/Aspire.Dashboard/Model/PauseManager.cs new file mode 100644 index 00000000000..9d271924845 --- /dev/null +++ b/src/Aspire.Dashboard/Model/PauseManager.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Aspire.Dashboard.Model; + +public sealed class PauseManager +{ + public bool StructuredLogsPaused { get; set; } + public bool TracesPaused { get; set; } + public bool MetricsPaused { get; set; } + + public bool ConsoleLogsPaused { get; set; } + public List ConsoleLogsPausedRanges { get; } = []; +} + +public class DateTimeRange(DateTime start, DateTime? end) +{ + public DateTime Start { get; } = start; + public DateTime? End { get; set; } = end; + + public bool IsOverlapping(DateTime date) + { + return date >= Start && (End is null || date <= End); + } +} diff --git a/src/Aspire.Dashboard/Model/StructuredLogsViewModel.cs b/src/Aspire.Dashboard/Model/StructuredLogsViewModel.cs index e29e21fb5a6..7eaf5c8a784 100644 --- a/src/Aspire.Dashboard/Model/StructuredLogsViewModel.cs +++ b/src/Aspire.Dashboard/Model/StructuredLogsViewModel.cs @@ -1,7 +1,6 @@ // 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.Otlp; using Aspire.Dashboard.Otlp.Model; using Aspire.Dashboard.Otlp.Storage; @@ -75,7 +74,7 @@ private void SetValue(ref T field, T value) _logs = null; } - public PagedResult GetLogs(DateTime? pausedAt) + public PagedResult GetLogs() { var logs = _logs; if (logs == null) @@ -91,11 +90,6 @@ public PagedResult GetLogs(DateTime? pausedAt) filters.Add(new TelemetryFilter { Field = nameof(OtlpLogEntry.Severity), Condition = FilterCondition.GreaterThanOrEqual, Value = _logLevel.Value.ToString() }); } - if (pausedAt is not null) - { - filters.Add(new TelemetryFilter { Field = nameof(OtlpLogEntry.TimeStamp), Condition = FilterCondition.LessThanOrEqual, Value = pausedAt.Value.ToString(CultureInfo.InvariantCulture) }); - } - logs = _telemetryRepository.GetLogs(new GetLogsContext { ApplicationKey = ApplicationKey, diff --git a/src/Aspire.Dashboard/Model/TracesViewModel.cs b/src/Aspire.Dashboard/Model/TracesViewModel.cs index ab6dfdd2f0d..b9b7f7eb8c8 100644 --- a/src/Aspire.Dashboard/Model/TracesViewModel.cs +++ b/src/Aspire.Dashboard/Model/TracesViewModel.cs @@ -1,7 +1,6 @@ // 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.Otlp; using Aspire.Dashboard.Otlp.Model; using Aspire.Dashboard.Otlp.Storage; @@ -73,18 +72,13 @@ private void SetValue(ref T field, T value) _traces = null; } - public PagedResult GetTraces(DateTime? pausedAt) + public PagedResult GetTraces() { var traces = _traces; if (traces == null) { var filters = Filters.ToList(); - if (pausedAt is not null) - { - filters.Add(new TelemetryFilter { Field = nameof(OtlpLogEntry.TimeStamp), Condition = FilterCondition.LessThanOrEqual, Value = pausedAt.Value.ToString(CultureInfo.InvariantCulture) }); - } - var result = _telemetryRepository.GetTraces(new GetTracesRequest { ApplicationKey = ApplicationKey, diff --git a/src/Aspire.Dashboard/Otlp/Storage/TelemetryRepository.cs b/src/Aspire.Dashboard/Otlp/Storage/TelemetryRepository.cs index 7cd09dd96f4..b375aff6d9f 100644 --- a/src/Aspire.Dashboard/Otlp/Storage/TelemetryRepository.cs +++ b/src/Aspire.Dashboard/Otlp/Storage/TelemetryRepository.cs @@ -8,6 +8,7 @@ using System.Runtime.InteropServices; using System.Text; using Aspire.Dashboard.Configuration; +using Aspire.Dashboard.Model; using Aspire.Dashboard.Otlp.Model; using Aspire.Dashboard.Otlp.Model.MetricValues; using Google.Protobuf.Collections; @@ -24,6 +25,7 @@ namespace Aspire.Dashboard.Otlp.Storage; public sealed class TelemetryRepository { + private readonly PauseManager _pauseManager; private readonly object _lock = new(); internal TimeSpan _subscriptionMinExecuteInterval = TimeSpan.FromMilliseconds(100); @@ -57,7 +59,7 @@ public sealed class TelemetryRepository internal List SpanLinks => _spanLinks; internal List TracesSubscriptions => _tracesSubscriptions; - public TelemetryRepository(ILoggerFactory loggerFactory, IOptions dashboardOptions) + public TelemetryRepository(ILoggerFactory loggerFactory, IOptions dashboardOptions, PauseManager pauseManager) { var logger = loggerFactory.CreateLogger(typeof(TelemetryRepository)); _otlpContext = new OtlpContext @@ -65,6 +67,7 @@ public TelemetryRepository(ILoggerFactory loggerFactory, IOptions subscriptions) public void AddLogs(AddContext context, RepeatedField resourceLogs) { + if (_pauseManager.StructuredLogsPaused) + { + return; + } + foreach (var rl in resourceLogs) { OtlpApplicationView applicationView; @@ -804,6 +812,11 @@ public Dictionary GetLogsFieldValues(string attributeName) public void AddMetrics(AddContext context, RepeatedField resourceMetrics) { + if (_pauseManager.MetricsPaused) + { + return; + } + foreach (var rm in resourceMetrics) { OtlpApplicationView applicationView; @@ -826,6 +839,11 @@ public void AddMetrics(AddContext context, RepeatedField resour public void AddTraces(AddContext context, RepeatedField resourceSpans) { + if (_pauseManager.TracesPaused) + { + return; + } + foreach (var rs in resourceSpans) { OtlpApplicationView applicationView; From 356b96b48a0e0a71a1ddbcfc3773d8c11ad61d94 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Thu, 20 Mar 2025 13:52:27 -0400 Subject: [PATCH 11/35] update dashboard tests --- .../Pages/ConsoleLogsTests.cs | 31 +++++++++---------- .../Pages/StructuredLogsTests.cs | 1 + .../Pages/TraceDetailsTests.cs | 1 + .../Shared/MetricsSetupHelpers.cs | 2 ++ .../Shared/ResourceSetupHelpers.cs | 1 + .../Shared/Telemetry/TelemetryTestHelpers.cs | 7 +++-- 6 files changed, 25 insertions(+), 18 deletions(-) diff --git a/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs b/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs index ad55ecd3e7b..fd33530586d 100644 --- a/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs +++ b/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs @@ -371,36 +371,34 @@ public void PauseResumeButton_TogglePauseResume_LogsPausedAndResumed() }); var instance = cut.Instance; - var loc = Services.GetRequiredService>(); // Assert initial state cut.WaitForState(() => instance.PageViewModel.SelectedResource == testResource); - cut.WaitForAssertion(() => Assert.Null(instance._pausedAt)); // Pause logs var pauseResumeButton = cut.FindComponent(); pauseResumeButton.Find("fluent-button").Click(); - // Assert paused state - cut.WaitForState(() => instance._pausedAt.HasValue); - // Add a new log while paused - consoleLogsChannel.Writer.TryWrite([new ResourceLogLine(1, "Log while paused", IsErrorMessage: false)]); + var pauseContent = $"{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ss.fffK} Log while paused"; + consoleLogsChannel.Writer.TryWrite([new ResourceLogLine(1, pauseContent, IsErrorMessage: false)]); + + pauseResumeButton.Find("fluent-button").Click(); + + cut.WaitForAssertion(() => Assert.False(Services.GetRequiredService().ConsoleLogsPaused)); + + var resumeContent = $"{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ss.fffK} Log after resume"; + consoleLogsChannel.Writer.TryWrite([new ResourceLogLine(1, resumeContent, IsErrorMessage: false)]); var logViewer = cut.FindComponent(); // Ensure the new log does not show up in visible entries when paused // but is still in the log entries - cut.WaitForAssertion(() => Assert.Contains("Log while paused", logViewer.Instance.LogEntries!.GetEntries().Select(e => e.RawContent))); - cut.WaitForAssertion(() => Assert.DoesNotContain("Log while paused", logViewer.Instance.GetEntries()!.Select(e => e.RawContent))); - - // Resume logs - pauseResumeButton.Find("fluent-button").Click(); - - // Assert resumed state - cut.WaitForState(() => !instance._pausedAt.HasValue); - cut.WaitForAssertion(() => Assert.Contains("Log while paused", logViewer.Instance.GetEntries()!.Select(e => e.RawContent))); - Assert.Equal(loc[nameof(Resources.ConsoleLogs.ConsoleLogsWatchingLogs)], instance.PageViewModel.Status); + cut.WaitForAssertion(() => + { + Assert.Contains(resumeContent, logViewer.Instance.LogEntries!.GetEntries().Select(e => e.RawContent)); + Assert.DoesNotContain(pauseContent, logViewer.Instance.LogEntries!.GetEntries().Select(e => e.RawContent)); + }); } private void SetupConsoleLogsServices(TestDashboardClient? dashboardClient = null, TestTimeProvider? timeProvider = null) @@ -448,6 +446,7 @@ private void SetupConsoleLogsServices(TestDashboardClient? dashboardClient = nul Services.AddSingleton(dashboardClient ?? new TestDashboardClient()); Services.AddSingleton(); Services.AddSingleton(); + Services.AddSingleton(); } private static string GetFluentFile(string filePath, Version version) diff --git a/tests/Aspire.Dashboard.Components.Tests/Pages/StructuredLogsTests.cs b/tests/Aspire.Dashboard.Components.Tests/Pages/StructuredLogsTests.cs index 99777f0bf64..873475b9b94 100644 --- a/tests/Aspire.Dashboard.Components.Tests/Pages/StructuredLogsTests.cs +++ b/tests/Aspire.Dashboard.Components.Tests/Pages/StructuredLogsTests.cs @@ -177,6 +177,7 @@ private void SetupStructureLogsServices() Services.AddLocalization(); Services.AddSingleton(); + Services.AddSingleton(); Services.AddSingleton(); Services.AddSingleton(); Services.AddSingleton>(Options.Create(new DashboardOptions())); diff --git a/tests/Aspire.Dashboard.Components.Tests/Pages/TraceDetailsTests.cs b/tests/Aspire.Dashboard.Components.Tests/Pages/TraceDetailsTests.cs index 2f98e547ec8..9e6ea12175a 100644 --- a/tests/Aspire.Dashboard.Components.Tests/Pages/TraceDetailsTests.cs +++ b/tests/Aspire.Dashboard.Components.Tests/Pages/TraceDetailsTests.cs @@ -170,6 +170,7 @@ private void SetupTraceDetailsServices() Services.AddLocalization(); Services.AddSingleton(); + Services.AddSingleton(); Services.AddSingleton(); Services.AddSingleton(); Services.AddSingleton>(Options.Create(new DashboardOptions())); diff --git a/tests/Aspire.Dashboard.Components.Tests/Shared/MetricsSetupHelpers.cs b/tests/Aspire.Dashboard.Components.Tests/Shared/MetricsSetupHelpers.cs index 6b23637b737..5b8e7afce29 100644 --- a/tests/Aspire.Dashboard.Components.Tests/Shared/MetricsSetupHelpers.cs +++ b/tests/Aspire.Dashboard.Components.Tests/Shared/MetricsSetupHelpers.cs @@ -39,6 +39,7 @@ internal static void SetupPlotlyChart(TestContext context) context.Services.AddLocalization(); context.Services.AddSingleton(); context.Services.AddSingleton(); + context.Services.AddSingleton(); context.Services.AddSingleton(); context.Services.AddSingleton(); } @@ -78,6 +79,7 @@ internal static void SetupMetricsPage(TestContext context, ISessionStorage? sess SetupChartContainer(context); context.Services.AddLocalization(); + context.Services.AddSingleton(); context.Services.AddSingleton(); context.Services.AddSingleton(); context.Services.AddSingleton>(Options.Create(new DashboardOptions())); diff --git a/tests/Aspire.Dashboard.Components.Tests/Shared/ResourceSetupHelpers.cs b/tests/Aspire.Dashboard.Components.Tests/Shared/ResourceSetupHelpers.cs index e9ebb6aa754..cfa4011af73 100644 --- a/tests/Aspire.Dashboard.Components.Tests/Shared/ResourceSetupHelpers.cs +++ b/tests/Aspire.Dashboard.Components.Tests/Shared/ResourceSetupHelpers.cs @@ -93,6 +93,7 @@ public static void SetupResourcesPage(TestContext context, ViewportInformation v context.Services.AddLocalization(); context.Services.AddSingleton(); + context.Services.AddSingleton(); context.Services.AddSingleton(); context.Services.AddSingleton(); context.Services.AddSingleton(Options.Create(new DashboardOptions())); diff --git a/tests/Shared/Telemetry/TelemetryTestHelpers.cs b/tests/Shared/Telemetry/TelemetryTestHelpers.cs index 68ada7bae1a..c40a2ef7e9a 100644 --- a/tests/Shared/Telemetry/TelemetryTestHelpers.cs +++ b/tests/Shared/Telemetry/TelemetryTestHelpers.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Text; using Aspire.Dashboard.Configuration; +using Aspire.Dashboard.Model; using Aspire.Dashboard.Otlp.Model; using Aspire.Dashboard.Otlp.Storage; using Google.Protobuf; @@ -225,7 +226,8 @@ public static TelemetryRepository CreateRepository( int? maxSpanEventCount = null, int? maxTraceCount = null, TimeSpan? subscriptionMinExecuteInterval = null, - ILoggerFactory? loggerFactory = null) + ILoggerFactory? loggerFactory = null, + PauseManager? pauseManager = null) { var options = new TelemetryLimitOptions(); if (maxMetricsCount != null) @@ -251,7 +253,8 @@ public static TelemetryRepository CreateRepository( var repository = new TelemetryRepository( loggerFactory ?? NullLoggerFactory.Instance, - Options.Create(new DashboardOptions { TelemetryLimits = options })); + Options.Create(new DashboardOptions { TelemetryLimits = options }), + pauseManager ?? new PauseManager()); if (subscriptionMinExecuteInterval != null) { repository._subscriptionMinExecuteInterval = subscriptionMinExecuteInterval.Value; From ccb568b4aceb767c8919a8321111e39a52f181c8 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Fri, 21 Mar 2025 13:46:40 -0400 Subject: [PATCH 12/35] Add title to clear signals button --- .../Components/Controls/ClearSignalsButton.razor | 9 ++++++--- .../Resources/ControlsStrings.Designer.cs | 6 ++++++ src/Aspire.Dashboard/Resources/ControlsStrings.resx | 3 +++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Controls/ClearSignalsButton.razor b/src/Aspire.Dashboard/Components/Controls/ClearSignalsButton.razor index 998e93d7e10..47843d590af 100644 --- a/src/Aspire.Dashboard/Components/Controls/ClearSignalsButton.razor +++ b/src/Aspire.Dashboard/Components/Controls/ClearSignalsButton.razor @@ -1,9 +1,12 @@ -@namespace Aspire.Dashboard.Components.Controls -@using Aspire.Dashboard.Resources +@using Aspire.Dashboard.Resources +@namespace Aspire.Dashboard.Components.Controls + +@inject IStringLocalizer Loc + ButtonClass="clear-button" + Title="@Loc[nameof(ControlsStrings.ClearSignalsButtonTitle)]" /> diff --git a/src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs b/src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs index 23dc25347c8..df74a451ca1 100644 --- a/src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs +++ b/src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs @@ -722,5 +722,11 @@ public static string ResumeButtonTitle { return ResourceManager.GetString("ResumeButtonTitle", resourceCulture); } } + + public static string ClearSignalsButtonTitle { + get { + return ResourceManager.GetString("ClearSignalsButtonTitle", resourceCulture); + } + } } } diff --git a/src/Aspire.Dashboard/Resources/ControlsStrings.resx b/src/Aspire.Dashboard/Resources/ControlsStrings.resx index 9a8898d03cd..e06491b4167 100644 --- a/src/Aspire.Dashboard/Resources/ControlsStrings.resx +++ b/src/Aspire.Dashboard/Resources/ControlsStrings.resx @@ -469,4 +469,7 @@ Resume incoming data + + Remove data + From 4f5fa2c570c39f2aafe2791f91a56207e85c2ae1 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Fri, 21 Mar 2025 13:46:51 -0400 Subject: [PATCH 13/35] Remove unused parameter --- src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs index 8de2fcc470a..fcc9a94167c 100644 --- a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs +++ b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs @@ -36,9 +36,6 @@ public sealed partial class LogViewer [Parameter] public bool IsTimestampUtc { get; set; } - [Parameter] - public DateTime? PausedAt { get; set; } - protected override void OnParametersSet() { if (_logEntries != LogEntries) From 378266bf932390ac0c17cff63855db730e19a8fe Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Fri, 21 Mar 2025 13:51:28 -0400 Subject: [PATCH 14/35] Rename button to PauseIncomingDataSwitch, remove disable parameter --- ...PauseResumeButton.razor => PauseIncomingDataSwitch.razor} | 3 +-- ...esumeButton.razor.cs => PauseIncomingDataSwitch.razor.cs} | 5 +---- src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor | 2 +- src/Aspire.Dashboard/Components/Pages/Metrics.razor | 4 +--- src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor | 2 +- src/Aspire.Dashboard/Components/Pages/Traces.razor | 2 +- src/Aspire.Dashboard/Resources/xlf/ControlsStrings.cs.xlf | 5 +++++ src/Aspire.Dashboard/Resources/xlf/ControlsStrings.de.xlf | 5 +++++ src/Aspire.Dashboard/Resources/xlf/ControlsStrings.es.xlf | 5 +++++ src/Aspire.Dashboard/Resources/xlf/ControlsStrings.fr.xlf | 5 +++++ src/Aspire.Dashboard/Resources/xlf/ControlsStrings.it.xlf | 5 +++++ src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ja.xlf | 5 +++++ src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ko.xlf | 5 +++++ src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pl.xlf | 5 +++++ src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pt-BR.xlf | 5 +++++ src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ru.xlf | 5 +++++ src/Aspire.Dashboard/Resources/xlf/ControlsStrings.tr.xlf | 5 +++++ .../Resources/xlf/ControlsStrings.zh-Hans.xlf | 5 +++++ .../Resources/xlf/ControlsStrings.zh-Hant.xlf | 5 +++++ .../Pages/ConsoleLogsTests.cs | 2 +- 20 files changed, 72 insertions(+), 13 deletions(-) rename src/Aspire.Dashboard/Components/Controls/{PauseResumeButton.razor => PauseIncomingDataSwitch.razor} (84%) rename src/Aspire.Dashboard/Components/Controls/{PauseResumeButton.razor.cs => PauseIncomingDataSwitch.razor.cs} (82%) diff --git a/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor b/src/Aspire.Dashboard/Components/Controls/PauseIncomingDataSwitch.razor similarity index 84% rename from src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor rename to src/Aspire.Dashboard/Components/Controls/PauseIncomingDataSwitch.razor index 5cb4f403e19..6aab1caf9de 100644 --- a/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor +++ b/src/Aspire.Dashboard/Components/Controls/PauseIncomingDataSwitch.razor @@ -3,8 +3,7 @@ + OnClick="@OnTogglePauseCoreAsync"> @if (IsPaused) { diff --git a/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor.cs b/src/Aspire.Dashboard/Components/Controls/PauseIncomingDataSwitch.razor.cs similarity index 82% rename from src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor.cs rename to src/Aspire.Dashboard/Components/Controls/PauseIncomingDataSwitch.razor.cs index 7c0c95443ae..3d04ab4ff97 100644 --- a/src/Aspire.Dashboard/Components/Controls/PauseResumeButton.razor.cs +++ b/src/Aspire.Dashboard/Components/Controls/PauseIncomingDataSwitch.razor.cs @@ -4,7 +4,7 @@ namespace Aspire.Dashboard.Components.Controls; -public partial class PauseResumeButton : ComponentBase +public partial class PauseIncomingDataSwitch : ComponentBase { [Parameter] public bool IsPaused { get; set; } @@ -12,9 +12,6 @@ public partial class PauseResumeButton : ComponentBase [Parameter] public EventCallback IsPausedChanged { get; set; } - [Parameter] - public bool Disabled { get; set; } - private async Task OnTogglePauseCoreAsync() { IsPaused = !IsPaused; diff --git a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor index 95c3f467d91..c9418cb83dd 100644 --- a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor +++ b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor @@ -29,7 +29,7 @@ - diff --git a/src/Aspire.Dashboard/Components/Pages/Metrics.razor b/src/Aspire.Dashboard/Components/Pages/Metrics.razor index 7e5329582c9..d64a01e6889 100644 --- a/src/Aspire.Dashboard/Components/Pages/Metrics.razor +++ b/src/Aspire.Dashboard/Components/Pages/Metrics.razor @@ -51,9 +51,7 @@ - + @if (!ViewportInformation.IsDesktop) { diff --git a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor index c00db59ec28..698e7d0f13c 100644 --- a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor +++ b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor @@ -40,7 +40,7 @@ - + - + Odebrat pro {0} + + Remove data + Remove data + + Details Podrobnosti diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.de.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.de.xlf index 7cd7b0a881b..a807ee0e10f 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.de.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.de.xlf @@ -107,6 +107,11 @@ Für {0} entfernen + + Remove data + Remove data + + Details Details diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.es.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.es.xlf index fd59c84aa25..d3636be990b 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.es.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.es.xlf @@ -107,6 +107,11 @@ Quitar para {0} + + Remove data + Remove data + + Details Detalles diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.fr.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.fr.xlf index 794327dbb20..c0fbf25e92b 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.fr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.fr.xlf @@ -107,6 +107,11 @@ Supprimer pour {0} + + Remove data + Remove data + + Details Détails diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.it.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.it.xlf index 3145362b13f..3a865553ed5 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.it.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.it.xlf @@ -107,6 +107,11 @@ Rimuovi per {0} + + Remove data + Remove data + + Details Dettagli diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ja.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ja.xlf index 06e45ae9c47..8d6d2027190 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ja.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ja.xlf @@ -107,6 +107,11 @@ {0} の削除 + + Remove data + Remove data + + Details 詳細 diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ko.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ko.xlf index ea9af5882bd..b47c3be003c 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ko.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ko.xlf @@ -107,6 +107,11 @@ {0} 제거 + + Remove data + Remove data + + Details 세부 정보 diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pl.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pl.xlf index 5797cd87eb0..59cf8ea2518 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pl.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pl.xlf @@ -107,6 +107,11 @@ Usuń dla {0} + + Remove data + Remove data + + Details Szczegóły diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pt-BR.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pt-BR.xlf index d386b8de82f..5f135a935f9 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pt-BR.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pt-BR.xlf @@ -107,6 +107,11 @@ Remover para {0} + + Remove data + Remove data + + Details Detalhes diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ru.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ru.xlf index ec1cf6cb21d..c9c772dce04 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ru.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ru.xlf @@ -107,6 +107,11 @@ Удалить для {0} + + Remove data + Remove data + + Details Сведения diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.tr.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.tr.xlf index 8b458cce4b2..1807258c4bf 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.tr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.tr.xlf @@ -107,6 +107,11 @@ Bu işlem için {0} + + Remove data + Remove data + + Details Ayrıntılar diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hans.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hans.xlf index 67ba0d68bda..543bea83031 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hans.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hans.xlf @@ -107,6 +107,11 @@ 删除 {0} + + Remove data + Remove data + + Details 详细信息 diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hant.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hant.xlf index 7b86333cf5f..ca3304775ee 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hant.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hant.xlf @@ -107,6 +107,11 @@ 拿掉 {0} + + Remove data + Remove data + + Details 詳細資料 diff --git a/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs b/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs index fd33530586d..056d72dac52 100644 --- a/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs +++ b/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs @@ -376,7 +376,7 @@ public void PauseResumeButton_TogglePauseResume_LogsPausedAndResumed() cut.WaitForState(() => instance.PageViewModel.SelectedResource == testResource); // Pause logs - var pauseResumeButton = cut.FindComponent(); + var pauseResumeButton = cut.FindComponent(); pauseResumeButton.Find("fluent-button").Click(); // Add a new log while paused From e49ca8c5b53ed229d15804f2fe87bbd4134585df Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Fri, 21 Mar 2025 15:35:53 -0400 Subject: [PATCH 15/35] add telemetry repository test, make console log pause range private --- .../Components/Pages/ConsoleLogs.razor.cs | 13 +- src/Aspire.Dashboard/Model/PauseManager.cs | 50 ++++++- .../Otlp/Storage/TelemetryRepository.cs | 9 +- .../TelemetryRepositoryTests.cs | 135 ++++++++++++++++++ 4 files changed, 188 insertions(+), 19 deletions(-) create mode 100644 tests/Aspire.Dashboard.Tests/TelemetryRepositoryTests/TelemetryRepositoryTests.cs diff --git a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs index 3beb5b895f6..94b5509f54b 100644 --- a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs @@ -485,7 +485,7 @@ private void LoadLogs(ConsoleLogsSubscription newConsoleLogsSubscription) var logEntry = logParser.CreateLogEntry(content, isErrorOutput); if (logEntry.Timestamp is not null && ((timestampFilterDate is not null && !(logEntry.Timestamp > timestampFilterDate)) - || PauseManager.ConsoleLogsPausedRanges.Any(range => range.IsOverlapping(logEntry.Timestamp.Value)))) + || PauseManager.IsConsoleLogFiltered(logEntry.Timestamp.Value))) { continue; } @@ -609,16 +609,7 @@ private async Task ClearConsoleLogs(ApplicationKey? key) private Task IsPausedChangedAsync(bool isPaused) { - PauseManager.ConsoleLogsPaused = isPaused; - if (isPaused) - { - PauseManager.ConsoleLogsPausedRanges.Add(new DateTimeRange(start: DateTime.UtcNow, end: null)); - } - else - { - PauseManager.ConsoleLogsPausedRanges.Last().End = DateTime.UtcNow; - } - + PauseManager.SetConsoleLogsPaused(isPaused); return Task.CompletedTask; } diff --git a/src/Aspire.Dashboard/Model/PauseManager.cs b/src/Aspire.Dashboard/Model/PauseManager.cs index 9d271924845..eabf1716fd5 100644 --- a/src/Aspire.Dashboard/Model/PauseManager.cs +++ b/src/Aspire.Dashboard/Model/PauseManager.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Immutable; +using System.Diagnostics; + namespace Aspire.Dashboard.Model; public sealed class PauseManager @@ -9,15 +12,50 @@ public sealed class PauseManager public bool TracesPaused { get; set; } public bool MetricsPaused { get; set; } - public bool ConsoleLogsPaused { get; set; } - public List ConsoleLogsPausedRanges { get; } = []; + public bool ConsoleLogsPaused { get; private set; } + + private ImmutableArray _consoleLogsPausedRanges = []; + + public bool IsConsoleLogFiltered(DateTime timestamp) + { + foreach (var range in _consoleLogsPausedRanges) + { + if (range.IsOverlapping(timestamp)) + { + return true; + } + } + + return false; + } + + public void SetConsoleLogsPaused(bool isPaused) + { + ConsoleLogsPaused = isPaused; + + ImmutableInterlocked.Update(ref _consoleLogsPausedRanges, ranges => + { + if (isPaused) + { + return ranges.Add(new DateTimeRange(Start: DateTime.UtcNow, End: null)); + } + else + { + Debug.Assert(ranges.Length > 0, "ConsoleLogsPausedRanges should not be empty when resuming."); + var lastRange = ranges.Last(); + if (lastRange.End is not null) + { + throw new InvalidOperationException("Last range end should be null when resuming."); + } + + return ranges.Replace(lastRange, lastRange with { End = DateTime.UtcNow }); + } + }); + } } -public class DateTimeRange(DateTime start, DateTime? end) +public record DateTimeRange(DateTime Start, DateTime? End) { - public DateTime Start { get; } = start; - public DateTime? End { get; set; } = end; - public bool IsOverlapping(DateTime date) { return date >= Start && (End is null || date <= End); diff --git a/src/Aspire.Dashboard/Otlp/Storage/TelemetryRepository.cs b/src/Aspire.Dashboard/Otlp/Storage/TelemetryRepository.cs index b375aff6d9f..1016b55a06a 100644 --- a/src/Aspire.Dashboard/Otlp/Storage/TelemetryRepository.cs +++ b/src/Aspire.Dashboard/Otlp/Storage/TelemetryRepository.cs @@ -26,6 +26,8 @@ namespace Aspire.Dashboard.Otlp.Storage; public sealed class TelemetryRepository { private readonly PauseManager _pauseManager; + private readonly ILogger _logger; + private readonly object _lock = new(); internal TimeSpan _subscriptionMinExecuteInterval = TimeSpan.FromMilliseconds(100); @@ -61,10 +63,10 @@ public sealed class TelemetryRepository public TelemetryRepository(ILoggerFactory loggerFactory, IOptions dashboardOptions, PauseManager pauseManager) { - var logger = loggerFactory.CreateLogger(typeof(TelemetryRepository)); + _logger = loggerFactory.CreateLogger(typeof(TelemetryRepository)); _otlpContext = new OtlpContext { - Logger = logger, + Logger = _logger, Options = dashboardOptions.Value.TelemetryLimits }; _pauseManager = pauseManager; @@ -276,6 +278,7 @@ public void AddLogs(AddContext context, RepeatedField resourceLogs { if (_pauseManager.StructuredLogsPaused) { + _logger.LogTrace("{LogCount} incoming structured log(s) was ignored because of an active pause.", resourceLogs.Count); return; } @@ -814,6 +817,7 @@ public void AddMetrics(AddContext context, RepeatedField resour { if (_pauseManager.MetricsPaused) { + _logger.LogTrace("{LogCount} incoming metric(s) was ignored because of an active pause.", resourceMetrics.Count); return; } @@ -841,6 +845,7 @@ public void AddTraces(AddContext context, RepeatedField resourceS { if (_pauseManager.TracesPaused) { + _logger.LogTrace("{LogCount} incoming trace(s) was ignored because of an active pause.", resourceSpans.Count); return; } diff --git a/tests/Aspire.Dashboard.Tests/TelemetryRepositoryTests/TelemetryRepositoryTests.cs b/tests/Aspire.Dashboard.Tests/TelemetryRepositoryTests/TelemetryRepositoryTests.cs new file mode 100644 index 00000000000..50ea580b111 --- /dev/null +++ b/tests/Aspire.Dashboard.Tests/TelemetryRepositoryTests/TelemetryRepositoryTests.cs @@ -0,0 +1,135 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Aspire.Dashboard.Model; +using Aspire.Dashboard.Otlp.Model; +using Aspire.Dashboard.Otlp.Storage; +using Google.Protobuf.Collections; +using OpenTelemetry.Proto.Logs.V1; +using OpenTelemetry.Proto.Metrics.V1; +using OpenTelemetry.Proto.Trace.V1; +using Xunit; + +using static Aspire.Tests.Shared.Telemetry.TelemetryTestHelpers; + +namespace Aspire.Dashboard.Tests.TelemetryRepositoryTests; + +public class TelemetryRepositoryTests +{ + [Fact] + public void AddData_WhilePaused_IsDiscarded() + { + // Arrange + var pauseManager = new PauseManager(); + var repository = CreateRepository(pauseManager: pauseManager); + using var subscription = repository.OnNewLogs(applicationKey: null, SubscriptionType.Other, () => Task.CompletedTask); + + // Act and assert + pauseManager.StructuredLogsPaused = true; + pauseManager.MetricsPaused = true; + pauseManager.TracesPaused = true; + AddLog(); + AddMetric(); + AddTrace(); + + var applicationKey = new ApplicationKey("resource", "resource"); + Assert.Empty(repository.GetLogs(new GetLogsContext { ApplicationKey = applicationKey, Count = 100, Filters = [], StartIndex = 0 }).Items); + Assert.Null(repository.GetApplication(applicationKey)); + Assert.Empty(repository.GetTraces(new GetTracesRequest { ApplicationKey = applicationKey, Count = 100, Filters = [], StartIndex = 0, FilterText = string.Empty }).PagedResult.Items); + + pauseManager.StructuredLogsPaused = false; + pauseManager.MetricsPaused = false; + pauseManager.TracesPaused = false; + + AddLog(); + AddMetric(); + AddTrace(); + Assert.Single(repository.GetLogs(new GetLogsContext { ApplicationKey = applicationKey, Count = 100, Filters = [], StartIndex = 0 }).Items); + var application = repository.GetApplication(applicationKey); + Assert.NotNull(application); + Assert.NotEmpty(application.GetInstrumentsSummary()); + Assert.Single(repository.GetTraces(new GetTracesRequest { ApplicationKey = applicationKey, Count = 100, Filters = [], StartIndex = 0, FilterText = string.Empty }).PagedResult.Items); + + void AddLog() + { + var addContext = new AddContext(); + repository.AddLogs(addContext, new RepeatedField() + { + new ResourceLogs + { + Resource = CreateResource(name: "resource", instanceId: "resource"), + ScopeLogs = + { + new ScopeLogs + { + Scope = CreateScope("TestLogger"), + LogRecords = + { + CreateLogRecord(time: DateTime.Now, message: "1", severity: SeverityNumber.Error), + } + } + } + } + }); + } + + void AddMetric() + { + var addContext = new AddContext(); + repository.AddMetrics(addContext, new RepeatedField() + { + new ResourceMetrics + { + Resource = CreateResource("resource", instanceId: "resource"), + ScopeMetrics = + { + new ScopeMetrics + { + Scope = CreateScope(name: "test-meter"), + Metrics = + { + CreateSumMetric(metricName: "test", startTime: DateTime.Now.AddMinutes(1)), + CreateSumMetric(metricName: "test", startTime: DateTime.Now.AddMinutes(2)), + CreateSumMetric(metricName: "test2", startTime: DateTime.Now.AddMinutes(1)), + } + }, + new ScopeMetrics + { + Scope = CreateScope(name: "test-meter2"), + Metrics = + { + CreateSumMetric(metricName: "test", startTime: DateTime.Now.AddMinutes(1)), + CreateHistogramMetric(metricName: "test2", startTime: DateTime.Now.AddMinutes(1)) + } + } + } + } + }); + } + + void AddTrace() + { + var addContext = new AddContext(); + repository.AddTraces(addContext, new RepeatedField() + { + new ResourceSpans + { + Resource = CreateResource("resource", instanceId: "resource"), + ScopeSpans = + { + new ScopeSpans + { + Scope = CreateScope(), + Spans = + { + CreateSpan(traceId: "1", spanId: "1-1", startTime: DateTime.Now.AddMinutes(1), endTime: DateTime.Now.AddMinutes(10)), + CreateSpan(traceId: "1", spanId: "1-2", startTime: DateTime.Now.AddMinutes(5), endTime: DateTime.Now.AddMinutes(10), parentSpanId: "1-1") + } + } + } + } + }); + } + } + +} From 97a34fcb9dea64acd2327cb133e510cd99480850 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Sat, 22 Mar 2025 01:00:46 -0400 Subject: [PATCH 16/35] Change button appearance, show pauses in the log viewer --- .../Components/Controls/LogViewer.razor | 67 +++++++++++++------ .../Components/Controls/LogViewer.razor.cs | 6 ++ .../Controls/PauseIncomingDataSwitch.razor | 2 +- .../Components/Pages/ConsoleLogs.razor | 43 ++++++------ .../Components/Pages/ConsoleLogs.razor.cs | 28 ++++++-- .../Components/Pages/Metrics.razor | 3 +- .../Components/Pages/StructuredLogs.razor | 3 +- .../Components/Pages/Traces.razor | 3 +- src/Aspire.Dashboard/Model/PauseManager.cs | 54 ++++++++++++--- src/Shared/ConsoleLogs/LogEntries.cs | 16 +++-- src/Shared/ConsoleLogs/LogEntry.cs | 12 +++- 11 files changed, 166 insertions(+), 71 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor index 62200f55cd8..fe2c28727ab 100644 --- a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor +++ b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor @@ -1,6 +1,5 @@ @namespace Aspire.Dashboard.Components @using System.Globalization -@using Aspire.Dashboard.Model @using Aspire.Dashboard.Utils @using Aspire.Hosting.ConsoleLogs @inject IJSRuntime JS @@ -11,29 +10,53 @@ @if (LogEntries is { } logEntries) { -
-
- - @context.LineNumber - - @{ - var hasPrefix = false; - } - @if (ShowTimestamp && context.Timestamp is { } timestamp) - { - hasPrefix = true; - @GetDisplayTimestamp(timestamp) - } - @if (context.Type == LogEntryType.Error) - { - hasPrefix = true; - stderr - } - @((MarkupString)((hasPrefix ? " " : string.Empty) + (context.Content ?? string.Empty))) + @if (context is { Type: LogEntryType.Pause, Timestamp: { } startTimestamp} && PauseManager.TryGetConsoleLogPause(startTimestamp, out var pause)) + { + // If this is a previous pause but no logs were obtained during the pause, we don't need to show anything. + if (!pause.HasFilteredLogsForApplication(ApplicationName, out var count) && pause.End is not null) + { + return; + } + + + var text = pause.End is null + ? string.Format( + "", + count) + : string.Format( + "", + FormatHelpers.FormatDateTime(TimeProvider, startTimestamp, MillisecondsDisplay.Full, CultureInfo.CurrentCulture), + FormatHelpers.FormatDateTime(TimeProvider, pause.End.Value, MillisecondsDisplay.Full, CultureInfo.CurrentCulture), + count); + + @text + } + else + { +
+
+ + @context.LineNumber + + @{ + var hasPrefix = false; + } + @if (ShowTimestamp && context.Timestamp is { } timestamp) + { + hasPrefix = true; + @GetDisplayTimestamp(timestamp) + } + @if (context.Type == LogEntryType.Error) + { + hasPrefix = true; + stderr + } + @((MarkupString)((hasPrefix ? " " : string.Empty) + (context.Content ?? string.Empty))) + - +
-
+ } }
diff --git a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs index fcc9a94167c..bddc9331902 100644 --- a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs +++ b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.cs @@ -27,6 +27,9 @@ public sealed partial class LogViewer [Inject] public required ILogger Logger { get; init; } + [Inject] + public required PauseManager PauseManager { get; init; } + [Parameter] public LogEntries? LogEntries { get; set; } = null!; @@ -36,6 +39,9 @@ public sealed partial class LogViewer [Parameter] public bool IsTimestampUtc { get; set; } + [Parameter] + public string? ApplicationName { get; set; } + protected override void OnParametersSet() { if (_logEntries != LogEntries) diff --git a/src/Aspire.Dashboard/Components/Controls/PauseIncomingDataSwitch.razor b/src/Aspire.Dashboard/Components/Controls/PauseIncomingDataSwitch.razor index 6aab1caf9de..de03ac0948d 100644 --- a/src/Aspire.Dashboard/Components/Controls/PauseIncomingDataSwitch.razor +++ b/src/Aspire.Dashboard/Components/Controls/PauseIncomingDataSwitch.razor @@ -1,7 +1,7 @@ @using Aspire.Dashboard.Resources @inject IStringLocalizer Loc - @if (IsPaused) diff --git a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor index c9418cb83dd..6f93953b635 100644 --- a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor +++ b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor @@ -27,28 +27,30 @@ @bind-SelectedResource:after="HandleSelectedOptionChangedAsync" LabelClass="toolbar-left" /> + - - - @foreach (var command in _highlightedCommands) + @if (_highlightedCommands.Count > 0) { - - @if (!string.IsNullOrEmpty(command.IconName) && CommandViewModel.ResolveIconName(command.IconName, command.IconVariant) is { } icon) - { - - } - else - { - @command.DisplayName - } - + Commands + + @foreach (var command in _highlightedCommands) + { + + @if (!string.IsNullOrEmpty(command.IconName) && CommandViewModel.ResolveIconName(command.IconName, command.IconVariant) is { } icon) + { + + } + else + { + @command.DisplayName + } + + } } @if (_resourceMenuItems.Count > 0) @@ -89,7 +91,8 @@ + IsTimestampUtc="@_isTimestampUtc" + ApplicationName="@PageViewModel.SelectedResource?.Name"/>
diff --git a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs index 94b5509f54b..6cc17836f8b 100644 --- a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs @@ -466,6 +466,12 @@ private void LoadLogs(ConsoleLogsSubscription newConsoleLogsSubscription) timestampFilterDate = _consoleLogFilters.FilterAllLogsDate; } + // Add entries for all previous pauses. + foreach (var pauseStart in PauseManager.ConsoleLogsPausedRanges.Keys) + { + _logEntries.InsertSorted(LogEntry.CreatePause(pauseStart)); + } + var logParser = new LogParser(); await foreach (var batch in subscription.ConfigureAwait(true)) { @@ -477,15 +483,18 @@ private void LoadLogs(ConsoleLogsSubscription newConsoleLogsSubscription) foreach (var (lineNumber, content, isErrorOutput) in batch) { // Set the base line number using the reported line number of the first log line. - if (_logEntries.EntriesCount == 0) + if (_logEntries.BaseLineNumber is null && !_logEntries.GetEntries().Any(e => e.Type is not LogEntryType.Pause)) { _logEntries.BaseLineNumber = lineNumber; } var logEntry = logParser.CreateLogEntry(content, isErrorOutput); - if (logEntry.Timestamp is not null && - ((timestampFilterDate is not null && !(logEntry.Timestamp > timestampFilterDate)) - || PauseManager.IsConsoleLogFiltered(logEntry.Timestamp.Value))) + if (logEntry.Timestamp is not null && timestampFilterDate is not null && !(logEntry.Timestamp > timestampFilterDate)) + { + continue; + } + + if (logEntry.Timestamp is not null && PauseManager.IsConsoleLogFiltered(logEntry.Timestamp.Value, newConsoleLogsSubscription.Name)) { continue; } @@ -609,7 +618,16 @@ private async Task ClearConsoleLogs(ApplicationKey? key) private Task IsPausedChangedAsync(bool isPaused) { - PauseManager.SetConsoleLogsPaused(isPaused); + var timestamp = DateTime.UtcNow; + + if (isPaused) + { + // Each pause has its own entry in the log entries and will be displayed + // unless it ended with 0 logs filtered out during + _logEntries.InsertSorted(LogEntry.CreatePause(timestamp)); + } + + PauseManager.SetConsoleLogsPaused(isPaused, timestamp); return Task.CompletedTask; } diff --git a/src/Aspire.Dashboard/Components/Pages/Metrics.razor b/src/Aspire.Dashboard/Components/Pages/Metrics.razor index d64a01e6889..05adef36504 100644 --- a/src/Aspire.Dashboard/Components/Pages/Metrics.razor +++ b/src/Aspire.Dashboard/Components/Pages/Metrics.razor @@ -48,11 +48,10 @@ CanSelectGrouping="true" LabelClass="toolbar-left" /> + - - @if (!ViewportInformation.IsDesktop) { diff --git a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor index 698e7d0f13c..c4907158e1f 100644 --- a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor +++ b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor @@ -37,11 +37,10 @@ CanSelectGrouping="true" LabelClass="toolbar-left" /> + - - + - - _consoleLogsPausedRanges = []; + private static readonly IComparer s_startTimeComparer = Comparer.Create((x, y) => x.CompareTo(y)); + private ImmutableSortedDictionary _consoleLogsPausedRanges = ImmutableSortedDictionary.Create(s_startTimeComparer); + public ImmutableSortedDictionary ConsoleLogsPausedRanges => _consoleLogsPausedRanges; - public bool IsConsoleLogFiltered(DateTime timestamp) + public bool TryGetConsoleLogPause(DateTime startTime, [NotNullWhen(true)] out ConsoleLogPause? pause) { - foreach (var range in _consoleLogsPausedRanges) + if (_consoleLogsPausedRanges.TryGetValue(startTime, out var range)) + { + pause = range; + return true; + } + + pause = null; + return false; + } + + public bool IsConsoleLogFiltered(DateTime timestamp, string application) + { + ConsoleLogPause? foundRange = null; + + foreach (var range in _consoleLogsPausedRanges.Values) { if (range.IsOverlapping(timestamp)) { - return true; + foundRange = range; + break; } } - return false; + if (foundRange is not null) + { + ImmutableInterlocked.Update( + ref _consoleLogsPausedRanges, + ranges => ranges.SetItem(foundRange.Start, + foundRange with { FilteredLogsByApplication = foundRange.FilteredLogsByApplication.SetItem(application, foundRange.FilteredLogsByApplication.GetValueOrDefault(application) + 1) })); + } + + return foundRange is not null; } - public void SetConsoleLogsPaused(bool isPaused) + public void SetConsoleLogsPaused(bool isPaused, DateTime timestamp) { ConsoleLogsPaused = isPaused; @@ -37,25 +63,31 @@ public void SetConsoleLogsPaused(bool isPaused) { if (isPaused) { - return ranges.Add(new DateTimeRange(Start: DateTime.UtcNow, End: null)); + return ranges.Add(timestamp, new ConsoleLogPause(Start: timestamp, End: null, FilteredLogsByApplication: ImmutableDictionary.Empty)); } else { - Debug.Assert(ranges.Length > 0, "ConsoleLogsPausedRanges should not be empty when resuming."); - var lastRange = ranges.Last(); + Debug.Assert(ranges.Count > 0, "ConsoleLogsPausedRanges should not be empty when resuming."); + var lastRange = ranges.Values.Last(); if (lastRange.End is not null) { throw new InvalidOperationException("Last range end should be null when resuming."); } - return ranges.Replace(lastRange, lastRange with { End = DateTime.UtcNow }); + return ranges.SetItem(lastRange.Start, lastRange with { End = DateTime.UtcNow }); } }); } } -public record DateTimeRange(DateTime Start, DateTime? End) +public record ConsoleLogPause(DateTime Start, DateTime? End, ImmutableDictionary FilteredLogsByApplication) { + public bool HasFilteredLogsForApplication(string? application, out int count) + { + count = 0; + return application is not null && FilteredLogsByApplication.TryGetValue(application, out count) && count > 0; + } + public bool IsOverlapping(DateTime date) { return date >= Start && (End is null || date <= End); diff --git a/src/Shared/ConsoleLogs/LogEntries.cs b/src/Shared/ConsoleLogs/LogEntries.cs index 798e03f5c18..9915dddb325 100644 --- a/src/Shared/ConsoleLogs/LogEntries.cs +++ b/src/Shared/ConsoleLogs/LogEntries.cs @@ -33,11 +33,11 @@ public void Clear() BaseLineNumber = null; } - public void InsertSorted(LogEntry logLine) + public void InsertSorted(LogEntry logLine, int skipLineCount = 1) { Debug.Assert(logLine.Timestamp == null || logLine.Timestamp.Value.Kind == DateTimeKind.Utc, "Timestamp should always be UTC."); - InsertSortedCore(logLine); + InsertSortedCore(logLine, skipLineCount); // Verify log entry order is correct in debug builds. VerifyLogEntryOrder(); @@ -64,10 +64,10 @@ private void VerifyLogEntryOrder() } } - private void InsertSortedCore(LogEntry logEntry) + private void InsertSortedCore(LogEntry logEntry, int skipLineCount) { // If there is no timestamp then add to the end. - if (logEntry.Timestamp == null) + if (logEntry.Timestamp == null || logEntry.Type is LogEntryType.Pause) { InsertAt(_logEntries.Count); return; @@ -128,6 +128,12 @@ private void InsertSortedCore(LogEntry logEntry) void InsertAt(int index) { + if (logEntry.Type is LogEntryType.Pause) + { + _logEntries.Insert(index, logEntry); + return; + } + // Set the line number of the log entry. if (index == 0) { @@ -136,7 +142,7 @@ void InsertAt(int index) } else { - logEntry.LineNumber = _logEntries[index - 1].LineNumber + 1; + logEntry.LineNumber = _logEntries[index - 1].LineNumber + skipLineCount; } if (_earliestTimestampIndex == null && logEntry.Timestamp != null) diff --git a/src/Shared/ConsoleLogs/LogEntry.cs b/src/Shared/ConsoleLogs/LogEntry.cs index edb00a8bdda..13d4833266f 100644 --- a/src/Shared/ConsoleLogs/LogEntry.cs +++ b/src/Shared/ConsoleLogs/LogEntry.cs @@ -22,6 +22,15 @@ internal sealed class LogEntry public LogEntryType Type { get; private set; } = LogEntryType.Default; public int LineNumber { get; set; } + public static LogEntry CreatePause(DateTime? timestamp) + { + return new LogEntry + { + Timestamp = timestamp, + Type = LogEntryType.Pause + }; + } + public static LogEntry Create(DateTime? timestamp, string logMessage, bool isErrorMessage) { return Create(timestamp, logMessage, logMessage, isErrorMessage); @@ -46,5 +55,6 @@ internal enum LogEntryType #endif { Default, - Error + Error, + Pause } From e0002238b83b5c88abf7e740ee7d15aba591dc8c Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Sat, 22 Mar 2025 01:25:39 -0400 Subject: [PATCH 17/35] clean up pause display --- .../Components/Controls/LogViewer.razor | 24 ++++++++++++------- .../Resources/ControlsStrings.Designer.cs | 12 ++++++++++ .../Resources/ControlsStrings.resx | 8 +++++++ .../Resources/xlf/ControlsStrings.cs.xlf | 10 ++++++++ .../Resources/xlf/ControlsStrings.de.xlf | 10 ++++++++ .../Resources/xlf/ControlsStrings.es.xlf | 10 ++++++++ .../Resources/xlf/ControlsStrings.fr.xlf | 10 ++++++++ .../Resources/xlf/ControlsStrings.it.xlf | 10 ++++++++ .../Resources/xlf/ControlsStrings.ja.xlf | 10 ++++++++ .../Resources/xlf/ControlsStrings.ko.xlf | 10 ++++++++ .../Resources/xlf/ControlsStrings.pl.xlf | 10 ++++++++ .../Resources/xlf/ControlsStrings.pt-BR.xlf | 10 ++++++++ .../Resources/xlf/ControlsStrings.ru.xlf | 10 ++++++++ .../Resources/xlf/ControlsStrings.tr.xlf | 10 ++++++++ .../Resources/xlf/ControlsStrings.zh-Hans.xlf | 10 ++++++++ .../Resources/xlf/ControlsStrings.zh-Hant.xlf | 10 ++++++++ 16 files changed, 166 insertions(+), 8 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor index fe2c28727ab..2f9fb3daaa7 100644 --- a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor +++ b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor @@ -1,8 +1,12 @@ @namespace Aspire.Dashboard.Components @using System.Globalization +@using Aspire.Dashboard.Resources @using Aspire.Dashboard.Utils @using Aspire.Hosting.ConsoleLogs + @inject IJSRuntime JS +@inject IStringLocalizer Loc + @implements IAsyncDisposable
@@ -18,18 +22,22 @@ return; } - var text = pause.End is null - ? string.Format( - "", - count) + ? string.Format(Loc[nameof(ControlsStrings.ConsoleLogsPauseActive)], count) : string.Format( - "", - FormatHelpers.FormatDateTime(TimeProvider, startTimestamp, MillisecondsDisplay.Full, CultureInfo.CurrentCulture), - FormatHelpers.FormatDateTime(TimeProvider, pause.End.Value, MillisecondsDisplay.Full, CultureInfo.CurrentCulture), + Loc[nameof(ControlsStrings.ConsoleLogsPauseDetails)], + FormatHelpers.FormatTimeWithOptionalDate(TimeProvider, startTimestamp, MillisecondsDisplay.Truncated), + FormatHelpers.FormatTimeWithOptionalDate(TimeProvider, pause.End.Value, MillisecondsDisplay.Truncated), count); - @text +
+
+
+ + @text +
+
+
} else { diff --git a/src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs b/src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs index df74a451ca1..8fa25fab23b 100644 --- a/src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs +++ b/src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs @@ -728,5 +728,17 @@ public static string ClearSignalsButtonTitle { return ResourceManager.GetString("ClearSignalsButtonTitle", resourceCulture); } } + + public static string ConsoleLogsPauseActive { + get { + return ResourceManager.GetString("ConsoleLogsPauseActive", resourceCulture); + } + } + + public static string ConsoleLogsPauseDetails { + get { + return ResourceManager.GetString("ConsoleLogsPauseDetails", resourceCulture); + } + } } } diff --git a/src/Aspire.Dashboard/Resources/ControlsStrings.resx b/src/Aspire.Dashboard/Resources/ControlsStrings.resx index e06491b4167..1735f55e5a2 100644 --- a/src/Aspire.Dashboard/Resources/ControlsStrings.resx +++ b/src/Aspire.Dashboard/Resources/ControlsStrings.resx @@ -472,4 +472,12 @@ Remove data + + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.cs.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.cs.xlf index d37e4b09457..283b7aa6f9f 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.cs.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.cs.xlf @@ -112,6 +112,16 @@ Remove data + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Details Podrobnosti diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.de.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.de.xlf index a807ee0e10f..5c1c63ebfb7 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.de.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.de.xlf @@ -112,6 +112,16 @@ Remove data + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Details Details diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.es.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.es.xlf index d3636be990b..3ef33bdc204 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.es.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.es.xlf @@ -112,6 +112,16 @@ Remove data + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Details Detalles diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.fr.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.fr.xlf index c0fbf25e92b..eab39c8d01d 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.fr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.fr.xlf @@ -112,6 +112,16 @@ Remove data + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Details Détails diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.it.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.it.xlf index 3a865553ed5..e307d99f767 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.it.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.it.xlf @@ -112,6 +112,16 @@ Remove data + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Details Dettagli diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ja.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ja.xlf index 8d6d2027190..ab54a52998b 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ja.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ja.xlf @@ -112,6 +112,16 @@ Remove data + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Details 詳細 diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ko.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ko.xlf index b47c3be003c..215e5694870 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ko.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ko.xlf @@ -112,6 +112,16 @@ Remove data + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Details 세부 정보 diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pl.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pl.xlf index 59cf8ea2518..9bfc849891a 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pl.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pl.xlf @@ -112,6 +112,16 @@ Remove data + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Details Szczegóły diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pt-BR.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pt-BR.xlf index 5f135a935f9..7e295d9b29a 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pt-BR.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pt-BR.xlf @@ -112,6 +112,16 @@ Remove data + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Details Detalhes diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ru.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ru.xlf index c9c772dce04..54cadf3c961 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ru.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ru.xlf @@ -112,6 +112,16 @@ Remove data + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Details Сведения diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.tr.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.tr.xlf index 1807258c4bf..da13f32fb00 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.tr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.tr.xlf @@ -112,6 +112,16 @@ Remove data + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Details Ayrıntılar diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hans.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hans.xlf index 543bea83031..00dee73aa11 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hans.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hans.xlf @@ -112,6 +112,16 @@ Remove data + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Details 详细信息 diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hant.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hant.xlf index ca3304775ee..16581d8d0d8 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hant.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hant.xlf @@ -112,6 +112,16 @@ Remove data + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Details 詳細資料 From efc0a2c9efdc7e5bab47d0e985bff40df20263bd Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Sat, 22 Mar 2025 01:59:04 -0400 Subject: [PATCH 18/35] Move 2 strings to consolelogs.resx, add a few tests --- .../Components/Controls/LogViewer.razor | 8 +- .../Resources/ConsoleLogs.Designer.cs | 168 ++++++------------ .../Resources/ConsoleLogs.resx | 8 + .../Resources/ControlsStrings.Designer.cs | 12 -- .../Resources/ControlsStrings.resx | 8 - .../Resources/xlf/ConsoleLogs.cs.xlf | 10 ++ .../Resources/xlf/ConsoleLogs.de.xlf | 10 ++ .../Resources/xlf/ConsoleLogs.es.xlf | 10 ++ .../Resources/xlf/ConsoleLogs.fr.xlf | 10 ++ .../Resources/xlf/ConsoleLogs.it.xlf | 10 ++ .../Resources/xlf/ConsoleLogs.ja.xlf | 10 ++ .../Resources/xlf/ConsoleLogs.ko.xlf | 10 ++ .../Resources/xlf/ConsoleLogs.pl.xlf | 10 ++ .../Resources/xlf/ConsoleLogs.pt-BR.xlf | 10 ++ .../Resources/xlf/ConsoleLogs.ru.xlf | 10 ++ .../Resources/xlf/ConsoleLogs.tr.xlf | 10 ++ .../Resources/xlf/ConsoleLogs.zh-Hans.xlf | 10 ++ .../Resources/xlf/ConsoleLogs.zh-Hant.xlf | 10 ++ .../Resources/xlf/ControlsStrings.cs.xlf | 10 -- .../Resources/xlf/ControlsStrings.de.xlf | 10 -- .../Resources/xlf/ControlsStrings.es.xlf | 10 -- .../Resources/xlf/ControlsStrings.fr.xlf | 10 -- .../Resources/xlf/ControlsStrings.it.xlf | 10 -- .../Resources/xlf/ControlsStrings.ja.xlf | 10 -- .../Resources/xlf/ControlsStrings.ko.xlf | 10 -- .../Resources/xlf/ControlsStrings.pl.xlf | 10 -- .../Resources/xlf/ControlsStrings.pt-BR.xlf | 10 -- .../Resources/xlf/ControlsStrings.ru.xlf | 10 -- .../Resources/xlf/ControlsStrings.tr.xlf | 10 -- .../Resources/xlf/ControlsStrings.zh-Hans.xlf | 10 -- .../Resources/xlf/ControlsStrings.zh-Hant.xlf | 10 -- .../Pages/ConsoleLogsTests.cs | 26 ++- .../ConsoleLogsTests/LogEntriesTests.cs | 42 +++++ 33 files changed, 261 insertions(+), 271 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor index 2f9fb3daaa7..1d26b359432 100644 --- a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor +++ b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor @@ -5,7 +5,7 @@ @using Aspire.Hosting.ConsoleLogs @inject IJSRuntime JS -@inject IStringLocalizer Loc +@inject IStringLocalizer Loc @implements IAsyncDisposable @@ -23,9 +23,9 @@ } var text = pause.End is null - ? string.Format(Loc[nameof(ControlsStrings.ConsoleLogsPauseActive)], count) + ? string.Format(Loc[nameof(ConsoleLogs.ConsoleLogsPauseActive)], count) : string.Format( - Loc[nameof(ControlsStrings.ConsoleLogsPauseDetails)], + Loc[nameof(ConsoleLogs.ConsoleLogsPauseDetails)], FormatHelpers.FormatTimeWithOptionalDate(TimeProvider, startTimestamp, MillisecondsDisplay.Truncated), FormatHelpers.FormatTimeWithOptionalDate(TimeProvider, pause.End.Value, MillisecondsDisplay.Truncated), count); @@ -34,7 +34,7 @@
- @text + @text
diff --git a/src/Aspire.Dashboard/Resources/ConsoleLogs.Designer.cs b/src/Aspire.Dashboard/Resources/ConsoleLogs.Designer.cs index c94c8871dc0..76f02420863 100644 --- a/src/Aspire.Dashboard/Resources/ConsoleLogs.Designer.cs +++ b/src/Aspire.Dashboard/Resources/ConsoleLogs.Designer.cs @@ -11,46 +11,32 @@ namespace Aspire.Dashboard.Resources { using System; - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class ConsoleLogs { - private static global::System.Resources.ResourceManager resourceMan; + private static System.Resources.ResourceManager resourceMan; - private static global::System.Globalization.CultureInfo resourceCulture; + private static System.Globalization.CultureInfo resourceCulture; - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal ConsoleLogs() { } - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Resources.ResourceManager ResourceManager { get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Aspire.Dashboard.Resources.ConsoleLogs", typeof(ConsoleLogs).Assembly); + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Aspire.Dashboard.Resources.ConsoleLogs", typeof(ConsoleLogs).Assembly); resourceMan = temp; } return resourceMan; } } - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -59,165 +45,123 @@ internal ConsoleLogs() { } } - /// - /// Looks up a localized string similar to Failed to initialize. - /// - public static string ConsoleLogsFailedToInitialize { + public static string ConsoleLogsHeader { get { - return ResourceManager.GetString("ConsoleLogsFailedToInitialize", resourceCulture); + return ResourceManager.GetString("ConsoleLogsHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Finished watching logs. - /// - public static string ConsoleLogsFinishedWatchingLogs { + public static string ConsoleLogsSelectResourceToolbar { get { - return ResourceManager.GetString("ConsoleLogsFinishedWatchingLogs", resourceCulture); + return ResourceManager.GetString("ConsoleLogsSelectResourceToolbar", resourceCulture); } } - /// - /// Looks up a localized string similar to Console logs. - /// - public static string ConsoleLogsHeader { + public static string ConsoleLogsPageTitle { get { - return ResourceManager.GetString("ConsoleLogsHeader", resourceCulture); + return ResourceManager.GetString("ConsoleLogsPageTitle", resourceCulture); } } - /// - /// Looks up a localized string similar to Initializing log viewer.... - /// public static string ConsoleLogsInitializingLogViewer { get { return ResourceManager.GetString("ConsoleLogsInitializingLogViewer", resourceCulture); } } - /// - /// Looks up a localized string similar to Loading resources .... - /// - public static string ConsoleLogsLoadingResources { + public static string ConsoleLogsLogsNotYetAvailable { get { - return ResourceManager.GetString("ConsoleLogsLoadingResources", resourceCulture); + return ResourceManager.GetString("ConsoleLogsLogsNotYetAvailable", resourceCulture); } } - /// - /// Looks up a localized string similar to Logs not yet available. - /// - public static string ConsoleLogsLogsNotYetAvailable { + public static string ConsoleLogsWatchingLogs { get { - return ResourceManager.GetString("ConsoleLogsLogsNotYetAvailable", resourceCulture); + return ResourceManager.GetString("ConsoleLogsWatchingLogs", resourceCulture); + } + } + + public static string ConsoleLogsFailedToInitialize { + get { + return ResourceManager.GetString("ConsoleLogsFailedToInitialize", resourceCulture); + } + } + + public static string ConsoleLogsFinishedWatchingLogs { + get { + return ResourceManager.GetString("ConsoleLogsFinishedWatchingLogs", resourceCulture); + } + } + + public static string ConsoleLogsLoadingResources { + get { + return ResourceManager.GetString("ConsoleLogsLoadingResources", resourceCulture); } } - /// - /// Looks up a localized string similar to No resource selected. - /// public static string ConsoleLogsNoResourceSelected { get { return ResourceManager.GetString("ConsoleLogsNoResourceSelected", resourceCulture); } } - /// - /// Looks up a localized string similar to {0} console logs. - /// - public static string ConsoleLogsPageTitle { + public static string ConsoleLogsUnknownState { get { - return ResourceManager.GetString("ConsoleLogsPageTitle", resourceCulture); + return ResourceManager.GetString("ConsoleLogsUnknownState", resourceCulture); } } - /// - /// Looks up a localized string similar to Resource commands. - /// - public static string ConsoleLogsResourceCommands { + public static string LogStatusLabel { get { - return ResourceManager.GetString("ConsoleLogsResourceCommands", resourceCulture); + return ResourceManager.GetString("LogStatusLabel", resourceCulture); } } - /// - /// Looks up a localized string similar to Select resource. - /// - public static string ConsoleLogsSelectResourceToolbar { + public static string DownloadLogs { get { - return ResourceManager.GetString("ConsoleLogsSelectResourceToolbar", resourceCulture); + return ResourceManager.GetString("DownloadLogs", resourceCulture); } } - /// - /// Looks up a localized string similar to Console logs settings. - /// public static string ConsoleLogsSettings { get { return ResourceManager.GetString("ConsoleLogsSettings", resourceCulture); } } - /// - /// Looks up a localized string similar to Hide timestamps. - /// - public static string ConsoleLogsTimestampHide { + public static string ConsoleLogsResourceCommands { get { - return ResourceManager.GetString("ConsoleLogsTimestampHide", resourceCulture); + return ResourceManager.GetString("ConsoleLogsResourceCommands", resourceCulture); } } - /// - /// Looks up a localized string similar to Show timestamps. - /// public static string ConsoleLogsTimestampShow { get { return ResourceManager.GetString("ConsoleLogsTimestampShow", resourceCulture); } } - /// - /// Looks up a localized string similar to UTC timestamps. - /// - public static string ConsoleLogsTimestampShowUtc { - get { - return ResourceManager.GetString("ConsoleLogsTimestampShowUtc", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unknown state. - /// - public static string ConsoleLogsUnknownState { + public static string ConsoleLogsTimestampHide { get { - return ResourceManager.GetString("ConsoleLogsUnknownState", resourceCulture); + return ResourceManager.GetString("ConsoleLogsTimestampHide", resourceCulture); } } - /// - /// Looks up a localized string similar to Watching logs.... - /// - public static string ConsoleLogsWatchingLogs { + public static string ConsoleLogsTimestampShowUtc { get { - return ResourceManager.GetString("ConsoleLogsWatchingLogs", resourceCulture); + return ResourceManager.GetString("ConsoleLogsTimestampShowUtc", resourceCulture); } } - /// - /// Looks up a localized string similar to Download logs. - /// - public static string DownloadLogs { + public static string ConsoleLogsPauseActive { get { - return ResourceManager.GetString("DownloadLogs", resourceCulture); + return ResourceManager.GetString("ConsoleLogsPauseActive", resourceCulture); } } - /// - /// Looks up a localized string similar to Service log status. - /// - public static string LogStatusLabel { + public static string ConsoleLogsPauseDetails { get { - return ResourceManager.GetString("LogStatusLabel", resourceCulture); + return ResourceManager.GetString("ConsoleLogsPauseDetails", resourceCulture); } } } diff --git a/src/Aspire.Dashboard/Resources/ConsoleLogs.resx b/src/Aspire.Dashboard/Resources/ConsoleLogs.resx index aa6b44339d9..7f85d5dada2 100644 --- a/src/Aspire.Dashboard/Resources/ConsoleLogs.resx +++ b/src/Aspire.Dashboard/Resources/ConsoleLogs.resx @@ -172,4 +172,12 @@ UTC timestamps + + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + diff --git a/src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs b/src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs index 8fa25fab23b..df74a451ca1 100644 --- a/src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs +++ b/src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs @@ -728,17 +728,5 @@ public static string ClearSignalsButtonTitle { return ResourceManager.GetString("ClearSignalsButtonTitle", resourceCulture); } } - - public static string ConsoleLogsPauseActive { - get { - return ResourceManager.GetString("ConsoleLogsPauseActive", resourceCulture); - } - } - - public static string ConsoleLogsPauseDetails { - get { - return ResourceManager.GetString("ConsoleLogsPauseDetails", resourceCulture); - } - } } } diff --git a/src/Aspire.Dashboard/Resources/ControlsStrings.resx b/src/Aspire.Dashboard/Resources/ControlsStrings.resx index 1735f55e5a2..e06491b4167 100644 --- a/src/Aspire.Dashboard/Resources/ControlsStrings.resx +++ b/src/Aspire.Dashboard/Resources/ControlsStrings.resx @@ -472,12 +472,4 @@ Remove data - - <Currently paused log capture, {0} entries filtered out> - {0} is a number - - - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number - diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.cs.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.cs.xlf index bd2f301662c..037bf56f672 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.cs.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.cs.xlf @@ -42,6 +42,16 @@ Protokoly konzoly aplikace {0} {0} is an application name + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Resource commands Příkazy prostředku diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.de.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.de.xlf index dee85e2b648..2a60f7b389f 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.de.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.de.xlf @@ -42,6 +42,16 @@ {0} Konsolenprotokolle {0} is an application name + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Resource commands Ressourcenbefehle diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.es.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.es.xlf index 2c187952764..cf35ea0e091 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.es.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.es.xlf @@ -42,6 +42,16 @@ Registros de consola de {0} {0} is an application name + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Resource commands Comandos de recursos diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.fr.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.fr.xlf index 9c9ba25c1f1..a2fe81b3633 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.fr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.fr.xlf @@ -42,6 +42,16 @@ Journaux de console {0} {0} is an application name + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Resource commands Commandes de ressource diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.it.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.it.xlf index 73979a9b3b6..9c8f0a23bd6 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.it.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.it.xlf @@ -42,6 +42,16 @@ {0} log della console {0} is an application name + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Resource commands Comandi risorsa diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ja.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ja.xlf index 482954299c1..e8cbe0dc4b7 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ja.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ja.xlf @@ -42,6 +42,16 @@ {0} のコンソール ログ {0} is an application name + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Resource commands リソース コマンド diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ko.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ko.xlf index fd364868690..08e2a797351 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ko.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ko.xlf @@ -42,6 +42,16 @@ {0} 콘솔 로그 {0} is an application name + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Resource commands 리소스 명령 diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pl.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pl.xlf index 39a58a31a7d..ccc600cc41b 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pl.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pl.xlf @@ -42,6 +42,16 @@ Dzienniki konsoli: {0} {0} is an application name + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Resource commands Polecenia zasobów diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pt-BR.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pt-BR.xlf index 17820d0c0f3..f9a48d2a0ee 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pt-BR.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pt-BR.xlf @@ -42,6 +42,16 @@ {0} logs do console {0} is an application name + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Resource commands Comandos de recursos diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ru.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ru.xlf index 8f1ff6756ef..cdd17d99504 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ru.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ru.xlf @@ -42,6 +42,16 @@ Журналов консоли: {0} {0} is an application name + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Resource commands Команды ресурсов diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.tr.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.tr.xlf index 8d448485be8..f687d072911 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.tr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.tr.xlf @@ -42,6 +42,16 @@ {0} konsol günlükleri {0} is an application name + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Resource commands Kaynak komutları diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hans.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hans.xlf index bccc47b481e..a2ed65e81a2 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hans.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hans.xlf @@ -42,6 +42,16 @@ {0} 控制台日志 {0} is an application name + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Resource commands 资源命令 diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hant.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hant.xlf index b1bfb6d86ad..bbf4ab0a593 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hant.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hant.xlf @@ -42,6 +42,16 @@ {0} 主控台記錄 {0} is an application name + + <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} entries filtered out> + {0} is a number + + + <Log capture paused between {0} and {1} {2} log entries filtered out> + <Log capture paused between {0} and {1} {2} log entries filtered out> + {0} is a date, {1} is a date, {2} is a number + Resource commands 資源命令 diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.cs.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.cs.xlf index 283b7aa6f9f..d37e4b09457 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.cs.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.cs.xlf @@ -112,16 +112,6 @@ Remove data - - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> - {0} is a number - - - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number - Details Podrobnosti diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.de.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.de.xlf index 5c1c63ebfb7..a807ee0e10f 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.de.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.de.xlf @@ -112,16 +112,6 @@ Remove data - - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> - {0} is a number - - - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number - Details Details diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.es.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.es.xlf index 3ef33bdc204..d3636be990b 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.es.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.es.xlf @@ -112,16 +112,6 @@ Remove data - - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> - {0} is a number - - - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number - Details Detalles diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.fr.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.fr.xlf index eab39c8d01d..c0fbf25e92b 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.fr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.fr.xlf @@ -112,16 +112,6 @@ Remove data - - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> - {0} is a number - - - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number - Details Détails diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.it.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.it.xlf index e307d99f767..3a865553ed5 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.it.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.it.xlf @@ -112,16 +112,6 @@ Remove data - - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> - {0} is a number - - - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number - Details Dettagli diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ja.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ja.xlf index ab54a52998b..8d6d2027190 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ja.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ja.xlf @@ -112,16 +112,6 @@ Remove data - - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> - {0} is a number - - - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number - Details 詳細 diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ko.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ko.xlf index 215e5694870..b47c3be003c 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ko.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ko.xlf @@ -112,16 +112,6 @@ Remove data - - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> - {0} is a number - - - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number - Details 세부 정보 diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pl.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pl.xlf index 9bfc849891a..59cf8ea2518 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pl.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pl.xlf @@ -112,16 +112,6 @@ Remove data - - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> - {0} is a number - - - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number - Details Szczegóły diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pt-BR.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pt-BR.xlf index 7e295d9b29a..5f135a935f9 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pt-BR.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pt-BR.xlf @@ -112,16 +112,6 @@ Remove data - - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> - {0} is a number - - - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number - Details Detalhes diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ru.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ru.xlf index 54cadf3c961..c9c772dce04 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ru.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ru.xlf @@ -112,16 +112,6 @@ Remove data - - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> - {0} is a number - - - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number - Details Сведения diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.tr.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.tr.xlf index da13f32fb00..1807258c4bf 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.tr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.tr.xlf @@ -112,16 +112,6 @@ Remove data - - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> - {0} is a number - - - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number - Details Ayrıntılar diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hans.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hans.xlf index 00dee73aa11..543bea83031 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hans.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hans.xlf @@ -112,16 +112,6 @@ Remove data - - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> - {0} is a number - - - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number - Details 详细信息 diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hant.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hant.xlf index 16581d8d0d8..ca3304775ee 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hant.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hant.xlf @@ -112,16 +112,6 @@ Remove data - - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> - {0} is a number - - - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number - Details 詳細資料 diff --git a/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs b/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs index 056d72dac52..d0c2b950d2e 100644 --- a/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs +++ b/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs @@ -359,6 +359,9 @@ public void PauseResumeButton_TogglePauseResume_LogsPausedAndResumed() SetupConsoleLogsServices(dashboardClient); + var pauseManager = Services.GetRequiredService(); + var timeProvider = Services.GetRequiredService(); + var loc = Services.GetRequiredService>(); var dimensionManager = Services.GetRequiredService(); var viewport = new ViewportInformation(IsDesktop: true, IsUltraLowHeight: false, IsUltraLowWidth: false); dimensionManager.InvokeOnViewportInformationChanged(viewport); @@ -379,23 +382,36 @@ public void PauseResumeButton_TogglePauseResume_LogsPausedAndResumed() var pauseResumeButton = cut.FindComponent(); pauseResumeButton.Find("fluent-button").Click(); - // Add a new log while paused + // A pause line should be visible + var pauseConsoleLogLine = cut.WaitForElement(".log-pause"); + + // Add a new log while paused and assert that the log viewer shows that 1 log was filtered var pauseContent = $"{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ss.fffK} Log while paused"; consoleLogsChannel.Writer.TryWrite([new ResourceLogLine(1, pauseContent, IsErrorMessage: false)]); + cut.WaitForAssertion(() => Assert.Equal(pauseConsoleLogLine.TextContent, string.Format(loc[Resources.ConsoleLogs.ConsoleLogsPauseActive], 1))); + // Resume and write a new log, 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().ConsoleLogsPaused)); var resumeContent = $"{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ss.fffK} Log after resume"; consoleLogsChannel.Writer.TryWrite([new ResourceLogLine(1, resumeContent, IsErrorMessage: false)]); var logViewer = cut.FindComponent(); - - // Ensure the new log does not show up in visible entries when paused - // but is still in the log entries cut.WaitForAssertion(() => { + var pause = Assert.Single(pauseManager.ConsoleLogsPausedRanges.Values); + Assert.NotNull(pause.End); + Assert.Equal( + pauseConsoleLogLine.TextContent, + string.Format( + loc[Resources.ConsoleLogs.ConsoleLogsPauseDetails], + FormatHelpers.FormatTimeWithOptionalDate(timeProvider, pause.Start, MillisecondsDisplay.Truncated), + FormatHelpers.FormatTimeWithOptionalDate(timeProvider, pause.End.Value, MillisecondsDisplay.Truncated), + 1)); Assert.Contains(resumeContent, logViewer.Instance.LogEntries!.GetEntries().Select(e => e.RawContent)); Assert.DoesNotContain(pauseContent, logViewer.Instance.LogEntries!.GetEntries().Select(e => e.RawContent)); }); diff --git a/tests/Aspire.Dashboard.Tests/ConsoleLogsTests/LogEntriesTests.cs b/tests/Aspire.Dashboard.Tests/ConsoleLogsTests/LogEntriesTests.cs index bf3c045e7a9..a6b1198c385 100644 --- a/tests/Aspire.Dashboard.Tests/ConsoleLogsTests/LogEntriesTests.cs +++ b/tests/Aspire.Dashboard.Tests/ConsoleLogsTests/LogEntriesTests.cs @@ -234,6 +234,48 @@ public void InsertSorted_TrimsToMaximumEntryCount_OutOfOrder() l => Assert.Equal("3", l.Content)); } + [Fact] + public void InsertSorted_PauseAtBeginning_InsertsCorrectly() + { + // Arrange + var logEntries = CreateLogEntries(); + var timestamp = DateTime.UtcNow; + + // Act + logEntries.InsertSorted(LogEntry.CreatePause(timestamp)); + logEntries.InsertSorted(LogEntry.CreatePause(timestamp.AddSeconds(1))); + logEntries.InsertSorted(LogEntry.Create(timestamp.AddSeconds(2), "1", isErrorMessage: false)); + + // Assert + var entries = logEntries.GetEntries(); + Assert.Collection(entries, + l => Assert.Equal(LogEntryType.Pause, l.Type), + l => Assert.Equal(LogEntryType.Pause, l.Type), + l => Assert.Equal("1", l.Content)); + } + + [Fact] + public void InsertSorted_AddPauseInMiddle_InsertsCorrectly() + { + // Arrange + var logEntries = CreateLogEntries(); + var timestamp = DateTime.UtcNow; + + // Act + logEntries.InsertSorted(LogEntry.Create(timestamp.AddSeconds(1), "1", isErrorMessage: false)); + logEntries.InsertSorted(LogEntry.CreatePause(timestamp.AddSeconds(2))); + logEntries.InsertSorted(LogEntry.Create(timestamp.AddSeconds(3), "3", isErrorMessage: false)); + logEntries.InsertSorted(LogEntry.CreatePause(timestamp.AddSeconds(4))); + + // Assert + var entries = logEntries.GetEntries(); + Assert.Collection(entries, + l => Assert.Equal("1", l.Content), + l => Assert.Equal(LogEntryType.Pause, l.Type), + l => Assert.Equal("3", l.Content), + l => Assert.Equal(LogEntryType.Pause, l.Type)); + } + [Fact] public void CreateLogEntry_AnsiAndUrl_HasUrlAnchor() { From 0795490f49d5a6a8798d46b39be2aec474e8b330 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Sat, 22 Mar 2025 16:56:13 -0400 Subject: [PATCH 19/35] Fix line number problem, add additional tests for pause manager, update existing log entries and console log test --- .../Components/Controls/LogViewer.razor | 7 +- .../Components/Pages/ConsoleLogs.razor.cs | 19 ++- src/Aspire.Dashboard/Model/PauseManager.cs | 17 +-- src/Shared/ConsoleLogs/LogEntries.cs | 10 +- src/Shared/ConsoleLogs/LogEntry.cs | 5 +- .../Pages/ConsoleLogsTests.cs | 4 +- .../ConsoleLogsTests/LogEntriesTests.cs | 32 +++-- .../PauseManagerTests.cs | 110 ++++++++++++++++++ 8 files changed, 177 insertions(+), 27 deletions(-) create mode 100644 tests/Aspire.Dashboard.Tests/PauseManagerTests.cs diff --git a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor index 1d26b359432..c3e68d6fd34 100644 --- a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor +++ b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor @@ -17,18 +17,19 @@ @if (context is { Type: LogEntryType.Pause, Timestamp: { } startTimestamp} && PauseManager.TryGetConsoleLogPause(startTimestamp, out var pause)) { // If this is a previous pause but no logs were obtained during the pause, we don't need to show anything. - if (!pause.HasFilteredLogsForApplication(ApplicationName, out var count) && pause.End is not null) + var filteredLogCount = pause.GetFilteredLogCount(ApplicationName); + if (filteredLogCount == 0 && pause.End is not null) { return; } var text = pause.End is null - ? string.Format(Loc[nameof(ConsoleLogs.ConsoleLogsPauseActive)], count) + ? string.Format(Loc[nameof(ConsoleLogs.ConsoleLogsPauseActive)], filteredLogCount) : string.Format( Loc[nameof(ConsoleLogs.ConsoleLogsPauseDetails)], FormatHelpers.FormatTimeWithOptionalDate(TimeProvider, startTimestamp, MillisecondsDisplay.Truncated), FormatHelpers.FormatTimeWithOptionalDate(TimeProvider, pause.End.Value, MillisecondsDisplay.Truncated), - count); + filteredLogCount);
diff --git a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs index 6cc17836f8b..da763853d0a 100644 --- a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs @@ -469,7 +469,7 @@ private void LoadLogs(ConsoleLogsSubscription newConsoleLogsSubscription) // Add entries for all previous pauses. foreach (var pauseStart in PauseManager.ConsoleLogsPausedRanges.Keys) { - _logEntries.InsertSorted(LogEntry.CreatePause(pauseStart)); + _logEntries.InsertSorted(LogEntry.CreatePause(pauseStart, previousLineNumber: 0)); } var logParser = new LogParser(); @@ -499,8 +499,20 @@ private void LoadLogs(ConsoleLogsSubscription newConsoleLogsSubscription) continue; } + var previousEntry = _logEntries.GetEntries().LastOrDefault(); + // Only add entries that are not ignored, or if they are null as we cannot know when they happened. - _logEntries.InsertSorted(logEntry); + // As we may have skipped some logs during a pause, we need to check how far to skip to keep the line count + // accurate. + if (previousEntry is { Type: LogEntryType.Pause, Timestamp: { } timestamp} && timestamp < logEntry.Timestamp) + { + Debug.Assert(PauseManager.TryGetConsoleLogPause(timestamp, out var pause)); + _logEntries.InsertSorted(logEntry, skipLineCount: pause.GetFilteredLogCount(newConsoleLogsSubscription.Name)); + } + else + { + _logEntries.InsertSorted(logEntry); + } } await InvokeAsync(StateHasChanged); @@ -624,7 +636,8 @@ private Task IsPausedChangedAsync(bool isPaused) { // Each pause has its own entry in the log entries and will be displayed // unless it ended with 0 logs filtered out during - _logEntries.InsertSorted(LogEntry.CreatePause(timestamp)); + var previousEntry = _logEntries.GetEntries().LastOrDefault(); + _logEntries.InsertSorted(LogEntry.CreatePause(timestamp, previousLineNumber: previousEntry?.LineNumber ?? 0)); } PauseManager.SetConsoleLogsPaused(isPaused, timestamp); diff --git a/src/Aspire.Dashboard/Model/PauseManager.cs b/src/Aspire.Dashboard/Model/PauseManager.cs index a5a8d54fc34..0059277b5cd 100644 --- a/src/Aspire.Dashboard/Model/PauseManager.cs +++ b/src/Aspire.Dashboard/Model/PauseManager.cs @@ -44,12 +44,12 @@ public bool IsConsoleLogFiltered(DateTime timestamp, string application) } } - if (foundRange is not null) + if (foundRange is not null && foundRange.FilteredLogsByApplication.GetValueOrDefault(application)?.Contains(timestamp) is not true) { ImmutableInterlocked.Update( ref _consoleLogsPausedRanges, ranges => ranges.SetItem(foundRange.Start, - foundRange with { FilteredLogsByApplication = foundRange.FilteredLogsByApplication.SetItem(application, foundRange.FilteredLogsByApplication.GetValueOrDefault(application) + 1) })); + foundRange with { FilteredLogsByApplication = foundRange.FilteredLogsByApplication.SetItem(application, foundRange.FilteredLogsByApplication.GetValueOrDefault(application)?.Add(timestamp) ?? [timestamp]) })); } return foundRange is not null; @@ -63,7 +63,7 @@ public void SetConsoleLogsPaused(bool isPaused, DateTime timestamp) { if (isPaused) { - return ranges.Add(timestamp, new ConsoleLogPause(Start: timestamp, End: null, FilteredLogsByApplication: ImmutableDictionary.Empty)); + return ranges.Add(timestamp, new ConsoleLogPause(Start: timestamp, End: null, FilteredLogsByApplication: ImmutableDictionary>.Empty)); } else { @@ -74,18 +74,19 @@ public void SetConsoleLogsPaused(bool isPaused, DateTime timestamp) throw new InvalidOperationException("Last range end should be null when resuming."); } - return ranges.SetItem(lastRange.Start, lastRange with { End = DateTime.UtcNow }); + return ranges.SetItem(lastRange.Start, lastRange with { End = timestamp }); } }); } } -public record ConsoleLogPause(DateTime Start, DateTime? End, ImmutableDictionary FilteredLogsByApplication) +public record ConsoleLogPause(DateTime Start, DateTime? End, ImmutableDictionary> FilteredLogsByApplication) { - public bool HasFilteredLogsForApplication(string? application, out int count) + public int GetFilteredLogCount(string? application) { - count = 0; - return application is not null && FilteredLogsByApplication.TryGetValue(application, out count) && count > 0; + return application is null || !FilteredLogsByApplication.TryGetValue(application, out var filteredLogs) + ? 0 + : filteredLogs.Count; } public bool IsOverlapping(DateTime date) diff --git a/src/Shared/ConsoleLogs/LogEntries.cs b/src/Shared/ConsoleLogs/LogEntries.cs index 9915dddb325..aa1bf18c610 100644 --- a/src/Shared/ConsoleLogs/LogEntries.cs +++ b/src/Shared/ConsoleLogs/LogEntries.cs @@ -33,7 +33,13 @@ public void Clear() BaseLineNumber = null; } - public void InsertSorted(LogEntry logLine, int skipLineCount = 1) + /// + /// Insert a log entry at the correct position in the list of log entries according to its timestamp. + /// + /// + /// How much to increment the line count by. This may be more than 0 if logs were + /// discarded during a pause + public void InsertSorted(LogEntry logLine, int skipLineCount = 0) { Debug.Assert(logLine.Timestamp == null || logLine.Timestamp.Value.Kind == DateTimeKind.Utc, "Timestamp should always be UTC."); @@ -142,7 +148,7 @@ void InsertAt(int index) } else { - logEntry.LineNumber = _logEntries[index - 1].LineNumber + skipLineCount; + logEntry.LineNumber = _logEntries[index - 1].LineNumber + skipLineCount + 1; } if (_earliestTimestampIndex == null && logEntry.Timestamp != null) diff --git a/src/Shared/ConsoleLogs/LogEntry.cs b/src/Shared/ConsoleLogs/LogEntry.cs index 13d4833266f..c5e0c39171f 100644 --- a/src/Shared/ConsoleLogs/LogEntry.cs +++ b/src/Shared/ConsoleLogs/LogEntry.cs @@ -22,12 +22,13 @@ internal sealed class LogEntry public LogEntryType Type { get; private set; } = LogEntryType.Default; public int LineNumber { get; set; } - public static LogEntry CreatePause(DateTime? timestamp) + public static LogEntry CreatePause(DateTime? timestamp, int previousLineNumber) { return new LogEntry { Timestamp = timestamp, - Type = LogEntryType.Pause + Type = LogEntryType.Pause, + LineNumber = previousLineNumber }; } diff --git a/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs b/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs index d0c2b950d2e..c3248ff1171 100644 --- a/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs +++ b/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs @@ -412,7 +412,9 @@ public void PauseResumeButton_TogglePauseResume_LogsPausedAndResumed() FormatHelpers.FormatTimeWithOptionalDate(timeProvider, pause.Start, MillisecondsDisplay.Truncated), FormatHelpers.FormatTimeWithOptionalDate(timeProvider, pause.End.Value, MillisecondsDisplay.Truncated), 1)); - Assert.Contains(resumeContent, logViewer.Instance.LogEntries!.GetEntries().Select(e => e.RawContent)); + var newLog = Assert.Single(logViewer.Instance.LogEntries!.GetEntries().Where(e => e.RawContent == resumeContent)); + // We discarded one log while paused, so the new log should be line 3, skipping one + Assert.Equal(2, newLog.LineNumber); Assert.DoesNotContain(pauseContent, logViewer.Instance.LogEntries!.GetEntries().Select(e => e.RawContent)); }); } diff --git a/tests/Aspire.Dashboard.Tests/ConsoleLogsTests/LogEntriesTests.cs b/tests/Aspire.Dashboard.Tests/ConsoleLogsTests/LogEntriesTests.cs index a6b1198c385..9481bdf9366 100644 --- a/tests/Aspire.Dashboard.Tests/ConsoleLogsTests/LogEntriesTests.cs +++ b/tests/Aspire.Dashboard.Tests/ConsoleLogsTests/LogEntriesTests.cs @@ -242,8 +242,8 @@ public void InsertSorted_PauseAtBeginning_InsertsCorrectly() var timestamp = DateTime.UtcNow; // Act - logEntries.InsertSorted(LogEntry.CreatePause(timestamp)); - logEntries.InsertSorted(LogEntry.CreatePause(timestamp.AddSeconds(1))); + logEntries.InsertSorted(LogEntry.CreatePause(timestamp, previousLineNumber: 0)); + logEntries.InsertSorted(LogEntry.CreatePause(timestamp.AddSeconds(1), previousLineNumber: 0)); logEntries.InsertSorted(LogEntry.Create(timestamp.AddSeconds(2), "1", isErrorMessage: false)); // Assert @@ -251,7 +251,11 @@ public void InsertSorted_PauseAtBeginning_InsertsCorrectly() Assert.Collection(entries, l => Assert.Equal(LogEntryType.Pause, l.Type), l => Assert.Equal(LogEntryType.Pause, l.Type), - l => Assert.Equal("1", l.Content)); + l => + { + Assert.Equal("1", l.Content); + Assert.Equal(1, l.LineNumber); + }); } [Fact] @@ -263,16 +267,28 @@ public void InsertSorted_AddPauseInMiddle_InsertsCorrectly() // Act logEntries.InsertSorted(LogEntry.Create(timestamp.AddSeconds(1), "1", isErrorMessage: false)); - logEntries.InsertSorted(LogEntry.CreatePause(timestamp.AddSeconds(2))); - logEntries.InsertSorted(LogEntry.Create(timestamp.AddSeconds(3), "3", isErrorMessage: false)); - logEntries.InsertSorted(LogEntry.CreatePause(timestamp.AddSeconds(4))); + logEntries.InsertSorted(LogEntry.CreatePause(timestamp.AddSeconds(2), previousLineNumber: 1)); + + // simulate 10 incoming lines being discarded due to a pause + logEntries.InsertSorted(LogEntry.Create(timestamp.AddSeconds(3), "3", isErrorMessage: false), skipLineCount: 10); + logEntries.InsertSorted(LogEntry.CreatePause(timestamp.AddSeconds(4), previousLineNumber: 12)); // Assert var entries = logEntries.GetEntries(); Assert.Collection(entries, - l => Assert.Equal("1", l.Content), + l => + { + Assert.Equal("1", l.Content); + Assert.Equal(LogEntryType.Default, l.Type); + Assert.Equal(1, l.LineNumber); + }, l => Assert.Equal(LogEntryType.Pause, l.Type), - l => Assert.Equal("3", l.Content), + l => + { + Assert.Equal("3", l.Content); + Assert.Equal(LogEntryType.Default, l.Type); + Assert.Equal(12, l.LineNumber); + }, l => Assert.Equal(LogEntryType.Pause, l.Type)); } diff --git a/tests/Aspire.Dashboard.Tests/PauseManagerTests.cs b/tests/Aspire.Dashboard.Tests/PauseManagerTests.cs new file mode 100644 index 00000000000..9108f8b8bef --- /dev/null +++ b/tests/Aspire.Dashboard.Tests/PauseManagerTests.cs @@ -0,0 +1,110 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Aspire.Dashboard.Model; +using Xunit; + +namespace Aspire.Dashboard.Tests; + +public class PauseManagerTests +{ + [Fact] + public void SetConsoleLogsPaused_ShouldAddPauseRange_WhenPaused() + { + // Arrange + var pauseManager = new PauseManager(); + var timestamp = DateTime.UtcNow; + + // Act + pauseManager.SetConsoleLogsPaused(true, timestamp); + + // Assert + Assert.True(pauseManager.ConsoleLogsPaused); + Assert.Single(pauseManager.ConsoleLogsPausedRanges); + Assert.Equal(timestamp, pauseManager.ConsoleLogsPausedRanges.Keys.First()); + } + + [Fact] + public void SetConsoleLogsPaused_ShouldUpdatePauseRange_WhenResumed() + { + // Arrange + var pauseManager = new PauseManager(); + var startTimestamp = DateTime.UtcNow; + pauseManager.SetConsoleLogsPaused(true, startTimestamp); + var endTimestamp = startTimestamp.AddMinutes(5); + + // Act + pauseManager.SetConsoleLogsPaused(false, endTimestamp); + + // Assert + Assert.False(pauseManager.ConsoleLogsPaused); + Assert.Single(pauseManager.ConsoleLogsPausedRanges); + var pauseRange = pauseManager.ConsoleLogsPausedRanges.Values.First(); + Assert.Equal(startTimestamp, pauseRange.Start); + Assert.Equal(endTimestamp, pauseRange.End); + } + + [Theory] + [InlineData(true, 1, true, 1)] + [InlineData(false, 6, false, 0)] + public void IsConsoleLogFiltered_ShouldReturnExpectedResult(bool isPaused, int minutesToAdd, bool expectedResult, int expectedFilteredLogCount) + { + // Arrange + var pauseManager = new PauseManager(); + var startTimestamp = DateTime.UtcNow; + pauseManager.SetConsoleLogsPaused(true, startTimestamp); + if (!isPaused) + { + var endTimestamp = startTimestamp.AddMinutes(5); + pauseManager.SetConsoleLogsPaused(false, endTimestamp); + } + var logTimestamp = startTimestamp.AddMinutes(minutesToAdd); + + // Act + var isFiltered1 = pauseManager.IsConsoleLogFiltered(logTimestamp, "app1"); + var isFiltered2 = pauseManager.IsConsoleLogFiltered(logTimestamp, "app1"); + var isFiltered3 = pauseManager.IsConsoleLogFiltered(logTimestamp, "app1"); + + // Assert + Assert.Equal(expectedResult, isFiltered1); + Assert.Equal(expectedResult, isFiltered2); + Assert.Equal(expectedResult, isFiltered3); + + if (pauseManager.TryGetConsoleLogPause(startTimestamp, out var pause)) + { + Assert.Equal(expectedFilteredLogCount, pause.GetFilteredLogCount("app1")); + } + } + + [Fact] + public void TryGetConsoleLogPause_ShouldReturnTrue_WhenPauseExists() + { + // Arrange + var pauseManager = new PauseManager(); + var startTimestamp = DateTime.UtcNow; + pauseManager.SetConsoleLogsPaused(true, startTimestamp); + + // Act + var result = pauseManager.TryGetConsoleLogPause(startTimestamp, out var pause); + + // Assert + Assert.True(result); + Assert.NotNull(pause); + Assert.Equal(startTimestamp, pause.Start); + } + + [Fact] + public void TryGetConsoleLogPause_ShouldReturnFalse_WhenPauseDoesNotExist() + { + // Arrange + var pauseManager = new PauseManager(); + var startTimestamp = DateTime.UtcNow; + + // Act + var result = pauseManager.TryGetConsoleLogPause(startTimestamp, out var pause); + + // Assert + Assert.False(result); + Assert.Null(pause); + } +} From cc75a50a764401f3db8278c445f6f357aced06bd Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Sat, 22 Mar 2025 17:27:50 -0400 Subject: [PATCH 20/35] Persist metric pause time so that start time is identical when navigating back after pause --- .../Components/Controls/Chart/ChartBase.cs | 7 +++++-- .../Controls/Chart/ChartContainer.razor.cs | 2 +- .../Components/Pages/Metrics.razor | 2 +- src/Aspire.Dashboard/Model/PauseManager.cs | 18 ++++++++++++++---- .../Otlp/Storage/TelemetryRepository.cs | 2 +- .../TelemetryRepositoryTests.cs | 4 ++-- 6 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Controls/Chart/ChartBase.cs b/src/Aspire.Dashboard/Components/Controls/Chart/ChartBase.cs index 0bad5be92c5..033b67da828 100644 --- a/src/Aspire.Dashboard/Components/Controls/Chart/ChartBase.cs +++ b/src/Aspire.Dashboard/Components/Controls/Chart/ChartBase.cs @@ -46,6 +46,9 @@ public abstract class ChartBase : ComponentBase, IAsyncDisposable [Inject] public required TelemetryRepository TelemetryRepository { get; init; } + [Inject] + public required PauseManager PauseManager { get; init; } + [Parameter, EditorRequired] public required InstrumentViewModel InstrumentViewModel { get; set; } @@ -66,7 +69,7 @@ protected override void OnInitialized() { // Copy the token so there is no chance it is accessed on CTS after it is disposed. CancellationToken = _cts.Token; - _currentDataStartTime = GetCurrentDataTime(); + _currentDataStartTime = PauseManager.AreMetricsPaused(out var pausedAt) ? pausedAt.Value : GetCurrentDataTime(); InstrumentViewModel.DataUpdateSubscriptions.Add(OnInstrumentDataUpdate); } @@ -80,7 +83,7 @@ InstrumentViewModel.MatchedDimensions is null || return; } - var inProgressDataTime = GetCurrentDataTime(); + var inProgressDataTime = PauseManager.AreMetricsPaused(out var pausedAt) ? pausedAt.Value : GetCurrentDataTime(); while (_currentDataStartTime.Add(_tickDuration) < inProgressDataTime) { diff --git a/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor.cs b/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor.cs index 75bdfbbdbd9..474fc5a2bf8 100644 --- a/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor.cs +++ b/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor.cs @@ -91,7 +91,7 @@ private async Task UpdateDataAsync() while (await timer!.WaitForNextTickAsync()) { _instrument = GetInstrument(); - if (_instrument == null || PauseManager.MetricsPaused) + if (_instrument == null || PauseManager.AreMetricsPaused(out _)) { continue; } diff --git a/src/Aspire.Dashboard/Components/Pages/Metrics.razor b/src/Aspire.Dashboard/Components/Pages/Metrics.razor index 05adef36504..2e2e06cf03a 100644 --- a/src/Aspire.Dashboard/Components/Pages/Metrics.razor +++ b/src/Aspire.Dashboard/Components/Pages/Metrics.razor @@ -48,7 +48,7 @@ CanSelectGrouping="true" LabelClass="toolbar-left" /> - + diff --git a/src/Aspire.Dashboard/Model/PauseManager.cs b/src/Aspire.Dashboard/Model/PauseManager.cs index 0059277b5cd..1281e69a501 100644 --- a/src/Aspire.Dashboard/Model/PauseManager.cs +++ b/src/Aspire.Dashboard/Model/PauseManager.cs @@ -11,14 +11,24 @@ public sealed class PauseManager { public bool StructuredLogsPaused { get; set; } public bool TracesPaused { get; set; } - public bool MetricsPaused { get; set; } - public bool ConsoleLogsPaused { get; private set; } + private DateTimeOffset? _metricsPausedAt; - private static readonly IComparer s_startTimeComparer = Comparer.Create((x, y) => x.CompareTo(y)); - private ImmutableSortedDictionary _consoleLogsPausedRanges = ImmutableSortedDictionary.Create(s_startTimeComparer); + public bool ConsoleLogsPaused { get; private set; } + private ImmutableSortedDictionary _consoleLogsPausedRanges = ImmutableSortedDictionary.Create(Comparer.Create((x, y) => x.CompareTo(y))); public ImmutableSortedDictionary ConsoleLogsPausedRanges => _consoleLogsPausedRanges; + public bool AreMetricsPaused([NotNullWhen(true)] out DateTimeOffset? pausedAt) + { + pausedAt = _metricsPausedAt; + return _metricsPausedAt is not null; + } + + public void SetMetricsPaused(bool isPaused) + { + _metricsPausedAt = isPaused ? DateTimeOffset.UtcNow : null; + } + public bool TryGetConsoleLogPause(DateTime startTime, [NotNullWhen(true)] out ConsoleLogPause? pause) { if (_consoleLogsPausedRanges.TryGetValue(startTime, out var range)) diff --git a/src/Aspire.Dashboard/Otlp/Storage/TelemetryRepository.cs b/src/Aspire.Dashboard/Otlp/Storage/TelemetryRepository.cs index 1016b55a06a..2fd2ad5ea94 100644 --- a/src/Aspire.Dashboard/Otlp/Storage/TelemetryRepository.cs +++ b/src/Aspire.Dashboard/Otlp/Storage/TelemetryRepository.cs @@ -815,7 +815,7 @@ public Dictionary GetLogsFieldValues(string attributeName) public void AddMetrics(AddContext context, RepeatedField resourceMetrics) { - if (_pauseManager.MetricsPaused) + if (_pauseManager.AreMetricsPaused(out _)) { _logger.LogTrace("{LogCount} incoming metric(s) was ignored because of an active pause.", resourceMetrics.Count); return; diff --git a/tests/Aspire.Dashboard.Tests/TelemetryRepositoryTests/TelemetryRepositoryTests.cs b/tests/Aspire.Dashboard.Tests/TelemetryRepositoryTests/TelemetryRepositoryTests.cs index 50ea580b111..1df96c88f55 100644 --- a/tests/Aspire.Dashboard.Tests/TelemetryRepositoryTests/TelemetryRepositoryTests.cs +++ b/tests/Aspire.Dashboard.Tests/TelemetryRepositoryTests/TelemetryRepositoryTests.cs @@ -26,7 +26,7 @@ public void AddData_WhilePaused_IsDiscarded() // Act and assert pauseManager.StructuredLogsPaused = true; - pauseManager.MetricsPaused = true; + pauseManager.SetMetricsPaused(true); pauseManager.TracesPaused = true; AddLog(); AddMetric(); @@ -38,7 +38,7 @@ public void AddData_WhilePaused_IsDiscarded() Assert.Empty(repository.GetTraces(new GetTracesRequest { ApplicationKey = applicationKey, Count = 100, Filters = [], StartIndex = 0, FilterText = string.Empty }).PagedResult.Items); pauseManager.StructuredLogsPaused = false; - pauseManager.MetricsPaused = false; + pauseManager.SetMetricsPaused(false); pauseManager.TracesPaused = false; AddLog(); From 8c1f0190ec64c4ff3cd05d20ebde5e20b04cacb0 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Sat, 22 Mar 2025 17:41:23 -0400 Subject: [PATCH 21/35] clean up --- src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor | 2 +- src/Shared/ConsoleLogs/LogEntries.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor index 6f93953b635..5cc715a9dc5 100644 --- a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor +++ b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor @@ -32,7 +32,7 @@ @if (_highlightedCommands.Count > 0) { - Commands + @Loc[nameof(Dashboard.Resources.ConsoleLogs.ConsoleLogsResourceCommands)] @foreach (var command in _highlightedCommands) { diff --git a/src/Shared/ConsoleLogs/LogEntries.cs b/src/Shared/ConsoleLogs/LogEntries.cs index aa1bf18c610..332282e5c4d 100644 --- a/src/Shared/ConsoleLogs/LogEntries.cs +++ b/src/Shared/ConsoleLogs/LogEntries.cs @@ -72,7 +72,7 @@ private void VerifyLogEntryOrder() private void InsertSortedCore(LogEntry logEntry, int skipLineCount) { - // If there is no timestamp then add to the end. + // If there is no timestamp or the entry is a pause then add to the end. if (logEntry.Timestamp == null || logEntry.Type is LogEntryType.Pause) { InsertAt(_logEntries.Count); From 51de86cb5aefb35b57fb89d1a501940d3e5cfc95 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Sat, 22 Mar 2025 17:43:47 -0400 Subject: [PATCH 22/35] run custom tool after merge --- .../Resources/ControlsStrings.Designer.cs | 837 +++++------------- 1 file changed, 240 insertions(+), 597 deletions(-) diff --git a/src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs b/src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs index 1c53e758809..0010ed69b38 100644 --- a/src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs +++ b/src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs @@ -1,7 +1,6 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -12,46 +11,32 @@ namespace Aspire.Dashboard.Resources { using System; - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class ControlsStrings { - private static global::System.Resources.ResourceManager resourceMan; + private static System.Resources.ResourceManager resourceMan; - private static global::System.Globalization.CultureInfo resourceCulture; + private static System.Globalization.CultureInfo resourceCulture; - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal ControlsStrings() { } - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Resources.ResourceManager ResourceManager { get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Aspire.Dashboard.Resources.ControlsStrings", typeof(ControlsStrings).Assembly); + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Aspire.Dashboard.Resources.ControlsStrings", typeof(ControlsStrings).Assembly); resourceMan = temp; } return resourceMan; } } - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -60,1029 +45,687 @@ internal ControlsStrings() { } } - /// - /// Looks up a localized string similar to Actions. - /// - public static string ActionsButtonText { + public static string ChartContainerUnableToDisplay { get { - return ResourceManager.GetString("ActionsButtonText", resourceCulture); + return ResourceManager.GetString("ChartContainerUnableToDisplay", resourceCulture); } } - /// - /// Looks up a localized string similar to Actions. - /// - public static string ActionsColumnHeader { + public static string ChartContainerFiltersHeader { get { - return ResourceManager.GetString("ActionsColumnHeader", resourceCulture); + return ResourceManager.GetString("ChartContainerFiltersHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Structured logs. - /// - public static string ActionStructuredLogsText { + public static string ChartContainerSelectFilters { get { - return ResourceManager.GetString("ActionStructuredLogsText", resourceCulture); + return ResourceManager.GetString("ChartContainerSelectFilters", resourceCulture); } } - /// - /// Looks up a localized string similar to View details. - /// - public static string ActionViewDetailsText { + public static string ChartContainerGraphTab { get { - return ResourceManager.GetString("ActionViewDetailsText", resourceCulture); + return ResourceManager.GetString("ChartContainerGraphTab", resourceCulture); } } - /// - /// Looks up a localized string similar to application. - /// - public static string ApplicationLower { + public static string ChartContainerTableTab { get { - return ResourceManager.GetString("ApplicationLower", resourceCulture); + return ResourceManager.GetString("ChartContainerTableTab", resourceCulture); } } - /// - /// Looks up a localized string similar to All tags. - /// - public static string ChartContainerAllTags { + public static string ChartContainerGraphAccessibleLabel { get { - return ResourceManager.GetString("ChartContainerAllTags", resourceCulture); + return ResourceManager.GetString("ChartContainerGraphAccessibleLabel", resourceCulture); } } - /// - /// Looks up a localized string similar to Filtered tags. - /// - public static string ChartContainerFilteredTags { + public static string EnvironmentVariablesFilterToggleShowSpecOnly { get { - return ResourceManager.GetString("ChartContainerFilteredTags", resourceCulture); + return ResourceManager.GetString("EnvironmentVariablesFilterToggleShowSpecOnly", resourceCulture); } } - /// - /// Looks up a localized string similar to Filters. - /// - public static string ChartContainerFiltersHeader { + public static string EnvironmentVariablesFilterToggleShowAll { get { - return ResourceManager.GetString("ChartContainerFiltersHeader", resourceCulture); + return ResourceManager.GetString("EnvironmentVariablesFilterToggleShowAll", resourceCulture); } } - /// - /// Looks up a localized string similar to Graph. For an accessible view please navigate to the Table tab. - /// - public static string ChartContainerGraphAccessibleLabel { + public static string EnvironmentVariablesShowVariableValues { get { - return ResourceManager.GetString("ChartContainerGraphAccessibleLabel", resourceCulture); + return ResourceManager.GetString("EnvironmentVariablesShowVariableValues", resourceCulture); } } - /// - /// Looks up a localized string similar to Graph. - /// - public static string ChartContainerGraphTab { + public static string EnvironmentVariablesHideVariableValues { get { - return ResourceManager.GetString("ChartContainerGraphTab", resourceCulture); + return ResourceManager.GetString("EnvironmentVariablesHideVariableValues", resourceCulture); } } - /// - /// Looks up a localized string similar to Options. - /// - public static string ChartContainerOptionsHeader { + public static string FilterPlaceholder { get { - return ResourceManager.GetString("ChartContainerOptionsHeader", resourceCulture); + return ResourceManager.GetString("FilterPlaceholder", resourceCulture); } } - /// - /// Looks up a localized string similar to Some dimensions for the metric have been dropped by the OpenTelemetry SDK.. - /// - public static string ChartContainerOverflowDescription { + public static string GridValueMaskShowValue { get { - return ResourceManager.GetString("ChartContainerOverflowDescription", resourceCulture); + return ResourceManager.GetString("GridValueMaskShowValue", resourceCulture); } } - /// - /// Looks up a localized string similar to For more information, see <a href="{0}" target="_blank">OpenTelemetry specification cardinality limits</a>.. - /// - public static string ChartContainerOverflowLink { + public static string GridValueMaskHideValue { get { - return ResourceManager.GetString("ChartContainerOverflowLink", resourceCulture); + return ResourceManager.GetString("GridValueMaskHideValue", resourceCulture); } } - /// - /// Looks up a localized string similar to Cardinality capping has been detected. - /// - public static string ChartContainerOverflowTitle { + public static string GridValueCopyToClipboard { get { - return ResourceManager.GetString("ChartContainerOverflowTitle", resourceCulture); + return ResourceManager.GetString("GridValueCopyToClipboard", resourceCulture); } } - /// - /// Looks up a localized string similar to Select filters. - /// - public static string ChartContainerSelectFilters { + public static string ExceptionDetailsTitle { get { - return ResourceManager.GetString("ChartContainerSelectFilters", resourceCulture); + return ResourceManager.GetString("ExceptionDetailsTitle", resourceCulture); } } - /// - /// Looks up a localized string similar to Show count. - /// - public static string ChartContainerShowCountLabel { + public static string GridValueCopied { get { - return ResourceManager.GetString("ChartContainerShowCountLabel", resourceCulture); + return ResourceManager.GetString("GridValueCopied", resourceCulture); } } - /// - /// Looks up a localized string similar to Table. - /// - public static string ChartContainerTableTab { + public static string PlotlyChartCount { get { - return ResourceManager.GetString("ChartContainerTableTab", resourceCulture); + return ResourceManager.GetString("PlotlyChartCount", resourceCulture); } } - /// - /// Looks up a localized string similar to Unable to display chart. - /// - public static string ChartContainerUnableToDisplay { + public static string PlotlyChartLength { get { - return ResourceManager.GetString("ChartContainerUnableToDisplay", resourceCulture); + return ResourceManager.GetString("PlotlyChartLength", resourceCulture); } } - /// - /// Looks up a localized string similar to Remove all. - /// - public static string ClearAllResources { + public static string PlotlyChartValue { get { - return ResourceManager.GetString("ClearAllResources", resourceCulture); + return ResourceManager.GetString("PlotlyChartValue", resourceCulture); } } - /// - /// Looks up a localized string similar to Remove for resource. - /// - public static string ClearPendingSelectedResource { + public static string NameColumnHeader { get { - return ResourceManager.GetString("ClearPendingSelectedResource", resourceCulture); + return ResourceManager.GetString("NameColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Remove for {0}. - /// - public static string ClearSelectedResource { + public static string PropertyGridValueColumnHeader { get { - return ResourceManager.GetString("ClearSelectedResource", resourceCulture); + return ResourceManager.GetString("PropertyGridValueColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Details. - /// - public static string DetailsColumnHeader { + public static string StateColumnHeader { get { - return ResourceManager.GetString("DetailsColumnHeader", resourceCulture); + return ResourceManager.GetString("StateColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Duration. - /// - public static string DurationColumnHeader { + public static string SpanDetailsResource { get { - return ResourceManager.GetString("DurationColumnHeader", resourceCulture); + return ResourceManager.GetString("SpanDetailsResource", resourceCulture); } } - /// - /// Looks up a localized string similar to Endpoint name. - /// - public static string EndpointNameColumnHeader { + public static string SpanDetailsDuration { get { - return ResourceManager.GetString("EndpointNameColumnHeader", resourceCulture); + return ResourceManager.GetString("SpanDetailsDuration", resourceCulture); } } - /// - /// Looks up a localized string similar to Show all. - /// - public static string EnvironmentVariablesFilterToggleShowAll { + public static string SpanDetailsStartTime { get { - return ResourceManager.GetString("EnvironmentVariablesFilterToggleShowAll", resourceCulture); + return ResourceManager.GetString("SpanDetailsStartTime", resourceCulture); } } - /// - /// Looks up a localized string similar to Show spec only. - /// - public static string EnvironmentVariablesFilterToggleShowSpecOnly { + public static string ViewLogsLink { get { - return ResourceManager.GetString("EnvironmentVariablesFilterToggleShowSpecOnly", resourceCulture); + return ResourceManager.GetString("ViewLogsLink", resourceCulture); } } - /// - /// Looks up a localized string similar to Hide values. - /// - public static string EnvironmentVariablesHideVariableValues { + public static string SummaryDetailsViewSplitHorizontal { get { - return ResourceManager.GetString("EnvironmentVariablesHideVariableValues", resourceCulture); + return ResourceManager.GetString("SummaryDetailsViewSplitHorizontal", resourceCulture); } } - /// - /// Looks up a localized string similar to Show values. - /// - public static string EnvironmentVariablesShowVariableValues { + public static string SummaryDetailsViewSplitVertical { get { - return ResourceManager.GetString("EnvironmentVariablesShowVariableValues", resourceCulture); + return ResourceManager.GetString("SummaryDetailsViewSplitVertical", resourceCulture); } } - /// - /// Looks up a localized string similar to Event. - /// - public static string EventColumnHeader { + public static string SummaryDetailsViewCloseView { get { - return ResourceManager.GetString("EventColumnHeader", resourceCulture); + return ResourceManager.GetString("SummaryDetailsViewCloseView", resourceCulture); } } - /// - /// Looks up a localized string similar to Exception details. - /// - public static string ExceptionDetailsTitle { + public static string TotalItemsFooterText { get { - return ResourceManager.GetString("ExceptionDetailsTitle", resourceCulture); + return ResourceManager.GetString("TotalItemsFooterText", resourceCulture); } } - /// - /// Looks up a localized string similar to Filter.... - /// - public static string FilterPlaceholder { + public static string SelectAnApplication { get { - return ResourceManager.GetString("FilterPlaceholder", resourceCulture); + return ResourceManager.GetString("SelectAnApplication", resourceCulture); } } - /// - /// Looks up a localized string similar to Grow column width. - /// - public static string FluentDataGridHeaderCellGrowAriaLabelText { + public static string ViewAction { get { - return ResourceManager.GetString("FluentDataGridHeaderCellGrowAriaLabelText", resourceCulture); + return ResourceManager.GetString("ViewAction", resourceCulture); } } - /// - /// Looks up a localized string similar to Reset column widths. - /// - public static string FluentDataGridHeaderCellResetAriaLabelText { + public static string LabelAll { get { - return ResourceManager.GetString("FluentDataGridHeaderCellResetAriaLabelText", resourceCulture); + return ResourceManager.GetString("LabelAll", resourceCulture); } } - /// - /// Looks up a localized string similar to Resize. - /// - public static string FluentDataGridHeaderCellResizeButtonText { + public static string ChartContainerAllTags { get { - return ResourceManager.GetString("FluentDataGridHeaderCellResizeButtonText", resourceCulture); + return ResourceManager.GetString("ChartContainerAllTags", resourceCulture); } } - /// - /// Looks up a localized string similar to Column width. - /// - public static string FluentDataGridHeaderCellResizeDiscreteLabel { + public static string ChartContainerFilteredTags { get { - return ResourceManager.GetString("FluentDataGridHeaderCellResizeDiscreteLabel", resourceCulture); + return ResourceManager.GetString("ChartContainerFilteredTags", resourceCulture); } } - /// - /// Looks up a localized string similar to Column width (in pixels). - /// - public static string FluentDataGridHeaderCellResizeLabel { + public static string ChartContainerOptionsHeader { get { - return ResourceManager.GetString("FluentDataGridHeaderCellResizeLabel", resourceCulture); + return ResourceManager.GetString("ChartContainerOptionsHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Shrink column width. - /// - public static string FluentDataGridHeaderCellShrinkAriaLabelText { + public static string ChartContainerShowCountLabel { get { - return ResourceManager.GetString("FluentDataGridHeaderCellShrinkAriaLabelText", resourceCulture); + return ResourceManager.GetString("ChartContainerShowCountLabel", resourceCulture); } } - /// - /// Looks up a localized string similar to Sort (ascending). - /// - public static string FluentDataGridHeaderCellSortAscendingButtonText { + public static string LabelNone { get { - return ResourceManager.GetString("FluentDataGridHeaderCellSortAscendingButtonText", resourceCulture); + return ResourceManager.GetString("LabelNone", resourceCulture); } } - /// - /// Looks up a localized string similar to Sort. - /// - public static string FluentDataGridHeaderCellSortButtonText { + public static string MetricTableStartColumnHeader { get { - return ResourceManager.GetString("FluentDataGridHeaderCellSortButtonText", resourceCulture); + return ResourceManager.GetString("MetricTableStartColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Sort (descending). - /// - public static string FluentDataGridHeaderCellSortDescendingButtonText { + public static string MetricTableShowLatestValues { get { - return ResourceManager.GetString("FluentDataGridHeaderCellSortDescendingButtonText", resourceCulture); + return ResourceManager.GetString("MetricTableShowLatestValues", resourceCulture); } } - /// - /// Looks up a localized string similar to Set column widths. - /// - public static string FluentDataGridHeaderCellSubmitAriaLabelText { + public static string MetricTableShowOnlyValueChanges { get { - return ResourceManager.GetString("FluentDataGridHeaderCellSubmitAriaLabelText", resourceCulture); + return ResourceManager.GetString("MetricTableShowOnlyValueChanges", resourceCulture); } } - /// - /// Looks up a localized string similar to Copied!. - /// - public static string GridValueCopied { + public static string MetricTableValueIncreased { get { - return ResourceManager.GetString("GridValueCopied", resourceCulture); + return ResourceManager.GetString("MetricTableValueIncreased", resourceCulture); } } - /// - /// Looks up a localized string similar to Copy to clipboard. - /// - public static string GridValueCopyToClipboard { + public static string MetricTableValueDecreased { get { - return ResourceManager.GetString("GridValueCopyToClipboard", resourceCulture); + return ResourceManager.GetString("MetricTableValueDecreased", resourceCulture); } } - /// - /// Looks up a localized string similar to Hide value. - /// - public static string GridValueMaskHideValue { + public static string MetricTableValueNoChange { get { - return ResourceManager.GetString("GridValueMaskHideValue", resourceCulture); + return ResourceManager.GetString("MetricTableValueNoChange", resourceCulture); } } - /// - /// Looks up a localized string similar to Show value. - /// - public static string GridValueMaskShowValue { + public static string MetricTableNoMetricsFound { get { - return ResourceManager.GetString("GridValueMaskShowValue", resourceCulture); + return ResourceManager.GetString("MetricTableNoMetricsFound", resourceCulture); } } - /// - /// Looks up a localized string similar to (All). - /// - public static string LabelAll { + public static string ResourceLabel { get { - return ResourceManager.GetString("LabelAll", resourceCulture); + return ResourceManager.GetString("ResourceLabel", resourceCulture); } } - /// - /// Looks up a localized string similar to (Empty). - /// - public static string LabelEmpty { + public static string TimeOffsetColumnHeader { get { - return ResourceManager.GetString("LabelEmpty", resourceCulture); + return ResourceManager.GetString("TimeOffsetColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to (None). - /// - public static string LabelNone { + public static string EventColumnHeader { get { - return ResourceManager.GetString("LabelNone", resourceCulture); + return ResourceManager.GetString("EventColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to (Unset). - /// - public static string LabelUnset { + public static string DurationColumnHeader { get { - return ResourceManager.GetString("LabelUnset", resourceCulture); + return ResourceManager.GetString("DurationColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Link. - /// - public static string LinkColumnHeader { + public static string TimestampColumnHeader { get { - return ResourceManager.GetString("LinkColumnHeader", resourceCulture); + return ResourceManager.GetString("TimestampColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Loading.... - /// - public static string Loading { + public static string DetailsColumnHeader { get { - return ResourceManager.GetString("Loading", resourceCulture); + return ResourceManager.GetString("DetailsColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Exemplars. - /// - public static string MetricTableExemplarsColumnHeader { + public static string ResourceDropdownReplicaAccessibleTitle { get { - return ResourceManager.GetString("MetricTableExemplarsColumnHeader", resourceCulture); + return ResourceManager.GetString("ResourceDropdownReplicaAccessibleTitle", resourceCulture); } } - /// - /// Looks up a localized string similar to No metrics data found. - /// - public static string MetricTableNoMetricsFound { + public static string ApplicationLower { get { - return ResourceManager.GetString("MetricTableNoMetricsFound", resourceCulture); + return ResourceManager.GetString("ApplicationLower", resourceCulture); } } - /// - /// Looks up a localized string similar to Show latest 10 values. - /// - public static string MetricTableShowLatestValues { + public static string Loading { get { - return ResourceManager.GetString("MetricTableShowLatestValues", resourceCulture); + return ResourceManager.GetString("Loading", resourceCulture); } } - /// - /// Looks up a localized string similar to Only show value updates. - /// - public static string MetricTableShowOnlyValueChanges { + public static string StructuredLogsDetailsResource { get { - return ResourceManager.GetString("MetricTableShowOnlyValueChanges", resourceCulture); + return ResourceManager.GetString("StructuredLogsDetailsResource", resourceCulture); } } - /// - /// Looks up a localized string similar to Time. - /// - public static string MetricTableStartColumnHeader { + public static string StructuredLogsDetailsTimestamp { get { - return ResourceManager.GetString("MetricTableStartColumnHeader", resourceCulture); + return ResourceManager.GetString("StructuredLogsDetailsTimestamp", resourceCulture); } } - /// - /// Looks up a localized string similar to Value decreased. - /// - public static string MetricTableValueDecreased { + public static string ResourceDetailsUrlsHeader { get { - return ResourceManager.GetString("MetricTableValueDecreased", resourceCulture); + return ResourceManager.GetString("ResourceDetailsUrlsHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Value increased. - /// - public static string MetricTableValueIncreased { + public static string ResourceDetailsEnvironmentVariablesHeader { get { - return ResourceManager.GetString("MetricTableValueIncreased", resourceCulture); + return ResourceManager.GetString("ResourceDetailsEnvironmentVariablesHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Value did not change. - /// - public static string MetricTableValueNoChange { + public static string ResourceDetailsVolumesHeader { get { - return ResourceManager.GetString("MetricTableValueNoChange", resourceCulture); + return ResourceManager.GetString("ResourceDetailsVolumesHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to View exemplars. - /// - public static string MetricTableViewExemplarsLabel { + public static string ResourceHealthChecksHeader { get { - return ResourceManager.GetString("MetricTableViewExemplarsLabel", resourceCulture); + return ResourceManager.GetString("ResourceHealthChecksHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Name. - /// - public static string NameColumnHeader { + public static string ResourceDetailsResourceHeader { get { - return ResourceManager.GetString("NameColumnHeader", resourceCulture); + return ResourceManager.GetString("ResourceDetailsResourceHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Page toolbar. - /// - public static string PageToolbarLandmark { + public static string SpanDetailsEventsHeader { get { - return ResourceManager.GetString("PageToolbarLandmark", resourceCulture); + return ResourceManager.GetString("SpanDetailsEventsHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Count. - /// - public static string PlotlyChartCount { + public static string SpanDetailsResourceHeader { get { - return ResourceManager.GetString("PlotlyChartCount", resourceCulture); + return ResourceManager.GetString("SpanDetailsResourceHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Exemplars. - /// - public static string PlotlyChartExemplars { + public static string SpanDetailsSpanHeader { get { - return ResourceManager.GetString("PlotlyChartExemplars", resourceCulture); + return ResourceManager.GetString("SpanDetailsSpanHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Length. - /// - public static string PlotlyChartLength { + public static string StructuredLogsDetailsContextHeader { get { - return ResourceManager.GetString("PlotlyChartLength", resourceCulture); + return ResourceManager.GetString("StructuredLogsDetailsContextHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Time. - /// - public static string PlotlyChartTime { + public static string StructuredLogsDetailsExceptionHeader { get { - return ResourceManager.GetString("PlotlyChartTime", resourceCulture); + return ResourceManager.GetString("StructuredLogsDetailsExceptionHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Trace. - /// - public static string PlotlyChartTrace { + public static string StructuredLogsDetailsLogEntryHeader { get { - return ResourceManager.GetString("PlotlyChartTrace", resourceCulture); + return ResourceManager.GetString("StructuredLogsDetailsLogEntryHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Value. - /// - public static string PlotlyChartValue { + public static string StructuredLogsDetailsResourceHeader { get { - return ResourceManager.GetString("PlotlyChartValue", resourceCulture); + return ResourceManager.GetString("StructuredLogsDetailsResourceHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Value. - /// - public static string PropertyGridValueColumnHeader { + public static string TraceDetailAttributesHeader { get { - return ResourceManager.GetString("PropertyGridValueColumnHeader", resourceCulture); + return ResourceManager.GetString("TraceDetailAttributesHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Back references. - /// - public static string ResourceDetailsBackReferences { + public static string SpanDetailsContextHeader { get { - return ResourceManager.GetString("ResourceDetailsBackReferences", resourceCulture); + return ResourceManager.GetString("SpanDetailsContextHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Environment variables. - /// - public static string ResourceDetailsEnvironmentVariablesHeader { + public static string MetricTableExemplarsColumnHeader { get { - return ResourceManager.GetString("ResourceDetailsEnvironmentVariablesHeader", resourceCulture); + return ResourceManager.GetString("MetricTableExemplarsColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to References. - /// - public static string ResourceDetailsReferences { + public static string MetricTableViewExemplarsLabel { get { - return ResourceManager.GetString("ResourceDetailsReferences", resourceCulture); + return ResourceManager.GetString("MetricTableViewExemplarsLabel", resourceCulture); } } - /// - /// Looks up a localized string similar to Resource. - /// - public static string ResourceDetailsResourceHeader { + public static string PlotlyChartTime { get { - return ResourceManager.GetString("ResourceDetailsResourceHeader", resourceCulture); + return ResourceManager.GetString("PlotlyChartTime", resourceCulture); } } - /// - /// Looks up a localized string similar to Type. - /// - public static string ResourceDetailsTypeHeader { + public static string PlotlyChartExemplars { get { - return ResourceManager.GetString("ResourceDetailsTypeHeader", resourceCulture); + return ResourceManager.GetString("PlotlyChartExemplars", resourceCulture); } } - /// - /// Looks up a localized string similar to URLs. - /// - public static string ResourceDetailsUrlsHeader { + public static string PlotlyChartTrace { get { - return ResourceManager.GetString("ResourceDetailsUrlsHeader", resourceCulture); + return ResourceManager.GetString("PlotlyChartTrace", resourceCulture); } } - /// - /// Looks up a localized string similar to Volumes. - /// - public static string ResourceDetailsVolumesHeader { + public static string SpanDetailsLinksHeader { get { - return ResourceManager.GetString("ResourceDetailsVolumesHeader", resourceCulture); + return ResourceManager.GetString("SpanDetailsLinksHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to {0} (replica of {1}). - /// - public static string ResourceDropdownReplicaAccessibleTitle { + public static string SpanDetailsSpanPrefix { get { - return ResourceManager.GetString("ResourceDropdownReplicaAccessibleTitle", resourceCulture); + return ResourceManager.GetString("SpanDetailsSpanPrefix", resourceCulture); } } - /// - /// Looks up a localized string similar to No endpoints. - /// - public static string ResourceGraphNoEndpoints { + public static string SpanDetailsSpanColumnHeader { get { - return ResourceManager.GetString("ResourceGraphNoEndpoints", resourceCulture); + return ResourceManager.GetString("SpanDetailsSpanColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Health checks. - /// - public static string ResourceHealthChecksHeader { + public static string SpanDetailsDetailsColumnHeader { get { - return ResourceManager.GetString("ResourceHealthChecksHeader", resourceCulture); + return ResourceManager.GetString("SpanDetailsDetailsColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Resource. - /// - public static string ResourceLabel { + public static string SpanDetailsBacklinksHeader { get { - return ResourceManager.GetString("ResourceLabel", resourceCulture); + return ResourceManager.GetString("SpanDetailsBacklinksHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Select an application. - /// - public static string SelectAnApplication { + public static string PageToolbarLandmark { get { - return ResourceManager.GetString("SelectAnApplication", resourceCulture); + return ResourceManager.GetString("PageToolbarLandmark", resourceCulture); } } - /// - /// Looks up a localized string similar to Backlinks. - /// - public static string SpanDetailsBacklinksHeader { + public static string FluentDataGridHeaderCellResizeLabel { get { - return ResourceManager.GetString("SpanDetailsBacklinksHeader", resourceCulture); + return ResourceManager.GetString("FluentDataGridHeaderCellResizeLabel", resourceCulture); } } - /// - /// Looks up a localized string similar to Context. - /// - public static string SpanDetailsContextHeader { + public static string FluentDataGridHeaderCellResizeDiscreteLabel { get { - return ResourceManager.GetString("SpanDetailsContextHeader", resourceCulture); + return ResourceManager.GetString("FluentDataGridHeaderCellResizeDiscreteLabel", resourceCulture); } } - /// - /// Looks up a localized string similar to Details. - /// - public static string SpanDetailsDetailsColumnHeader { + public static string FluentDataGridHeaderCellSortButtonText { get { - return ResourceManager.GetString("SpanDetailsDetailsColumnHeader", resourceCulture); + return ResourceManager.GetString("FluentDataGridHeaderCellSortButtonText", resourceCulture); } } - /// - /// Looks up a localized string similar to Duration <strong>{0}</strong>. - /// - public static string SpanDetailsDuration { + public static string FluentDataGridHeaderCellSortAscendingButtonText { get { - return ResourceManager.GetString("SpanDetailsDuration", resourceCulture); + return ResourceManager.GetString("FluentDataGridHeaderCellSortAscendingButtonText", resourceCulture); } } - /// - /// Looks up a localized string similar to Events. - /// - public static string SpanDetailsEventsHeader { + public static string FluentDataGridHeaderCellSortDescendingButtonText { get { - return ResourceManager.GetString("SpanDetailsEventsHeader", resourceCulture); + return ResourceManager.GetString("FluentDataGridHeaderCellSortDescendingButtonText", resourceCulture); } } - /// - /// Looks up a localized string similar to Links. - /// - public static string SpanDetailsLinksHeader { + public static string FluentDataGridHeaderCellResizeButtonText { get { - return ResourceManager.GetString("SpanDetailsLinksHeader", resourceCulture); + return ResourceManager.GetString("FluentDataGridHeaderCellResizeButtonText", resourceCulture); } } - /// - /// Looks up a localized string similar to Resource <strong>{0}</strong>. - /// - public static string SpanDetailsResource { + public static string FluentDataGridHeaderCellGrowAriaLabelText { get { - return ResourceManager.GetString("SpanDetailsResource", resourceCulture); + return ResourceManager.GetString("FluentDataGridHeaderCellGrowAriaLabelText", resourceCulture); } } - /// - /// Looks up a localized string similar to Resource. - /// - public static string SpanDetailsResourceHeader { + public static string FluentDataGridHeaderCellResetAriaLabelText { get { - return ResourceManager.GetString("SpanDetailsResourceHeader", resourceCulture); + return ResourceManager.GetString("FluentDataGridHeaderCellResetAriaLabelText", resourceCulture); } } - /// - /// Looks up a localized string similar to Span. - /// - public static string SpanDetailsSpanColumnHeader { + public static string FluentDataGridHeaderCellShrinkAriaLabelText { get { - return ResourceManager.GetString("SpanDetailsSpanColumnHeader", resourceCulture); + return ResourceManager.GetString("FluentDataGridHeaderCellShrinkAriaLabelText", resourceCulture); } } - /// - /// Looks up a localized string similar to Span. - /// - public static string SpanDetailsSpanHeader { + public static string FluentDataGridHeaderCellSubmitAriaLabelText { get { - return ResourceManager.GetString("SpanDetailsSpanHeader", resourceCulture); + return ResourceManager.GetString("FluentDataGridHeaderCellSubmitAriaLabelText", resourceCulture); } } - /// - /// Looks up a localized string similar to Span. - /// - public static string SpanDetailsSpanPrefix { + public static string StructuredFilteringFilters { get { - return ResourceManager.GetString("SpanDetailsSpanPrefix", resourceCulture); + return ResourceManager.GetString("StructuredFilteringFilters", resourceCulture); } } - /// - /// Looks up a localized string similar to Start time <strong>{0}</strong>. - /// - public static string SpanDetailsStartTime { + public static string StructuredFilteringNoFilters { get { - return ResourceManager.GetString("SpanDetailsStartTime", resourceCulture); + return ResourceManager.GetString("StructuredFilteringNoFilters", resourceCulture); } } - /// - /// Looks up a localized string similar to State. - /// - public static string StateColumnHeader { + public static string StructuredFilteringAddFilter { get { - return ResourceManager.GetString("StateColumnHeader", resourceCulture); + return ResourceManager.GetString("StructuredFilteringAddFilter", resourceCulture); } } - /// - /// Looks up a localized string similar to Add filter. - /// - public static string StructuredFilteringAddFilter { + public static string LabelEmpty { get { - return ResourceManager.GetString("StructuredFilteringAddFilter", resourceCulture); + return ResourceManager.GetString("LabelEmpty", resourceCulture); } } - /// - /// Looks up a localized string similar to Filters. - /// - public static string StructuredFilteringFilters { + public static string LabelUnset { get { - return ResourceManager.GetString("StructuredFilteringFilters", resourceCulture); + return ResourceManager.GetString("LabelUnset", resourceCulture); } } - /// - /// Looks up a localized string similar to No filters. - /// - public static string StructuredFilteringNoFilters { + public static string ActionsColumnHeader { get { - return ResourceManager.GetString("StructuredFilteringNoFilters", resourceCulture); + return ResourceManager.GetString("ActionsColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Context. - /// - public static string StructuredLogsDetailsContextHeader { + public static string ActionViewDetailsText { get { - return ResourceManager.GetString("StructuredLogsDetailsContextHeader", resourceCulture); + return ResourceManager.GetString("ActionViewDetailsText", resourceCulture); } } - /// - /// Looks up a localized string similar to Exception. - /// - public static string StructuredLogsDetailsExceptionHeader { + public static string ActionsButtonText { get { - return ResourceManager.GetString("StructuredLogsDetailsExceptionHeader", resourceCulture); + return ResourceManager.GetString("ActionsButtonText", resourceCulture); } } - /// - /// Looks up a localized string similar to Log entry. - /// - public static string StructuredLogsDetailsLogEntryHeader { + public static string ActionStructuredLogsText { get { - return ResourceManager.GetString("StructuredLogsDetailsLogEntryHeader", resourceCulture); + return ResourceManager.GetString("ActionStructuredLogsText", resourceCulture); } } - /// - /// Looks up a localized string similar to Resource <strong>{0}</strong>. - /// - public static string StructuredLogsDetailsResource { + public static string ResourceDetailsTypeHeader { get { - return ResourceManager.GetString("StructuredLogsDetailsResource", resourceCulture); + return ResourceManager.GetString("ResourceDetailsTypeHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Resource. - /// - public static string StructuredLogsDetailsResourceHeader { + public static string ResourceDetailsReferences { get { - return ResourceManager.GetString("StructuredLogsDetailsResourceHeader", resourceCulture); + return ResourceManager.GetString("ResourceDetailsReferences", resourceCulture); } } - /// - /// Looks up a localized string similar to Timestamp <strong>{0}</strong>. - /// - public static string StructuredLogsDetailsTimestamp { + public static string ResourceDetailsBackReferences { get { - return ResourceManager.GetString("StructuredLogsDetailsTimestamp", resourceCulture); + return ResourceManager.GetString("ResourceDetailsBackReferences", resourceCulture); } } - /// - /// Looks up a localized string similar to Close. - /// - public static string SummaryDetailsViewCloseView { + public static string VolumePathColumnHeader { get { - return ResourceManager.GetString("SummaryDetailsViewCloseView", resourceCulture); + return ResourceManager.GetString("VolumePathColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Split horizontal. - /// - public static string SummaryDetailsViewSplitHorizontal { + public static string VolumeMountTypeColumnHeader { get { - return ResourceManager.GetString("SummaryDetailsViewSplitHorizontal", resourceCulture); + return ResourceManager.GetString("VolumeMountTypeColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Split vertical. - /// - public static string SummaryDetailsViewSplitVertical { + public static string ClearAllResources { get { - return ResourceManager.GetString("SummaryDetailsViewSplitVertical", resourceCulture); + return ResourceManager.GetString("ClearAllResources", resourceCulture); } } - /// - /// Looks up a localized string similar to Time offset. - /// - public static string TimeOffsetColumnHeader { + public static string ClearSelectedResource { get { - return ResourceManager.GetString("TimeOffsetColumnHeader", resourceCulture); + return ResourceManager.GetString("ClearSelectedResource", resourceCulture); } } - /// - /// Looks up a localized string similar to Timestamp. - /// - public static string TimestampColumnHeader { + public static string ClearPendingSelectedResource { get { - return ResourceManager.GetString("TimestampColumnHeader", resourceCulture); + return ResourceManager.GetString("ClearPendingSelectedResource", resourceCulture); } } - /// - /// Looks up a localized string similar to Total: <strong>{0} results found</strong>. - /// - public static string TotalItemsFooterText { + public static string ChartContainerOverflowDescription { get { - return ResourceManager.GetString("TotalItemsFooterText", resourceCulture); + return ResourceManager.GetString("ChartContainerOverflowDescription", resourceCulture); } } - /// - /// Looks up a localized string similar to Attributes. - /// - public static string TraceDetailAttributesHeader { + public static string ChartContainerOverflowTitle { get { - return ResourceManager.GetString("TraceDetailAttributesHeader", resourceCulture); + return ResourceManager.GetString("ChartContainerOverflowTitle", resourceCulture); } } - /// - /// Looks up a localized string similar to View. - /// - public static string ViewAction { + public static string ChartContainerOverflowLink { get { - return ResourceManager.GetString("ViewAction", resourceCulture); + return ResourceManager.GetString("ChartContainerOverflowLink", resourceCulture); } } - /// - /// Looks up a localized string similar to View logs. - /// - public static string ViewLogsLink { + public static string EndpointNameColumnHeader { get { - return ResourceManager.GetString("ViewLogsLink", resourceCulture); + return ResourceManager.GetString("EndpointNameColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Mount type. - /// - public static string VolumeMountTypeColumnHeader { + public static string LinkColumnHeader { get { - return ResourceManager.GetString("VolumeMountTypeColumnHeader", resourceCulture); + return ResourceManager.GetString("LinkColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Path. - /// - public static string VolumePathColumnHeader { + public static string ResourceGraphNoEndpoints { get { - return ResourceManager.GetString("VolumePathColumnHeader", resourceCulture); + return ResourceManager.GetString("ResourceGraphNoEndpoints", resourceCulture); } } From 247868c01ae6055ad13e30d12516fa6cdc47d39a Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Sat, 22 Mar 2025 17:56:41 -0400 Subject: [PATCH 23/35] use LogEntry instead of Timestamp as the entry in PauseManager because there can be multiple entries with same timestamp --- .../Components/Pages/ConsoleLogs.razor.cs | 2 +- src/Aspire.Dashboard/Model/PauseManager.cs | 15 +++++++++------ src/Shared/ConsoleLogs/LogEntry.cs | 19 +++++++++++++++++++ src/Shared/StringComparers.cs | 2 ++ .../PauseManagerTests.cs | 8 +++++--- 5 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs index da763853d0a..b2575b6a55a 100644 --- a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs @@ -494,7 +494,7 @@ private void LoadLogs(ConsoleLogsSubscription newConsoleLogsSubscription) continue; } - if (logEntry.Timestamp is not null && PauseManager.IsConsoleLogFiltered(logEntry.Timestamp.Value, newConsoleLogsSubscription.Name)) + if (logEntry.Timestamp is not null && PauseManager.IsConsoleLogFiltered(logEntry, newConsoleLogsSubscription.Name)) { continue; } diff --git a/src/Aspire.Dashboard/Model/PauseManager.cs b/src/Aspire.Dashboard/Model/PauseManager.cs index 1281e69a501..92bded62c60 100644 --- a/src/Aspire.Dashboard/Model/PauseManager.cs +++ b/src/Aspire.Dashboard/Model/PauseManager.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using Aspire.Hosting.ConsoleLogs; namespace Aspire.Dashboard.Model; @@ -41,25 +42,27 @@ public bool TryGetConsoleLogPause(DateTime startTime, [NotNullWhen(true)] out Co return false; } - public bool IsConsoleLogFiltered(DateTime timestamp, string application) + public bool IsConsoleLogFiltered(LogEntry entry, string application) { + Debug.Assert(entry.Timestamp is not null, "Log entry timestamp should not be null."); + ConsoleLogPause? foundRange = null; foreach (var range in _consoleLogsPausedRanges.Values) { - if (range.IsOverlapping(timestamp)) + if (range.IsOverlapping(entry.Timestamp.Value)) { foundRange = range; break; } } - if (foundRange is not null && foundRange.FilteredLogsByApplication.GetValueOrDefault(application)?.Contains(timestamp) is not true) + if (foundRange is not null && foundRange.FilteredLogsByApplication.GetValueOrDefault(application)?.Contains(entry) is not true) { ImmutableInterlocked.Update( ref _consoleLogsPausedRanges, ranges => ranges.SetItem(foundRange.Start, - foundRange with { FilteredLogsByApplication = foundRange.FilteredLogsByApplication.SetItem(application, foundRange.FilteredLogsByApplication.GetValueOrDefault(application)?.Add(timestamp) ?? [timestamp]) })); + foundRange with { FilteredLogsByApplication = foundRange.FilteredLogsByApplication.SetItem(application, foundRange.FilteredLogsByApplication.GetValueOrDefault(application)?.Add(entry) ?? [entry]) })); } return foundRange is not null; @@ -73,7 +76,7 @@ public void SetConsoleLogsPaused(bool isPaused, DateTime timestamp) { if (isPaused) { - return ranges.Add(timestamp, new ConsoleLogPause(Start: timestamp, End: null, FilteredLogsByApplication: ImmutableDictionary>.Empty)); + return ranges.Add(timestamp, new ConsoleLogPause(Start: timestamp, End: null, FilteredLogsByApplication: ImmutableDictionary>.Empty)); } else { @@ -90,7 +93,7 @@ public void SetConsoleLogsPaused(bool isPaused, DateTime timestamp) } } -public record ConsoleLogPause(DateTime Start, DateTime? End, ImmutableDictionary> FilteredLogsByApplication) +public record ConsoleLogPause(DateTime Start, DateTime? End, ImmutableDictionary> FilteredLogsByApplication) { public int GetFilteredLogCount(string? application) { diff --git a/src/Shared/ConsoleLogs/LogEntry.cs b/src/Shared/ConsoleLogs/LogEntry.cs index c5e0c39171f..cc9a718647d 100644 --- a/src/Shared/ConsoleLogs/LogEntry.cs +++ b/src/Shared/ConsoleLogs/LogEntry.cs @@ -47,6 +47,25 @@ public static LogEntry Create(DateTime? timestamp, string logMessage, string raw Type = isErrorMessage ? LogEntryType.Error : LogEntryType.Default }; } + + private bool Equals(LogEntry other) + { + return string.Equals(Content, other.Content, StringComparisons.ConsoleLogContent) + && string.Equals(RawContent, other.RawContent, StringComparisons.ConsoleLogContent) + && Nullable.Equals(Timestamp, other.Timestamp) + && Type == other.Type + && LineNumber == other.LineNumber; + } + + public override bool Equals(object? obj) + { + return ReferenceEquals(this, obj) || obj is LogEntry other && Equals(other); + } + + public override int GetHashCode() + { + return HashCode.Combine(Content, RawContent, Timestamp, (int)Type, LineNumber); + } } #if ASPIRE_DASHBOARD diff --git a/src/Shared/StringComparers.cs b/src/Shared/StringComparers.cs index 5f4668b5d13..9a1f05fe5ca 100644 --- a/src/Shared/StringComparers.cs +++ b/src/Shared/StringComparers.cs @@ -26,6 +26,7 @@ internal static class StringComparers public static StringComparer OtlpFieldValue => StringComparer.OrdinalIgnoreCase; public static StringComparer OtlpSpanId => StringComparer.Ordinal; public static StringComparer HealthReportPropertyValue => StringComparer.Ordinal; + public static StringComparer ConsoleLogContent => StringComparer.Ordinal; public static StringComparer CultureName => StringComparer.OrdinalIgnoreCase; } @@ -50,5 +51,6 @@ internal static class StringComparisons public static StringComparison OtlpFieldValue => StringComparison.OrdinalIgnoreCase; public static StringComparison OtlpSpanId => StringComparison.Ordinal; public static StringComparison HealthReportPropertyValue => StringComparison.Ordinal; + public static StringComparison ConsoleLogContent => StringComparison.Ordinal; public static StringComparison CultureName => StringComparison.OrdinalIgnoreCase; } diff --git a/tests/Aspire.Dashboard.Tests/PauseManagerTests.cs b/tests/Aspire.Dashboard.Tests/PauseManagerTests.cs index 9108f8b8bef..ffa703a1a47 100644 --- a/tests/Aspire.Dashboard.Tests/PauseManagerTests.cs +++ b/tests/Aspire.Dashboard.Tests/PauseManagerTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Dashboard.Model; +using Aspire.Hosting.ConsoleLogs; using Xunit; namespace Aspire.Dashboard.Tests; @@ -59,11 +60,12 @@ public void IsConsoleLogFiltered_ShouldReturnExpectedResult(bool isPaused, int m pauseManager.SetConsoleLogsPaused(false, endTimestamp); } var logTimestamp = startTimestamp.AddMinutes(minutesToAdd); + var entry = LogEntry.Create(logTimestamp, "msg", false); // Act - var isFiltered1 = pauseManager.IsConsoleLogFiltered(logTimestamp, "app1"); - var isFiltered2 = pauseManager.IsConsoleLogFiltered(logTimestamp, "app1"); - var isFiltered3 = pauseManager.IsConsoleLogFiltered(logTimestamp, "app1"); + var isFiltered1 = pauseManager.IsConsoleLogFiltered(entry, "app1"); + var isFiltered2 = pauseManager.IsConsoleLogFiltered(entry, "app1"); + var isFiltered3 = pauseManager.IsConsoleLogFiltered(entry, "app1"); // Assert Assert.Equal(expectedResult, isFiltered1); From da5693c4d873ea75933e7626f90b35695f92389a Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Sat, 22 Mar 2025 18:01:16 -0400 Subject: [PATCH 24/35] Filter out pauses when downloading logs --- src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs index b2575b6a55a..4b26f0c2dbc 100644 --- a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs @@ -588,6 +588,11 @@ private async Task DownloadLogsAsync() { foreach (var entry in _logEntries.GetEntries()) { + if (entry.Type is LogEntryType.Pause) + { + continue; + } + // It's ok to use sync stream methods here because we're writing to a MemoryStream. if (entry.RawContent is not null) { From c89e5fee5d6d304cb0626eac0686c938f2e645eb Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Sat, 22 Mar 2025 18:26:06 -0400 Subject: [PATCH 25/35] remove debug assrt --- src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs index 4b26f0c2dbc..5fbc1440519 100644 --- a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs @@ -504,9 +504,8 @@ private void LoadLogs(ConsoleLogsSubscription newConsoleLogsSubscription) // Only add entries that are not ignored, or if they are null as we cannot know when they happened. // As we may have skipped some logs during a pause, we need to check how far to skip to keep the line count // accurate. - if (previousEntry is { Type: LogEntryType.Pause, Timestamp: { } timestamp} && timestamp < logEntry.Timestamp) + if (previousEntry is { Type: LogEntryType.Pause, Timestamp: { } timestamp} && timestamp < logEntry.Timestamp && PauseManager.TryGetConsoleLogPause(timestamp, out var pause)) { - Debug.Assert(PauseManager.TryGetConsoleLogPause(timestamp, out var pause)); _logEntries.InsertSorted(logEntry, skipLineCount: pause.GetFilteredLogCount(newConsoleLogsSubscription.Name)); } else From 4757bf039defd1e18df6af5116e79ee5cd26da84 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Tue, 25 Mar 2025 06:35:22 -0400 Subject: [PATCH 26/35] Update pause strings --- .../Otlp/Storage/TelemetryRepository.cs | 6 +++--- src/Aspire.Dashboard/Resources/ConsoleLogs.resx | 6 +++--- src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.cs.xlf | 10 +++++----- src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.de.xlf | 10 +++++----- src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.es.xlf | 10 +++++----- src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.fr.xlf | 10 +++++----- src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.it.xlf | 10 +++++----- src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ja.xlf | 10 +++++----- src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ko.xlf | 10 +++++----- src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pl.xlf | 10 +++++----- .../Resources/xlf/ConsoleLogs.pt-BR.xlf | 10 +++++----- src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ru.xlf | 10 +++++----- src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.tr.xlf | 10 +++++----- .../Resources/xlf/ConsoleLogs.zh-Hans.xlf | 10 +++++----- .../Resources/xlf/ConsoleLogs.zh-Hant.xlf | 10 +++++----- 15 files changed, 71 insertions(+), 71 deletions(-) diff --git a/src/Aspire.Dashboard/Otlp/Storage/TelemetryRepository.cs b/src/Aspire.Dashboard/Otlp/Storage/TelemetryRepository.cs index 2fd2ad5ea94..8c143d99382 100644 --- a/src/Aspire.Dashboard/Otlp/Storage/TelemetryRepository.cs +++ b/src/Aspire.Dashboard/Otlp/Storage/TelemetryRepository.cs @@ -278,7 +278,7 @@ public void AddLogs(AddContext context, RepeatedField resourceLogs { if (_pauseManager.StructuredLogsPaused) { - _logger.LogTrace("{LogCount} incoming structured log(s) was ignored because of an active pause.", resourceLogs.Count); + _logger.LogTrace("{Count} incoming structured log(s) ignored because of an active pause.", resourceLogs.Count); return; } @@ -817,7 +817,7 @@ public void AddMetrics(AddContext context, RepeatedField resour { if (_pauseManager.AreMetricsPaused(out _)) { - _logger.LogTrace("{LogCount} incoming metric(s) was ignored because of an active pause.", resourceMetrics.Count); + _logger.LogTrace("{Count} incoming metric(s) ignored because of an active pause.", resourceMetrics.Count); return; } @@ -845,7 +845,7 @@ public void AddTraces(AddContext context, RepeatedField resourceS { if (_pauseManager.TracesPaused) { - _logger.LogTrace("{LogCount} incoming trace(s) was ignored because of an active pause.", resourceSpans.Count); + _logger.LogTrace("{Count} incoming trace(s) ignored because of an active pause.", resourceSpans.Count); return; } diff --git a/src/Aspire.Dashboard/Resources/ConsoleLogs.resx b/src/Aspire.Dashboard/Resources/ConsoleLogs.resx index 7f85d5dada2..4fd401ed63f 100644 --- a/src/Aspire.Dashboard/Resources/ConsoleLogs.resx +++ b/src/Aspire.Dashboard/Resources/ConsoleLogs.resx @@ -173,11 +173,11 @@ UTC timestamps - <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} log(s) filtered out> {0} is a number - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + {0} is a date, {1} is a date, {2} is a number. diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.cs.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.cs.xlf index 25ea215d19f..56a26ddffbd 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.cs.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.cs.xlf @@ -43,14 +43,14 @@ {0} is an application name - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} log(s) filtered out> + <Currently paused log capture, {0} log(s) filtered out> {0} is a number - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + {0} is a date, {1} is a date, {2} is a number. Resource commands diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.de.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.de.xlf index 4d0fb0e9d18..ad5373e29e0 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.de.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.de.xlf @@ -43,14 +43,14 @@ {0} is an application name - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} log(s) filtered out> + <Currently paused log capture, {0} log(s) filtered out> {0} is a number - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + {0} is a date, {1} is a date, {2} is a number. Resource commands diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.es.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.es.xlf index 90de278b2af..e6c2fb91664 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.es.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.es.xlf @@ -43,14 +43,14 @@ {0} is an application name - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} log(s) filtered out> + <Currently paused log capture, {0} log(s) filtered out> {0} is a number - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + {0} is a date, {1} is a date, {2} is a number. Resource commands diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.fr.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.fr.xlf index 46c9657dbce..19e02d94302 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.fr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.fr.xlf @@ -43,14 +43,14 @@ {0} is an application name - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} log(s) filtered out> + <Currently paused log capture, {0} log(s) filtered out> {0} is a number - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + {0} is a date, {1} is a date, {2} is a number. Resource commands diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.it.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.it.xlf index 546daa70004..4ad3021a2ef 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.it.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.it.xlf @@ -43,14 +43,14 @@ {0} is an application name - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} log(s) filtered out> + <Currently paused log capture, {0} log(s) filtered out> {0} is a number - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + {0} is a date, {1} is a date, {2} is a number. Resource commands diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ja.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ja.xlf index de0df2cfd28..6a1592140bc 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ja.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ja.xlf @@ -43,14 +43,14 @@ {0} is an application name - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} log(s) filtered out> + <Currently paused log capture, {0} log(s) filtered out> {0} is a number - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + {0} is a date, {1} is a date, {2} is a number. Resource commands diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ko.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ko.xlf index 577b150db20..7c326169b6e 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ko.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ko.xlf @@ -43,14 +43,14 @@ {0} is an application name - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} log(s) filtered out> + <Currently paused log capture, {0} log(s) filtered out> {0} is a number - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + {0} is a date, {1} is a date, {2} is a number. Resource commands diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pl.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pl.xlf index 6e4ce9b8b9a..7f8f011af95 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pl.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pl.xlf @@ -43,14 +43,14 @@ {0} is an application name - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} log(s) filtered out> + <Currently paused log capture, {0} log(s) filtered out> {0} is a number - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + {0} is a date, {1} is a date, {2} is a number. Resource commands diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pt-BR.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pt-BR.xlf index 1912ba5c778..66129b356d4 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pt-BR.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pt-BR.xlf @@ -43,14 +43,14 @@ {0} is an application name - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} log(s) filtered out> + <Currently paused log capture, {0} log(s) filtered out> {0} is a number - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + {0} is a date, {1} is a date, {2} is a number. Resource commands diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ru.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ru.xlf index bf0a908a4e6..92b4e9a4922 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ru.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ru.xlf @@ -43,14 +43,14 @@ {0} is an application name - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} log(s) filtered out> + <Currently paused log capture, {0} log(s) filtered out> {0} is a number - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + {0} is a date, {1} is a date, {2} is a number. Resource commands diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.tr.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.tr.xlf index 13ebbcb42c1..0e1eea20be9 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.tr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.tr.xlf @@ -43,14 +43,14 @@ {0} is an application name - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} log(s) filtered out> + <Currently paused log capture, {0} log(s) filtered out> {0} is a number - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + {0} is a date, {1} is a date, {2} is a number. Resource commands diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hans.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hans.xlf index 6547000a3ac..f163ce7cba3 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hans.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hans.xlf @@ -43,14 +43,14 @@ {0} is an application name - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} log(s) filtered out> + <Currently paused log capture, {0} log(s) filtered out> {0} is a number - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + {0} is a date, {1} is a date, {2} is a number. Resource commands diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hant.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hant.xlf index b2627025711..eeb26942340 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hant.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hant.xlf @@ -43,14 +43,14 @@ {0} is an application name - <Currently paused log capture, {0} entries filtered out> - <Currently paused log capture, {0} entries filtered out> + <Currently paused log capture, {0} log(s) filtered out> + <Currently paused log capture, {0} log(s) filtered out> {0} is a number - <Log capture paused between {0} and {1} {2} log entries filtered out> - <Log capture paused between {0} and {1} {2} log entries filtered out> - {0} is a date, {1} is a date, {2} is a number + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + <Log capture paused between {0} and {1}, {2} log(s) filtered out> + {0} is a date, {1} is a date, {2} is a number. Resource commands From 28ef56249b154dfa539705ed15a9f15f1ab531ee Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Tue, 25 Mar 2025 06:36:20 -0400 Subject: [PATCH 27/35] Avoid pluralizing in TotalItemsFooterText --- src/Aspire.Dashboard/Resources/ControlsStrings.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Aspire.Dashboard/Resources/ControlsStrings.resx b/src/Aspire.Dashboard/Resources/ControlsStrings.resx index 90a7c492aae..90f263fe880 100644 --- a/src/Aspire.Dashboard/Resources/ControlsStrings.resx +++ b/src/Aspire.Dashboard/Resources/ControlsStrings.resx @@ -212,7 +212,7 @@ Close - Total: <strong>{0} results found</strong> + Total: <strong>{0} result(s) found</strong> {0} is a number. This is raw markup, so <strong> and </strong> should not be modified From 9fb557a1ffa0d75495096df443da5040ad656326 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Tue, 25 Mar 2025 09:45:49 -0400 Subject: [PATCH 28/35] include pause info in trace/structured log footers --- .../Components/Controls/LogViewer.razor | 7 +- .../Controls/TotalItemsFooter.razor | 12 +- .../Components/Pages/ConsoleLogs.razor | 2 +- .../Components/Pages/ConsoleLogs.razor.cs | 3 +- .../Components/Pages/Metrics.razor | 2 +- .../Components/Pages/StructuredLogs.razor | 8 +- .../Components/Pages/StructuredLogs.razor.cs | 7 + .../Components/Pages/Traces.razor | 7 +- .../Components/Pages/Traces.razor.cs | 7 + src/Aspire.Dashboard/Model/PauseManager.cs | 26 ++- .../Otlp/Storage/TelemetryRepository.cs | 4 +- .../Resources/ConsoleLogs.resx | 4 +- .../Resources/StructuredLogs.Designer.cs | 177 ++++++------------ .../Resources/StructuredLogs.resx | 59 +++--- .../Resources/Traces.Designer.cs | 121 ++++-------- src/Aspire.Dashboard/Resources/Traces.resx | 59 +++--- .../Resources/xlf/ConsoleLogs.cs.xlf | 6 +- .../Resources/xlf/ConsoleLogs.de.xlf | 6 +- .../Resources/xlf/ConsoleLogs.es.xlf | 6 +- .../Resources/xlf/ConsoleLogs.fr.xlf | 6 +- .../Resources/xlf/ConsoleLogs.it.xlf | 6 +- .../Resources/xlf/ConsoleLogs.ja.xlf | 6 +- .../Resources/xlf/ConsoleLogs.ko.xlf | 6 +- .../Resources/xlf/ConsoleLogs.pl.xlf | 6 +- .../Resources/xlf/ConsoleLogs.pt-BR.xlf | 6 +- .../Resources/xlf/ConsoleLogs.ru.xlf | 6 +- .../Resources/xlf/ConsoleLogs.tr.xlf | 6 +- .../Resources/xlf/ConsoleLogs.zh-Hans.xlf | 6 +- .../Resources/xlf/ConsoleLogs.zh-Hant.xlf | 6 +- .../Resources/xlf/ControlsStrings.cs.xlf | 4 +- .../Resources/xlf/ControlsStrings.de.xlf | 4 +- .../Resources/xlf/ControlsStrings.es.xlf | 4 +- .../Resources/xlf/ControlsStrings.fr.xlf | 4 +- .../Resources/xlf/ControlsStrings.it.xlf | 4 +- .../Resources/xlf/ControlsStrings.ja.xlf | 4 +- .../Resources/xlf/ControlsStrings.ko.xlf | 4 +- .../Resources/xlf/ControlsStrings.pl.xlf | 4 +- .../Resources/xlf/ControlsStrings.pt-BR.xlf | 4 +- .../Resources/xlf/ControlsStrings.ru.xlf | 4 +- .../Resources/xlf/ControlsStrings.tr.xlf | 4 +- .../Resources/xlf/ControlsStrings.zh-Hans.xlf | 4 +- .../Resources/xlf/ControlsStrings.zh-Hant.xlf | 4 +- .../Resources/xlf/StructuredLogs.cs.xlf | 5 + .../Resources/xlf/StructuredLogs.de.xlf | 5 + .../Resources/xlf/StructuredLogs.es.xlf | 5 + .../Resources/xlf/StructuredLogs.fr.xlf | 5 + .../Resources/xlf/StructuredLogs.it.xlf | 5 + .../Resources/xlf/StructuredLogs.ja.xlf | 5 + .../Resources/xlf/StructuredLogs.ko.xlf | 5 + .../Resources/xlf/StructuredLogs.pl.xlf | 5 + .../Resources/xlf/StructuredLogs.pt-BR.xlf | 5 + .../Resources/xlf/StructuredLogs.ru.xlf | 5 + .../Resources/xlf/StructuredLogs.tr.xlf | 5 + .../Resources/xlf/StructuredLogs.zh-Hans.xlf | 5 + .../Resources/xlf/StructuredLogs.zh-Hant.xlf | 5 + .../Resources/xlf/Traces.cs.xlf | 5 + .../Resources/xlf/Traces.de.xlf | 5 + .../Resources/xlf/Traces.es.xlf | 5 + .../Resources/xlf/Traces.fr.xlf | 5 + .../Resources/xlf/Traces.it.xlf | 5 + .../Resources/xlf/Traces.ja.xlf | 5 + .../Resources/xlf/Traces.ko.xlf | 5 + .../Resources/xlf/Traces.pl.xlf | 5 + .../Resources/xlf/Traces.pt-BR.xlf | 5 + .../Resources/xlf/Traces.ru.xlf | 5 + .../Resources/xlf/Traces.tr.xlf | 5 + .../Resources/xlf/Traces.zh-Hans.xlf | 5 + .../Resources/xlf/Traces.zh-Hant.xlf | 5 + src/Aspire.Dashboard/wwwroot/css/app.css | 5 + .../TelemetryRepositoryTests.cs | 8 +- 70 files changed, 425 insertions(+), 353 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor index c3e68d6fd34..ae7dbac6ffb 100644 --- a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor +++ b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor @@ -24,8 +24,13 @@ } var text = pause.End is null - ? string.Format(Loc[nameof(ConsoleLogs.ConsoleLogsPauseActive)], filteredLogCount) + ? string.Format( + CultureInfo.CurrentCulture, + Loc[nameof(ConsoleLogs.ConsoleLogsPauseActive)], + FormatHelpers.FormatTimeWithOptionalDate(TimeProvider, startTimestamp, MillisecondsDisplay.Truncated), + filteredLogCount) : string.Format( + CultureInfo.CurrentCulture, Loc[nameof(ConsoleLogs.ConsoleLogsPauseDetails)], FormatHelpers.FormatTimeWithOptionalDate(TimeProvider, startTimestamp, MillisecondsDisplay.Truncated), FormatHelpers.FormatTimeWithOptionalDate(TimeProvider, pause.End.Value, MillisecondsDisplay.Truncated), diff --git a/src/Aspire.Dashboard/Components/Controls/TotalItemsFooter.razor b/src/Aspire.Dashboard/Components/Controls/TotalItemsFooter.razor index 6f782c4a4b7..c01d1d76cfa 100644 --- a/src/Aspire.Dashboard/Components/Controls/TotalItemsFooter.razor +++ b/src/Aspire.Dashboard/Components/Controls/TotalItemsFooter.razor @@ -2,7 +2,14 @@ @namespace Aspire.Dashboard.Components @inject IStringLocalizer Loc - + @code { // Total item count can be set via the parameter or via method. @@ -15,6 +22,9 @@ [Parameter] public int TotalItemCount { get; set; } + [Parameter] + public string? PauseText { get; set; } + /// /// Called when data grid data is refreshed. This sets the count explicitly and forces the control to re-render. /// diff --git a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor index 5cc715a9dc5..c0fb9944114 100644 --- a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor +++ b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor @@ -27,7 +27,7 @@ @bind-SelectedResource:after="HandleSelectedOptionChangedAsync" LabelClass="toolbar-left" /> - + @if (_highlightedCommands.Count > 0) diff --git a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs index 5fbc1440519..5951b2a2a2f 100644 --- a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs @@ -632,7 +632,7 @@ private async Task ClearConsoleLogs(ApplicationKey? key) await ConsoleLogsManager.UpdateFiltersAsync(_consoleLogFilters); } - private Task IsPausedChangedAsync(bool isPaused) + private void OnPausedChanged(bool isPaused) { var timestamp = DateTime.UtcNow; @@ -645,7 +645,6 @@ private Task IsPausedChangedAsync(bool isPaused) } PauseManager.SetConsoleLogsPaused(isPaused, timestamp); - return Task.CompletedTask; } public async ValueTask DisposeAsync() diff --git a/src/Aspire.Dashboard/Components/Pages/Metrics.razor b/src/Aspire.Dashboard/Components/Pages/Metrics.razor index 2e2e06cf03a..6600e1e6c6e 100644 --- a/src/Aspire.Dashboard/Components/Pages/Metrics.razor +++ b/src/Aspire.Dashboard/Components/Pages/Metrics.razor @@ -48,7 +48,7 @@ CanSelectGrouping="true" LabelClass="toolbar-left" /> - + diff --git a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor index 046aaa6deaf..25c08f33069 100644 --- a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor +++ b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor @@ -38,7 +38,7 @@ CanSelectGrouping="true" LabelClass="toolbar-left" /> - + @@ -185,9 +185,11 @@ - - +
diff --git a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor.cs b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor.cs index 4edf01e4339..75fec5127dd 100644 --- a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor.cs @@ -408,6 +408,13 @@ private void OnBrowserResize(object? o, EventArgs args) }); } + private string? PauseText => PauseManager.AreStructuredLogsPaused(out var startTime) + ? string.Format( + CultureInfo.CurrentCulture, + Loc[nameof(Dashboard.Resources.StructuredLogs.PauseInProgressText)], + FormatHelpers.FormatTimeWithOptionalDate(TimeProvider, startTime.Value, MillisecondsDisplay.Truncated)) + : null; + public void Dispose() { _applicationsSubscription?.Dispose(); diff --git a/src/Aspire.Dashboard/Components/Pages/Traces.razor b/src/Aspire.Dashboard/Components/Pages/Traces.razor index e530e645ea3..c348046a227 100644 --- a/src/Aspire.Dashboard/Components/Pages/Traces.razor +++ b/src/Aspire.Dashboard/Components/Pages/Traces.razor @@ -36,7 +36,7 @@ CanSelectGrouping="true" LabelClass="toolbar-left" /> - + @@ -170,7 +170,10 @@
- +
diff --git a/src/Aspire.Dashboard/Components/Pages/Traces.razor.cs b/src/Aspire.Dashboard/Components/Pages/Traces.razor.cs index a90423811c5..09b480d2396 100644 --- a/src/Aspire.Dashboard/Components/Pages/Traces.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/Traces.razor.cs @@ -248,6 +248,13 @@ private void OnBrowserResize(object? o, EventArgs args) }); } + private string? PauseText => PauseManager.AreTracesPaused(out var startTime) + ? string.Format( + CultureInfo.CurrentCulture, + Loc[nameof(Dashboard.Resources.StructuredLogs.PauseInProgressText)], + FormatHelpers.FormatTimeWithOptionalDate(TimeProvider, startTime.Value, MillisecondsDisplay.Truncated)) + : null; + public void Dispose() { _applicationsSubscription?.Dispose(); diff --git a/src/Aspire.Dashboard/Model/PauseManager.cs b/src/Aspire.Dashboard/Model/PauseManager.cs index 92bded62c60..0289c3f009a 100644 --- a/src/Aspire.Dashboard/Model/PauseManager.cs +++ b/src/Aspire.Dashboard/Model/PauseManager.cs @@ -10,24 +10,36 @@ namespace Aspire.Dashboard.Model; public sealed class PauseManager { - public bool StructuredLogsPaused { get; set; } - public bool TracesPaused { get; set; } - - private DateTimeOffset? _metricsPausedAt; + private DateTime? _metricsPausedAt; + private DateTime? _tracesPausedAt; + private DateTime? _structuredLogsPausedAt; public bool ConsoleLogsPaused { get; private set; } private ImmutableSortedDictionary _consoleLogsPausedRanges = ImmutableSortedDictionary.Create(Comparer.Create((x, y) => x.CompareTo(y))); public ImmutableSortedDictionary ConsoleLogsPausedRanges => _consoleLogsPausedRanges; - public bool AreMetricsPaused([NotNullWhen(true)] out DateTimeOffset? pausedAt) + public void SetMetricsPaused(bool isPaused) => _metricsPausedAt = isPaused ? DateTime.UtcNow : null; + + public bool AreMetricsPaused([NotNullWhen(true)] out DateTime? pausedAt) { pausedAt = _metricsPausedAt; return _metricsPausedAt is not null; } - public void SetMetricsPaused(bool isPaused) + public void SetTracesPaused(bool isPaused) => _tracesPausedAt = isPaused ? DateTime.UtcNow : null; + + public bool AreTracesPaused([NotNullWhen(true)] out DateTime? pausedAt) + { + pausedAt = _tracesPausedAt; + return _tracesPausedAt is not null; + } + + public void SetStructuredLogsPaused(bool isPaused) => _structuredLogsPausedAt = isPaused ? DateTime.UtcNow : null; + + public bool AreStructuredLogsPaused([NotNullWhen(true)] out DateTime? pausedAt) { - _metricsPausedAt = isPaused ? DateTimeOffset.UtcNow : null; + pausedAt = _structuredLogsPausedAt; + return _structuredLogsPausedAt is not null; } public bool TryGetConsoleLogPause(DateTime startTime, [NotNullWhen(true)] out ConsoleLogPause? pause) diff --git a/src/Aspire.Dashboard/Otlp/Storage/TelemetryRepository.cs b/src/Aspire.Dashboard/Otlp/Storage/TelemetryRepository.cs index 8c143d99382..9c5045d3ceb 100644 --- a/src/Aspire.Dashboard/Otlp/Storage/TelemetryRepository.cs +++ b/src/Aspire.Dashboard/Otlp/Storage/TelemetryRepository.cs @@ -276,7 +276,7 @@ private void RaiseSubscriptionChanged(List subscriptions) public void AddLogs(AddContext context, RepeatedField resourceLogs) { - if (_pauseManager.StructuredLogsPaused) + if (_pauseManager.AreStructuredLogsPaused(out _)) { _logger.LogTrace("{Count} incoming structured log(s) ignored because of an active pause.", resourceLogs.Count); return; @@ -843,7 +843,7 @@ public void AddMetrics(AddContext context, RepeatedField resour public void AddTraces(AddContext context, RepeatedField resourceSpans) { - if (_pauseManager.TracesPaused) + if (_pauseManager.AreTracesPaused(out _)) { _logger.LogTrace("{Count} incoming trace(s) ignored because of an active pause.", resourceSpans.Count); return; diff --git a/src/Aspire.Dashboard/Resources/ConsoleLogs.resx b/src/Aspire.Dashboard/Resources/ConsoleLogs.resx index 4fd401ed63f..a4583114402 100644 --- a/src/Aspire.Dashboard/Resources/ConsoleLogs.resx +++ b/src/Aspire.Dashboard/Resources/ConsoleLogs.resx @@ -173,8 +173,8 @@ UTC timestamps - <Currently paused log capture, {0} log(s) filtered out> - {0} is a number + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + {0} is a date, {1} is a number <Log capture paused between {0} and {1}, {2} log(s) filtered out> diff --git a/src/Aspire.Dashboard/Resources/StructuredLogs.Designer.cs b/src/Aspire.Dashboard/Resources/StructuredLogs.Designer.cs index 186204e28f0..f6601883f6b 100644 --- a/src/Aspire.Dashboard/Resources/StructuredLogs.Designer.cs +++ b/src/Aspire.Dashboard/Resources/StructuredLogs.Designer.cs @@ -1,7 +1,6 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -12,46 +11,32 @@ namespace Aspire.Dashboard.Resources { using System; - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class StructuredLogs { - private static global::System.Resources.ResourceManager resourceMan; + private static System.Resources.ResourceManager resourceMan; - private static global::System.Globalization.CultureInfo resourceCulture; + private static System.Globalization.CultureInfo resourceCulture; - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal StructuredLogs() { } - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Resources.ResourceManager ResourceManager { get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Aspire.Dashboard.Resources.StructuredLogs", typeof(StructuredLogs).Assembly); + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Aspire.Dashboard.Resources.StructuredLogs", typeof(StructuredLogs).Assembly); resourceMan = temp; } return resourceMan; } } - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -60,183 +45,129 @@ internal StructuredLogs() { } } - /// - /// Looks up a localized string similar to Log message. - /// - public static string ActionLogMessageText { + public static string StructuredLogsPageTitle { get { - return ResourceManager.GetString("ActionLogMessageText", resourceCulture); + return ResourceManager.GetString("StructuredLogsPageTitle", resourceCulture); } } - /// - /// Looks up a localized string similar to A maximum of {0} structured logs are stored. Old structured logs are automatically removed.. - /// - public static string MessageExceededLimitBody { + public static string StructuredLogsHeader { get { - return ResourceManager.GetString("MessageExceededLimitBody", resourceCulture); + return ResourceManager.GetString("StructuredLogsHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Exceeded structured log limit. - /// - public static string MessageExceededLimitTitle { + public static string StructuredLogsMinimumLogFilter { get { - return ResourceManager.GetString("MessageExceededLimitTitle", resourceCulture); + return ResourceManager.GetString("StructuredLogsMinimumLogFilter", resourceCulture); } } - /// - /// Looks up a localized string similar to Add filter. - /// - public static string StructuredLogsAddFilter { + public static string StructuredLogsSelectMinimumLogLevel { get { - return ResourceManager.GetString("StructuredLogsAddFilter", resourceCulture); + return ResourceManager.GetString("StructuredLogsSelectMinimumLogLevel", resourceCulture); } } - /// - /// Looks up a localized string similar to Edit filter. - /// - public static string StructuredLogsEditFilter { + public static string StructuredLogsFilters { get { - return ResourceManager.GetString("StructuredLogsEditFilter", resourceCulture); + return ResourceManager.GetString("StructuredLogsFilters", resourceCulture); } } - /// - /// Looks up a localized string similar to Log entry details. - /// - public static string StructuredLogsEntryDetails { + public static string StructuredLogsNoFilters { get { - return ResourceManager.GetString("StructuredLogsEntryDetails", resourceCulture); + return ResourceManager.GetString("StructuredLogsNoFilters", resourceCulture); } } - /// - /// Looks up a localized string similar to Filters. - /// - public static string StructuredLogsFilters { + public static string StructuredLogsAddFilter { get { - return ResourceManager.GetString("StructuredLogsFilters", resourceCulture); + return ResourceManager.GetString("StructuredLogsAddFilter", resourceCulture); } } - /// - /// Looks up a localized string similar to Structured logs. - /// - public static string StructuredLogsHeader { + public static string StructuredLogsEntryDetails { get { - return ResourceManager.GetString("StructuredLogsHeader", resourceCulture); + return ResourceManager.GetString("StructuredLogsEntryDetails", resourceCulture); + } + } + + public static string StructuredLogsResourceColumnHeader { + get { + return ResourceManager.GetString("StructuredLogsResourceColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Level. - /// public static string StructuredLogsLevelColumnHeader { get { return ResourceManager.GetString("StructuredLogsLevelColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Level. - /// - public static string StructuredLogsLevels { + public static string StructuredLogsTimestampColumnHeader { get { - return ResourceManager.GetString("StructuredLogsLevels", resourceCulture); + return ResourceManager.GetString("StructuredLogsTimestampColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Message. - /// public static string StructuredLogsMessageColumnHeader { get { return ResourceManager.GetString("StructuredLogsMessageColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Message filter. - /// - public static string StructuredLogsMessageFilter { + public static string StructuredLogsTraceColumnHeader { get { - return ResourceManager.GetString("StructuredLogsMessageFilter", resourceCulture); + return ResourceManager.GetString("StructuredLogsTraceColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Minimum log level filter. - /// - public static string StructuredLogsMinimumLogFilter { + public static string StructuredLogsNoLogsFound { get { - return ResourceManager.GetString("StructuredLogsMinimumLogFilter", resourceCulture); + return ResourceManager.GetString("StructuredLogsNoLogsFound", resourceCulture); } } - /// - /// Looks up a localized string similar to No filters. - /// - public static string StructuredLogsNoFilters { + public static string StructuredLogsEditFilter { get { - return ResourceManager.GetString("StructuredLogsNoFilters", resourceCulture); + return ResourceManager.GetString("StructuredLogsEditFilter", resourceCulture); } } - /// - /// Looks up a localized string similar to No structured logs found. - /// - public static string StructuredLogsNoLogsFound { + public static string StructuredLogsMessageFilter { get { - return ResourceManager.GetString("StructuredLogsNoLogsFound", resourceCulture); + return ResourceManager.GetString("StructuredLogsMessageFilter", resourceCulture); } } - /// - /// Looks up a localized string similar to {0} structured logs. - /// - public static string StructuredLogsPageTitle { + public static string StructuredLogsLevels { get { - return ResourceManager.GetString("StructuredLogsPageTitle", resourceCulture); + return ResourceManager.GetString("StructuredLogsLevels", resourceCulture); } } - /// - /// Looks up a localized string similar to Resource. - /// - public static string StructuredLogsResourceColumnHeader { + public static string MessageExceededLimitBody { get { - return ResourceManager.GetString("StructuredLogsResourceColumnHeader", resourceCulture); + return ResourceManager.GetString("MessageExceededLimitBody", resourceCulture); } } - /// - /// Looks up a localized string similar to Select a minimum log level. - /// - public static string StructuredLogsSelectMinimumLogLevel { + public static string MessageExceededLimitTitle { get { - return ResourceManager.GetString("StructuredLogsSelectMinimumLogLevel", resourceCulture); + return ResourceManager.GetString("MessageExceededLimitTitle", resourceCulture); } } - /// - /// Looks up a localized string similar to Timestamp. - /// - public static string StructuredLogsTimestampColumnHeader { + public static string ActionLogMessageText { get { - return ResourceManager.GetString("StructuredLogsTimestampColumnHeader", resourceCulture); + return ResourceManager.GetString("ActionLogMessageText", resourceCulture); } } - /// - /// Looks up a localized string similar to Trace. - /// - public static string StructuredLogsTraceColumnHeader { + public static string PauseInProgressText { get { - return ResourceManager.GetString("StructuredLogsTraceColumnHeader", resourceCulture); + return ResourceManager.GetString("PauseInProgressText", resourceCulture); } } } diff --git a/src/Aspire.Dashboard/Resources/StructuredLogs.resx b/src/Aspire.Dashboard/Resources/StructuredLogs.resx index 3296265ec94..cee6cba04ec 100644 --- a/src/Aspire.Dashboard/Resources/StructuredLogs.resx +++ b/src/Aspire.Dashboard/Resources/StructuredLogs.resx @@ -1,17 +1,17 @@  - @@ -179,4 +179,7 @@ Log message - \ No newline at end of file + + Currently paused structured logs capture starting at {0} + + diff --git a/src/Aspire.Dashboard/Resources/Traces.Designer.cs b/src/Aspire.Dashboard/Resources/Traces.Designer.cs index c0b2ea6b8aa..62d4f018883 100644 --- a/src/Aspire.Dashboard/Resources/Traces.Designer.cs +++ b/src/Aspire.Dashboard/Resources/Traces.Designer.cs @@ -1,7 +1,6 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -12,46 +11,32 @@ namespace Aspire.Dashboard.Resources { using System; - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class Traces { - private static global::System.Resources.ResourceManager resourceMan; + private static System.Resources.ResourceManager resourceMan; - private static global::System.Globalization.CultureInfo resourceCulture; + private static System.Globalization.CultureInfo resourceCulture; - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Traces() { } - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Resources.ResourceManager ResourceManager { get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Aspire.Dashboard.Resources.Traces", typeof(Traces).Assembly); + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Aspire.Dashboard.Resources.Traces", typeof(Traces).Assembly); resourceMan = temp; } return resourceMan; } } - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -60,112 +45,82 @@ internal Traces() { } } - /// - /// Looks up a localized string similar to A maximum of {0} traces are stored. Old traces are automatically removed.. - /// - public static string MessageExceededLimitBody { - get { - return ResourceManager.GetString("MessageExceededLimitBody", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Exceeded trace limit. - /// - public static string MessageExceededLimitTitle { - get { - return ResourceManager.GetString("MessageExceededLimitTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Name: {0}. - /// - public static string TracesFullName { + public static string TracesPageTitle { get { - return ResourceManager.GetString("TracesFullName", resourceCulture); + return ResourceManager.GetString("TracesPageTitle", resourceCulture); } } - /// - /// Looks up a localized string similar to Traces. - /// public static string TracesHeader { get { return ResourceManager.GetString("TracesHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Name filter. - /// public static string TracesNameFilter { get { return ResourceManager.GetString("TracesNameFilter", resourceCulture); } } - /// - /// Looks up a localized string similar to No traces found. - /// public static string TracesNoTraces { get { return ResourceManager.GetString("TracesNoTraces", resourceCulture); } } - /// - /// Looks up a localized string similar to {0} traces. - /// - public static string TracesPageTitle { + public static string TracesSpansColumnHeader { get { - return ResourceManager.GetString("TracesPageTitle", resourceCulture); + return ResourceManager.GetString("TracesSpansColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to {0} spans. - /// public static string TracesResourceSpans { get { return ResourceManager.GetString("TracesResourceSpans", resourceCulture); } } - /// - /// Looks up a localized string similar to Spans. - /// - public static string TracesSpansColumnHeader { + public static string TracesTotalTraces { get { - return ResourceManager.GetString("TracesSpansColumnHeader", resourceCulture); + return ResourceManager.GetString("TracesTotalTraces", resourceCulture); } } - /// - /// Looks up a localized string similar to Errored: {0}. - /// public static string TracesTotalErroredTraces { get { return ResourceManager.GetString("TracesTotalErroredTraces", resourceCulture); } } - /// - /// Looks up a localized string similar to Total: {0}. - /// - public static string TracesTotalTraces { + public static string TracesFullName { get { - return ResourceManager.GetString("TracesTotalTraces", resourceCulture); + return ResourceManager.GetString("TracesFullName", resourceCulture); } } - /// - /// Looks up a localized string similar to Trace Id: {0}. - /// public static string TracesTraceId { get { return ResourceManager.GetString("TracesTraceId", resourceCulture); } } + + public static string MessageExceededLimitTitle { + get { + return ResourceManager.GetString("MessageExceededLimitTitle", resourceCulture); + } + } + + public static string MessageExceededLimitBody { + get { + return ResourceManager.GetString("MessageExceededLimitBody", resourceCulture); + } + } + + public static string PauseInProgressText { + get { + return ResourceManager.GetString("PauseInProgressText", resourceCulture); + } + } } } diff --git a/src/Aspire.Dashboard/Resources/Traces.resx b/src/Aspire.Dashboard/Resources/Traces.resx index 8b6d29e1f32..569d278a0f5 100644 --- a/src/Aspire.Dashboard/Resources/Traces.resx +++ b/src/Aspire.Dashboard/Resources/Traces.resx @@ -1,17 +1,17 @@ - @@ -157,4 +157,7 @@ A maximum of {0} traces are stored. Old traces are automatically removed. {0} is the max count - \ No newline at end of file + + Currently paused trace capture starting at {0} + + diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.cs.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.cs.xlf index 56a26ddffbd..4405d598e14 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.cs.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.cs.xlf @@ -43,9 +43,9 @@ {0} is an application name - <Currently paused log capture, {0} log(s) filtered out> - <Currently paused log capture, {0} log(s) filtered out> - {0} is a number + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + {0} is a date, {1} is a number <Log capture paused between {0} and {1}, {2} log(s) filtered out> diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.de.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.de.xlf index ad5373e29e0..462b222ec23 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.de.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.de.xlf @@ -43,9 +43,9 @@ {0} is an application name - <Currently paused log capture, {0} log(s) filtered out> - <Currently paused log capture, {0} log(s) filtered out> - {0} is a number + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + {0} is a date, {1} is a number <Log capture paused between {0} and {1}, {2} log(s) filtered out> diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.es.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.es.xlf index e6c2fb91664..6d0a8eb9f5d 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.es.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.es.xlf @@ -43,9 +43,9 @@ {0} is an application name - <Currently paused log capture, {0} log(s) filtered out> - <Currently paused log capture, {0} log(s) filtered out> - {0} is a number + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + {0} is a date, {1} is a number <Log capture paused between {0} and {1}, {2} log(s) filtered out> diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.fr.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.fr.xlf index 19e02d94302..7e152dc2097 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.fr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.fr.xlf @@ -43,9 +43,9 @@ {0} is an application name - <Currently paused log capture, {0} log(s) filtered out> - <Currently paused log capture, {0} log(s) filtered out> - {0} is a number + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + {0} is a date, {1} is a number <Log capture paused between {0} and {1}, {2} log(s) filtered out> diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.it.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.it.xlf index 4ad3021a2ef..328f8d4fdc3 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.it.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.it.xlf @@ -43,9 +43,9 @@ {0} is an application name - <Currently paused log capture, {0} log(s) filtered out> - <Currently paused log capture, {0} log(s) filtered out> - {0} is a number + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + {0} is a date, {1} is a number <Log capture paused between {0} and {1}, {2} log(s) filtered out> diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ja.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ja.xlf index 6a1592140bc..96857ac4df5 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ja.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ja.xlf @@ -43,9 +43,9 @@ {0} is an application name - <Currently paused log capture, {0} log(s) filtered out> - <Currently paused log capture, {0} log(s) filtered out> - {0} is a number + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + {0} is a date, {1} is a number <Log capture paused between {0} and {1}, {2} log(s) filtered out> diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ko.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ko.xlf index 7c326169b6e..03166eddd84 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ko.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ko.xlf @@ -43,9 +43,9 @@ {0} is an application name - <Currently paused log capture, {0} log(s) filtered out> - <Currently paused log capture, {0} log(s) filtered out> - {0} is a number + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + {0} is a date, {1} is a number <Log capture paused between {0} and {1}, {2} log(s) filtered out> diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pl.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pl.xlf index 7f8f011af95..4d355c07c6c 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pl.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pl.xlf @@ -43,9 +43,9 @@ {0} is an application name - <Currently paused log capture, {0} log(s) filtered out> - <Currently paused log capture, {0} log(s) filtered out> - {0} is a number + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + {0} is a date, {1} is a number <Log capture paused between {0} and {1}, {2} log(s) filtered out> diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pt-BR.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pt-BR.xlf index 66129b356d4..fbb4df6eb73 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pt-BR.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pt-BR.xlf @@ -43,9 +43,9 @@ {0} is an application name - <Currently paused log capture, {0} log(s) filtered out> - <Currently paused log capture, {0} log(s) filtered out> - {0} is a number + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + {0} is a date, {1} is a number <Log capture paused between {0} and {1}, {2} log(s) filtered out> diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ru.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ru.xlf index 92b4e9a4922..d46b4769992 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ru.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ru.xlf @@ -43,9 +43,9 @@ {0} is an application name - <Currently paused log capture, {0} log(s) filtered out> - <Currently paused log capture, {0} log(s) filtered out> - {0} is a number + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + {0} is a date, {1} is a number <Log capture paused between {0} and {1}, {2} log(s) filtered out> diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.tr.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.tr.xlf index 0e1eea20be9..6c6bab7e666 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.tr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.tr.xlf @@ -43,9 +43,9 @@ {0} is an application name - <Currently paused log capture, {0} log(s) filtered out> - <Currently paused log capture, {0} log(s) filtered out> - {0} is a number + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + {0} is a date, {1} is a number <Log capture paused between {0} and {1}, {2} log(s) filtered out> diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hans.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hans.xlf index f163ce7cba3..9634a0bcc6c 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hans.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hans.xlf @@ -43,9 +43,9 @@ {0} is an application name - <Currently paused log capture, {0} log(s) filtered out> - <Currently paused log capture, {0} log(s) filtered out> - {0} is a number + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + {0} is a date, {1} is a number <Log capture paused between {0} and {1}, {2} log(s) filtered out> diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hant.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hant.xlf index eeb26942340..c532959909f 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hant.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hant.xlf @@ -43,9 +43,9 @@ {0} is an application name - <Currently paused log capture, {0} log(s) filtered out> - <Currently paused log capture, {0} log(s) filtered out> - {0} is a number + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + <Currently paused log capture starting at {0}, {1} log(s) filtered out> + {0} is a date, {1} is a number <Log capture paused between {0} and {1}, {2} log(s) filtered out> diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.cs.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.cs.xlf index 47d38df921a..bbf00c6721d 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.cs.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.cs.xlf @@ -573,8 +573,8 @@ - Total: <strong>{0} results found</strong> - Celkem: <strong>nalezené výsledky: {0} </strong> + Total: <strong>{0} result(s) found</strong> + Celkem: <strong>nalezené výsledky: {0} </strong> {0} is a number. This is raw markup, so <strong> and </strong> should not be modified diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.de.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.de.xlf index 386c16d3800..b188d37ce7d 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.de.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.de.xlf @@ -573,8 +573,8 @@ - Total: <strong>{0} results found</strong> - Gesamt: <strong>{0} Ergebnisse gefunden</strong> + Total: <strong>{0} result(s) found</strong> + Gesamt: <strong>{0} Ergebnisse gefunden</strong> {0} is a number. This is raw markup, so <strong> and </strong> should not be modified diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.es.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.es.xlf index 8f492718137..dca6631dad0 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.es.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.es.xlf @@ -573,8 +573,8 @@ - Total: <strong>{0} results found</strong> - Total: <strong>{0} resultados encontrados</strong> + Total: <strong>{0} result(s) found</strong> + Total: <strong>{0} resultados encontrados</strong> {0} is a number. This is raw markup, so <strong> and </strong> should not be modified diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.fr.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.fr.xlf index 085421ee41a..7ad83cd2688 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.fr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.fr.xlf @@ -573,8 +573,8 @@ - Total: <strong>{0} results found</strong> - Total : <strong>{0} résultats trouvés</strong> + Total: <strong>{0} result(s) found</strong> + Total : <strong>{0} résultats trouvés</strong> {0} is a number. This is raw markup, so <strong> and </strong> should not be modified diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.it.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.it.xlf index 8c7b3a31919..5a2b6d4757b 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.it.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.it.xlf @@ -573,8 +573,8 @@ - Total: <strong>{0} results found</strong> - Totale: <strong>{0} risultati trovati</strong> + Total: <strong>{0} result(s) found</strong> + Totale: <strong>{0} risultati trovati</strong> {0} is a number. This is raw markup, so <strong> and </strong> should not be modified diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ja.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ja.xlf index 407a7ad6233..82154e48794 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ja.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ja.xlf @@ -573,8 +573,8 @@ - Total: <strong>{0} results found</strong> - 合計: <strong>{0} 件の結果が見つかりました</strong> + Total: <strong>{0} result(s) found</strong> + 合計: <strong>{0} 件の結果が見つかりました</strong> {0} is a number. This is raw markup, so <strong> and </strong> should not be modified diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ko.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ko.xlf index f69f51a4ce2..df3359e2be3 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ko.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ko.xlf @@ -573,8 +573,8 @@ - Total: <strong>{0} results found</strong> - 합계: <strong>{0}개 검색 결과를 찾음</strong> + Total: <strong>{0} result(s) found</strong> + 합계: <strong>{0}개 검색 결과를 찾음</strong> {0} is a number. This is raw markup, so <strong> and </strong> should not be modified diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pl.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pl.xlf index df3fb19f062..4460c1e9009 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pl.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pl.xlf @@ -573,8 +573,8 @@ - Total: <strong>{0} results found</strong> - Łączna liczba <strong>znalezionych wyników {0}</strong> + Total: <strong>{0} result(s) found</strong> + Łączna liczba <strong>znalezionych wyników {0}</strong> {0} is a number. This is raw markup, so <strong> and </strong> should not be modified diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pt-BR.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pt-BR.xlf index 8ad829e60a9..f4d040f4b5c 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pt-BR.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pt-BR.xlf @@ -573,8 +573,8 @@ - Total: <strong>{0} results found</strong> - Total: <strong>{0} resultados encontrados</strong> + Total: <strong>{0} result(s) found</strong> + Total: <strong>{0} resultados encontrados</strong> {0} is a number. This is raw markup, so <strong> and </strong> should not be modified diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ru.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ru.xlf index f3cef9ddc37..71cb886e2ca 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ru.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ru.xlf @@ -573,8 +573,8 @@ - Total: <strong>{0} results found</strong> - Всего найдено результатов: <strong>{0}</strong> + Total: <strong>{0} result(s) found</strong> + Всего найдено результатов: <strong>{0}</strong> {0} is a number. This is raw markup, so <strong> and </strong> should not be modified diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.tr.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.tr.xlf index 4e0f0ba787b..8d18cb67f7d 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.tr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.tr.xlf @@ -573,8 +573,8 @@ - Total: <strong>{0} results found</strong> - Toplam: <strong>{0} sonuç bulundu</strong> + Total: <strong>{0} result(s) found</strong> + Toplam: <strong>{0} sonuç bulundu</strong> {0} is a number. This is raw markup, so <strong> and </strong> should not be modified diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hans.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hans.xlf index c7cc4626f73..4e5841d6992 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hans.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hans.xlf @@ -573,8 +573,8 @@ - Total: <strong>{0} results found</strong> - 总计: 找到<strong>{0} 个结果</strong> + Total: <strong>{0} result(s) found</strong> + 总计: 找到<strong>{0} 个结果</strong> {0} is a number. This is raw markup, so <strong> and </strong> should not be modified diff --git a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hant.xlf b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hant.xlf index 19909914134..5f94d998187 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hant.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hant.xlf @@ -573,8 +573,8 @@ - Total: <strong>{0} results found</strong> - 總共<strong>找到了 {0} 個結果</strong> + Total: <strong>{0} result(s) found</strong> + 總共<strong>找到了 {0} 個結果</strong> {0} is a number. This is raw markup, so <strong> and </strong> should not be modified diff --git a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.cs.xlf b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.cs.xlf index abcdbf63eb7..837aaa2fa58 100644 --- a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.cs.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.cs.xlf @@ -17,6 +17,11 @@ Překročil se limit strukturovaných protokolů + + Currently paused structured logs capture starting at {0} + Currently paused structured logs capture starting at {0} + + Add filter Přidat filtr diff --git a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.de.xlf b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.de.xlf index 6a75f8a6e51..109d8fb8fb5 100644 --- a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.de.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.de.xlf @@ -17,6 +17,11 @@ Grenzwert für strukturiertes Protokoll überschritten + + Currently paused structured logs capture starting at {0} + Currently paused structured logs capture starting at {0} + + Add filter Filter hinzufügen diff --git a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.es.xlf b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.es.xlf index 17af7609fc9..8a1c565025f 100644 --- a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.es.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.es.xlf @@ -17,6 +17,11 @@ Se superó el límite de registro estructurado + + Currently paused structured logs capture starting at {0} + Currently paused structured logs capture starting at {0} + + Add filter Agregar filtro diff --git a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.fr.xlf b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.fr.xlf index 23a0718b4e5..20f6ad54bb3 100644 --- a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.fr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.fr.xlf @@ -17,6 +17,11 @@ Limite de journaux structurés dépassée + + Currently paused structured logs capture starting at {0} + Currently paused structured logs capture starting at {0} + + Add filter Ajouter un filtre diff --git a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.it.xlf b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.it.xlf index 6876b06fa3a..d0a0f5a2537 100644 --- a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.it.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.it.xlf @@ -17,6 +17,11 @@ È stato superato il limite di log strutturati + + Currently paused structured logs capture starting at {0} + Currently paused structured logs capture starting at {0} + + Add filter Aggiungi filtro diff --git a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.ja.xlf b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.ja.xlf index 230f6b09114..2a4cd11397d 100644 --- a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.ja.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.ja.xlf @@ -17,6 +17,11 @@ 構造化ログの制限を超えました + + Currently paused structured logs capture starting at {0} + Currently paused structured logs capture starting at {0} + + Add filter フィルターの追加 diff --git a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.ko.xlf b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.ko.xlf index cfba6c274b9..a4cd366258a 100644 --- a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.ko.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.ko.xlf @@ -17,6 +17,11 @@ 구조적 로그 제한 초과함 + + Currently paused structured logs capture starting at {0} + Currently paused structured logs capture starting at {0} + + Add filter 필터 추가 diff --git a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.pl.xlf b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.pl.xlf index c6004fa7a81..57531cec9f6 100644 --- a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.pl.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.pl.xlf @@ -17,6 +17,11 @@ Przekroczono limit dzienników strukturalnych + + Currently paused structured logs capture starting at {0} + Currently paused structured logs capture starting at {0} + + Add filter Dodaj filtr diff --git a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.pt-BR.xlf b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.pt-BR.xlf index ae8537bcc53..ad08778323b 100644 --- a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.pt-BR.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.pt-BR.xlf @@ -17,6 +17,11 @@ O limite de log estruturado foi excedido + + Currently paused structured logs capture starting at {0} + Currently paused structured logs capture starting at {0} + + Add filter Adicionar filtro diff --git a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.ru.xlf b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.ru.xlf index 26e406a8d88..15ff9d3cb81 100644 --- a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.ru.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.ru.xlf @@ -17,6 +17,11 @@ Превышено ограничение структурированных журналов + + Currently paused structured logs capture starting at {0} + Currently paused structured logs capture starting at {0} + + Add filter Добавить фильтр diff --git a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.tr.xlf b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.tr.xlf index 66d3cd58266..caef3464cfe 100644 --- a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.tr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.tr.xlf @@ -17,6 +17,11 @@ Yapılandırılmış günlük sınırı aşıldı + + Currently paused structured logs capture starting at {0} + Currently paused structured logs capture starting at {0} + + Add filter Filtre ekle diff --git a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.zh-Hans.xlf b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.zh-Hans.xlf index 9712cedd9ad..dd454b5608d 100644 --- a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.zh-Hans.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.zh-Hans.xlf @@ -17,6 +17,11 @@ 已超出结构化日志限制 + + Currently paused structured logs capture starting at {0} + Currently paused structured logs capture starting at {0} + + Add filter 添加筛选器 diff --git a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.zh-Hant.xlf b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.zh-Hant.xlf index d8f98f74795..4118f5889ab 100644 --- a/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.zh-Hant.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/StructuredLogs.zh-Hant.xlf @@ -17,6 +17,11 @@ 超過結構化記錄限制 + + Currently paused structured logs capture starting at {0} + Currently paused structured logs capture starting at {0} + + Add filter 新增篩選 diff --git a/src/Aspire.Dashboard/Resources/xlf/Traces.cs.xlf b/src/Aspire.Dashboard/Resources/xlf/Traces.cs.xlf index e99b57c6d11..4ea0e71a2a7 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Traces.cs.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Traces.cs.xlf @@ -12,6 +12,11 @@ Překročil se limit trasování + + Currently paused trace capture starting at {0} + Currently paused trace capture starting at {0} + + Name: {0} Název: {0} diff --git a/src/Aspire.Dashboard/Resources/xlf/Traces.de.xlf b/src/Aspire.Dashboard/Resources/xlf/Traces.de.xlf index 0972a8f4d06..910cfd2730f 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Traces.de.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Traces.de.xlf @@ -12,6 +12,11 @@ Ablaufverfolgungslimit überschritten + + Currently paused trace capture starting at {0} + Currently paused trace capture starting at {0} + + Name: {0} Name: {0} diff --git a/src/Aspire.Dashboard/Resources/xlf/Traces.es.xlf b/src/Aspire.Dashboard/Resources/xlf/Traces.es.xlf index c62fb4b0b48..6208a7ebe96 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Traces.es.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Traces.es.xlf @@ -12,6 +12,11 @@ Se superó el límite de seguimiento + + Currently paused trace capture starting at {0} + Currently paused trace capture starting at {0} + + Name: {0} Nombre: {0} diff --git a/src/Aspire.Dashboard/Resources/xlf/Traces.fr.xlf b/src/Aspire.Dashboard/Resources/xlf/Traces.fr.xlf index 46f6baa2eb8..9e858ca9fb1 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Traces.fr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Traces.fr.xlf @@ -12,6 +12,11 @@ Limite de trace dépassée + + Currently paused trace capture starting at {0} + Currently paused trace capture starting at {0} + + Name: {0} Nom : {0} diff --git a/src/Aspire.Dashboard/Resources/xlf/Traces.it.xlf b/src/Aspire.Dashboard/Resources/xlf/Traces.it.xlf index 23e947313d3..d86061dea70 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Traces.it.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Traces.it.xlf @@ -12,6 +12,11 @@ È stato superato il limite di tracce + + Currently paused trace capture starting at {0} + Currently paused trace capture starting at {0} + + Name: {0} Nome: {0} diff --git a/src/Aspire.Dashboard/Resources/xlf/Traces.ja.xlf b/src/Aspire.Dashboard/Resources/xlf/Traces.ja.xlf index f9b3a1c387f..89a21bbf803 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Traces.ja.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Traces.ja.xlf @@ -12,6 +12,11 @@ トレースの制限を超えました + + Currently paused trace capture starting at {0} + Currently paused trace capture starting at {0} + + Name: {0} 名前: {0} diff --git a/src/Aspire.Dashboard/Resources/xlf/Traces.ko.xlf b/src/Aspire.Dashboard/Resources/xlf/Traces.ko.xlf index 42be3120aae..3c772ff4a29 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Traces.ko.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Traces.ko.xlf @@ -12,6 +12,11 @@ 추적 제한을 초과했습니다. + + Currently paused trace capture starting at {0} + Currently paused trace capture starting at {0} + + Name: {0} 이름: {0} diff --git a/src/Aspire.Dashboard/Resources/xlf/Traces.pl.xlf b/src/Aspire.Dashboard/Resources/xlf/Traces.pl.xlf index 9e8ad0003cc..0d7bf45379b 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Traces.pl.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Traces.pl.xlf @@ -12,6 +12,11 @@ Przekroczono limit śladów + + Currently paused trace capture starting at {0} + Currently paused trace capture starting at {0} + + Name: {0} Nazwa: {0} diff --git a/src/Aspire.Dashboard/Resources/xlf/Traces.pt-BR.xlf b/src/Aspire.Dashboard/Resources/xlf/Traces.pt-BR.xlf index 3bdb0f99e01..9b948c77f48 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Traces.pt-BR.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Traces.pt-BR.xlf @@ -12,6 +12,11 @@ Limite de rastreamento excedido + + Currently paused trace capture starting at {0} + Currently paused trace capture starting at {0} + + Name: {0} Nome: {0} diff --git a/src/Aspire.Dashboard/Resources/xlf/Traces.ru.xlf b/src/Aspire.Dashboard/Resources/xlf/Traces.ru.xlf index 3eb80e2629c..b2a57f565b7 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Traces.ru.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Traces.ru.xlf @@ -12,6 +12,11 @@ Превышено ограничение трассировок + + Currently paused trace capture starting at {0} + Currently paused trace capture starting at {0} + + Name: {0} Имя: {0} diff --git a/src/Aspire.Dashboard/Resources/xlf/Traces.tr.xlf b/src/Aspire.Dashboard/Resources/xlf/Traces.tr.xlf index e495f538824..f2e17371ea4 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Traces.tr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Traces.tr.xlf @@ -12,6 +12,11 @@ İzleme sınırı aşıldı + + Currently paused trace capture starting at {0} + Currently paused trace capture starting at {0} + + Name: {0} Ad: {0} diff --git a/src/Aspire.Dashboard/Resources/xlf/Traces.zh-Hans.xlf b/src/Aspire.Dashboard/Resources/xlf/Traces.zh-Hans.xlf index f837407fd0d..f7ab6a8185e 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Traces.zh-Hans.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Traces.zh-Hans.xlf @@ -12,6 +12,11 @@ 已超出跟踪限制 + + Currently paused trace capture starting at {0} + Currently paused trace capture starting at {0} + + Name: {0} 名称: {0} diff --git a/src/Aspire.Dashboard/Resources/xlf/Traces.zh-Hant.xlf b/src/Aspire.Dashboard/Resources/xlf/Traces.zh-Hant.xlf index 9d97b4979a8..17952402000 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Traces.zh-Hant.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Traces.zh-Hant.xlf @@ -12,6 +12,11 @@ 超過追蹤限制 + + Currently paused trace capture starting at {0} + Currently paused trace capture starting at {0} + + Name: {0} 名稱: {0} diff --git a/src/Aspire.Dashboard/wwwroot/css/app.css b/src/Aspire.Dashboard/wwwroot/css/app.css index 1e1d5c5ab7e..853ca3b3696 100644 --- a/src/Aspire.Dashboard/wwwroot/css/app.css +++ b/src/Aspire.Dashboard/wwwroot/css/app.css @@ -758,3 +758,8 @@ fluent-switch.table-switch::part(label) { fluent-tooltip[anchor="dialog_close"] > div { word-break: keep-all; } + +.data-paused-text { + font-weight: 500; + color: var(--error); +} diff --git a/tests/Aspire.Dashboard.Tests/TelemetryRepositoryTests/TelemetryRepositoryTests.cs b/tests/Aspire.Dashboard.Tests/TelemetryRepositoryTests/TelemetryRepositoryTests.cs index 1df96c88f55..f4438bc7817 100644 --- a/tests/Aspire.Dashboard.Tests/TelemetryRepositoryTests/TelemetryRepositoryTests.cs +++ b/tests/Aspire.Dashboard.Tests/TelemetryRepositoryTests/TelemetryRepositoryTests.cs @@ -25,9 +25,9 @@ public void AddData_WhilePaused_IsDiscarded() using var subscription = repository.OnNewLogs(applicationKey: null, SubscriptionType.Other, () => Task.CompletedTask); // Act and assert - pauseManager.StructuredLogsPaused = true; + pauseManager.SetStructuredLogsPaused(true); pauseManager.SetMetricsPaused(true); - pauseManager.TracesPaused = true; + pauseManager.SetTracesPaused(true); AddLog(); AddMetric(); AddTrace(); @@ -37,9 +37,9 @@ public void AddData_WhilePaused_IsDiscarded() Assert.Null(repository.GetApplication(applicationKey)); Assert.Empty(repository.GetTraces(new GetTracesRequest { ApplicationKey = applicationKey, Count = 100, Filters = [], StartIndex = 0, FilterText = string.Empty }).PagedResult.Items); - pauseManager.StructuredLogsPaused = false; + pauseManager.SetStructuredLogsPaused(false); pauseManager.SetMetricsPaused(false); - pauseManager.TracesPaused = false; + pauseManager.SetTracesPaused(false); AddLog(); AddMetric(); From f75c55375a1e89426085e74a10b7ade3ebb1b7b7 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Tue, 25 Mar 2025 09:52:07 -0400 Subject: [PATCH 29/35] fix test --- .../Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs b/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs index c3248ff1171..a5bbf924c4f 100644 --- a/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs +++ b/tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs @@ -388,7 +388,7 @@ public void PauseResumeButton_TogglePauseResume_LogsPausedAndResumed() // Add a new log while paused and assert that the log viewer shows that 1 log was filtered var pauseContent = $"{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ss.fffK} Log while paused"; consoleLogsChannel.Writer.TryWrite([new ResourceLogLine(1, pauseContent, IsErrorMessage: false)]); - cut.WaitForAssertion(() => Assert.Equal(pauseConsoleLogLine.TextContent, string.Format(loc[Resources.ConsoleLogs.ConsoleLogsPauseActive], 1))); + cut.WaitForAssertion(() => Assert.Equal(pauseConsoleLogLine.TextContent, string.Format(loc[Resources.ConsoleLogs.ConsoleLogsPauseActive], FormatHelpers.FormatTimeWithOptionalDate(timeProvider, pauseManager.ConsoleLogsPausedRanges.Keys.Last(), MillisecondsDisplay.Truncated), 1))); // Resume and write a new log, check that // - the pause line has been replaced with pause details From 2ab4c296fe1aab824be54d2494df6d8a78a4d445 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Wed, 26 Mar 2025 13:51:37 +0800 Subject: [PATCH 30/35] Text and style changes --- .../Controls/Chart/ChartContainer.razor | 6 +- .../Controls/Chart/ChartContainer.razor.css | 35 - .../Controls/TotalItemsFooter.razor | 17 +- .../Components/Pages/ConsoleLogs.razor.cs | 2 +- .../Components/Pages/StructuredLogs.razor.css | 1 - .../Resources/ConsoleLogs.Designer.cs | 175 +++- .../Resources/ConsoleLogs.resx | 58 +- .../Resources/ControlsStrings.Designer.cs | 867 +++++++++++++----- .../Resources/ControlsStrings.resx | 59 +- .../Resources/StructuredLogs.Designer.cs | 178 +++- .../Resources/StructuredLogs.resx | 60 +- .../Resources/Traces.Designer.cs | 130 ++- src/Aspire.Dashboard/Resources/Traces.resx | 58 +- .../Resources/xlf/ConsoleLogs.cs.xlf | 4 +- .../Resources/xlf/ConsoleLogs.de.xlf | 4 +- .../Resources/xlf/ConsoleLogs.es.xlf | 4 +- .../Resources/xlf/ConsoleLogs.fr.xlf | 4 +- .../Resources/xlf/ConsoleLogs.it.xlf | 4 +- .../Resources/xlf/ConsoleLogs.ja.xlf | 4 +- .../Resources/xlf/ConsoleLogs.ko.xlf | 4 +- .../Resources/xlf/ConsoleLogs.pl.xlf | 4 +- .../Resources/xlf/ConsoleLogs.pt-BR.xlf | 4 +- .../Resources/xlf/ConsoleLogs.ru.xlf | 4 +- .../Resources/xlf/ConsoleLogs.tr.xlf | 4 +- .../Resources/xlf/ConsoleLogs.zh-Hans.xlf | 4 +- .../Resources/xlf/ConsoleLogs.zh-Hant.xlf | 4 +- .../Resources/xlf/ControlsStrings.cs.xlf | 5 + .../Resources/xlf/ControlsStrings.de.xlf | 5 + .../Resources/xlf/ControlsStrings.es.xlf | 5 + .../Resources/xlf/ControlsStrings.fr.xlf | 5 + .../Resources/xlf/ControlsStrings.it.xlf | 5 + .../Resources/xlf/ControlsStrings.ja.xlf | 5 + .../Resources/xlf/ControlsStrings.ko.xlf | 5 + .../Resources/xlf/ControlsStrings.pl.xlf | 5 + .../Resources/xlf/ControlsStrings.pt-BR.xlf | 5 + .../Resources/xlf/ControlsStrings.ru.xlf | 5 + .../Resources/xlf/ControlsStrings.tr.xlf | 5 + .../Resources/xlf/ControlsStrings.zh-Hans.xlf | 5 + .../Resources/xlf/ControlsStrings.zh-Hant.xlf | 5 + .../Resources/xlf/StructuredLogs.cs.xlf | 4 +- .../Resources/xlf/StructuredLogs.de.xlf | 4 +- .../Resources/xlf/StructuredLogs.es.xlf | 4 +- .../Resources/xlf/StructuredLogs.fr.xlf | 4 +- .../Resources/xlf/StructuredLogs.it.xlf | 4 +- .../Resources/xlf/StructuredLogs.ja.xlf | 4 +- .../Resources/xlf/StructuredLogs.ko.xlf | 4 +- .../Resources/xlf/StructuredLogs.pl.xlf | 4 +- .../Resources/xlf/StructuredLogs.pt-BR.xlf | 4 +- .../Resources/xlf/StructuredLogs.ru.xlf | 4 +- .../Resources/xlf/StructuredLogs.tr.xlf | 4 +- .../Resources/xlf/StructuredLogs.zh-Hans.xlf | 4 +- .../Resources/xlf/StructuredLogs.zh-Hant.xlf | 4 +- .../Resources/xlf/Traces.cs.xlf | 4 +- .../Resources/xlf/Traces.de.xlf | 4 +- .../Resources/xlf/Traces.es.xlf | 4 +- .../Resources/xlf/Traces.fr.xlf | 4 +- .../Resources/xlf/Traces.it.xlf | 4 +- .../Resources/xlf/Traces.ja.xlf | 4 +- .../Resources/xlf/Traces.ko.xlf | 4 +- .../Resources/xlf/Traces.pl.xlf | 4 +- .../Resources/xlf/Traces.pt-BR.xlf | 4 +- .../Resources/xlf/Traces.ru.xlf | 4 +- .../Resources/xlf/Traces.tr.xlf | 4 +- .../Resources/xlf/Traces.zh-Hans.xlf | 4 +- .../Resources/xlf/Traces.zh-Hant.xlf | 4 +- src/Aspire.Dashboard/wwwroot/css/app.css | 47 +- 66 files changed, 1290 insertions(+), 624 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor b/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor index ab7236c3c10..756ab8c26d5 100644 --- a/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor +++ b/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor @@ -17,12 +17,12 @@ else

@_instrument.Summary.Description

@if (_instrument.HasOverflow) { -
-
+
+
-
+
@Loc[nameof(ControlsStrings.ChartContainerOverflowTitle)] @Loc[nameof(ControlsStrings.ChartContainerOverflowDescription)]
@((MarkupString)string.Format(ControlsStrings.ChartContainerOverflowLink, "https://aka.ms/dotnet/aspire/cardinality-limits")) diff --git a/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor.css b/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor.css index 32f2bbb35ce..3ad3007eeca 100644 --- a/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor.css +++ b/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor.css @@ -5,38 +5,3 @@ ::deep .metric-tab { margin-top: 10px; } - -.overflow-warning { - font-family: var(--body-font); - border: 1px solid var(--messagebar-warning-border-color); - background-color: var(--messagebar-warning-background-color); - color: var(--neutral-foreground-rest); - display: grid; - grid-template-columns: 24px auto; - width: fit-content; - align-items: center; - min-height: 36px; - border-radius: calc(var(--control-corner-radius)* 1px); - padding: 0 12px; - column-gap: 8px; -} - -.overflow-warning-icon { - grid-column: 1; - display: flex; - justify-content: center; -} - -.overflow-warning-message { - grid-column: 2; - padding: 10px 0; - align-self: center; - font-size: 12px; - font-weight: 400; - line-height: 16px; -} - -.overflow-warning-message .title { - font-weight: 600; - padding: 0 4px 0 0; -} diff --git a/src/Aspire.Dashboard/Components/Controls/TotalItemsFooter.razor b/src/Aspire.Dashboard/Components/Controls/TotalItemsFooter.razor index c01d1d76cfa..a66beeea69b 100644 --- a/src/Aspire.Dashboard/Components/Controls/TotalItemsFooter.razor +++ b/src/Aspire.Dashboard/Components/Controls/TotalItemsFooter.razor @@ -2,12 +2,23 @@ @namespace Aspire.Dashboard.Components @inject IStringLocalizer Loc -