Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions doc/MailTemplate.Announce.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
To: [email protected], [email protected]
Subject: [ANNOUNCE] Apache log4net 3.2.1 released
Subject: [ANNOUNCE] Apache log4net 3.3.0 released

Hi,

the Apache log4net team is pleased to announce the 3.2.1 release.
the Apache log4net team is pleased to announce the 3.3.0 release.
For further information (support, download, etc.) see
- https://logging.apache.org/log4net/release-notes.html
- https://github.com/apache/logging-log4net/releases/tag/rel%2F3.2.1
- https://www.nuget.org/packages/log4net/3.2.1
- https://github.com/apache/logging-log4net/releases/tag/rel%2F3.3.0
- https://www.nuget.org/packages/log4net/3.3.0
4 changes: 2 additions & 2 deletions doc/MailTemplate.Result.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
To: [email protected]
Subject: [RESULT][VOTE] Release Apache Log4net 3.2.1
Subject: [RESULT][VOTE] Release Apache Log4net 3.3.0

and here is my +1.

Expand All @@ -9,6 +9,6 @@ I will continue the release process.
Jan

---------------------------------------------------------------------------------------------------
This is a vote to release the Apache Log4net 3.2.1.
This is a vote to release the Apache Log4net 3.3.0.

...
6 changes: 3 additions & 3 deletions doc/MailTemplate.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
To: [email protected]
Subject: [VOTE] Release Apache Log4net 3.2.1
Subject: [VOTE] Release Apache Log4net 3.3.0

This is a vote to release the Apache Log4net 3.2.1.
This is a vote to release the Apache Log4net 3.3.0.

Website: https://logging.staged.apache.org/log4net/release-notes.html
GitHub: https://github.com/apache/logging-log4net
Commit: <todo>
Distribution: https://dist.apache.org/repos/dist/dev/logging/log4net/3.2.1
Distribution: https://dist.apache.org/repos/dist/dev/logging/log4net/3.3.0
Signing key: 0x7D24496A230E29D6349A99EF583E491578F02D5D
Review kit: https://logging.staged.apache.org/log4net/release-review.html

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "log4net",
"version": "3.2.1",
"version": "3.3.0",
"description": "Log4Net is a logging framework for .NET",
"repository": {
"type": "git",
Expand All @@ -17,4 +17,4 @@
"@antora/site-generator-default": "^3.2.0-alpha.9",
"@asciidoctor/tabs": "^1.0.0-beta.6"
}
}
}
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<packaging>pom</packaging>
<groupId>org.apache.logging.log4net</groupId>
<artifactId>apache-log4net</artifactId>
<version>3.2.1</version>
<version>3.3.0</version>
<name>Apache log4net</name>
<description>Logging framework for Microsoft .NET Framework.</description>
<url>https://logging.apache.org/log4net</url>
Expand Down
2 changes: 1 addition & 1 deletion scripts/build-preview.ps1
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
param(
$Version = '3.2.1',
$Version = '3.3.0',
$Preview = '1'
)
'building ...'
Expand Down
2 changes: 1 addition & 1 deletion scripts/build-release.ps1
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
param(
$Version = '3.2.1'
$Version = '3.3.0'
)

Set-StrictMode -Version Latest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
<release xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://logging.apache.org/xml/ns"
xsi:schemaLocation="https://logging.apache.org/xml/ns https://logging.apache.org/xml/ns/log4j-changelog-0.xsd"
date="2025-10-22"
version="3.2.1"/>
date="2025-12-22"
version="3.3.0"/>
12 changes: 12 additions & 0 deletions src/changelog/3.3.0/274-newline-handling.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://logging.apache.org/xml/ns"
xsi:schemaLocation="https://logging.apache.org/xml/ns https://logging.apache.org/xml/ns/log4j-changelog-0.xsd"
type="changed">
<issue id="274" link="https://github.com/apache/logging-log4net/issue/274"/>
<issue id="276" link="https://github.com/apache/logging-log4net/pull/276"/>
<description format="asciidoc">
https://logging.apache.org/log4net/manual/configuration/appenders/remotesyslogappender.html#newlinehandling[Newline handling] changed
(by @FreeAndNil in https://github.com/apache/logging-log4net/pull/276[#276])
</description>
</entry>
81 changes: 75 additions & 6 deletions src/log4net.Tests/Appender/RemoteSyslogAppenderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
//
#endregion

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using log4net.Appender;
Expand Down Expand Up @@ -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",
});
Expand All @@ -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();
}
}
59 changes: 53 additions & 6 deletions src/log4net/Appender/RemoteSyslogAppender.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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>
Expand Down Expand Up @@ -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;
}
}
}
Expand All @@ -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();
Expand Down Expand Up @@ -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
{
Expand Down
6 changes: 3 additions & 3 deletions src/log4net/log4net.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Version>3.2.1</Version>
<Version>3.3.0</Version>
<PackageId>log4net</PackageId>
<Product>Apache log4net</Product>
<Title>$(Product)</Title>
Expand Down Expand Up @@ -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->'%(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')" />
<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')" />
</ItemGroup>
</Target>
</Project>
Loading
Loading