EllieHub/EllieHub/Features/BotConfig/Services/LogWriter.cs

99 lines
No EOL
3.1 KiB
C#

using EllieHub.Features.AppConfig.Models;
using EllieHub.Features.BotConfig.Models;
using EllieHub.Features.BotConfig.Services.Abstractions;
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;
using System.Text;
namespace EllieHub.Features.BotConfig.Services;
/// <summary>
/// Defines a service that writes logs of bot instances to the disk.
/// </summary>
public sealed class LogWriter : ILogWriter
{
private readonly ConcurrentDictionary<Guid, StringBuilder> _botLogs = [];
private readonly ReadOnlyAppSettings _appConfig;
/// <inheritdoc/>
public event EventHandler<ILogWriter, LogFlushEventArgs>? OnLogCreated;
/// <summary>
/// Creates a service that writes logs of bot instances to the disk.
/// </summary>
/// <param name="appConfig">The application settings.</param>
public LogWriter(ReadOnlyAppSettings appConfig)
=> _appConfig = appConfig;
/// <inheritdoc/>
public async Task<bool> FlushAllAsync(bool removeFromMemory = false, CancellationToken cToken = default)
{
var result = await Task.WhenAll(_botLogs.Keys.Select(x => FlushAsync(x, false, cToken)));
if (removeFromMemory)
_botLogs.Clear();
return result.Any(x => x);
}
/// <inheritdoc/>
public async Task<bool> FlushAsync(Guid botId, bool removeFromMemory = false, CancellationToken cToken = default)
{
if (!_botLogs.TryGetValue(botId, out var logStringBuilder))
return false;
if (removeFromMemory)
_botLogs.Remove(botId, out _);
if (logStringBuilder.Length is 0)
return false;
Directory.CreateDirectory(_appConfig.LogsDirectoryUri);
var logByteSize = (logStringBuilder.Length * 2) + 1;
var botEntry = _appConfig.BotEntries[botId];
var now = DateTimeOffset.Now;
var date = new DateOnly(now.Year, now.Month, now.Day).ToShortDateString().Replace('/', '-');
var fileUri = Path.Join(_appConfig.LogsDirectoryUri, $"{botEntry.Name}_v{botEntry.Version}_{date}-{now.ToUnixTimeSeconds()}.txt");
await File.WriteAllTextAsync(fileUri, logStringBuilder.ToString(), cToken);
logStringBuilder.Clear();
OnLogCreated?.Invoke(this, new(fileUri, logByteSize, now));
return true;
}
/// <inheritdoc/>
public bool TryAdd(Guid botId, string message)
{
if (string.IsNullOrWhiteSpace(message) || _appConfig.LogMaxSizeMb <= 0.0)
return false;
if (!_botLogs.TryGetValue(botId, out var logStringBuilder))
{
logStringBuilder = new();
_botLogs.TryAdd(botId, logStringBuilder);
}
logStringBuilder.AppendLine(message);
if (logStringBuilder.Length > _appConfig.LogMaxSizeMb * 1_000_000)
_ = FlushAsync(botId);
return true;
}
/// <inheritdoc/>
public bool TryRead(Guid botId, [MaybeNullWhen(false)] out string log)
{
if (_botLogs.TryGetValue(botId, out var logStringBuilder))
{
log = logStringBuilder.ToString();
return true;
}
log = null;
return false;
}
}