From be2cb3486b67fd427c7fd8f295fa73db92e67280 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Fri, 27 Oct 2023 13:41:14 +0800 Subject: [PATCH] Add log level select (#541) --- .../Components/Pages/Metrics.razor | 4 +-- .../Components/Pages/Metrics.razor.cs | 8 ++--- .../Components/Pages/StructuredLogs.razor | 16 ++++++++-- .../Components/Pages/StructuredLogs.razor.cs | 32 ++++++++++++++++--- .../Components/Pages/Traces.razor | 2 +- .../Components/Pages/Traces.razor.cs | 8 ++--- ...icationViewModel.cs => SelectViewModel.cs} | 4 +-- .../Model/StructuredLogsViewModel.cs | 8 +++++ 8 files changed, 61 insertions(+), 21 deletions(-) rename src/Aspire.Dashboard/Model/Otlp/{ApplicationViewModel.cs => SelectViewModel.cs} (74%) diff --git a/src/Aspire.Dashboard/Components/Pages/Metrics.razor b/src/Aspire.Dashboard/Components/Pages/Metrics.razor index eaa6a90e9a..bc65f384f5 100644 --- a/src/Aspire.Dashboard/Components/Pages/Metrics.razor +++ b/src/Aspire.Dashboard/Components/Pages/Metrics.razor @@ -9,9 +9,7 @@

Metrics

- s_selectApplication = new SelectViewModel { Id = null, Name = "Select service..." }; private static readonly List s_durations = new List { new MetricsDurationViewModel { Text = "Last 1 minute", Duration = TimeSpan.FromMinutes(1) }, @@ -28,8 +28,8 @@ public partial class Metrics : IDisposable }; private static readonly TimeSpan s_defaultDuration = TimeSpan.FromMinutes(5); - private List _applications = default!; - private ApplicationViewModel _selectedApplication = s_selectApplication; + private List> _applications = default!; + private SelectViewModel _selectedApplication = s_selectApplication; private MetricsDurationViewModel _selectedDuration = s_durations.Single(d => d.Duration == s_defaultDuration); private Subscription? _applicationsSubscription; private Subscription? _metricsSubscription; @@ -105,7 +105,7 @@ protected override void OnParametersSet() private void UpdateApplications() { - _applications = TelemetryRepository.GetApplications().Select(a => new ApplicationViewModel { Id = a.InstanceId, Name = a.ApplicationName }).ToList(); + _applications = TelemetryRepository.GetApplications().Select(a => new SelectViewModel { Id = a.InstanceId, Name = a.ApplicationName }).ToList(); _applications.Insert(0, s_selectApplication); UpdateSubscription(); } diff --git a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor index 6ce3675c5e..d1b680f2df 100644 --- a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor +++ b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor @@ -17,9 +17,8 @@

Structured Logs

- @@ -29,6 +28,17 @@ Placeholder="Filter..." slot="end" /> + Level: + + + Filters: @if (ViewModel.Filters.Count == 0) { @@ -51,7 +61,7 @@ @context.Application.ApplicationName - + @if (context.Severity is LogLevel.Error or LogLevel.Critical) { diff --git a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor.cs b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor.cs index 480b244d1e..3e55c0e2ce 100644 --- a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor.cs @@ -7,17 +7,21 @@ using Aspire.Dashboard.Otlp.Model; using Aspire.Dashboard.Otlp.Storage; using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Logging; using Microsoft.Fast.Components.FluentUI; using Microsoft.JSInterop; namespace Aspire.Dashboard.Components.Pages; + public partial class StructuredLogs { - private static readonly ApplicationViewModel s_allApplication = new ApplicationViewModel { Id = null, Name = "(All)" }; + private static readonly SelectViewModel s_allApplication = new SelectViewModel { Id = null, Name = "(All)" }; private TotalItemsFooter _totalItemsFooter = default!; - private List _applications = default!; - private ApplicationViewModel _selectedApplication = s_allApplication; + private List> _applications = default!; + private List> _logLevels = default!; + private SelectViewModel _selectedApplication = s_allApplication; + private SelectViewModel _selectedLogLevel = default!; private Subscription? _applicationsSubscription; private Subscription? _logsSubscription; private bool _applicationChanged; @@ -69,6 +73,18 @@ protected override Task OnInitializedAsync() ViewModel.AddFilter(new LogFilter { Field = "SpanId", Condition = FilterCondition.Equals, Value = SpanId }); } + _logLevels = new List> + { + new SelectViewModel { Id = LogLevel.Trace, Name = "(All)" }, + new SelectViewModel { Id = LogLevel.Trace, Name = "Trace" }, + new SelectViewModel { Id = LogLevel.Debug, Name = "Debug" }, + new SelectViewModel { Id = LogLevel.Information, Name = "Information" }, + new SelectViewModel { Id = LogLevel.Warning, Name = "Warning" }, + new SelectViewModel { Id = LogLevel.Error, Name = "Error" }, + new SelectViewModel { Id = LogLevel.Critical, Name = "Critical" }, + }; + _selectedLogLevel = _logLevels[0]; + UpdateApplications(); _applicationsSubscription = TelemetryRepository.OnNewApplications(() => InvokeAsync(() => { @@ -88,7 +104,7 @@ protected override void OnParametersSet() private void UpdateApplications() { - _applications = TelemetryRepository.GetApplications().Select(a => new ApplicationViewModel { Id = a.InstanceId, Name = a.ApplicationName }).ToList(); + _applications = TelemetryRepository.GetApplications().Select(a => new SelectViewModel { Id = a.InstanceId, Name = a.ApplicationName }).ToList(); _applications.Insert(0, s_allApplication); } @@ -100,6 +116,14 @@ private Task HandleSelectedApplicationChangedAsync() return Task.CompletedTask; } + private Task HandleSelectedLogLevelChangedAsync() + { + ViewModel.LogLevel = _selectedLogLevel.Id; + _applicationChanged = true; + + return Task.CompletedTask; + } + private void UpdateSubscription() { // Subscribe to updates. diff --git a/src/Aspire.Dashboard/Components/Pages/Traces.razor b/src/Aspire.Dashboard/Components/Pages/Traces.razor index 8b48a9bfb8..7b31e39fce 100644 --- a/src/Aspire.Dashboard/Components/Pages/Traces.razor +++ b/src/Aspire.Dashboard/Components/Pages/Traces.razor @@ -18,7 +18,7 @@

Traces

- s_allApplication = new SelectViewModel { Id = null, Name = "(All)" }; private TotalItemsFooter _totalItemsFooter = default!; - private List _applications = default!; - private ApplicationViewModel _selectedApplication = s_allApplication; + private List> _applications = default!; + private SelectViewModel _selectedApplication = s_allApplication; private Subscription? _applicationsSubscription; private Subscription? _tracesSubscription; private bool _applicationChanged; @@ -81,7 +81,7 @@ protected override void OnParametersSet() private void UpdateApplications() { - _applications = TelemetryRepository.GetApplications().Select(a => new ApplicationViewModel { Id = a.InstanceId, Name = a.ApplicationName }).ToList(); + _applications = TelemetryRepository.GetApplications().Select(a => new SelectViewModel { Id = a.InstanceId, Name = a.ApplicationName }).ToList(); _applications.Insert(0, s_allApplication); UpdateSubscription(); } diff --git a/src/Aspire.Dashboard/Model/Otlp/ApplicationViewModel.cs b/src/Aspire.Dashboard/Model/Otlp/SelectViewModel.cs similarity index 74% rename from src/Aspire.Dashboard/Model/Otlp/ApplicationViewModel.cs rename to src/Aspire.Dashboard/Model/Otlp/SelectViewModel.cs index 0345c6c613..32a95faa23 100644 --- a/src/Aspire.Dashboard/Model/Otlp/ApplicationViewModel.cs +++ b/src/Aspire.Dashboard/Model/Otlp/SelectViewModel.cs @@ -3,8 +3,8 @@ namespace Aspire.Dashboard.Model.Otlp; -public class ApplicationViewModel +public class SelectViewModel { public required string Name { get; init; } - public required string? Id { get; init; } + public required T? Id { get; init; } } diff --git a/src/Aspire.Dashboard/Model/StructuredLogsViewModel.cs b/src/Aspire.Dashboard/Model/StructuredLogsViewModel.cs index 4fac7246ab..983cf93166 100644 --- a/src/Aspire.Dashboard/Model/StructuredLogsViewModel.cs +++ b/src/Aspire.Dashboard/Model/StructuredLogsViewModel.cs @@ -4,6 +4,7 @@ using Aspire.Dashboard.Model.Otlp; using Aspire.Dashboard.Otlp.Model; using Aspire.Dashboard.Otlp.Storage; +using Microsoft.Extensions.Logging; namespace Aspire.Dashboard.Model; @@ -17,6 +18,7 @@ public class StructuredLogsViewModel private string _filterText = string.Empty; private int _logsStartIndex; private int? _logsCount; + private LogLevel? _logLevel; public StructuredLogsViewModel(TelemetryRepository telemetryRepository) { @@ -42,6 +44,7 @@ public bool RemoveFilter(LogFilter filter) } public int StartIndex { get => _logsStartIndex; set => SetValue(ref _logsStartIndex, value); } public int? Count { get => _logsCount; set => SetValue(ref _logsCount, value); } + public LogLevel? LogLevel { get => _logLevel; set => SetValue(ref _logLevel, value); } private void SetValue(ref T field, T value) { @@ -64,6 +67,11 @@ public PagedResult GetLogs() { filters.Add(new LogFilter { Field = "Message", Condition = FilterCondition.Contains, Value = FilterText }); } + // If the log level is set and it is not the bottom level, which has no effect, then add a filter. + if (_logLevel != null && _logLevel != Microsoft.Extensions.Logging.LogLevel.Trace) + { + filters.Add(new LogFilter { Field = "Severity", Condition = FilterCondition.GreaterThanOrEqual, Value = _logLevel.Value.ToString() }); + } logs = _telemetryRepository.GetLogs(new GetLogsContext {