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

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

commit a7abf189a982e8d172aabbc63976f6e5178894b5
Author: Jan Friedrich <freeand...@apache.org>
AuthorDate: Thu Jun 19 15:10:06 2025 +0200

    #255 added unit test for RemoteSyslogAppender
---
 src/log4net.Tests/Appender/Internal/UdpMock.cs     |  60 ++++++++++++
 .../Appender/RemoteSyslogAppenderTest.cs           |  75 +++++++++++++++
 src/log4net.Tests/Appender/TelnetAppenderTest.cs   |   4 +-
 src/log4net/Appender/AppenderSkeleton.cs           |   4 +-
 src/log4net/Appender/Internal/IUdpConnection.cs    |  51 +++++++++++
 src/log4net/Appender/Internal/UdpConnection.cs     |  58 ++++++++++++
 src/log4net/Appender/RemoteSyslogAppender.cs       | 102 ++++++++++-----------
 src/log4net/Appender/UdpAppender.cs                |  43 +++------
 src/log4net/Core/ErrorCode.cs                      |   2 +-
 src/log4net/Core/LoggerManager.cs                  |   2 +-
 src/log4net/Core/LoggingEvent.cs                   |  15 ++-
 src/log4net/log4net.csproj                         |   4 +-
 12 files changed, 321 insertions(+), 99 deletions(-)

diff --git a/src/log4net.Tests/Appender/Internal/UdpMock.cs 
b/src/log4net.Tests/Appender/Internal/UdpMock.cs
new file mode 100644
index 00000000..152c625e
--- /dev/null
+++ b/src/log4net.Tests/Appender/Internal/UdpMock.cs
@@ -0,0 +1,60 @@
+#region Apache License
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more 
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership. 
+// The ASF licenses this file to you under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with 
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#endregion
+
+using System.Collections.Generic;
+using System.Net;
+using System.Threading.Tasks;
+using log4net.Appender.Internal;
+
+namespace log4net.Tests.Appender.Internal;
+
+/// <summary>
+/// Mock implementation of <see cref="IUdpConnection"/> for testing purposes.
+/// </summary>
+internal sealed class UdpMock : IUdpConnection
+{
+  /// <summary>
+  /// Passed to <see cref="SendAsync(byte[], int)"/>
+  /// </summary>
+  public List<(byte[] Datagram, int Bytes)> Sent { get; } = [];
+
+  /// <summary>
+  /// Was <see cref="Dispose"/> called
+  /// </summary>
+  internal bool WasDisposed { get; private set; }
+
+  /// <summary>
+  /// Parameters passed to <see cref="Connect(int, IPAddress, int)"/>
+  /// </summary>
+  internal (int LocalPort, IPAddress Host, int RemotePort)? ConnectedTo { get; 
private set; }
+
+  /// <inheritdoc/>
+  public void Connect(int localPort, IPAddress host, int remotePort) 
+    => ConnectedTo = (localPort, host, remotePort);
+
+  /// <inheritdoc/>
+  public void Dispose() => WasDisposed = true;
+
+  /// <inheritdoc/>
+  public Task<int> SendAsync(byte[] datagram, int bytes)
+  {
+    Sent.Add((datagram, bytes));
+    return Task.FromResult(bytes);
+  }
+}
\ No newline at end of file
diff --git a/src/log4net.Tests/Appender/RemoteSyslogAppenderTest.cs 
b/src/log4net.Tests/Appender/RemoteSyslogAppenderTest.cs
new file mode 100644
index 00000000..bc5ea526
--- /dev/null
+++ b/src/log4net.Tests/Appender/RemoteSyslogAppenderTest.cs
@@ -0,0 +1,75 @@
+#region Apache License
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more 
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership. 
+// The ASF licenses this file to you under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with 
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#endregion
+
+using System.Text;
+using log4net.Appender;
+using log4net.Appender.Internal;
+using log4net.Core;
+using log4net.Layout;
+using log4net.Tests.Appender.Internal;
+using NUnit.Framework;
+
+namespace log4net.Tests.Appender;
+
+/// <summary>
+/// Tests for <see cref="RemoteSyslogAppender"/>
+/// </summary>
+[TestFixture]
+public sealed class RemoteSyslogAppenderTest
+{
+  private sealed class RemoteAppender : RemoteSyslogAppender
+  {
+    /// <summary>
+    /// Mock
+    /// </summary>
+    internal UdpMock Mock { get; } = new();
+
+    /// <inheritdoc/>
+    protected override IUdpConnection CreateUdpConnection() => Mock;
+  }
+
+  /// <summary>
+  /// Simple Test for the <see cref="RemoteSyslogAppenderTest"/>
+  /// </summary>
+  /// <remarks>
+  /// https://github.com/apache/logging-log4net/issues/255
+  /// </remarks>
+  [Test]
+  public void RemoteSyslogTest()
+  {
+    System.Net.IPAddress ipAddress = new([127, 0, 0, 1]);
+    RemoteAppender appender = new() { RemoteAddress = ipAddress, Layout = new 
PatternLayout("%-5level - %message%newline") };
+    appender.ActivateOptions();
+    LoggingEvent loggingEvent = new(new()
+    {
+      Level = Level.Info,
+      Message = "Test message",
+      LoggerName = "TestLogger",
+      Domain = "TestDomain",
+    });
+    appender.DoAppend(loggingEvent);
+    appender.Close();
+    Assert.That(appender.Mock.ConnectedTo, Is.EqualTo((0, ipAddress, 514)));
+    Assert.That(appender.Mock.Sent, Has.Count.EqualTo(1));
+    Assert.That(appender.Mock.WasDisposed, Is.True);
+    Assert.That(appender.Mock.Sent, Has.Count.EqualTo(1));
+    const string expectedData = @"<14>TestDomain: INFO  - Test message";
+    Assert.That(Encoding.ASCII.GetString(appender.Mock.Sent[0].Datagram), 
Is.EqualTo(expectedData));
+  }
+}
\ No newline at end of file
diff --git a/src/log4net.Tests/Appender/TelnetAppenderTest.cs 
b/src/log4net.Tests/Appender/TelnetAppenderTest.cs
index 0e8d5f84..ea153e76 100644
--- a/src/log4net.Tests/Appender/TelnetAppenderTest.cs
+++ b/src/log4net.Tests/Appender/TelnetAppenderTest.cs
@@ -1,4 +1,4 @@
-#region Apache License
+#region Apache License
 //
 // Licensed to the Apache Software Foundation (ASF) under one or more 
 // contributor license agreements. See the NOTICE file distributed with
@@ -37,7 +37,7 @@ namespace log4net.Tests.Appender;
 public sealed class TelnetAppenderTest
 {
   /// <summary>
-  /// Simple Test für the <see cref="TelnetAppender"/>
+  /// Simple Test for the <see cref="TelnetAppender"/>
   /// </summary>
   /// <remarks>
   /// https://github.com/apache/logging-log4net/issues/194
diff --git a/src/log4net/Appender/AppenderSkeleton.cs 
b/src/log4net/Appender/AppenderSkeleton.cs
index 216e4ec0..474bac42 100644
--- a/src/log4net/Appender/AppenderSkeleton.cs
+++ b/src/log4net/Appender/AppenderSkeleton.cs
@@ -353,7 +353,7 @@ public void DoAppend(LoggingEvent[] loggingEvents)
       {
         _recursiveGuard = true;
 
-        var filteredEvents = new List<LoggingEvent>(loggingEvents.Length);
+        List<LoggingEvent> filteredEvents = new(loggingEvents.Length);
 
         foreach (LoggingEvent loggingEvent in loggingEvents)
         {
@@ -628,7 +628,7 @@ protected string RenderLoggingEvent(LoggingEvent 
loggingEvent)
     lock (LockObj)
     {
       // Create the render writer on first use
-      _renderWriter ??= new 
ReusableStringWriter(System.Globalization.CultureInfo.InvariantCulture);
+      _renderWriter ??= new(System.Globalization.CultureInfo.InvariantCulture);
 
       // Reset the writer so we can reuse it
       _renderWriter.Reset(RenderBufferMaxCapacity, RenderBufferSize);
diff --git a/src/log4net/Appender/Internal/IUdpConnection.cs 
b/src/log4net/Appender/Internal/IUdpConnection.cs
new file mode 100644
index 00000000..cf0dd2c3
--- /dev/null
+++ b/src/log4net/Appender/Internal/IUdpConnection.cs
@@ -0,0 +1,51 @@
+#region Apache License
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more 
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership. 
+// The ASF licenses this file to you under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with 
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#endregion
+
+using System;
+using System.ComponentModel;
+using System.Net;
+using System.Threading.Tasks;
+
+namespace log4net.Appender.Internal;
+
+/// <summary>
+/// Interface for UDP connection management.
+/// Only public for unit testing purposes.
+/// Do not use outside of log4net.
+/// Signatures may change without notice.
+/// </summary>
+[EditorBrowsable(EditorBrowsableState.Never)]
+public interface IUdpConnection : IDisposable
+{
+  /// <summary>
+  /// Establishes a default remote host using the specified host name and port 
number.
+  /// </summary>
+  /// <param name="localPort">The local port number</param>
+  /// <param name="host">The remote host to which you intend send data.</param>
+  /// <param name="remotePort">The port number on the remote host to which you 
intend to send data.</param>
+  void Connect(int localPort, IPAddress host, int remotePort);
+
+  /// <summary>
+  /// Sends a UDP datagram asynchronously to a remote host.
+  /// </summary>
+  /// <param name="datagram">An array of type System.Byte that specifies the 
UDP datagram that you intend to send represented as an array of bytes.</param>
+  /// <param name="bytes">The number of bytes in the datagram.</param>
+  /// <returns>Task for Completion</returns>
+  Task<int> SendAsync(byte[] datagram, int bytes);
+}
\ No newline at end of file
diff --git a/src/log4net/Appender/Internal/UdpConnection.cs 
b/src/log4net/Appender/Internal/UdpConnection.cs
new file mode 100644
index 00000000..d39cd536
--- /dev/null
+++ b/src/log4net/Appender/Internal/UdpConnection.cs
@@ -0,0 +1,58 @@
+#region Apache License
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more 
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership. 
+// The ASF licenses this file to you under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with 
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#endregion
+
+using System.Net;
+using System.Net.Sockets;
+using System.Threading.Tasks;
+using log4net.Util;
+
+namespace log4net.Appender.Internal;
+
+/// <summary>
+/// Wrapper for <see cref="UdpClient"/> to manage UDP connections.
+/// </summary>
+internal sealed class UdpConnection : IUdpConnection
+{
+  private UdpClient? _client;
+
+  private UdpClient Client 
+    => _client.EnsureNotNull(errorMessage: "Client is not initialized. Call 
Connect first.");
+
+  /// <inheritdoc/>
+  public void Connect(int localPort, IPAddress remoteAddress, int remotePort)
+  {
+    _client = CreateClient(localPort, remoteAddress);
+    Client.Connect(remoteAddress, remotePort);
+  }
+
+  /// <inheritdoc/>
+  public Task<int> SendAsync(byte[] datagram, int bytes) => 
Client.SendAsync(datagram, bytes);
+
+  /// <inheritdoc/>
+  public void Dispose() => _client?.Dispose();
+
+  /// <summary>
+  /// Creates a new <see cref="UdpClient"/> instance configured with the 
specified local port and remote address.
+  /// </summary>
+  /// <returns>A <see cref="UdpClient"/> instance configured with the 
specified parameters.</returns>
+  internal static UdpClient CreateClient(int localPort, System.Net.IPAddress 
remoteAddress)
+    => localPort == 0
+      ? new (remoteAddress.AddressFamily)
+      : new (localPort, remoteAddress.AddressFamily);
+}
\ No newline at end of file
diff --git a/src/log4net/Appender/RemoteSyslogAppender.cs 
b/src/log4net/Appender/RemoteSyslogAppender.cs
index 95a79a56..f9f46f76 100644
--- a/src/log4net/Appender/RemoteSyslogAppender.cs
+++ b/src/log4net/Appender/RemoteSyslogAppender.cs
@@ -18,15 +18,14 @@
 #endregion
 
 using System;
-
-using log4net.Core;
-using log4net.Util;
-using log4net.Layout;
+using System.Collections.Concurrent;
 using System.Text;
-using System.Net.Sockets;
-using System.Threading.Tasks;
 using System.Threading;
-using System.Collections.Concurrent;
+using System.Threading.Tasks;
+using log4net.Appender.Internal;
+using log4net.Core;
+using log4net.Layout;
+using log4net.Util;
 
 namespace log4net.Appender;
 
@@ -260,9 +259,9 @@ public enum SyslogFacility
   }
 
   private readonly BlockingCollection<byte[]> _sendQueue = new();
-  private CancellationTokenSource? _cts;
+  private CancellationTokenSource? _cancellationTokenSource;
   private Task? _pumpTask;
-  
+
   /// <summary>
   /// Initializes a new instance of the <see cref="RemoteSyslogAppender" /> 
class.
   /// </summary>
@@ -301,6 +300,11 @@ public RemoteSyslogAppender()
   /// </remarks>
   public SyslogFacility Facility { get; set; } = SyslogFacility.User;
 
+  /// <summary>
+  /// Gets or sets the delegate used to create instances of <see 
cref="IUdpConnection"/>.
+  /// </summary>
+  protected virtual IUdpConnection CreateUdpConnection() => new 
UdpConnection();
+
   /// <summary>
   /// Add a mapping of level to severity
   /// </summary>
@@ -326,15 +330,6 @@ public RemoteSyslogAppender()
   /// </remarks>
   protected override void Append(LoggingEvent loggingEvent)
   {
-    if (Client is null)
-    {
-      ErrorHandler.Error(
-        $"Unable to send logging event to remote syslog {RemoteAddress} on 
port {RemotePort}, no client created",
-        e: null,
-        ErrorCode.WriteFailure);
-      return;
-    }
-
     loggingEvent.EnsureNotNull();
     try
     {
@@ -342,22 +337,14 @@ protected override void Append(LoggingEvent loggingEvent)
       int priority = GeneratePriority(Facility, 
GetSeverity(loggingEvent.Level));
 
       // Identity
-      string? identity;
-      if (Identity is not null)
-      {
-        identity = Identity.Format(loggingEvent);
-      }
-      else
-      {
-        identity = loggingEvent.Domain;
-      }
+      string? identity = Identity?.Format(loggingEvent) ?? loggingEvent.Domain;
 
       // Message. The message goes after the tag/identity
       string message = RenderLoggingEvent(loggingEvent);
 
       int i = 0;
 
-      var builder = new StringBuilder();
+      StringBuilder builder = new();
 
       while (i < message.Length)
       {
@@ -375,14 +362,13 @@ protected override void Append(LoggingEvent loggingEvent)
         // Grab as a byte array
         byte[] buffer = Encoding.GetBytes(builder.ToString());
 
-        //Client.SendAsync(buffer, buffer.Length, RemoteEndPoint).Wait();
         _sendQueue.Add(buffer);
       }
     }
     catch (Exception e) when (!e.IsFatal())
     {
       ErrorHandler.Error(
-        $"Unable to send logging event to remote syslog {RemoteAddress} on 
port {RemotePort}.",
+        $"Unable to enqueue logging event to remote syslog {RemoteAddress} on 
port {RemotePort}.",
         e, ErrorCode.WriteFailure);
     }
   }
@@ -434,10 +420,11 @@ public override void ActivateOptions()
     base.ActivateOptions();
     _levelMapping.ActivateOptions();
     // Start the background pump
-    _cts = new CancellationTokenSource();
-    _pumpTask = Task.Run(() => ProcessQueueAsync(_cts.Token), 
CancellationToken.None);
+    _cancellationTokenSource = new();
+    _pumpTask = Task.Factory.StartNew(() => 
ProcessQueueAsync(_cancellationTokenSource.Token), CancellationToken.None,
+      TaskCreationOptions.LongRunning, TaskScheduler.Default);
   }
-  
+
   /// <summary>
   /// Translates a log4net level to a syslog severity.
   /// </summary>
@@ -544,44 +531,49 @@ public class LevelSeverity : LevelMappingEntry
     public SyslogSeverity Severity { get; set; }
   }
 
+  /// <inheritdoc/>
   protected override void OnClose()
   {
     // Signal shutdown and wait for the pump to drain
-    _cts?.Cancel();
-    _pumpTask?.Wait(TimeSpan.FromSeconds(5)); // or your own timeout
+    _cancellationTokenSource?.Cancel();
+    _pumpTask?.Wait(TimeSpan.FromSeconds(5));
     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);
+    using IUdpConnection udpClient = CreateUdpConnection();
+    udpClient.Connect(LocalPort, RemoteAddress.EnsureNotNull(), RemotePort);
 
-      try
+    try
+    {
+      while (!token.IsCancellationRequested)
       {
-        while (!token.IsCancellationRequested)
+        // Take next message or throw when cancelled
+        byte[] datagram = _sendQueue.Take(token);
+        try
+        {
+          await udpClient.SendAsync(datagram, 
datagram.Length).ConfigureAwait(false);
+        }
+        catch (Exception ex) when (!ex.IsFatal())
         {
-          // 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);
-          }
+          ErrorHandler.Error("RemoteSyslogAppender: send failed", ex, 
ErrorCode.WriteFailure);
         }
       }
-      catch (OperationCanceledException)
+    }
+    catch (OperationCanceledException)
+    {
+      // Clean shutdown: drain remaining items if desired
+      while (_sendQueue.TryTake(out byte[]? leftover))
       {
-        // Clean shutdown: drain remaining items if desired
-        while (_sendQueue.TryTake(out var leftover))
+        try
+        {
+          await udpClient.SendAsync(leftover, 
leftover.Length).ConfigureAwait(false);
+        }
+        catch (Exception ex) when (!ex.IsFatal())
         {
-          try { await udp.SendAsync(leftover, leftover.Length); }
-          catch { /* ignore */ }
+          ErrorHandler.Error("RemoteSyslogAppender: send failed during 
shutdown", ex, ErrorCode.FlushFailure);
         }
       }
     }
diff --git a/src/log4net/Appender/UdpAppender.cs 
b/src/log4net/Appender/UdpAppender.cs
index cf4f03f9..2e0dc957 100644
--- a/src/log4net/Appender/UdpAppender.cs
+++ b/src/log4net/Appender/UdpAppender.cs
@@ -21,7 +21,7 @@
 using System.Net;
 using System.Net.Sockets;
 using System.Text;
-
+using log4net.Appender.Internal;
 using log4net.Core;
 using log4net.Util;
 
@@ -206,13 +206,10 @@ public int RemotePort
     {
       if (value is < IPEndPoint.MinPort or > IPEndPoint.MaxPort)
       {
-        throw Util.SystemInfo.CreateArgumentOutOfRangeException(nameof(value), 
value,
+        throw SystemInfo.CreateArgumentOutOfRangeException(nameof(value), 
value,
           $"The value specified is less than {IPEndPoint.MinPort} or greater 
than {IPEndPoint.MaxPort}.");
       }
-      else
-      {
-        _remotePort = value;
-      }
+      _remotePort = value;
     }
   }
 
@@ -240,13 +237,10 @@ public int LocalPort
     {
       if (value is not 0 and (< IPEndPoint.MinPort or > IPEndPoint.MaxPort))
       {
-        throw Util.SystemInfo.CreateArgumentOutOfRangeException(nameof(value), 
value,
+        throw SystemInfo.CreateArgumentOutOfRangeException(nameof(value), 
value,
           $"The value specified is less than {IPEndPoint.MinPort} or greater 
than {IPEndPoint.MaxPort}.");
       }
-      else
-      {
-        _localPort = value;
-      }
+      _localPort = value;
     }
   }
 
@@ -270,7 +264,7 @@ public int LocalPort
   /// The underlying <see cref="UdpClient" />.
   /// </value>
   /// <remarks>
-  /// <see cref="UdpAppender" /> creates a <see cref="UdpClient" /> to send 
logging events 
+  /// <see cref="UdpAppender" /> creates a <see cref="UdpClient" /> to send 
logging events
   /// over a network.  Classes deriving from <see cref="UdpAppender" /> can 
use this
   /// property to get or set this <see cref="UdpClient" />.  Use the 
underlying <see cref="UdpClient" />
   /// returned from <see cref="Client" /> if you require access beyond that 
which 
@@ -282,7 +276,7 @@ public int LocalPort
   /// Gets or sets the cached remote endpoint to which the logging events 
should be sent.
   /// </summary>
   /// <remarks>
-  /// The <see cref="ActivateOptions" /> method will initialize the remote 
endpoint 
+  /// The <see cref="ActivateOptions" /> method will initialize the remote 
endpoint
   /// with the values of the <see cref="RemoteAddress" /> and <see 
cref="RemotePort"/>
   /// properties.
   /// </remarks>
@@ -294,13 +288,13 @@ public int LocalPort
   /// <remarks>
   /// <para>
   /// This is part of the <see cref="IOptionHandler"/> delayed object
-  /// activation scheme. The <see cref="ActivateOptions"/> method must 
+  /// activation scheme. The <see cref="ActivateOptions"/> method must
   /// be called on this object after the configuration properties have
   /// been set. Until <see cref="ActivateOptions"/> is called this
-  /// object is in an undefined state and must not be used. 
+  /// object is in an undefined state and must not be used.
   /// </para>
   /// <para>
-  /// If any of the configuration properties are modified then 
+  /// If any of the configuration properties are modified then
   /// <see cref="ActivateOptions"/> must be called again.
   /// </para>
   /// <para>
@@ -371,7 +365,7 @@ protected override void Append(LoggingEvent loggingEvent)
   protected override bool RequiresLayout => true;
 
   /// <summary>
-  /// Closes the UDP connection and releases all resources associated with 
+  /// Closes the UDP connection and releases all resources associated with
   /// this <see cref="UdpAppender" /> instance.
   /// </summary>
   /// <remarks>
@@ -392,7 +386,7 @@ protected override void OnClose()
   /// </summary>
   /// <remarks>
   /// <para>
-  /// The underlying <see cref="UdpClient"/> is initialized and binds to the 
+  /// The underlying <see cref="UdpClient"/> is initialized and binds to the
   /// port number from which you intend to communicate.
   /// </para>
   /// <para>
@@ -403,14 +397,7 @@ protected virtual void InitializeClientConnection()
   {
     try
     {
-      if (LocalPort == 0)
-      {
-        Client = new(RemoteAddress!.AddressFamily);
-      }
-      else
-      {
-        Client = new(LocalPort, RemoteAddress!.AddressFamily);
-      }
+      Client = UdpConnection.CreateClient(LocalPort, 
RemoteAddress.EnsureNotNull());
     }
     catch (Exception e) when (!e.IsFatal())
     {
@@ -423,7 +410,7 @@ protected virtual void InitializeClientConnection()
   }
 
   /// <summary>
-  /// The TCP port number of the remote host or multicast group to 
+  /// The TCP port number of the remote host or multicast group to
   /// which the logging event will be sent.
   /// </summary>
   private int _remotePort;
@@ -432,4 +419,4 @@ protected virtual void InitializeClientConnection()
   /// The TCP port number from which the <see cref="UdpClient" /> will 
communicate.
   /// </summary>
   private int _localPort;
-}
+}
\ No newline at end of file
diff --git a/src/log4net/Core/ErrorCode.cs b/src/log4net/Core/ErrorCode.cs
index c936b64e..5faf0921 100644
--- a/src/log4net/Core/ErrorCode.cs
+++ b/src/log4net/Core/ErrorCode.cs
@@ -66,4 +66,4 @@ public enum ErrorCode : int
   /// Failed to parse address
   /// </summary>
   AddressParseFailure
-}
+}
\ No newline at end of file
diff --git a/src/log4net/Core/LoggerManager.cs 
b/src/log4net/Core/LoggerManager.cs
index 212e66f8..ab6fb89b 100644
--- a/src/log4net/Core/LoggerManager.cs
+++ b/src/log4net/Core/LoggerManager.cs
@@ -527,7 +527,7 @@ public static ILoggerRepository CreateRepository(Assembly 
repositoryAssembly, Ty
   /// <returns>A string of version info.</returns>
   private static string GetVersionInfo()
   {
-    var sb = new StringBuilder();
+    StringBuilder sb = new();
 
     Assembly myAssembly = Assembly.GetExecutingAssembly();
     sb.Append("log4net assembly [").Append(myAssembly.FullName).Append("]. ");
diff --git a/src/log4net/Core/LoggingEvent.cs b/src/log4net/Core/LoggingEvent.cs
index 20e7892c..cdc13465 100644
--- a/src/log4net/Core/LoggingEvent.cs
+++ b/src/log4net/Core/LoggingEvent.cs
@@ -803,7 +803,7 @@ private static string ReviseThreadName(string? threadName)
       return null;
     }
 #endif
-    using var identity = WindowsIdentity.GetCurrent();
+    using WindowsIdentity identity = WindowsIdentity.GetCurrent();
     return identity?.Name ?? string.Empty;
   }
 
@@ -1140,14 +1140,13 @@ protected virtual void FixVolatileData(FixFlags flags)
 
   private void CreateCompositeProperties()
   {
-    var compositeProperties = new CompositeProperties();
+    CompositeProperties compositeProperties = new();
 
     if (_eventProperties is not null)
     {
       compositeProperties.Add(_eventProperties);
     }
-    var logicalThreadProperties = 
LogicalThreadContext.Properties.GetProperties(false);
-    if (logicalThreadProperties is not null)
+    if (LogicalThreadContext.Properties.GetProperties(false) is 
PropertiesDictionary logicalThreadProperties)
     {
       compositeProperties.Add(logicalThreadProperties);
     }
@@ -1163,7 +1162,7 @@ private void CreateCompositeProperties()
     bool shouldFixIdentity = (_fixFlags & FixFlags.Identity) != 0;
     if (shouldFixIdentity || shouldFixUserName)
     {
-      var eventProperties = new PropertiesDictionary();
+      PropertiesDictionary eventProperties = new();
       if (shouldFixUserName)
       {
         eventProperties[UserNameProperty] = UserName;
@@ -1178,7 +1177,7 @@ private void CreateCompositeProperties()
     }
 
     compositeProperties.Add(GlobalContext.Properties.GetReadOnlyProperties());
-    this._compositeProperties = compositeProperties;
+    _compositeProperties = compositeProperties;
   }
 
   private void CacheProperties()
@@ -1190,9 +1189,9 @@ private void CacheProperties()
         CreateCompositeProperties();
       }
 
-      var flattenedProperties = _compositeProperties!.Flatten();
+      PropertiesDictionary flattenedProperties = 
_compositeProperties!.Flatten();
 
-      var fixedProperties = new PropertiesDictionary();
+      PropertiesDictionary fixedProperties = new();
 
       // Validate properties
       foreach (KeyValuePair<string, object?> entry in flattenedProperties)
diff --git a/src/log4net/log4net.csproj b/src/log4net/log4net.csproj
index e6d6d105..6a16ea0b 100644
--- a/src/log4net/log4net.csproj
+++ b/src/log4net/log4net.csproj
@@ -107,8 +107,8 @@ log4net is designed with two distinct goals in mind: speed 
and flexibility
     <!-- "Workaround" for missing '.pdb'-Files from NuGet Packages -->
     <!-- https://github.com/dotnet/sdk/issues/1458#issuecomment-420456386 -->
     <ItemGroup>
-      <ReferenceCopyLocalPaths 
Include="@(ReferenceCopyLocalPaths-&gt;'%(RootDir)%(Directory)%(Filename).pdb')"
 Condition="'%(ReferenceCopyLocalPaths.NuGetPackageId)' != '' and 
Exists('%(RootDir)%(Directory)%(Filename).pdb')" />
-      <ReferenceCopyLocalPaths 
Include="@(ReferenceCopyLocalPaths-&gt;'%(RootDir)%(Directory)%(Filename).xml')"
 Condition="'%(ReferenceCopyLocalPaths.NuGetPackageId)' != '' and 
Exists('%(RootDir)%(Directory)%(Filename).xml')" />
+      <ReferenceCopyLocalPaths 
Include="@(ReferenceCopyLocalPaths->'%(RootDir)%(Directory)%(Filename).pdb')" 
Condition="'%(ReferenceCopyLocalPaths.NuGetPackageId)' != '' and 
Exists('%(RootDir)%(Directory)%(Filename).pdb')" />
+      <ReferenceCopyLocalPaths 
Include="@(ReferenceCopyLocalPaths->'%(RootDir)%(Directory)%(Filename).xml')" 
Condition="'%(ReferenceCopyLocalPaths.NuGetPackageId)' != '' and 
Exists('%(RootDir)%(Directory)%(Filename).xml')" />
     </ItemGroup>
   </Target>
 </Project>
\ No newline at end of file

Reply via email to