This is an automated email from the ASF dual-hosted git repository. freeandnil pushed a commit to branch Feature/AsyncRemoteSyslogAppender in repository https://gitbox.apache.org/repos/asf/logging-log4net.git
commit a33f8f1ac80bcbb55c15c1fe3c30d03fb35b85e6 Author: yogitasingh001 <[email protected]> AuthorDate: Mon Jun 16 14:52:04 2025 +0200 Asynchronous Sending for RemoteSyslogAppender in log4net (#253) Co-authored-by: yogita singh <[email protected]> --- src/log4net/Appender/RemoteSyslogAppender.cs | 59 +++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/src/log4net/Appender/RemoteSyslogAppender.cs b/src/log4net/Appender/RemoteSyslogAppender.cs index a111200e..95a79a56 100644 --- a/src/log4net/Appender/RemoteSyslogAppender.cs +++ b/src/log4net/Appender/RemoteSyslogAppender.cs @@ -23,6 +23,10 @@ using log4net.Util; using log4net.Layout; using System.Text; +using System.Net.Sockets; +using System.Threading.Tasks; +using System.Threading; +using System.Collections.Concurrent; namespace log4net.Appender; @@ -255,6 +259,10 @@ public enum SyslogFacility Local7 = 23 } + private readonly BlockingCollection<byte[]> _sendQueue = new(); + private CancellationTokenSource? _cts; + private Task? _pumpTask; + /// <summary> /// Initializes a new instance of the <see cref="RemoteSyslogAppender" /> class. /// </summary> @@ -367,7 +375,8 @@ protected override void Append(LoggingEvent loggingEvent) // Grab as a byte array byte[] buffer = Encoding.GetBytes(builder.ToString()); - Client.SendAsync(buffer, buffer.Length, RemoteEndPoint).Wait(); + //Client.SendAsync(buffer, buffer.Length, RemoteEndPoint).Wait(); + _sendQueue.Add(buffer); } } catch (Exception e) when (!e.IsFatal()) @@ -424,8 +433,11 @@ public override void ActivateOptions() { base.ActivateOptions(); _levelMapping.ActivateOptions(); + // Start the background pump + _cts = new CancellationTokenSource(); + _pumpTask = Task.Run(() => ProcessQueueAsync(_cts.Token), CancellationToken.None); } - + /// <summary> /// Translates a log4net level to a syslog severity. /// </summary> @@ -531,4 +543,47 @@ public class LevelSeverity : LevelMappingEntry /// </remarks> public SyslogSeverity Severity { get; set; } } + + protected override void OnClose() + { + // Signal shutdown and wait for the pump to drain + _cts?.Cancel(); + _pumpTask?.Wait(TimeSpan.FromSeconds(5)); // or your own timeout + base.OnClose(); + } + + private async Task ProcessQueueAsync(CancellationToken token) + { + // We create our own UdpClient here, so that client lifetime is tied to this task + using (var udp = new UdpClient()) + { + udp.Connect(RemoteAddress?.ToString(), RemotePort); + + try + { + while (!token.IsCancellationRequested) + { + // Take next message or throw when cancelled + byte[] datagram = _sendQueue.Take(token); + try + { + await udp.SendAsync(datagram, datagram.Length); + } + catch (Exception ex) when (!ex.IsFatal()) + { + ErrorHandler.Error("RemoteSyslogAppender: send failed", ex, ErrorCode.WriteFailure); + } + } + } + catch (OperationCanceledException) + { + // Clean shutdown: drain remaining items if desired + while (_sendQueue.TryTake(out var leftover)) + { + try { await udp.SendAsync(leftover, leftover.Length); } + catch { /* ignore */ } + } + } + } + } } \ No newline at end of file
