Updated
This commit is contained in:
@@ -165,7 +165,8 @@ public sealed class FileLoggerProvider : BatchingLoggerProvider, IDisposable
|
||||
_ = PeriodicFlushAsync().ContinueWith(_ => Interlocked.Exchange(ref _isFlushing, 0));
|
||||
}
|
||||
|
||||
internal override Task WriteMessagesAsync(IReadOnlyList<LogMessage> messages, CancellationToken token)
|
||||
internal override Task WriteMessagesAsync(IReadOnlyList<LogMessage> messages, CancellationToken token
|
||||
)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -384,22 +385,43 @@ public sealed class FileLoggerProvider : BatchingLoggerProvider, IDisposable
|
||||
|
||||
private async Task CompressionWorkerAsync()
|
||||
{
|
||||
while (!_disposed)
|
||||
try
|
||||
{
|
||||
await _queueSignal.WaitAsync();
|
||||
if (_compressionQueue.TryDequeue(out var filePath))
|
||||
while (!_disposed)
|
||||
{
|
||||
await _compressionSemaphore.WaitAsync();
|
||||
try
|
||||
{
|
||||
await CompressOldLogFileAsync(filePath);
|
||||
// Use a timeout to avoid hanging if disposed
|
||||
if (!await _queueSignal.WaitAsync(TimeSpan.FromSeconds(1)))
|
||||
{
|
||||
if (_disposed) break;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
finally
|
||||
catch
|
||||
{
|
||||
_compressionSemaphore.Release();
|
||||
// Handle cancellation or disposal race condition
|
||||
break;
|
||||
}
|
||||
|
||||
if (_compressionQueue.TryDequeue(out var filePath))
|
||||
{
|
||||
await _compressionSemaphore.WaitAsync();
|
||||
try
|
||||
{
|
||||
await CompressOldLogFileAsync(filePath);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_compressionSemaphore.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// Normal shutdown
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -777,10 +799,21 @@ public sealed class FileLoggerProvider : BatchingLoggerProvider, IDisposable
|
||||
_files.Clear();
|
||||
_messageQueues.Clear();
|
||||
|
||||
// Wait for compression worker to finish remaining tasks
|
||||
while (_compressionQueue.Count > 0)
|
||||
// Signal compression worker to stop and wait for it to finish
|
||||
_compressionSemaphore?.Dispose();
|
||||
_queueSignal?.Dispose();
|
||||
|
||||
// Wait for compression worker to finish remaining tasks with timeout
|
||||
try
|
||||
{
|
||||
await Task.Delay(100);
|
||||
if (_compressionWorker != null && !_compressionWorker.IsCompleted)
|
||||
{
|
||||
await Task.WhenAny(_compressionWorker, Task.Delay(TimeSpan.FromSeconds(5)));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
_aes?.Dispose();
|
||||
|
||||
@@ -117,12 +117,25 @@ namespace EonaCat.Logger.EonaCatCoreLogger
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_processingTask == null || _processingTask.IsCompleted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_cts.Cancel();
|
||||
_queue.CompleteAdding();
|
||||
|
||||
try
|
||||
{
|
||||
_processingTask.Wait();
|
||||
// Use a timeout to avoid hanging
|
||||
if (!_processingTask.Wait(TimeSpan.FromSeconds(5)))
|
||||
{
|
||||
// Task didn't complete in time, but we'll dispose anyway
|
||||
}
|
||||
}
|
||||
catch (AggregateException ex) when (ex.InnerException is OperationCanceledException)
|
||||
{
|
||||
// Expected during cancellation
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -132,6 +145,8 @@ namespace EonaCat.Logger.EonaCatCoreLogger
|
||||
_queue.Dispose();
|
||||
_cts.Dispose();
|
||||
_client.Dispose();
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,15 @@ public abstract class BatchingLoggerProvider : ILoggerProvider, IDisposable
|
||||
if (batch.Count == 0)
|
||||
{
|
||||
// Wait until a new log arrives or cancellation is requested
|
||||
WaitHandle.WaitAny(new WaitHandle[] { _signal, _cts.Token.WaitHandle });
|
||||
try
|
||||
{
|
||||
WaitHandle.WaitAny(new WaitHandle[] { _signal, _cts.Token.WaitHandle }, TimeSpan.FromSeconds(1));
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Handle any WaitHandle disposal race condition
|
||||
if (_disposed) break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -172,11 +180,12 @@ public abstract class BatchingLoggerProvider : ILoggerProvider, IDisposable
|
||||
_disposed = true;
|
||||
|
||||
_cts.Cancel();
|
||||
_worker.Join();
|
||||
_worker.Join(TimeSpan.FromSeconds(5));
|
||||
|
||||
OnShutdownFlushAsync().ConfigureAwait(false);
|
||||
|
||||
_cts.Dispose();
|
||||
_signal.Dispose();
|
||||
}
|
||||
|
||||
protected virtual async Task OnShutdownFlushAsync()
|
||||
|
||||
@@ -298,6 +298,7 @@ namespace EonaCat.Logger.Managers
|
||||
|
||||
await StopLoggingAsync().ConfigureAwait(false);
|
||||
|
||||
// Unsubscribe from events to prevent memory leaks
|
||||
LogHelper.OnException -= LogHelper_OnException;
|
||||
LogHelper.OnLogLevelDisabled -= LogHelper_OnLogLevelDisabled;
|
||||
|
||||
|
||||
@@ -134,6 +134,10 @@ namespace EonaCat.Logger.Servers.Splunk
|
||||
|
||||
return await _httpClient.SendAsync(request).ConfigureAwait(false);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnException?.Invoke(this, ex);
|
||||
|
||||
@@ -177,8 +177,17 @@ namespace EonaCat.Logger.Servers.Tcp
|
||||
if (disposing)
|
||||
{
|
||||
DisposeTcp();
|
||||
_sendLock.Dispose();
|
||||
try
|
||||
{
|
||||
_sendLock.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Handle any potential disposal issues
|
||||
}
|
||||
}
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
~Tcp()
|
||||
|
||||
@@ -198,8 +198,17 @@ namespace EonaCat.Logger.Servers.Udp
|
||||
if (disposing)
|
||||
{
|
||||
DisposeUdp();
|
||||
_sendLock.Dispose();
|
||||
try
|
||||
{
|
||||
_sendLock.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Handle any potential disposal issues
|
||||
}
|
||||
}
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
~Udp()
|
||||
|
||||
Reference in New Issue
Block a user