App logs: add Refresh and Download logs buttons; add api/logging/logs/download endpoint

This commit is contained in:
2026-03-02 23:10:39 +10:00
parent baaba38e23
commit a9f8961c32
3 changed files with 43 additions and 0 deletions
@@ -31,3 +31,7 @@
</p>
<AppLogsFiltersModal IsVisible="_filtersModalVisible" OnClose="CloseFiltersModal" />
<LogsPreView Id="app-logs-pre" Placeholder="@_initialPlaceholder" Freeze="_logsContentReceived" />
<div class="mt-2 d-flex flex-wrap gap-2 align-items-center">
<button class="btn btn-primary btn-sm" @onclick="RequestRefreshAsync" disabled="@_refreshing"><i class="bi bi-arrow-repeat me-1" aria-hidden="true"></i>Refresh</button>
<a href="api/logging/logs/download" download="app.log" class="btn btn-primary btn-sm"><i class="bi bi-download me-1" aria-hidden="true"></i>Download logs</a>
</div>
@@ -19,6 +19,7 @@ public partial class AppLogsSection : IAsyncDisposable
private bool _justUpdated;
private bool _logsContentReceived;
private bool _refreshing;
private int _intervalSeconds;
private string _logLevel = "Information";
private bool _logLevelDisabled;
@@ -91,6 +92,25 @@ public partial class AppLogsSection : IAsyncDisposable
private void OpenFiltersModal() => _filtersModalVisible = true;
private void CloseFiltersModal() => _filtersModalVisible = false;
private async Task RequestRefreshAsync()
{
if (_hubConnection?.State != HubConnectionState.Connected)
return;
_refreshing = true;
StateHasChanged();
try
{
await _hubConnection.InvokeAsync("RequestAppLogsSnapshot", _cts.Token);
}
catch (OperationCanceledException) { }
catch (Exception) { /* ignore */ }
finally
{
_refreshing = false;
StateHasChanged();
}
}
private async Task OnLogLevelChanged()
{
if (string.IsNullOrEmpty(_logLevel)) return;
@@ -1,6 +1,8 @@
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using DnsmasqWebUI.Infrastructure.Logging;
using DnsmasqWebUI.Infrastructure.Services.Logs.Abstractions;
using DnsmasqWebUI.Models.Config;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
@@ -12,22 +14,39 @@ namespace DnsmasqWebUI.Controllers;
[Route("api/[controller]")]
public class LoggingController : ControllerBase
{
private const int AppLogsDownloadMaxLines = 5000;
private readonly IConfiguration _configuration;
private readonly IConfigurationRoot _configurationRoot;
private readonly RuntimeOverridesOptions _overridesOptions;
private readonly IAppLogsBuffer _appLogsBuffer;
private readonly ILogger<LoggingController> _logger;
public LoggingController(
IConfiguration configuration,
IOptions<RuntimeOverridesOptions> overridesOptions,
IAppLogsBuffer appLogsBuffer,
ILogger<LoggingController> logger)
{
_configuration = configuration;
_configurationRoot = (IConfigurationRoot)configuration;
_overridesOptions = overridesOptions.Value;
_appLogsBuffer = appLogsBuffer;
_logger = logger;
}
/// <summary>Download recent app logs from the in-memory buffer (up to AppLogsDownloadMaxLines).</summary>
[HttpGet("logs/download")]
public IActionResult GetAppLogsDownload()
{
var lines = _appLogsBuffer.GetRecent(maxLines: AppLogsDownloadMaxLines);
var content = string.Join(Environment.NewLine, lines);
if (lines.Count > 0 && !content.EndsWith(Environment.NewLine))
content += Environment.NewLine;
_logger.LogDebug("App logs download, lines={Count}", lines.Count);
return File(Encoding.UTF8.GetBytes(content), "text/plain", "app.log");
}
/// <summary>Get the current minimum log level from configuration (Logging:LogLevel:Default).</summary>
[HttpGet("level")]
public ActionResult<LogLevelResponse> GetLevel()