108 lines
4.9 KiB
C#
108 lines
4.9 KiB
C#
using AyCode.Core.Enums;
|
|
using AyCode.Core.Helpers;
|
|
using AyCode.Core.Loggers;
|
|
using AyCode.Entities;
|
|
using AyCode.Entities.LogItems;
|
|
using Microsoft.AspNetCore.SignalR.Client;
|
|
|
|
namespace AyCode.Services.Loggers
|
|
{
|
|
public class AcSignaRClientLogItemWriter : AcLogItemWriterBase<AcLogItemClient>, IAcLogWriterClientBase
|
|
{
|
|
private readonly HubConnection _hubConnection;
|
|
private readonly string _fullHubName;
|
|
|
|
// A log-csatorna a SAJÁT hibáit nem logolhatja önmagán át (rekurzió) → Console.Error.
|
|
// Spam-védelem: hiba-állapotonként EGY jelentés; sikeres küldés után a kapu újraélesedik, és
|
|
// helyreálláskor kiírjuk, hány log-item veszett el. (Egyszerű mezők — a torz dupla-jelentés ártalmatlan.)
|
|
private bool _failureReported;
|
|
private long _droppedCount;
|
|
|
|
public AcSignaRClientLogItemWriter(string fullHubName, AppType appType = AppType.Web, LogLevel logLevel = LogLevel.Detail, string? categoryName = null) : base(appType, logLevel, categoryName)
|
|
{
|
|
_fullHubName = fullHubName;
|
|
|
|
_hubConnection = new HubConnectionBuilder()
|
|
.WithUrl(fullHubName)
|
|
//.WithAutomaticReconnect()
|
|
//.AddMessagePackProtocol(options => options.SerializerOptions = MessagePackSerializerOptions.Standard.WithSecurity(MessagePackSecurity.UntrustedData))
|
|
.Build();
|
|
|
|
// A .Forget() logger nélkül elnyelné az induló kapcsolat hibáját → jelentő wrapper.
|
|
StartConnectionReportedAsync().Forget();
|
|
}
|
|
|
|
public async Task StartConnection()
|
|
{
|
|
if (_hubConnection.State == HubConnectionState.Disconnected)
|
|
await _hubConnection.StartAsync();
|
|
|
|
if (_hubConnection.State != HubConnectionState.Connected)
|
|
await TaskHelper.WaitToAsync(() => _hubConnection.State == HubConnectionState.Connected, 10000, 10, 25);
|
|
}
|
|
|
|
public async Task StopConnection()
|
|
{
|
|
await _hubConnection.StopAsync();
|
|
await _hubConnection.DisposeAsync();
|
|
}
|
|
|
|
public override void Write(AppType appType, LogLevel logLevel, string? logText, string? callerMemberName, string? categoryName, string? errorType, string? exMessage)
|
|
=> WriteLogItem(CreateLogItem(DateTime.UtcNow, appType, Environment.CurrentManagedThreadId, logLevel, logText, callerMemberName, categoryName, errorType, exMessage));
|
|
|
|
protected override async void WriteLogItemCallback(AcLogItemClient logItem)
|
|
{
|
|
// Teljes try/catch: async void — egy StartAsync/SendAsync-kivétel különben kezeletlenül szökne el.
|
|
try
|
|
{
|
|
//Ez fontos, mert a signalR nem küldi a DateTime.Kind-ot! A szeró oldalon kap egy utc DateTime-ot, ami a kliens lokális DateTime-ját tartalmazza! - J.
|
|
logItem.TimeStampUtc = logItem.TimeStampUtc.ToUniversalTime();
|
|
|
|
await StartConnection();
|
|
|
|
if (_hubConnection.State != HubConnectionState.Connected)
|
|
{
|
|
_droppedCount++;
|
|
ReportFailureOnce($"connection not available ({_hubConnection.State}), log item DROPPED", null);
|
|
return;
|
|
}
|
|
|
|
//var refreshToken = Setting.UserBasicDetails?.RefreshToken ?? Guid.NewGuid().ToString("N");
|
|
await _hubConnection.SendAsync("AddLogItem", /*refreshToken,*/ logItem);
|
|
|
|
ReportRecoveryIfNeeded();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_droppedCount++;
|
|
ReportFailureOnce("send failed, log item DROPPED", ex);
|
|
}
|
|
}
|
|
|
|
private async Task StartConnectionReportedAsync()
|
|
{
|
|
try { await StartConnection(); }
|
|
catch (Exception ex) { ReportFailureOnce("initial connect failed", ex); }
|
|
}
|
|
|
|
/// <summary>Hiba-állapotonként EGYSZER ír a Console.Error-ra (nem spamel) — a következő sikeres küldés élesíti újra.</summary>
|
|
private void ReportFailureOnce(string message, Exception? ex)
|
|
{
|
|
if (_failureReported) return;
|
|
_failureReported = true;
|
|
|
|
Console.Error.WriteLine($"[{nameof(AcSignaRClientLogItemWriter)}] {message}; url: {_fullHubName}; droppedCount: {_droppedCount}{(ex == null ? string.Empty : $"; ex: {ex.GetType().Name}: {ex.Message}")}");
|
|
}
|
|
|
|
/// <summary>Sikeres küldésnél: ha hiba-állapotból jöttünk vissza, jelentjük a kiesés alatt elveszett logok számát.</summary>
|
|
private void ReportRecoveryIfNeeded()
|
|
{
|
|
if (!_failureReported) return;
|
|
_failureReported = false;
|
|
|
|
Console.Error.WriteLine($"[{nameof(AcSignaRClientLogItemWriter)}] connection recovered; url: {_fullHubName}; DROPPED items while down: {_droppedCount}");
|
|
_droppedCount = 0;
|
|
}
|
|
}
|
|
}
|