Updated
This commit is contained in:
@@ -14,7 +14,7 @@ It features a rich fluent API for routing log events to dozens of destinations f
|
|||||||
<Copyright>EonaCat (Jeroen Saey)</Copyright>
|
<Copyright>EonaCat (Jeroen Saey)</Copyright>
|
||||||
<PackageTags>EonaCat;Logger;EonaCatLogStack;Log;Writer;Flows;LogStack;Memory;Speed;Jeroen;Saey</PackageTags>
|
<PackageTags>EonaCat;Logger;EonaCatLogStack;Log;Writer;Flows;LogStack;Memory;Speed;Jeroen;Saey</PackageTags>
|
||||||
<PackageIconUrl />
|
<PackageIconUrl />
|
||||||
<FileVersion>0.1.9</FileVersion>
|
<FileVersion>0.2.0</FileVersion>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||||
@@ -25,7 +25,7 @@ It features a rich fluent API for routing log events to dozens of destinations f
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<EVRevisionFormat>0.1.9+{chash:10}.{c:ymd}</EVRevisionFormat>
|
<EVRevisionFormat>0.2.0+{chash:10}.{c:ymd}</EVRevisionFormat>
|
||||||
<EVDefault>true</EVDefault>
|
<EVDefault>true</EVDefault>
|
||||||
<EVInfo>true</EVInfo>
|
<EVInfo>true</EVInfo>
|
||||||
<EVTagMatch>v[0-9]*</EVTagMatch>
|
<EVTagMatch>v[0-9]*</EVTagMatch>
|
||||||
@@ -36,7 +36,7 @@ It features a rich fluent API for routing log events to dozens of destinations f
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>0.1.9</Version>
|
<Version>0.2.0</Version>
|
||||||
<PackageId>EonaCat.LogStack</PackageId>
|
<PackageId>EonaCat.LogStack</PackageId>
|
||||||
<Product>EonaCat.LogStack</Product>
|
<Product>EonaCat.LogStack</Product>
|
||||||
<RepositoryUrl>https://git.saey.me/EonaCat/EonaCat.LogStack</RepositoryUrl>
|
<RepositoryUrl>https://git.saey.me/EonaCat/EonaCat.LogStack</RepositoryUrl>
|
||||||
|
|||||||
@@ -718,20 +718,17 @@ namespace EonaCat.LogStack
|
|||||||
// Drain and stop the async channel pipeline if active
|
// Drain and stop the async channel pipeline if active
|
||||||
if (_asyncChannel != null)
|
if (_asyncChannel != null)
|
||||||
{
|
{
|
||||||
// Flush all logs from flows first to ensure they're written to disk
|
// Complete the channel immediately - no more writes allowed
|
||||||
await FlushAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
// Complete the channel - no more writes allowed
|
|
||||||
_asyncChannel.Writer.TryComplete();
|
_asyncChannel.Writer.TryComplete();
|
||||||
|
|
||||||
if (_asyncConsumer != null)
|
if (_asyncConsumer != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Wait for the consumer task to finish draining the channel
|
// Give the consumer a very short window (1 second) to finish naturally
|
||||||
// Use a generous timeout (30 seconds) since we're dealing with legitimate I/O
|
// If it doesn't complete in time, we proceed anyway to not block app shutdown
|
||||||
// but prevent infinite hangs if something is truly deadlocked
|
// This is critical for ensuring the logger never blocks application exit
|
||||||
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)))
|
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -739,33 +736,75 @@ namespace EonaCat.LogStack
|
|||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
// Do nothing
|
// Timeout expired - consumer didn't finish in time
|
||||||
|
// This is acceptable; the background task will continue draining
|
||||||
|
// but we don't wait for it to allow app exit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// Do nothing
|
// Ignore any errors during consumer shutdown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to flush flows with a very short timeout
|
||||||
|
// Don't await indefinitely - prioritize app exit over log flushing
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(500)))
|
||||||
|
{
|
||||||
|
await FlushAsync(cts.Token).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
// Flush timed out - that's OK, some logs might be lost but app exits cleanly
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Ignore flush errors
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dispose flows with a short timeout
|
||||||
|
var disposeTasks = _concurrentFlows.Select(f => f.DisposeAsync().AsTask()).ToArray();
|
||||||
|
if (disposeTasks.Length > 0)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)))
|
||||||
|
{
|
||||||
|
await Task.WhenAll(disposeTasks).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
// Disposal timed out - proceed anyway
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Ignore disposal errors
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If using synchronous mode, just flush
|
// If using synchronous mode, attempt a quick flush but don't block
|
||||||
await FlushAsync().ConfigureAwait(false);
|
try
|
||||||
}
|
{
|
||||||
|
using (var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(500)))
|
||||||
// Dispose flows - they should already be flushed above
|
{
|
||||||
var disposeTasks = _concurrentFlows.Select(f => f.DisposeAsync().AsTask()).ToArray();
|
await FlushAsync(cts.Token).ConfigureAwait(false);
|
||||||
try
|
}
|
||||||
{
|
}
|
||||||
await Task.WhenAll(disposeTasks).ConfigureAwait(false);
|
catch
|
||||||
}
|
{
|
||||||
catch (Exception ex)
|
// Ignore errors during sync-mode flush
|
||||||
{
|
}
|
||||||
// Do nothing
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Request cancellation of the async pipeline if it's still running
|
||||||
|
_asyncCts?.Cancel();
|
||||||
_asyncCts?.Dispose();
|
_asyncCts?.Dispose();
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ namespace EonaCat.LogStack.Flows
|
|||||||
// Dedicated writer thread
|
// Dedicated writer thread
|
||||||
_writerThread = new Thread(WriterThreadBody)
|
_writerThread = new Thread(WriterThreadBody)
|
||||||
{
|
{
|
||||||
IsBackground = false,
|
IsBackground = true,
|
||||||
Name = "FileFlow.Writer[" + filePrefix + "]",
|
Name = "FileFlow.Writer[" + filePrefix + "]",
|
||||||
Priority = ThreadPriority.AboveNormal,
|
Priority = ThreadPriority.AboveNormal,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user