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