1+ public sealed class AsyncLogger : IAsyncDisposable
2+ {
3+ private readonly LockFreeRingBuffer < string > _ringBuffer ;
4+ private readonly CancellationTokenSource _cancellationTokenSource ;
5+ private readonly ManualResetEvent _newMessageEvent ;
6+ private readonly Task _logProcessorTask ;
7+ private bool _disposed ;
8+
9+ public AsyncLogger ( )
10+ {
11+ _ringBuffer = new LockFreeRingBuffer < string > ( 2 ) ;
12+ _cancellationTokenSource = new CancellationTokenSource ( ) ;
13+ _newMessageEvent = new ManualResetEvent ( false ) ;
14+ _logProcessorTask = Task . Run ( ProcessLogs ) ;
15+ }
16+
17+ public void Log ( string message )
18+ {
19+ ObjectDisposedException . ThrowIf ( _disposed , this ) ;
20+
21+ while ( ! _ringBuffer . TryWrite ( message ) )
22+ {
23+ // Handle buffer being full, e.g., wait, retry, or drop the message.
24+ }
25+
26+ _newMessageEvent . Set ( ) ;
27+ }
28+
29+ private void ProcessLogs ( )
30+ {
31+ while ( ! _cancellationTokenSource . IsCancellationRequested )
32+ {
33+ _newMessageEvent . WaitOne ( ) ;
34+ ProcessAllAvailableMessages ( ) ;
35+ _newMessageEvent . Reset ( ) ;
36+ }
37+
38+ // Final flush of all messages before exiting
39+ ProcessAllAvailableMessages ( ) ;
40+ }
41+
42+ private void ProcessAllAvailableMessages ( )
43+ {
44+ while ( _ringBuffer . TryRead ( out var logMessage ) )
45+ {
46+ // Process the log message
47+ Console . WriteLine ( logMessage ) ;
48+ }
49+ }
50+
51+ public async ValueTask DisposeAsync ( )
52+ {
53+ await _cancellationTokenSource . CancelAsync ( ) ;
54+ _newMessageEvent . Set ( ) ; // Ensure the log processing task wakes up to process remaining messages
55+ await _logProcessorTask ;
56+ _cancellationTokenSource . Dispose ( ) ;
57+ _newMessageEvent . Close ( ) ;
58+
59+ _disposed = true ;
60+ }
61+ }
0 commit comments