This is an automated email from the ASF dual-hosted git repository.

freeandnil pushed a commit to branch Feature/ImprovementRemoteSyslogApp
in repository https://gitbox.apache.org/repos/asf/logging-log4net.git


The following commit(s) were added to 
refs/heads/Feature/ImprovementRemoteSyslogApp by this push:
     new ed3ed52d Asynchronous Sending for RemoteSyslogAppender in log4net 
(#253)
ed3ed52d is described below

commit ed3ed52d82f05d4593a3999936c2f1dce6c44b5f
Author: yogitasingh001 <[email protected]>
AuthorDate: Thu Jun 12 02:02:00 2025 +0530

    Asynchronous Sending for RemoteSyslogAppender in log4net (#253)
    
    Co-authored-by: yogita singh <[email protected]>
---
 ...nousSendingforRemoteSyslogAppenderinlog4net.pdf | Bin 0 -> 322016 bytes
 src/log4net/Appender/RemoteSyslogAppender.cs       |  70 +++++++++++++++++++--
 2 files changed, 64 insertions(+), 6 deletions(-)

diff --git a/docs/AsynchronousSendingforRemoteSyslogAppenderinlog4net.pdf 
b/docs/AsynchronousSendingforRemoteSyslogAppenderinlog4net.pdf
new file mode 100644
index 00000000..b69445fa
Binary files /dev/null and 
b/docs/AsynchronousSendingforRemoteSyslogAppenderinlog4net.pdf differ
diff --git a/src/log4net/Appender/RemoteSyslogAppender.cs 
b/src/log4net/Appender/RemoteSyslogAppender.cs
index a111200e..6444155d 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;
 
@@ -367,7 +371,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())
@@ -420,11 +425,11 @@ protected virtual void AppendMessage(string message, ref 
int characterIndex, Str
   /// Initialize the level to syslog severity mappings set on this appender.
   /// </para>
   /// </remarks>
-  public override void ActivateOptions()
-  {
-    base.ActivateOptions();
-    _levelMapping.ActivateOptions();
-  }
+  //public override void ActivateOptions()
+  //{
+  //  base.ActivateOptions();
+  //  _levelMapping.ActivateOptions();
+  //}
 
   /// <summary>
   /// Translates a log4net level to a syslog severity.
@@ -531,4 +536,57 @@ public class LevelSeverity : LevelMappingEntry
     /// </remarks>
     public SyslogSeverity Severity { get; set; }
   }
+  private readonly BlockingCollection<byte[]> _sendQueue = new();
+  private CancellationTokenSource? _cts;
+  private Task? _pumpTask;
+  public override void ActivateOptions()
+  {
+    base.ActivateOptions();
+    // Start the background pump
+    _cts = new CancellationTokenSource();
+    _pumpTask = Task.Run(() => ProcessQueueAsync(_cts.Token), 
CancellationToken.None);
+  }
+
+  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

Reply via email to