diff --git a/src/NLog/LayoutRenderers/AllEventPropertiesLayoutRenderer.cs b/src/NLog/LayoutRenderers/AllEventPropertiesLayoutRenderer.cs
index 306b434689..1489e490bd 100644
--- a/src/NLog/LayoutRenderers/AllEventPropertiesLayoutRenderer.cs
+++ b/src/NLog/LayoutRenderers/AllEventPropertiesLayoutRenderer.cs
@@ -31,6 +31,8 @@
// THE POSSIBILITY OF SUCH DAMAGE.
//
+using System.Collections;
+
namespace NLog.LayoutRenderers
{
using System;
@@ -70,6 +72,14 @@ public AllEventPropertiesLayoutRenderer()
///
public string Separator { get; set; }
+ ///
+ /// Get or set if empty values should be included.
+ ///
+ /// A value is empty when null or in case of a string, null or empty string.
+ ///
+ [DefaultValue(false)]
+ public bool IncludeEmptyValues { get; set; } = false;
+
#if NET4_5
///
@@ -101,7 +111,7 @@ public string Format
_format = value;
- var formatSplit = _format.Split(new [] { "[key]", "[value]" }, StringSplitOptions.None);
+ var formatSplit = _format.Split(new[] { "[key]", "[value]" }, StringSplitOptions.None);
if (formatSplit.Length == 3)
{
_beforeKey = formatSplit[0];
@@ -129,7 +139,12 @@ protected override void Append(StringBuilder builder, LogEventInfo logEvent)
var formatProvider = GetFormatProvider(logEvent);
bool first = true;
- foreach (var property in GetProperties(logEvent))
+ IEnumerable> properties = GetProperties(logEvent);
+ if (!IncludeEmptyValues)
+ {
+ properties = properties.Where(p => !IsEmptyPropertyValue(p.Value));
+ }
+ foreach (var property in properties)
{
if (!first)
{
@@ -158,6 +173,16 @@ protected override void Append(StringBuilder builder, LogEventInfo logEvent)
}
}
+ private static bool IsEmptyPropertyValue(object value)
+ {
+ if (value is string s)
+ {
+ return string.IsNullOrEmpty(s);
+ }
+
+ return value == null;
+ }
+
#if NET4_5
///
@@ -183,6 +208,7 @@ protected override void Append(StringBuilder builder, LogEventInfo logEvent)
{
var properties = logEvent.Properties;
#if NET4_5
+
if (IncludeCallerInformation)
{
return properties;
diff --git a/tests/NLog.UnitTests/Layouts/AllEventPropertiesTests.cs b/tests/NLog.UnitTests/Layouts/AllEventPropertiesTests.cs
index 61fd97f261..04d52a27e9 100644
--- a/tests/NLog.UnitTests/Layouts/AllEventPropertiesTests.cs
+++ b/tests/NLog.UnitTests/Layouts/AllEventPropertiesTests.cs
@@ -48,7 +48,7 @@ public void AllParametersAreSetToDefault()
{
var renderer = new AllEventPropertiesLayoutRenderer();
var ev = BuildLogEventWithProperties();
-
+
var result = renderer.Render(ev);
Assert.Equal("a=1, hello=world, 17=100", result);
@@ -141,8 +141,8 @@ public void AllEventWithFluent_without_callerInformation()
.Write();
- AssertDebugLastMessage("m","Test=InfoWrite, coolness=200%, a=not b");
-
+ AssertDebugLastMessage("m", "Test=InfoWrite, coolness=200%, a=not b");
+
}
#if NET3_5 || NET4_0
@@ -169,7 +169,7 @@ public void AllEventWithFluent_with_callerInformation()
");
LogManager.Configuration = configuration;
-
+
var logger = LogManager.GetCurrentClassLogger();
logger.Debug()
.Message("This is a test fluent message '{0}'.", DateTime.Now.Ticks)
@@ -183,6 +183,31 @@ public void AllEventWithFluent_with_callerInformation()
AssertDebugLastMessageContains("m", "CallerLineNumber=");
}
+ [Theory]
+ [InlineData(null, "a=1, hello=world, 17=100, notempty=0")]
+ [InlineData(false, "a=1, hello=world, 17=100, notempty=0")]
+ [InlineData(true, "a=1, hello=world, 17=100, empty1=, empty2=, notempty=0")]
+ public void IncludeEmptyValuesTest(bool? includeEmptyValues, string expected)
+ {
+ // Arrange
+ var renderer = new AllEventPropertiesLayoutRenderer();
+ if (includeEmptyValues != null)
+ {
+ renderer.IncludeEmptyValues = includeEmptyValues.Value;
+ }
+
+ var ev = BuildLogEventWithProperties();
+ ev.Properties["empty1"] = null;
+ ev.Properties["empty2"] = "";
+ ev.Properties["notempty"] = 0;
+
+ // Act
+ var result = renderer.Render(ev);
+
+ // Assert
+ Assert.Equal(expected, result);
+ }
+
private static LogEventInfo BuildLogEventWithProperties()
{
var ev = new LogEventInfo();