You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by fr...@apache.org on 2025/12/07 19:55:54 UTC
(logging-log4net) branch Feature/RemoteSysLogAppender-NewLineHandling created (now fe2b7caa)
This is an automated email from the ASF dual-hosted git repository.
freeandnil pushed a change to branch Feature/RemoteSysLogAppender-NewLineHandling
in repository https://gitbox.apache.org/repos/asf/logging-log4net.git
at fe2b7caa added NewLineHandling to RemoteSyslogAppender - fixes #274
This branch includes the following new commits:
new fe2b7caa added NewLineHandling to RemoteSyslogAppender - fixes #274
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(logging-log4net) 01/01: added NewLineHandling to RemoteSyslogAppender - fixes #274
Posted by fr...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
freeandnil pushed a commit to branch Feature/RemoteSysLogAppender-NewLineHandling
in repository https://gitbox.apache.org/repos/asf/logging-log4net.git
commit fe2b7caaaa145033e5b960bcbd7613ab84dc8b37
Author: Jan Friedrich <fr...@apache.org>
AuthorDate: Sun Dec 7 20:55:36 2025 +0100
added NewLineHandling to RemoteSyslogAppender - fixes #274
---
.../Appender/RemoteSyslogAppenderTest.cs | 81 ++++++++++++++++++++--
src/log4net/Appender/RemoteSyslogAppender.cs | 59 ++++++++++++++--
2 files changed, 128 insertions(+), 12 deletions(-)
diff --git a/src/log4net.Tests/Appender/RemoteSyslogAppenderTest.cs b/src/log4net.Tests/Appender/RemoteSyslogAppenderTest.cs
index 2a6c94fb..99b9c309 100644
--- a/src/log4net.Tests/Appender/RemoteSyslogAppenderTest.cs
+++ b/src/log4net.Tests/Appender/RemoteSyslogAppenderTest.cs
@@ -17,6 +17,8 @@
//
#endregion
+using System.Collections.Generic;
+using System.Linq;
using System.Text;
using System.Threading;
using log4net.Appender;
@@ -46,21 +48,90 @@ private sealed class RemoteAppender : RemoteSyslogAppender
}
/// <summary>
- /// Simple Test for the <see cref="RemoteSyslogAppenderTest"/>
+ /// Simple Test for the <see cref="RemoteSyslogAppender"/>
/// </summary>
/// <remarks>
/// https://github.com/apache/logging-log4net/issues/255
/// </remarks>
[Test]
public void RemoteSyslogTest()
+ {
+ List<byte[]> sentBytes = ExecuteAppend("Test message");
+ const string expectedData = @"<14>TestDomain: INFO - Test message";
+ Assert.That(sentBytes, Has.Count.EqualTo(1));
+ Assert.That(Encoding.ASCII.GetString(sentBytes[0]), Is.EqualTo(expectedData));
+ }
+
+ /// <summary>
+ /// Test for the <see cref="RemoteSyslogAppender.NewLineHandling"/>
+ /// with <see cref="RemoteSyslogAppender.SyslogNewLineHandling.Escape"/>
+ /// </summary>
+ /// <remarks>
+ /// https://github.com/apache/logging-log4net/issues/274
+ /// </remarks>
+ [Test]
+ public void RemoteSyslogNewLineHandlingEscapeTest()
+ {
+ List<byte[]> sentBytes = ExecuteAppend("Test\r\nmessage");
+ // ReSharper disable once StringLiteralTypo
+ const string expectedData = @"<14>TestDomain: INFO - Test\r\nmessage";
+ Assert.That(sentBytes, Has.Count.EqualTo(1));
+ Assert.That(Encoding.ASCII.GetString(sentBytes[0]), Is.EqualTo(expectedData));
+ }
+
+ /// <summary>
+ /// Test for the <see cref="RemoteSyslogAppender.NewLineHandling"/>
+ /// with <see cref="RemoteSyslogAppender.SyslogNewLineHandling.Keep"/>
+ /// </summary>
+ /// <remarks>
+ /// https://github.com/apache/logging-log4net/issues/274
+ /// </remarks>
+ [Test]
+ public void RemoteSyslogNewLineHandlingKeepTest()
+ {
+ List<byte[]> sentBytes = ExecuteAppend("Test\r\nmessage",
+ RemoteSyslogAppender.SyslogNewLineHandling.Keep);
+ // ReSharper disable once StringLiteralTypo
+ const string expectedData = "<14>TestDomain: INFO - Test\r\nmessage";
+ Assert.That(sentBytes, Has.Count.EqualTo(1));
+ Assert.That(Encoding.ASCII.GetString(sentBytes[0]), Is.EqualTo(expectedData));
+ }
+
+ /// <summary>
+ /// Test for the <see cref="RemoteSyslogAppender.NewLineHandling"/>
+ /// with <see cref="RemoteSyslogAppender.SyslogNewLineHandling.Split"/>
+ /// </summary>
+ /// <remarks>
+ /// https://github.com/apache/logging-log4net/issues/274
+ /// </remarks>
+ [Test]
+ public void RemoteSyslogNewLineHandlingSplitTest()
+ {
+ List<byte[]> sentBytes = ExecuteAppend("Test\r\nmessage",
+ RemoteSyslogAppender.SyslogNewLineHandling.Split);
+ // ReSharper disable once StringLiteralTypo
+ Assert.That(sentBytes, Has.Count.EqualTo(2));
+ const string expectedData0 = "<14>TestDomain: INFO - Test";
+ Assert.That(Encoding.ASCII.GetString(sentBytes[0]), Is.EqualTo(expectedData0));
+ const string expectedData1 = "<14>TestDomain: message";
+ Assert.That(Encoding.ASCII.GetString(sentBytes[1]), Is.EqualTo(expectedData1));
+ }
+
+ private static List<byte[]> ExecuteAppend(string message,
+ RemoteSyslogAppender.SyslogNewLineHandling newLineHandling = default)
{
System.Net.IPAddress ipAddress = new([127, 0, 0, 1]);
- RemoteAppender appender = new() { RemoteAddress = ipAddress, Layout = new PatternLayout("%-5level - %message%newline") };
+ RemoteAppender appender = new()
+ {
+ RemoteAddress = ipAddress,
+ Layout = new PatternLayout("%-5level - %message"),
+ NewLineHandling = newLineHandling
+ };
appender.ActivateOptions();
LoggingEvent loggingEvent = new(new()
{
Level = Level.Info,
- Message = "Test message",
+ Message = message,
LoggerName = "TestLogger",
Domain = "TestDomain",
});
@@ -74,9 +145,7 @@ public void RemoteSyslogTest()
}
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);
- const string expectedData = @"<14>TestDomain: INFO - Test message";
- Assert.That(Encoding.ASCII.GetString(appender.Mock.Sent[0].Datagram), Is.EqualTo(expectedData));
+ return appender.Mock.Sent.Select(item => item.Datagram).ToList();
}
}
\ No newline at end of file
diff --git a/src/log4net/Appender/RemoteSyslogAppender.cs b/src/log4net/Appender/RemoteSyslogAppender.cs
index f9f46f76..8b5b21ea 100644
--- a/src/log4net/Appender/RemoteSyslogAppender.cs
+++ b/src/log4net/Appender/RemoteSyslogAppender.cs
@@ -258,6 +258,27 @@ public enum SyslogFacility
Local7 = 23
}
+ /// <summary>
+ /// Options for handling newlines (\r or \n) in <see ref="AppendMessage" />
+ /// </summary>
+ public enum SyslogNewLineHandling
+ {
+ /// <summary>
+ /// escape the newlines (\\r for \r and \\n for \n)
+ /// </summary>
+ Escape,
+
+ /// <summary>
+ /// split the message at new lines
+ /// </summary>
+ Split,
+
+ /// <summary>
+ /// keep newlines as is (many syslog servers can handle newlines in the message part)
+ /// </summary>
+ Keep
+ }
+
private readonly BlockingCollection<byte[]> _sendQueue = new();
private CancellationTokenSource? _cancellationTokenSource;
private Task? _pumpTask;
@@ -300,6 +321,12 @@ public RemoteSyslogAppender()
/// </remarks>
public SyslogFacility Facility { get; set; } = SyslogFacility.User;
+ /// <summary>
+ /// NewLine handling
+ /// </summary>
+ /// <remarks>The default value is <see cref="SyslogNewLineHandling.Escape"/>.</remarks>
+ public SyslogNewLineHandling NewLineHandling { get; set; }
+
/// <summary>
/// Gets or sets the delegate used to create instances of <see cref="IUdpConnection"/>.
/// </summary>
@@ -393,16 +420,31 @@ protected virtual void AppendMessage(string message, ref int characterIndex, Str
{
builder.Append(c);
}
- // If character is newline, break and send the current line
+ // If character is newline
else if (c is '\r' or '\n')
{
- // Check the next character to handle \r\n or \n\r
- if ((message.Length > characterIndex + 1) && ((message[characterIndex + 1] == '\r') || (message[characterIndex + 1] == '\n')))
+ if (NewLineHandling == SyslogNewLineHandling.Escape)
+ {
+ // escape
+ builder.Append(c == '\r' ? "\\r" : "\\n");
+ }
+ else if (NewLineHandling == SyslogNewLineHandling.Keep)
{
+ // keep
+ builder.Append(c);
+ }
+ else if (NewLineHandling == SyslogNewLineHandling.Split)
+ {
+ // break and send the current line
+ // Check the next character to handle \r\n or \n\r
+ if ((message.Length > characterIndex + 1)
+ && ((message[characterIndex + 1] == '\r') || (message[characterIndex + 1] == '\n')))
+ {
+ characterIndex++;
+ }
characterIndex++;
+ break;
}
- characterIndex++;
- break;
}
}
}
@@ -418,6 +460,11 @@ protected virtual void AppendMessage(string message, ref int characterIndex, Str
public override void ActivateOptions()
{
base.ActivateOptions();
+ if (NewLineHandling is not (SyslogNewLineHandling.Escape or SyslogNewLineHandling.Keep or SyslogNewLineHandling.Split))
+ {
+ throw SystemInfo.CreateArgumentOutOfRangeException(nameof(NewLineHandling), NewLineHandling,
+ $"The NewLineHandling is not {SyslogNewLineHandling.Escape} or {SyslogNewLineHandling.Keep} or {SyslogNewLineHandling.Split}.");
+ }
_levelMapping.ActivateOptions();
// Start the background pump
_cancellationTokenSource = new();
@@ -550,7 +597,7 @@ private async Task ProcessQueueAsync(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
- // Take next message or throw when cancelled
+ // Take next message or throw when canceled
byte[] datagram = _sendQueue.Take(token);
try
{