Skip to content

Commit add0603

Browse files
yogitasingh001yogita singh
authored andcommitted
Asynchronous Sending for RemoteSyslogAppender in log4net (#253)
Co-authored-by: yogita singh <[email protected]>
1 parent 5eb00bd commit add0603

File tree

1 file changed

+57
-2
lines changed

1 file changed

+57
-2
lines changed

src/log4net/Appender/RemoteSyslogAppender.cs

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
using log4net.Util;
2424
using log4net.Layout;
2525
using System.Text;
26+
using System.Net.Sockets;
27+
using System.Threading.Tasks;
28+
using System.Threading;
29+
using System.Collections.Concurrent;
2630

2731
namespace log4net.Appender;
2832

@@ -255,6 +259,10 @@ public enum SyslogFacility
255259
Local7 = 23
256260
}
257261

262+
private readonly BlockingCollection<byte[]> _sendQueue = new();
263+
private CancellationTokenSource? _cts;
264+
private Task? _pumpTask;
265+
258266
/// <summary>
259267
/// Initializes a new instance of the <see cref="RemoteSyslogAppender" /> class.
260268
/// </summary>
@@ -367,7 +375,8 @@ protected override void Append(LoggingEvent loggingEvent)
367375
// Grab as a byte array
368376
byte[] buffer = Encoding.GetBytes(builder.ToString());
369377

370-
Client.SendAsync(buffer, buffer.Length, RemoteEndPoint).Wait();
378+
//Client.SendAsync(buffer, buffer.Length, RemoteEndPoint).Wait();
379+
_sendQueue.Add(buffer);
371380
}
372381
}
373382
catch (Exception e) when (!e.IsFatal())
@@ -424,8 +433,11 @@ public override void ActivateOptions()
424433
{
425434
base.ActivateOptions();
426435
_levelMapping.ActivateOptions();
436+
// Start the background pump
437+
_cts = new CancellationTokenSource();
438+
_pumpTask = Task.Run(() => ProcessQueueAsync(_cts.Token), CancellationToken.None);
427439
}
428-
440+
429441
/// <summary>
430442
/// Translates a log4net level to a syslog severity.
431443
/// </summary>
@@ -531,4 +543,47 @@ public class LevelSeverity : LevelMappingEntry
531543
/// </remarks>
532544
public SyslogSeverity Severity { get; set; }
533545
}
546+
547+
protected override void OnClose()
548+
{
549+
// Signal shutdown and wait for the pump to drain
550+
_cts?.Cancel();
551+
_pumpTask?.Wait(TimeSpan.FromSeconds(5)); // or your own timeout
552+
base.OnClose();
553+
}
554+
555+
private async Task ProcessQueueAsync(CancellationToken token)
556+
{
557+
// We create our own UdpClient here, so that client lifetime is tied to this task
558+
using (var udp = new UdpClient())
559+
{
560+
udp.Connect(RemoteAddress?.ToString(), RemotePort);
561+
562+
try
563+
{
564+
while (!token.IsCancellationRequested)
565+
{
566+
// Take next message or throw when cancelled
567+
byte[] datagram = _sendQueue.Take(token);
568+
try
569+
{
570+
await udp.SendAsync(datagram, datagram.Length);
571+
}
572+
catch (Exception ex) when (!ex.IsFatal())
573+
{
574+
ErrorHandler.Error("RemoteSyslogAppender: send failed", ex, ErrorCode.WriteFailure);
575+
}
576+
}
577+
}
578+
catch (OperationCanceledException)
579+
{
580+
// Clean shutdown: drain remaining items if desired
581+
while (_sendQueue.TryTake(out var leftover))
582+
{
583+
try { await udp.SendAsync(leftover, leftover.Length); }
584+
catch { /* ignore */ }
585+
}
586+
}
587+
}
588+
}
534589
}

0 commit comments

Comments
 (0)