Skip to content

Commit c54b697

Browse files
committed
Always write the value XML attributes in properties, even when the value is null
Also make the null text configurable through a new `UseNullText()` method on the options builder. The default null text value is `(null)` in order to match the log4net behavior. Fixes #287
1 parent fd05f94 commit c54b697

14 files changed

+73
-19
lines changed

src/Log4NetTextFormatter.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -407,10 +407,7 @@ private void WritePropertyElement(XmlWriter writer, string name, LogEventPropert
407407
WriteStartElement(writer, "data");
408408
writer.WriteAttributeString("name", name);
409409
var isNullValue = value is ScalarValue { Value: null };
410-
if (!isNullValue)
411-
{
412-
writer.WriteAttributeString("value", RenderValue(value));
413-
}
410+
writer.WriteAttributeString("value", isNullValue ? _options.NullText : RenderValue(value));
414411
writer.WriteEndElement();
415412
}
416413

src/Log4NetTextFormatterOptions.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ namespace Serilog.Formatting.Log4Net;
88
/// </summary>
99
internal sealed class Log4NetTextFormatterOptions
1010
{
11-
internal Log4NetTextFormatterOptions(IFormatProvider? formatProvider, CDataMode cDataMode, XmlQualifiedName? xmlNamespace, XmlWriterSettings xmlWriterSettings, PropertyFilter filterProperty, MessageFormatter formatMessage, ExceptionFormatter formatException)
11+
internal Log4NetTextFormatterOptions(IFormatProvider? formatProvider, CDataMode cDataMode, string nullText, XmlQualifiedName? xmlNamespace, XmlWriterSettings xmlWriterSettings, PropertyFilter filterProperty, MessageFormatter formatMessage, ExceptionFormatter formatException)
1212
{
1313
FormatProvider = formatProvider;
1414
CDataMode = cDataMode;
15+
NullText = nullText;
1516
XmlNamespace = xmlNamespace;
1617
XmlWriterSettings = xmlWriterSettings;
1718
FilterProperty = filterProperty;
@@ -25,6 +26,9 @@ internal Log4NetTextFormatterOptions(IFormatProvider? formatProvider, CDataMode
2526
/// <summary>See <see cref="Log4NetTextFormatterOptionsBuilder.UseCDataMode"/></summary>
2627
internal CDataMode CDataMode { get; }
2728

29+
/// <summary>See <see cref="Log4NetTextFormatterOptionsBuilder.UseNullText"/></summary>
30+
internal string NullText { get; }
31+
2832
/// <summary>See <see cref="Log4NetTextFormatterOptionsBuilder.UseNoXmlNamespace"/></summary>
2933
internal XmlQualifiedName? XmlNamespace { get; }
3034

src/Log4NetTextFormatterOptionsBuilder.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,12 @@ internal Log4NetTextFormatterOptionsBuilder()
3131
/// <summary>See <see cref="UseFormatProvider"/></summary>
3232
private IFormatProvider? _formatProvider;
3333

34-
/// <summary> See <see cref="UseCDataMode"/></summary>
34+
/// <summary>See <see cref="UseCDataMode"/></summary>
3535
private CDataMode _cDataMode = CDataMode.Always;
3636

37+
/// <summary>See <see cref="UseNullText"/></summary>
38+
private string _nullText = "(null)";
39+
3740
/// <summary>See <see cref="UseNoXmlNamespace"/></summary>
3841
private XmlQualifiedName? _xmlNamespace = Log4NetXmlNamespace;
3942

@@ -78,6 +81,19 @@ public Log4NetTextFormatterOptionsBuilder UseCDataMode(CDataMode cDataMode)
7881
return this;
7982
}
8083

84+
/// <summary>
85+
/// Sets how <see langword="null"/> properties are rendered as textual representation inside XML attributes.
86+
/// <para/>
87+
/// The default value is <c>(null)</c>.
88+
/// </summary>
89+
/// <param name="nullText">The text to use to represent <see langword="null"/> properties.</param>
90+
/// <returns>The builder in order to fluently chain all options.</returns>
91+
public Log4NetTextFormatterOptionsBuilder UseNullText(string nullText)
92+
{
93+
_nullText = nullText ?? throw new ArgumentNullException(nameof(nullText), "The null text can not be null.");
94+
return this;
95+
}
96+
8197
/// <summary>
8298
/// Do not use any XML namespace for log4net events.
8399
/// <para/>
@@ -197,7 +213,7 @@ public void UseLog4JCompatibility()
197213
}
198214

199215
internal Log4NetTextFormatterOptions Build()
200-
=> new(_formatProvider, _cDataMode, _xmlNamespace, CreateXmlWriterSettings(_lineEnding, _indentationSettings), _filterProperty, _formatMessage, _formatException);
216+
=> new(_formatProvider, _cDataMode, _nullText, _xmlNamespace, CreateXmlWriterSettings(_lineEnding, _indentationSettings), _filterProperty, _formatMessage, _formatException);
201217

202218
private static XmlWriterSettings CreateXmlWriterSettings(LineEnding lineEnding, IndentationSettings? indentationSettings)
203219
{

tests/Log4NetTextFormatterTest.DefaultMessageFormatter_eventId=1_eventIdName=EventName.verified.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<log4net:data name="Name" value="World" />
44
<log4net:data name="EventId.Id" value="1" />
55
<log4net:data name="EventId.Name" value="EventName" />
6-
<log4net:data name="EventId.More" />
6+
<log4net:data name="EventId.More" value="(null)" />
77
</log4net:properties>
88
<log4net:message><![CDATA[Hello World!]]></log4net:message>
99
</log4net:event>

tests/Log4NetTextFormatterTest.NullProperty.verified.xml

Lines changed: 0 additions & 6 deletions
This file was deleted.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<log4net:event timestamp="2003-01-04T15:09:26.535+01:00" level="INFO" xmlns:log4net="http://logging.apache.org/log4net/schemas/log4net-events-1.2/">
2+
<log4net:properties>
3+
<log4net:data name="n/a" value="&lt;null&gt;" />
4+
</log4net:properties>
5+
<log4net:message><![CDATA[Hello from Serilog]]></log4net:message>
6+
</log4net:event>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<log4net:event timestamp="2003-01-04T15:09:26.535+01:00" level="INFO" xmlns:log4net="http://logging.apache.org/log4net/schemas/log4net-events-1.2/">
2+
<log4net:properties>
3+
<log4net:data name="n/a" value="" />
4+
</log4net:properties>
5+
<log4net:message><![CDATA[Hello from Serilog]]></log4net:message>
6+
</log4net:event>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<log4net:event timestamp="2003-01-04T15:09:26.535+01:00" level="INFO" xmlns:log4net="http://logging.apache.org/log4net/schemas/log4net-events-1.2/">
2+
<log4net:properties>
3+
<log4net:data name="n/a" value="(null)" />
4+
</log4net:properties>
5+
<log4net:message><![CDATA[Hello from Serilog]]></log4net:message>
6+
</log4net:event>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<log4net:event timestamp="2003-01-04T15:09:26.535+01:00" level="INFO" xmlns:log4net="http://logging.apache.org/log4net/schemas/log4net-events-1.2/">
2+
<log4net:properties>
3+
<log4net:data name="n/a" value="🌀" />
4+
</log4net:properties>
5+
<log4net:message><![CDATA[Hello from Serilog]]></log4net:message>
6+
</log4net:event>

tests/Log4NetTextFormatterTest.TwoPropertiesOneNull.verified.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<log4net:event timestamp="2003-01-04T15:09:26.535+01:00" level="INFO" xmlns:log4net="http://logging.apache.org/log4net/schemas/log4net-events-1.2/">
22
<log4net:properties>
3-
<log4net:data name="n/a" />
3+
<log4net:data name="n/a" value="(null)" />
44
<log4net:data name="one" value="1" />
55
</log4net:properties>
66
<log4net:message><![CDATA[Hello from Serilog]]></log4net:message>

0 commit comments

Comments
 (0)