mirror of
https://github.com/alexhopeoconnor/dnsmasq-webui.git
synced 2026-10-03 22:12:00 +10:00
App logs: add Refresh and Download logs buttons; add api/logging/logs/download endpoint
This commit is contained in:
@@ -31,3 +31,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<AppLogsFiltersModal IsVisible="_filtersModalVisible" OnClose="CloseFiltersModal" />
|
<AppLogsFiltersModal IsVisible="_filtersModalVisible" OnClose="CloseFiltersModal" />
|
||||||
<LogsPreView Id="app-logs-pre" Placeholder="@_initialPlaceholder" Freeze="_logsContentReceived" />
|
<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 _justUpdated;
|
||||||
private bool _logsContentReceived;
|
private bool _logsContentReceived;
|
||||||
|
private bool _refreshing;
|
||||||
private int _intervalSeconds;
|
private int _intervalSeconds;
|
||||||
private string _logLevel = "Information";
|
private string _logLevel = "Information";
|
||||||
private bool _logLevelDisabled;
|
private bool _logLevelDisabled;
|
||||||
@@ -91,6 +92,25 @@ public partial class AppLogsSection : IAsyncDisposable
|
|||||||
private void OpenFiltersModal() => _filtersModalVisible = true;
|
private void OpenFiltersModal() => _filtersModalVisible = true;
|
||||||
private void CloseFiltersModal() => _filtersModalVisible = false;
|
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()
|
private async Task OnLogLevelChanged()
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(_logLevel)) return;
|
if (string.IsNullOrEmpty(_logLevel)) return;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using DnsmasqWebUI.Infrastructure.Logging;
|
using DnsmasqWebUI.Infrastructure.Logging;
|
||||||
|
using DnsmasqWebUI.Infrastructure.Services.Logs.Abstractions;
|
||||||
using DnsmasqWebUI.Models.Config;
|
using DnsmasqWebUI.Models.Config;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
@@ -12,22 +14,39 @@ namespace DnsmasqWebUI.Controllers;
|
|||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
public class LoggingController : ControllerBase
|
public class LoggingController : ControllerBase
|
||||||
{
|
{
|
||||||
|
private const int AppLogsDownloadMaxLines = 5000;
|
||||||
|
|
||||||
private readonly IConfiguration _configuration;
|
private readonly IConfiguration _configuration;
|
||||||
private readonly IConfigurationRoot _configurationRoot;
|
private readonly IConfigurationRoot _configurationRoot;
|
||||||
private readonly RuntimeOverridesOptions _overridesOptions;
|
private readonly RuntimeOverridesOptions _overridesOptions;
|
||||||
|
private readonly IAppLogsBuffer _appLogsBuffer;
|
||||||
private readonly ILogger<LoggingController> _logger;
|
private readonly ILogger<LoggingController> _logger;
|
||||||
|
|
||||||
public LoggingController(
|
public LoggingController(
|
||||||
IConfiguration configuration,
|
IConfiguration configuration,
|
||||||
IOptions<RuntimeOverridesOptions> overridesOptions,
|
IOptions<RuntimeOverridesOptions> overridesOptions,
|
||||||
|
IAppLogsBuffer appLogsBuffer,
|
||||||
ILogger<LoggingController> logger)
|
ILogger<LoggingController> logger)
|
||||||
{
|
{
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_configurationRoot = (IConfigurationRoot)configuration;
|
_configurationRoot = (IConfigurationRoot)configuration;
|
||||||
_overridesOptions = overridesOptions.Value;
|
_overridesOptions = overridesOptions.Value;
|
||||||
|
_appLogsBuffer = appLogsBuffer;
|
||||||
_logger = logger;
|
_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>
|
/// <summary>Get the current minimum log level from configuration (Logging:LogLevel:Default).</summary>
|
||||||
[HttpGet("level")]
|
[HttpGet("level")]
|
||||||
public ActionResult<LogLevelResponse> GetLevel()
|
public ActionResult<LogLevelResponse> GetLevel()
|
||||||
|
|||||||
Reference in New Issue
Block a user