Add debug export functionality for channel analysis
Implemented a new endpoint for exporting debug data related to channel scheduling, allowing users to download an archive containing channel settings, slot states, and trace information. Updated the frontend to include a button for triggering the export, along with necessary API adjustments for handling the download. Enhanced localization strings to support the new debug export feature in both English and Russian. Updated .gitignore to include debug export files while ensuring the directory structure is maintained for development.
This commit is contained in:
@@ -7,6 +7,7 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using TeleWave.Application.Broadcast.Bumpers;
|
||||
using TeleWave.Application.Broadcast.Scheduling;
|
||||
using TeleWave.Application.Common;
|
||||
using TeleWave.Application.Common.Interfaces;
|
||||
using TeleWave.Application.Streaming;
|
||||
using TeleWave.Domain.Broadcast.Scheduling;
|
||||
@@ -18,6 +19,7 @@ using TeleWave.Infrastructure.Metadata;
|
||||
using TeleWave.Infrastructure.Persistence;
|
||||
using TeleWave.Infrastructure.Settings;
|
||||
using TeleWave.Infrastructure.Streaming;
|
||||
using TeleWave.Infrastructure.Support;
|
||||
|
||||
namespace TeleWave.Infrastructure;
|
||||
|
||||
@@ -149,6 +151,10 @@ public static class DependencyInjection
|
||||
private static void AddMedia(IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.Configure<StorageOptions>(configuration.GetSection(StorageOptions.SectionName));
|
||||
services.Configure<DebugExportOptions>(
|
||||
configuration.GetSection(DebugExportOptions.SectionName)
|
||||
);
|
||||
services.AddSingleton<IDebugExportStore, DebugExportStore>();
|
||||
services.Configure<MediaOptions>(configuration.GetSection(MediaOptions.SectionName));
|
||||
|
||||
services.AddSingleton<MediaPathResolver>();
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using TeleWave.Application.Common;
|
||||
using TeleWave.Application.Common.Interfaces;
|
||||
|
||||
namespace TeleWave.Infrastructure.Support;
|
||||
|
||||
/// <summary>
|
||||
/// Складывает копии отладочных дампов в настроенный каталог и подрезает его до последних N архивов.
|
||||
///
|
||||
/// Ошибки записи только логируются: дамп к этому моменту уже собран и уходит в браузер, и валить
|
||||
/// запрос из-за того, что папка недоступна, значит терять данные ровно тогда, когда они нужны.
|
||||
/// </summary>
|
||||
public sealed class DebugExportStore(
|
||||
IOptions<DebugExportOptions> options,
|
||||
ILogger<DebugExportStore> logger
|
||||
) : IDebugExportStore
|
||||
{
|
||||
private const string ArchivePattern = "*.zip";
|
||||
|
||||
private readonly DebugExportOptions _options = options.Value;
|
||||
|
||||
public async Task<string?> SaveAsync(
|
||||
string fileName,
|
||||
byte[] content,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_options.ExportDirectory))
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
var directory = Path.GetFullPath(_options.ExportDirectory);
|
||||
Directory.CreateDirectory(directory);
|
||||
|
||||
var path = Path.Combine(directory, Path.GetFileName(fileName));
|
||||
await File.WriteAllBytesAsync(path, content, cancellationToken);
|
||||
|
||||
Prune(directory);
|
||||
return path;
|
||||
}
|
||||
catch (Exception exception) when (exception is IOException or UnauthorizedAccessException)
|
||||
{
|
||||
logger.LogWarning(
|
||||
exception,
|
||||
"Не удалось сохранить отладочный дамп в {Directory}",
|
||||
_options.ExportDirectory
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Оставляет последние <see cref="DebugExportOptions.KeepLast"/> архивов по времени записи.</summary>
|
||||
private void Prune(string directory)
|
||||
{
|
||||
var keep = Math.Max(1, _options.KeepLast);
|
||||
var stale = new DirectoryInfo(directory)
|
||||
.GetFiles(ArchivePattern)
|
||||
.OrderByDescending(file => file.LastWriteTimeUtc)
|
||||
.Skip(keep)
|
||||
.ToList();
|
||||
|
||||
foreach (var file in stale)
|
||||
{
|
||||
try
|
||||
{
|
||||
file.Delete();
|
||||
}
|
||||
catch (Exception exception)
|
||||
when (exception is IOException or UnauthorizedAccessException)
|
||||
{
|
||||
// Файл держит открытым архиватор или антивирус — не повод срывать экспорт.
|
||||
logger.LogDebug(exception, "Не удалось удалить старый дамп {File}", file.FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user