Skip to content

Commit 1f72626

Browse files
committed
Refine the API for configuring XML namespaces
Do not allow an arbitrary XML namespace, only allow log4net (default), log4j (through UseLog4JCompatibility) or none (through UseNoXmlNamespace).
1 parent b69993c commit 1f72626

6 files changed

+33
-22
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,10 @@ new Log4NetTextFormatter(c => c.UseCDataMode(CDataMode.Never))
7878

7979
### XML Namespace
8080

81-
You can remove the `log4net` XML namespace by setting the `Log4NetXmlNamespace` option to `null`. This is useful if you want to spare some bytes and your log reader supports log4net XML events without namespace, like [Log4View](https://www.log4view.com) does. You *could* also change the namespace to something else than the default `log4net:http://logging.apache.org/log4net/schemas/log4net-events-1.2/` but that would probably not be a good idea.
81+
You can remove the `log4net` XML namespace by calling `UseNoXmlNamespace()` on the options builder. This is useful if you want to spare some bytes and your log reader supports log4net XML events without namespace, like [Log4View](https://www.log4view.com) does.
8282

8383
```c#
84-
new Log4NetTextFormatter(c => c.UseLog4NetXmlNamespace(null))
84+
new Log4NetTextFormatter(c => c.UseNoXmlNamespace())
8585
```
8686

8787
### Line ending

src/Log4NetTextFormatter.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ public void Format(LogEvent logEvent, TextWriter output)
8888
output.Write(_options.XmlWriterSettings.NewLineChars);
8989
}
9090

91+
private bool UsesLog4JCompatibility => ReferenceEquals(Log4NetTextFormatterOptionsBuilder.Log4JXmlNamespace, _options.XmlNamespace);
92+
9193
/// <summary>
9294
/// Write the log event into the XML writer.
9395
/// </summary>
@@ -96,10 +98,9 @@ public void Format(LogEvent logEvent, TextWriter output)
9698
/// <remarks>https://github.com/apache/logging-log4net/blob/rel/2.0.8/src/Layout/XmlLayout.cs#L218-L310</remarks>
9799
private void WriteEvent(LogEvent logEvent, XmlWriter writer)
98100
{
99-
var useLog4JCompatibility = _options.Log4NetXmlNamespace?.Name == "log4j";
100101
WriteStartElement(writer, "event");
101102
WriteEventAttribute(logEvent, writer, "logger", Constants.SourceContextPropertyName);
102-
var timestamp = useLog4JCompatibility ? XmlConvert.ToString(logEvent.Timestamp.ToUnixTimeMilliseconds()) : XmlConvert.ToString(logEvent.Timestamp);
103+
var timestamp = UsesLog4JCompatibility ? XmlConvert.ToString(logEvent.Timestamp.ToUnixTimeMilliseconds()) : XmlConvert.ToString(logEvent.Timestamp);
103104
writer.WriteAttributeString("timestamp", timestamp);
104105
writer.WriteAttributeString("level", LogLevel(logEvent.Level));
105106
WriteEventAttribute(logEvent, writer, "thread", ThreadIdPropertyName);
@@ -111,7 +112,7 @@ private void WriteEvent(LogEvent logEvent, XmlWriter writer)
111112
WriteProperties(logEvent, writer, properties, machineNameProperty);
112113
}
113114
WriteMessage(logEvent, writer);
114-
WriteException(logEvent, writer, useLog4JCompatibility ? "throwable" : "exception");
115+
WriteException(logEvent, writer, UsesLog4JCompatibility ? "throwable" : "exception");
115116
writer.WriteEndElement();
116117
}
117118

@@ -374,13 +375,13 @@ private void WriteException(LogEvent logEvent, XmlWriter writer, string elementN
374375
}
375376

376377
/// <summary>
377-
/// Start writing an XML element, taking into account the configured <see cref="Log4NetTextFormatterOptions.Log4NetXmlNamespace"/>.
378+
/// Start writing an XML element, taking into account the configured <see cref="Log4NetTextFormatterOptions.XmlNamespace"/>.
378379
/// </summary>
379380
/// <param name="writer">The XML writer.</param>
380381
/// <param name="elementName">The name of the XML element to write.</param>
381382
private void WriteStartElement(XmlWriter writer, string elementName)
382383
{
383-
var qualifiedName = _options.Log4NetXmlNamespace;
384+
var qualifiedName = _options.XmlNamespace;
384385
if (qualifiedName != null)
385386
{
386387
writer.WriteStartElement(qualifiedName.Name, elementName, qualifiedName.Namespace);

src/Log4NetTextFormatterOptions.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ namespace Serilog.Formatting.Log4Net
88
/// </summary>
99
internal class Log4NetTextFormatterOptions
1010
{
11-
internal Log4NetTextFormatterOptions(IFormatProvider? formatProvider, CDataMode cDataMode, XmlQualifiedName? log4NetXmlNamespace, XmlWriterSettings xmlWriterSettings, PropertyFilter filterProperty, ExceptionFormatter formatException)
11+
internal Log4NetTextFormatterOptions(IFormatProvider? formatProvider, CDataMode cDataMode, XmlQualifiedName? xmlNamespace, XmlWriterSettings xmlWriterSettings, PropertyFilter filterProperty, ExceptionFormatter formatException)
1212
{
1313
FormatProvider = formatProvider;
1414
CDataMode = cDataMode;
15-
Log4NetXmlNamespace = log4NetXmlNamespace;
15+
XmlNamespace = xmlNamespace;
1616
XmlWriterSettings = xmlWriterSettings;
1717
FilterProperty = filterProperty;
1818
FormatException = formatException;
@@ -24,8 +24,8 @@ internal Log4NetTextFormatterOptions(IFormatProvider? formatProvider, CDataMode
2424
/// <summary>See <see cref="Log4NetTextFormatterOptionsBuilder.UseCDataMode"/></summary>
2525
internal CDataMode CDataMode { get; }
2626

27-
/// <summary>See <see cref="Log4NetTextFormatterOptionsBuilder.UseLog4NetXmlNamespace"/></summary>
28-
internal XmlQualifiedName? Log4NetXmlNamespace { get; }
27+
/// <summary>See <see cref="Log4NetTextFormatterOptionsBuilder.UseNoXmlNamespace"/></summary>
28+
internal XmlQualifiedName? XmlNamespace { get; }
2929

3030
/// <summary>See <see cref="Log4NetTextFormatterOptionsBuilder.CreateXmlWriterSettings"/></summary>
3131
internal XmlWriterSettings XmlWriterSettings { get; }

src/Log4NetTextFormatterOptionsBuilder.cs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,18 @@ namespace Serilog.Formatting.Log4Net
99
/// </summary>
1010
public class Log4NetTextFormatterOptionsBuilder
1111
{
12+
/// <summary>
13+
/// The XML namespace used for log4net events.
14+
/// </summary>
15+
/// <remarks>https://github.com/apache/logging-log4net/blob/rel/2.0.8/src/Layout/XmlLayout.cs#L49</remarks>
16+
private static readonly XmlQualifiedName Log4NetXmlNamespace = new("log4net", "http://logging.apache.org/log4net/schemas/log4net-events-1.2/");
17+
18+
/// <summary>
19+
/// The XML namespace used for Log4j events.
20+
/// </summary>
21+
/// <remarks>// https://github.com/apache/log4j/blob/v1_2_17/src/main/java/org/apache/log4j/xml/XMLLayout.java#L137</remarks>
22+
internal static readonly XmlQualifiedName Log4JXmlNamespace = new("log4j", "http://jakarta.apache.org/log4j/");
23+
1224
/// <summary>
1325
/// Initialize a new instance of the <see cref="Log4NetTextFormatterOptionsBuilder"/> class.
1426
/// </summary>
@@ -22,9 +34,8 @@ internal Log4NetTextFormatterOptionsBuilder()
2234
/// <summary> See <see cref="UseCDataMode"/></summary>
2335
private CDataMode _cDataMode = CDataMode.Always;
2436

25-
/// <summary>See <see cref="UseLog4NetXmlNamespace"/></summary>
26-
/// <remarks>https://github.com/apache/logging-log4net/blob/rel/2.0.8/src/Layout/XmlLayout.cs#L49</remarks>
27-
private XmlQualifiedName? _log4NetXmlNamespace = new("log4net", "http://logging.apache.org/log4net/schemas/log4net-events-1.2/");
37+
/// <summary>See <see cref="UseNoXmlNamespace"/></summary>
38+
private XmlQualifiedName? _xmlNamespace = Log4NetXmlNamespace;
2839

2940
/// <summary>See <see cref="UseLineEnding"/></summary>
3041
private LineEnding _lineEnding = LineEnding.LineFeed;
@@ -65,15 +76,14 @@ public Log4NetTextFormatterOptionsBuilder UseCDataMode(CDataMode cDataMode)
6576
}
6677

6778
/// <summary>
68-
/// Sets the XML namespace used for log4net events. Set to <see langword="null"/> in order not to use a namespace.
79+
/// Do not use any XML namespace for log4net events.
6980
/// <para/>
7081
/// The default value has prefix <c>log4net</c> and namespace <c>http://logging.apache.org/log4net/schemas/log4net-events-1.2/</c>.
7182
/// </summary>
72-
/// <param name="log4NetXmlNamespace">The XML namespace to use.</param>
7383
/// <returns>The builder in order to fluently chain all options.</returns>
74-
public Log4NetTextFormatterOptionsBuilder UseLog4NetXmlNamespace(XmlQualifiedName? log4NetXmlNamespace)
84+
public Log4NetTextFormatterOptionsBuilder UseNoXmlNamespace()
7585
{
76-
_log4NetXmlNamespace = log4NetXmlNamespace;
86+
_xmlNamespace = null;
7787
return this;
7888
}
7989

@@ -160,14 +170,14 @@ public void UseLog4JCompatibility()
160170
_lineEnding = LineEnding.CarriageReturn | LineEnding.LineFeed;
161171

162172
// https://github.com/apache/log4j/blob/v1_2_17/src/main/java/org/apache/log4j/xml/XMLLayout.java#L137
163-
_log4NetXmlNamespace = new XmlQualifiedName("log4j", "http://jakarta.apache.org/log4j/");
173+
_xmlNamespace = Log4JXmlNamespace;
164174

165175
// https://github.com/apache/log4j/blob/v1_2_17/src/main/java/org/apache/log4j/xml/XMLLayout.java#L147
166176
_cDataMode = CDataMode.Always;
167177
}
168178

169179
internal Log4NetTextFormatterOptions Build()
170-
=> new(_formatProvider, _cDataMode, _log4NetXmlNamespace, CreateXmlWriterSettings(_lineEnding, _indentationSettings), _filterProperty, _formatException);
180+
=> new(_formatProvider, _cDataMode, _xmlNamespace, CreateXmlWriterSettings(_lineEnding, _indentationSettings), _filterProperty, _formatException);
171181

172182
private static XmlWriterSettings CreateXmlWriterSettings(LineEnding lineEnding, IndentationSettings? indentationSettings)
173183
{

tests/Log4NetTextFormatterTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ public void NoNamespace()
258258
// Arrange
259259
using var output = new StringWriter();
260260
var logEvent = CreateLogEvent();
261-
var formatter = new Log4NetTextFormatter(options => options.UseLog4NetXmlNamespace(null));
261+
var formatter = new Log4NetTextFormatter(options => options.UseNoXmlNamespace());
262262

263263
// Act
264264
formatter.Format(logEvent, output);

tests/PublicApi.Serilog.Formatting.Log4Net.approved.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ namespace Serilog.Formatting.Log4Net
4141
public Serilog.Formatting.Log4Net.Log4NetTextFormatterOptionsBuilder UseIndentationSettings(Serilog.Formatting.Log4Net.IndentationSettings indentationSettings) { }
4242
public Serilog.Formatting.Log4Net.Log4NetTextFormatterOptionsBuilder UseLineEnding(Serilog.Formatting.Log4Net.LineEnding lineEnding) { }
4343
public void UseLog4JCompatibility() { }
44-
public Serilog.Formatting.Log4Net.Log4NetTextFormatterOptionsBuilder UseLog4NetXmlNamespace(System.Xml.XmlQualifiedName? log4NetXmlNamespace) { }
4544
public Serilog.Formatting.Log4Net.Log4NetTextFormatterOptionsBuilder UseNoIndentation() { }
45+
public Serilog.Formatting.Log4Net.Log4NetTextFormatterOptionsBuilder UseNoXmlNamespace() { }
4646
public Serilog.Formatting.Log4Net.Log4NetTextFormatterOptionsBuilder UsePropertyFilter(Serilog.Formatting.Log4Net.PropertyFilter filterProperty) { }
4747
}
4848
public delegate bool PropertyFilter(Serilog.Events.LogEvent logEvent, string propertyName);

0 commit comments

Comments
 (0)