From 3cb0d55f7737bcdb76ba536ec015fcc3d054d957 Mon Sep 17 00:00:00 2001 From: Rolf Kristensen Date: Sat, 18 May 2019 02:13:02 +0200 Subject: [PATCH 1/9] FilteringTargetWrapper - Add support for batch writing and use of whenRepeated as Filter --- src/NLog/Config/LoggingConfigurationParser.cs | 29 ++++++ src/NLog/Filters/ConditionBasedFilter.cs | 4 +- .../Wrappers/FilteringTargetWrapper.cs | 92 ++++++++++++++++--- .../Wrappers/PostFilteringTargetWrapper.cs | 83 ++++++++++------- tests/NLog.UnitTests/Targets/TargetTests.cs | 4 +- .../Wrappers/FilteringTargetWrapperTests.cs | 34 +++++++ .../PostFilteringTargetWrapperTests.cs | 20 ++++ tools/MakeNLogXSD/XsdFileGenerator.cs | 3 + 8 files changed, 222 insertions(+), 47 deletions(-) diff --git a/src/NLog/Config/LoggingConfigurationParser.cs b/src/NLog/Config/LoggingConfigurationParser.cs index a193162a42..7a12c75c72 100644 --- a/src/NLog/Config/LoggingConfigurationParser.cs +++ b/src/NLog/Config/LoggingConfigurationParser.cs @@ -1021,6 +1021,11 @@ private void SetPropertyFromElement(object o, ILoggingConfigurationElement eleme return; } + if (SetFilterFromElement(o, propInfo, element)) + { + return; + } + SetItemFromElement(o, propInfo, element); } @@ -1095,6 +1100,30 @@ private Layout TryCreateLayoutInstance(ILoggingConfigurationElement element, Typ return _configurationItemFactory.Layouts.CreateInstance(ExpandSimpleVariables(layoutTypeName)); } + private bool SetFilterFromElement(object o, PropertyInfo propInfo, ILoggingConfigurationElement layoutElement) + { + // Check if it is a Filter + if (!typeof(Filter).IsAssignableFrom(propInfo.PropertyType)) + return false; + + // Check if the 'type' attribute has been specified + string filterTypeName = GetConfigItemTypeAttribute(layoutElement); + if (filterTypeName == null) + return false; + + Filter filter = _configurationItemFactory.Filters.CreateInstance(ExpandSimpleVariables(filterTypeName)); + // and is a Filter and 'type' attribute has been specified + if (filter != null) + { + ConfigureObjectFromAttributes(filter, layoutElement, true); + ConfigureObjectFromElement(filter, layoutElement); + propInfo.SetValue(o, filter, null); + return true; + } + + return false; + } + private void SetItemFromElement(object o, PropertyInfo propInfo, ILoggingConfigurationElement element) { object item = propInfo.GetValue(o, null); diff --git a/src/NLog/Filters/ConditionBasedFilter.cs b/src/NLog/Filters/ConditionBasedFilter.cs index 5b6be277e9..a629008e8f 100644 --- a/src/NLog/Filters/ConditionBasedFilter.cs +++ b/src/NLog/Filters/ConditionBasedFilter.cs @@ -55,6 +55,8 @@ public class ConditionBasedFilter : Filter [RequiredParameter] public ConditionExpression Condition { get; set; } + internal FilterResult DefaultFilterResult { get; set; } = FilterResult.Neutral; + /// /// Checks whether log event should be logged or not. /// @@ -72,7 +74,7 @@ protected override FilterResult Check(LogEventInfo logEvent) return Action; } - return FilterResult.Neutral; + return DefaultFilterResult; } } } diff --git a/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs b/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs index 0e8404f6e0..ffeb5bc863 100644 --- a/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs +++ b/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs @@ -33,11 +33,11 @@ namespace NLog.Targets.Wrappers { - using System; - using Common; - using Conditions; - using Config; - using Internal; + using System.Collections.Generic; + using NLog.Common; + using NLog.Conditions; + using NLog.Config; + using NLog.Filters; /// /// Filters log entries based on a condition. @@ -59,8 +59,6 @@ namespace NLog.Targets.Wrappers [Target("FilteringWrapper", IsWrapper = true)] public class FilteringTargetWrapper : WrapperTargetBase { - private static readonly object boxedBooleanTrue = true; - /// /// Initializes a new instance of the class. /// @@ -90,7 +88,6 @@ public FilteringTargetWrapper(Target wrappedTarget, ConditionExpression conditio { WrappedTarget = wrappedTarget; Condition = condition; - OptimizeBufferReuse = GetType() == typeof(FilteringTargetWrapper); // Class not sealed, reduce breaking changes } /// @@ -98,8 +95,25 @@ public FilteringTargetWrapper(Target wrappedTarget, ConditionExpression conditio /// to the wrapped target. /// /// + public ConditionExpression Condition { get => (Filter as ConditionBasedFilter)?.Condition; set => Filter = value != null ? new ConditionBasedFilter() { Condition = value, DefaultFilterResult = FilterResult.Ignore } : null; } + + /// + /// Gets or sets the filter. Log events who evaluates to will be discarded + /// + /// [RequiredParameter] - public ConditionExpression Condition { get; set; } + public Filter Filter { get; set; } + + /// + protected override void InitializeTarget() + { + base.InitializeTarget(); + + if (!OptimizeBufferReuse && WrappedTarget != null && WrappedTarget.OptimizeBufferReuse) + { + OptimizeBufferReuse = GetType() == typeof(FilteringTargetWrapper); // Class not sealed, reduce breaking changes + } + } /// /// Checks the condition against the passed log event. @@ -109,8 +123,7 @@ public FilteringTargetWrapper(Target wrappedTarget, ConditionExpression conditio /// Log event. protected override void Write(AsyncLogEventInfo logEvent) { - object v = Condition.Evaluate(logEvent.LogEvent); - if (boxedBooleanTrue.Equals(v)) + if (FilterIncludeLogEvent(logEvent.LogEvent)) { WrappedTarget.WriteAsyncLogEvent(logEvent); } @@ -119,5 +132,62 @@ protected override void Write(AsyncLogEventInfo logEvent) logEvent.Continuation(null); } } + + /// + protected override void Write(IList logEvents) + { + bool hasIgnoredLogEvents = false; + IList filterLogEvents = null; + AsyncLogEventInfo filterLogEvent = default(AsyncLogEventInfo); + for (int i = 0; i < logEvents.Count; ++i) + { + if (FilterIncludeLogEvent(logEvents[i].LogEvent)) + { + if (hasIgnoredLogEvents && filterLogEvents == null) + { + if (filterLogEvent.LogEvent != null) + { + filterLogEvents = new List(); + filterLogEvents.Add(filterLogEvent); + filterLogEvent = default(AsyncLogEventInfo); + } + else + { + filterLogEvent = logEvents[i]; + } + } + + if (filterLogEvents != null) + filterLogEvents.Add(logEvents[i]); + } + else + { + if (!hasIgnoredLogEvents && i > 0) + { + filterLogEvents = new List(); + for (int j = 0; j < i; ++j) + filterLogEvents.Add(logEvents[j]); + } + hasIgnoredLogEvents = true; + logEvents[i].Continuation(null); + } + } + + if (!hasIgnoredLogEvents) + WrappedTarget.WriteAsyncLogEvents(logEvents); + else if (filterLogEvents != null) + WrappedTarget.WriteAsyncLogEvents(filterLogEvents); + else if (filterLogEvent.LogEvent != null) + WrappedTarget.WriteAsyncLogEvent(filterLogEvent); + } + + private bool FilterIncludeLogEvent(LogEventInfo logEvent) + { + var filterResult = Filter.GetFilterResult(logEvent); + if (filterResult == FilterResult.Ignore || filterResult == FilterResult.IgnoreFinal) + return false; + else + return true; + } } } diff --git a/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs b/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs index f027e76bb0..b9caf81f63 100644 --- a/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs +++ b/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs @@ -35,10 +35,10 @@ namespace NLog.Targets.Wrappers { using System; using System.Collections.Generic; - using Common; - using Conditions; - using Config; - using Internal; + using NLog.Common; + using NLog.Conditions; + using NLog.Config; + using NLog.Internal; /// /// Filters buffered log entries based on a set of conditions that are evaluated on a group of events. @@ -75,18 +75,17 @@ public class PostFilteringTargetWrapper : WrapperTargetBase /// /// Initializes a new instance of the class. /// - public PostFilteringTargetWrapper() : this(null) + public PostFilteringTargetWrapper() + : this(null) { - Rules = new List(); } /// /// Initializes a new instance of the class. /// public PostFilteringTargetWrapper(Target wrappedTarget) + : this(null, wrappedTarget) { - Rules = new List(); - WrappedTarget = wrappedTarget; } /// @@ -95,9 +94,10 @@ public PostFilteringTargetWrapper(Target wrappedTarget) /// Name of the target. /// The wrapped target. public PostFilteringTargetWrapper(string name, Target wrappedTarget) - : this(wrappedTarget) { Name = name; + WrappedTarget = wrappedTarget; + Rules = new List(); } /// @@ -115,6 +115,23 @@ public PostFilteringTargetWrapper(string name, Target wrappedTarget) [ArrayParameter(typeof(FilteringRule), "when")] public IList Rules { get; private set; } + /// + protected override void InitializeTarget() + { + base.InitializeTarget(); + + if (!OptimizeBufferReuse && WrappedTarget != null && WrappedTarget.OptimizeBufferReuse) + { + OptimizeBufferReuse = GetType() == typeof(PostFilteringTargetWrapper); // Class not sealed, reduce breaking changes + } + } + + /// + protected override void Write(AsyncLogEventInfo logEvent) + { + Write((IList)new[] { logEvent }); // Single LogEvent should also work + } + /// /// NOTE! Obsolete, instead override Write(IList{AsyncLogEventInfo} logEvents) /// @@ -138,12 +155,9 @@ protected override void Write(AsyncLogEventInfo[] logEvents) /// Array of log events to be post-filtered. protected override void Write(IList logEvents) { - - InternalLogger.Trace("PostFilteringWrapper(Name={0}): Running on {1} events", Name, logEvents.Count); var resultFilter = EvaluateAllRules(logEvents) ?? DefaultFilter; - if (resultFilter == null) { WrappedTarget.WriteAsyncLogEvents(logEvents); @@ -151,9 +165,7 @@ protected override void Write(IList logEvents) else { InternalLogger.Trace("PostFilteringWrapper(Name={0}): Filter to apply: {1}", Name, resultFilter); - var resultBuffer = ApplyFilter(logEvents, resultFilter); - InternalLogger.Trace("PostFilteringWrapper(Name={0}): After filtering: {1} events.", Name, resultBuffer.Count); if (resultBuffer.Count > 0) { @@ -169,25 +181,38 @@ protected override void Write(IList logEvents) /// /// /// - private static List ApplyFilter(IList logEvents, ConditionExpression resultFilter) + private static IList ApplyFilter(IList logEvents, ConditionExpression resultFilter) { - var resultBuffer = new List(); - + bool hasIgnoredLogEvents = false; + IList resultBuffer = null; for (int i = 0; i < logEvents.Count; ++i) { object v = resultFilter.Evaluate(logEvents[i].LogEvent); if (boxedTrue.Equals(v)) { - resultBuffer.Add(logEvents[i]); + if (hasIgnoredLogEvents && resultBuffer == null) + { + resultBuffer = new List(); + } + + if (resultBuffer != null) + resultBuffer.Add(logEvents[i]); } else { + if (!hasIgnoredLogEvents && i > 0) + { + resultBuffer = new List(); + for (int j = 0; j < i; ++j) + resultBuffer.Add(logEvents[j]); + } + hasIgnoredLogEvents = true; // anything not passed down will be notified about successful completion logEvents[i].Continuation(null); } } - return resultBuffer; + return resultBuffer ?? (hasIgnoredLogEvents ? ArrayHelper.Empty() : logEvents); } /// @@ -197,30 +222,24 @@ private static List ApplyFilter(IList logE /// private ConditionExpression EvaluateAllRules(IList logEvents) { - ConditionExpression resultFilter = null; - + if (Rules.Count == 0) + return null; + for (int i = 0; i < logEvents.Count; ++i) { - foreach (FilteringRule rule in Rules) + for (int j = 0; j < Rules.Count; ++j) { + var rule = Rules[j]; object v = rule.Exists.Evaluate(logEvents[i].LogEvent); - if (boxedTrue.Equals(v)) { InternalLogger.Trace("PostFilteringWrapper(Name={0}): Rule matched: {1}", Name, rule.Exists); - - resultFilter = rule.Filter; - break; + return rule.Filter; } } - - if (resultFilter != null) - { - break; - } } - return resultFilter; + return null; } } } diff --git a/tests/NLog.UnitTests/Targets/TargetTests.cs b/tests/NLog.UnitTests/Targets/TargetTests.cs index b9da4143ff..9f6e0f6b16 100644 --- a/tests/NLog.UnitTests/Targets/TargetTests.cs +++ b/tests/NLog.UnitTests/Targets/TargetTests.cs @@ -84,8 +84,6 @@ public void TargetContructorWithNameTest() var args = new List { fileTarget }; - - //default ctor var defaultConstructedTarget = (WrapperTargetBase)Activator.CreateInstance(targetType); defaultConstructedTarget.Name = name; @@ -94,7 +92,7 @@ public void TargetContructorWithNameTest() //specials cases if (targetType == typeof(FilteringTargetWrapper)) { - var cond = new ConditionLoggerNameExpression(); + ConditionLoggerNameExpression cond = null; args.Add(cond); var target = (FilteringTargetWrapper) defaultConstructedTarget; target.Condition = cond; diff --git a/tests/NLog.UnitTests/Targets/Wrappers/FilteringTargetWrapperTests.cs b/tests/NLog.UnitTests/Targets/Wrappers/FilteringTargetWrapperTests.cs index b69ea31ea5..ec36acf28f 100644 --- a/tests/NLog.UnitTests/Targets/Wrappers/FilteringTargetWrapperTests.cs +++ b/tests/NLog.UnitTests/Targets/Wrappers/FilteringTargetWrapperTests.cs @@ -37,6 +37,7 @@ namespace NLog.UnitTests.Targets.Wrappers using System.Threading; using NLog.Common; using NLog.Conditions; + using NLog.Config; using NLog.Targets; using NLog.Targets.Wrappers; using Xunit; @@ -267,6 +268,39 @@ public void FilteringTargetWrapperAsyncWithExceptionTest2() Assert.Equal(2, myMockCondition.CallCount); } + [Fact] + public void FilteringTargetWrapperWhenRepeatedFilter() + { + LogManager.Configuration = XmlLoggingConfiguration.CreateFromXmlString(@" + + + + + + + + + + + + + "); + + var myTarget = LogManager.Configuration.FindTargetByName("memory"); + var logger = LogManager.GetLogger(nameof(FilteringTargetWrapperWhenRepeatedFilter)); + logger.Info("Hello World"); + logger.Info("Hello World"); // Will be ignored + logger.Info("Goodbye World"); + logger.Warn("Goodbye World"); + LogManager.Flush(); + Assert.Equal(3, myTarget.Logs.Count); + logger.Info("Hello World"); // Will be ignored + logger.Error("Goodbye World"); + logger.Fatal("Goodbye World"); + LogManager.Flush(); + Assert.Equal(5, myTarget.Logs.Count); + } + class MyAsyncTarget : Target { public int WriteCount { get; private set; } diff --git a/tests/NLog.UnitTests/Targets/Wrappers/PostFilteringTargetWrapperTests.cs b/tests/NLog.UnitTests/Targets/Wrappers/PostFilteringTargetWrapperTests.cs index 922c0ed4d9..218988e8e6 100644 --- a/tests/NLog.UnitTests/Targets/Wrappers/PostFilteringTargetWrapperTests.cs +++ b/tests/NLog.UnitTests/Targets/Wrappers/PostFilteringTargetWrapperTests.cs @@ -203,6 +203,26 @@ public void PostFilteringTargetWrapperUsingDefaultNonFilterTest2() Assert.Equal(events.Length, exceptions.Count); } + [Fact] + public void PostFilteringTargetWrapperOnlyDefaultFilter() + { + var target = new MyTarget() { OptimizeBufferReuse = true }; + var wrapper = new PostFilteringTargetWrapper() + { + WrappedTarget = target, + DefaultFilter = "level >= LogLevel.Info", // by default log info and above + }; + + wrapper.Initialize(null); + target.Initialize(null); + + var exceptions = new List(); + wrapper.WriteAsyncLogEvent(new LogEventInfo(LogLevel.Info, "Logger1", "Hello").WithContinuation(exceptions.Add)); + Assert.Single(target.Events); + wrapper.WriteAsyncLogEvent(new LogEventInfo(LogLevel.Debug, "Logger1", "Hello").WithContinuation(exceptions.Add)); + Assert.Single(target.Events); + } + [Fact] public void PostFilteringTargetWrapperNoFiltersDefined() { diff --git a/tools/MakeNLogXSD/XsdFileGenerator.cs b/tools/MakeNLogXSD/XsdFileGenerator.cs index 26bc2d6460..f9069e47e5 100644 --- a/tools/MakeNLogXSD/XsdFileGenerator.cs +++ b/tools/MakeNLogXSD/XsdFileGenerator.cs @@ -312,6 +312,9 @@ private static string GetXsdType(string apiTypeName, bool attribute) case "Layout": return attribute ? "SimpleLayoutAttribute" : "Layout"; + case "NLog.Filters.Filter": + return "Filter"; + case "Condition": return "Condition"; From c529bdf1547363dfe6f5e2ec9b586a4917b4f882 Mon Sep 17 00:00:00 2001 From: Julian Verdurmen <304NotModified@users.noreply.github.com> Date: Sat, 18 May 2019 15:17:53 +0200 Subject: [PATCH 2/9] small refactorings --- src/NLog/Config/LoggingConfigurationParser.cs | 8 ++-- .../Wrappers/FilteringTargetWrapper.cs | 45 +++++++++++-------- .../Wrappers/PostFilteringTargetWrapper.cs | 8 ++-- 3 files changed, 34 insertions(+), 27 deletions(-) diff --git a/src/NLog/Config/LoggingConfigurationParser.cs b/src/NLog/Config/LoggingConfigurationParser.cs index 7a12c75c72..e1e1c638e4 100644 --- a/src/NLog/Config/LoggingConfigurationParser.cs +++ b/src/NLog/Config/LoggingConfigurationParser.cs @@ -1070,15 +1070,15 @@ private object ParseArrayItemFromElement(Type elementType, ILoggingConfiguration return arrayItem; } - private bool SetLayoutFromElement(object o, PropertyInfo propInfo, ILoggingConfigurationElement layoutElement) + private bool SetLayoutFromElement(object o, PropertyInfo propInfo, ILoggingConfigurationElement element) { - Layout layout = TryCreateLayoutInstance(layoutElement, propInfo.PropertyType); + var layout = TryCreateLayoutInstance(element, propInfo.PropertyType); // and is a Layout and 'type' attribute has been specified if (layout != null) { - ConfigureObjectFromAttributes(layout, layoutElement, true); - ConfigureObjectFromElement(layout, layoutElement); + ConfigureObjectFromAttributes(layout, element, true); + ConfigureObjectFromElement(layout, element); propInfo.SetValue(o, layout, null); return true; } diff --git a/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs b/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs index ffeb5bc863..7a03ab0135 100644 --- a/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs +++ b/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs @@ -95,7 +95,7 @@ public FilteringTargetWrapper(Target wrappedTarget, ConditionExpression conditio /// to the wrapped target. /// /// - public ConditionExpression Condition { get => (Filter as ConditionBasedFilter)?.Condition; set => Filter = value != null ? new ConditionBasedFilter() { Condition = value, DefaultFilterResult = FilterResult.Ignore } : null; } + public ConditionExpression Condition { get => (Filter as ConditionBasedFilter)?.Condition; set => Filter = CreateFilter(value); } /// /// Gets or sets the filter. Log events who evaluates to will be discarded @@ -123,7 +123,7 @@ protected override void InitializeTarget() /// Log event. protected override void Write(AsyncLogEventInfo logEvent) { - if (FilterIncludeLogEvent(logEvent.LogEvent)) + if (ShouldLogEvent(logEvent.LogEvent, Filter)) { WrappedTarget.WriteAsyncLogEvent(logEvent); } @@ -136,40 +136,40 @@ protected override void Write(AsyncLogEventInfo logEvent) /// protected override void Write(IList logEvents) { - bool hasIgnoredLogEvents = false; + var hasIgnoredLogEvents = false; IList filterLogEvents = null; - AsyncLogEventInfo filterLogEvent = default(AsyncLogEventInfo); - for (int i = 0; i < logEvents.Count; ++i) + var filterLogEvent = default(AsyncLogEventInfo); + for (var i = 0; i < logEvents.Count; ++i) { - if (FilterIncludeLogEvent(logEvents[i].LogEvent)) + var logEvent = logEvents[i]; + + if (ShouldLogEvent(logEvent.LogEvent, Filter)) { if (hasIgnoredLogEvents && filterLogEvents == null) { if (filterLogEvent.LogEvent != null) { - filterLogEvents = new List(); - filterLogEvents.Add(filterLogEvent); + filterLogEvents = new List {filterLogEvent}; filterLogEvent = default(AsyncLogEventInfo); } else { - filterLogEvent = logEvents[i]; + filterLogEvent = logEvent; } } - if (filterLogEvents != null) - filterLogEvents.Add(logEvents[i]); + filterLogEvents?.Add(logEvent); } else { if (!hasIgnoredLogEvents && i > 0) { filterLogEvents = new List(); - for (int j = 0; j < i; ++j) + for (var j = 0; j < i; ++j) filterLogEvents.Add(logEvents[j]); } hasIgnoredLogEvents = true; - logEvents[i].Continuation(null); + logEvent.Continuation(null); } } @@ -181,13 +181,20 @@ protected override void Write(IList logEvents) WrappedTarget.WriteAsyncLogEvent(filterLogEvent); } - private bool FilterIncludeLogEvent(LogEventInfo logEvent) + private static bool ShouldLogEvent(LogEventInfo logEvent, Filter filter) { - var filterResult = Filter.GetFilterResult(logEvent); - if (filterResult == FilterResult.Ignore || filterResult == FilterResult.IgnoreFinal) - return false; - else - return true; + var filterResult = filter.GetFilterResult(logEvent); + return filterResult != FilterResult.Ignore && filterResult != FilterResult.IgnoreFinal; + } + + private static ConditionBasedFilter CreateFilter(ConditionExpression value) + { + if (value == null) + { + return null; + } + + return new ConditionBasedFilter {Condition = value, DefaultFilterResult = FilterResult.Ignore}; } } } diff --git a/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs b/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs index b9caf81f63..0b0aff45f0 100644 --- a/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs +++ b/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs @@ -187,7 +187,8 @@ private static IList ApplyFilter(IList log IList resultBuffer = null; for (int i = 0; i < logEvents.Count; ++i) { - object v = resultFilter.Evaluate(logEvents[i].LogEvent); + var logEvent = logEvents[i]; + object v = resultFilter.Evaluate(logEvent.LogEvent); if (boxedTrue.Equals(v)) { if (hasIgnoredLogEvents && resultBuffer == null) @@ -195,8 +196,7 @@ private static IList ApplyFilter(IList log resultBuffer = new List(); } - if (resultBuffer != null) - resultBuffer.Add(logEvents[i]); + resultBuffer?.Add(logEvent); } else { @@ -208,7 +208,7 @@ private static IList ApplyFilter(IList log } hasIgnoredLogEvents = true; // anything not passed down will be notified about successful completion - logEvents[i].Continuation(null); + logEvent.Continuation(null); } } From 255fccf7f13673c05275fa2824b6d36dab94fb63 Mon Sep 17 00:00:00 2001 From: Julian Verdurmen <304NotModified@users.noreply.github.com> Date: Sun, 19 May 2019 20:55:03 +0200 Subject: [PATCH 3/9] extract method --- src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs | 12 +++++++++--- .../Targets/Wrappers/PostFilteringTargetWrapper.cs | 12 +++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs b/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs index 7a03ab0135..139f335685 100644 --- a/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs +++ b/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs @@ -164,9 +164,7 @@ protected override void Write(IList logEvents) { if (!hasIgnoredLogEvents && i > 0) { - filterLogEvents = new List(); - for (var j = 0; j < i; ++j) - filterLogEvents.Add(logEvents[j]); + filterLogEvents = CreateAsyncLogEventList(logEvents, i); } hasIgnoredLogEvents = true; logEvent.Continuation(null); @@ -181,6 +179,14 @@ protected override void Write(IList logEvents) WrappedTarget.WriteAsyncLogEvent(filterLogEvent); } + private static IList CreateAsyncLogEventList(IList logEvents, int untilIndex) + { + IList list = new List(); + for (var i = 0; i < untilIndex; ++i) + list.Add(logEvents[i]); + return list; + } + private static bool ShouldLogEvent(LogEventInfo logEvent, Filter filter) { var filterResult = filter.GetFilterResult(logEvent); diff --git a/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs b/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs index 0b0aff45f0..b8569f70f2 100644 --- a/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs +++ b/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs @@ -202,9 +202,7 @@ private static IList ApplyFilter(IList log { if (!hasIgnoredLogEvents && i > 0) { - resultBuffer = new List(); - for (int j = 0; j < i; ++j) - resultBuffer.Add(logEvents[j]); + resultBuffer = CreateAsyncLogEventList(logEvents, i); } hasIgnoredLogEvents = true; // anything not passed down will be notified about successful completion @@ -215,6 +213,14 @@ private static IList ApplyFilter(IList log return resultBuffer ?? (hasIgnoredLogEvents ? ArrayHelper.Empty() : logEvents); } + private static IList CreateAsyncLogEventList(IList logEvents, int untilIndex) + { + IList list = new List(); + for (var i = 0; i < untilIndex; ++i) + list.Add(logEvents[i]); + return list; + } + /// /// Evaluate all the rules to get the filtering condition /// From 3f645828a287a44ad3dff19dff5f5c902180f1ff Mon Sep 17 00:00:00 2001 From: Julian Verdurmen <304NotModified@users.noreply.github.com> Date: Sun, 19 May 2019 21:03:43 +0200 Subject: [PATCH 4/9] method into extension --- src/NLog/Internal/ArrayHelper.cs | 31 +++++++++--- src/NLog/Internal/CollectionExtensions.cs | 49 +++++++++++++++++++ .../Wrappers/FilteringTargetWrapper.cs | 11 +---- .../Wrappers/PostFilteringTargetWrapper.cs | 10 +--- 4 files changed, 75 insertions(+), 26 deletions(-) create mode 100644 src/NLog/Internal/CollectionExtensions.cs diff --git a/src/NLog/Internal/ArrayHelper.cs b/src/NLog/Internal/ArrayHelper.cs index f640b439dd..73574ec68e 100644 --- a/src/NLog/Internal/ArrayHelper.cs +++ b/src/NLog/Internal/ArrayHelper.cs @@ -31,19 +31,34 @@ // THE POSSIBILITY OF SUCH DAMAGE. // +using System; +using System.Collections.Generic; +using JetBrains.Annotations; + namespace NLog.Internal { - internal static class ArrayHelper + internal static class CollectionExtensions { - private static class EmptyArray + /// + /// Create a partial list with the items from the parameter + /// + /// + /// items to include into the returning list. + /// until index, not included. + /// New list + /// IList as input for performance reasons. + public static IList CreatePartialList([NotNull] this IList items, int untilIndex) { - internal static readonly T[] Instance = new T[0]; - } + if (items == null) + { + throw new ArgumentNullException(nameof(items)); + } - internal static T[] Empty() - { - // TODO Use Array.Empty in NET 4.6 when we are ready - return EmptyArray.Instance; + IList list = new List(); + for (var i = 0; i < untilIndex && i < items.Count; ++i) + list.Add(items[i]); + return list; } + } } diff --git a/src/NLog/Internal/CollectionExtensions.cs b/src/NLog/Internal/CollectionExtensions.cs new file mode 100644 index 0000000000..f640b439dd --- /dev/null +++ b/src/NLog/Internal/CollectionExtensions.cs @@ -0,0 +1,49 @@ +// +// Copyright (c) 2004-2019 Jaroslaw Kowalski , Kim Christensen, Julian Verdurmen +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of Jaroslaw Kowalski nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +// + +namespace NLog.Internal +{ + internal static class ArrayHelper + { + private static class EmptyArray + { + internal static readonly T[] Instance = new T[0]; + } + + internal static T[] Empty() + { + // TODO Use Array.Empty in NET 4.6 when we are ready + return EmptyArray.Instance; + } + } +} diff --git a/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs b/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs index 139f335685..4c90b7937c 100644 --- a/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs +++ b/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs @@ -38,6 +38,7 @@ namespace NLog.Targets.Wrappers using NLog.Conditions; using NLog.Config; using NLog.Filters; + using NLog.Internal; /// /// Filters log entries based on a condition. @@ -164,7 +165,7 @@ protected override void Write(IList logEvents) { if (!hasIgnoredLogEvents && i > 0) { - filterLogEvents = CreateAsyncLogEventList(logEvents, i); + filterLogEvents = logEvents.CreatePartialList(i); } hasIgnoredLogEvents = true; logEvent.Continuation(null); @@ -179,14 +180,6 @@ protected override void Write(IList logEvents) WrappedTarget.WriteAsyncLogEvent(filterLogEvent); } - private static IList CreateAsyncLogEventList(IList logEvents, int untilIndex) - { - IList list = new List(); - for (var i = 0; i < untilIndex; ++i) - list.Add(logEvents[i]); - return list; - } - private static bool ShouldLogEvent(LogEventInfo logEvent, Filter filter) { var filterResult = filter.GetFilterResult(logEvent); diff --git a/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs b/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs index b8569f70f2..ce6139e4e4 100644 --- a/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs +++ b/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs @@ -202,7 +202,7 @@ private static IList ApplyFilter(IList log { if (!hasIgnoredLogEvents && i > 0) { - resultBuffer = CreateAsyncLogEventList(logEvents, i); + resultBuffer = logEvents.CreatePartialList(i); } hasIgnoredLogEvents = true; // anything not passed down will be notified about successful completion @@ -213,14 +213,6 @@ private static IList ApplyFilter(IList log return resultBuffer ?? (hasIgnoredLogEvents ? ArrayHelper.Empty() : logEvents); } - private static IList CreateAsyncLogEventList(IList logEvents, int untilIndex) - { - IList list = new List(); - for (var i = 0; i < untilIndex; ++i) - list.Add(logEvents[i]); - return list; - } - /// /// Evaluate all the rules to get the filtering condition /// From 4bb326294f752f5df67c08429006e4bf4094ef50 Mon Sep 17 00:00:00 2001 From: Julian Verdurmen <304NotModified@users.noreply.github.com> Date: Sun, 19 May 2019 21:09:02 +0200 Subject: [PATCH 5/9] fix filenames --- src/NLog/Internal/ArrayHelper.cs | 31 ++++++----------------- src/NLog/Internal/CollectionExtensions.cs | 31 +++++++++++++++++------ 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/NLog/Internal/ArrayHelper.cs b/src/NLog/Internal/ArrayHelper.cs index 73574ec68e..f640b439dd 100644 --- a/src/NLog/Internal/ArrayHelper.cs +++ b/src/NLog/Internal/ArrayHelper.cs @@ -31,34 +31,19 @@ // THE POSSIBILITY OF SUCH DAMAGE. // -using System; -using System.Collections.Generic; -using JetBrains.Annotations; - namespace NLog.Internal { - internal static class CollectionExtensions + internal static class ArrayHelper { - /// - /// Create a partial list with the items from the parameter - /// - /// - /// items to include into the returning list. - /// until index, not included. - /// New list - /// IList as input for performance reasons. - public static IList CreatePartialList([NotNull] this IList items, int untilIndex) + private static class EmptyArray { - if (items == null) - { - throw new ArgumentNullException(nameof(items)); - } - - IList list = new List(); - for (var i = 0; i < untilIndex && i < items.Count; ++i) - list.Add(items[i]); - return list; + internal static readonly T[] Instance = new T[0]; } + internal static T[] Empty() + { + // TODO Use Array.Empty in NET 4.6 when we are ready + return EmptyArray.Instance; + } } } diff --git a/src/NLog/Internal/CollectionExtensions.cs b/src/NLog/Internal/CollectionExtensions.cs index f640b439dd..73574ec68e 100644 --- a/src/NLog/Internal/CollectionExtensions.cs +++ b/src/NLog/Internal/CollectionExtensions.cs @@ -31,19 +31,34 @@ // THE POSSIBILITY OF SUCH DAMAGE. // +using System; +using System.Collections.Generic; +using JetBrains.Annotations; + namespace NLog.Internal { - internal static class ArrayHelper + internal static class CollectionExtensions { - private static class EmptyArray + /// + /// Create a partial list with the items from the parameter + /// + /// + /// items to include into the returning list. + /// until index, not included. + /// New list + /// IList as input for performance reasons. + public static IList CreatePartialList([NotNull] this IList items, int untilIndex) { - internal static readonly T[] Instance = new T[0]; - } + if (items == null) + { + throw new ArgumentNullException(nameof(items)); + } - internal static T[] Empty() - { - // TODO Use Array.Empty in NET 4.6 when we are ready - return EmptyArray.Instance; + IList list = new List(); + for (var i = 0; i < untilIndex && i < items.Count; ++i) + list.Add(items[i]); + return list; } + } } From 11f82f712e955aec5568477366e3e629f0da0f9d Mon Sep 17 00:00:00 2001 From: Julian Verdurmen <304NotModified@users.noreply.github.com> Date: Sun, 19 May 2019 21:20:10 +0200 Subject: [PATCH 6/9] Deduplicate code --- src/NLog/Config/LoggingConfigurationParser.cs | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/NLog/Config/LoggingConfigurationParser.cs b/src/NLog/Config/LoggingConfigurationParser.cs index e1e1c638e4..092bb74e5c 100644 --- a/src/NLog/Config/LoggingConfigurationParser.cs +++ b/src/NLog/Config/LoggingConfigurationParser.cs @@ -1077,9 +1077,7 @@ private bool SetLayoutFromElement(object o, PropertyInfo propInfo, ILoggingConfi // and is a Layout and 'type' attribute has been specified if (layout != null) { - ConfigureObjectFromAttributes(layout, element, true); - ConfigureObjectFromElement(layout, element); - propInfo.SetValue(o, layout, null); + SetItemOnProperty(o, propInfo, element, layout); return true; } @@ -1089,7 +1087,7 @@ private bool SetLayoutFromElement(object o, PropertyInfo propInfo, ILoggingConfi private Layout TryCreateLayoutInstance(ILoggingConfigurationElement element, Type type) { // Check if it is a Layout - if (!typeof(Layout).IsAssignableFrom(type)) + if (!IsAssignableFrom(type)) return null; // Check if the 'type' attribute has been specified @@ -1100,14 +1098,14 @@ private Layout TryCreateLayoutInstance(ILoggingConfigurationElement element, Typ return _configurationItemFactory.Layouts.CreateInstance(ExpandSimpleVariables(layoutTypeName)); } - private bool SetFilterFromElement(object o, PropertyInfo propInfo, ILoggingConfigurationElement layoutElement) + private bool SetFilterFromElement(object o, PropertyInfo propInfo, ILoggingConfigurationElement element) { // Check if it is a Filter - if (!typeof(Filter).IsAssignableFrom(propInfo.PropertyType)) + if (!IsAssignableFrom(propInfo.PropertyType)) return false; // Check if the 'type' attribute has been specified - string filterTypeName = GetConfigItemTypeAttribute(layoutElement); + string filterTypeName = GetConfigItemTypeAttribute(element); if (filterTypeName == null) return false; @@ -1115,15 +1113,25 @@ private bool SetFilterFromElement(object o, PropertyInfo propInfo, ILoggingConfi // and is a Filter and 'type' attribute has been specified if (filter != null) { - ConfigureObjectFromAttributes(filter, layoutElement, true); - ConfigureObjectFromElement(filter, layoutElement); - propInfo.SetValue(o, filter, null); + SetItemOnProperty(o, propInfo, element, filter); return true; } return false; } + private static bool IsAssignableFrom(Type type) + { + return typeof(T).IsAssignableFrom(type); + } + + private void SetItemOnProperty(object o, PropertyInfo propInfo, ILoggingConfigurationElement element, object properyValue) + { + ConfigureObjectFromAttributes(properyValue, element, true); + ConfigureObjectFromElement(properyValue, element); + propInfo.SetValue(o, properyValue, null); + } + private void SetItemFromElement(object o, PropertyInfo propInfo, ILoggingConfigurationElement element) { object item = propInfo.GetValue(o, null); @@ -1252,7 +1260,7 @@ private static string StripOptionalNamespacePrefix(string attributeValue) return attributeValue.Substring(p + 1); } - + private static string GetName(Target target) { return string.IsNullOrEmpty(target.Name) ? target.GetType().Name : target.Name; From 417ed1ba72b84d6d2a12a5d7d55704ebaa3a3117 Mon Sep 17 00:00:00 2001 From: Julian Verdurmen <304NotModified@users.noreply.github.com> Date: Sun, 19 May 2019 21:28:29 +0200 Subject: [PATCH 7/9] deduplicate TryCreateInstance from factory --- src/NLog/Config/LoggingConfigurationParser.cs | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/src/NLog/Config/LoggingConfigurationParser.cs b/src/NLog/Config/LoggingConfigurationParser.cs index 092bb74e5c..c8ee2b0b50 100644 --- a/src/NLog/Config/LoggingConfigurationParser.cs +++ b/src/NLog/Config/LoggingConfigurationParser.cs @@ -1083,33 +1083,12 @@ private bool SetLayoutFromElement(object o, PropertyInfo propInfo, ILoggingConfi return false; } - - private Layout TryCreateLayoutInstance(ILoggingConfigurationElement element, Type type) - { - // Check if it is a Layout - if (!IsAssignableFrom(type)) - return null; - - // Check if the 'type' attribute has been specified - string layoutTypeName = GetConfigItemTypeAttribute(element); - if (layoutTypeName == null) - return null; - - return _configurationItemFactory.Layouts.CreateInstance(ExpandSimpleVariables(layoutTypeName)); - } - + private bool SetFilterFromElement(object o, PropertyInfo propInfo, ILoggingConfigurationElement element) { - // Check if it is a Filter - if (!IsAssignableFrom(propInfo.PropertyType)) - return false; + var type = propInfo.PropertyType; - // Check if the 'type' attribute has been specified - string filterTypeName = GetConfigItemTypeAttribute(element); - if (filterTypeName == null) - return false; - - Filter filter = _configurationItemFactory.Filters.CreateInstance(ExpandSimpleVariables(filterTypeName)); + Filter filter = TryCreateFilterInstance(element, type); // and is a Filter and 'type' attribute has been specified if (filter != null) { @@ -1120,6 +1099,31 @@ private bool SetFilterFromElement(object o, PropertyInfo propInfo, ILoggingConfi return false; } + private Layout TryCreateLayoutInstance(ILoggingConfigurationElement element, Type type) + { + return TryCreateInstance(element, type, _configurationItemFactory.Layouts); + } + + private Filter TryCreateFilterInstance(ILoggingConfigurationElement element, Type type) + { + return TryCreateInstance(element, type, _configurationItemFactory.Filters); + } + + private T TryCreateInstance(ILoggingConfigurationElement element, Type type, INamedItemFactory factory) + where T : class + { + // Check if correct type + if (!IsAssignableFrom(type)) + return null; + + // Check if the 'type' attribute has been specified + string layoutTypeName = GetConfigItemTypeAttribute(element); + if (layoutTypeName == null) + return null; + + return factory.CreateInstance(ExpandSimpleVariables(layoutTypeName)); + } + private static bool IsAssignableFrom(Type type) { return typeof(T).IsAssignableFrom(type); From 3092199613ef5e60e791ab2f7039487e8325a6f2 Mon Sep 17 00:00:00 2001 From: Rolf Kristensen Date: Sun, 19 May 2019 21:36:55 +0200 Subject: [PATCH 8/9] FilteringTargetWrapper - Moved filtering logic into a reusable method --- src/NLog/Internal/CollectionExtensions.cs | 42 ++++++++----- .../Wrappers/FilteringTargetWrapper.cs | 63 +++++-------------- .../Wrappers/PostFilteringTargetWrapper.cs | 44 +++---------- 3 files changed, 51 insertions(+), 98 deletions(-) diff --git a/src/NLog/Internal/CollectionExtensions.cs b/src/NLog/Internal/CollectionExtensions.cs index 73574ec68e..a662f7adbb 100644 --- a/src/NLog/Internal/CollectionExtensions.cs +++ b/src/NLog/Internal/CollectionExtensions.cs @@ -39,26 +39,34 @@ namespace NLog.Internal { internal static class CollectionExtensions { - /// - /// Create a partial list with the items from the parameter - /// - /// - /// items to include into the returning list. - /// until index, not included. - /// New list - /// IList as input for performance reasons. - public static IList CreatePartialList([NotNull] this IList items, int untilIndex) + public static IList FilterList([NotNull] this IList items, TState state, Func filter) { - if (items == null) + var hasIgnoredLogEvents = false; + IList filterLogEvents = null; + for (var i = 0; i < items.Count; ++i) { - throw new ArgumentNullException(nameof(items)); - } + var item = items[i]; + if (filter(item, state)) + { + if (hasIgnoredLogEvents && filterLogEvents == null) + { + filterLogEvents = new List(); + } - IList list = new List(); - for (var i = 0; i < untilIndex && i < items.Count; ++i) - list.Add(items[i]); - return list; + filterLogEvents?.Add(item); + } + else + { + if (!hasIgnoredLogEvents && i > 0) + { + filterLogEvents = new List(); + for (var j = 0; j < i; ++j) + filterLogEvents.Add(items[j]); + } + hasIgnoredLogEvents = true; + } + } + return filterLogEvents ?? (hasIgnoredLogEvents ? ArrayHelper.Empty() : items); } - } } diff --git a/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs b/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs index 4c90b7937c..30b6615c2a 100644 --- a/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs +++ b/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs @@ -33,6 +33,7 @@ namespace NLog.Targets.Wrappers { + using System; using System.Collections.Generic; using NLog.Common; using NLog.Conditions; @@ -124,7 +125,7 @@ protected override void InitializeTarget() /// Log event. protected override void Write(AsyncLogEventInfo logEvent) { - if (ShouldLogEvent(logEvent.LogEvent, Filter)) + if (ShouldLogEvent(logEvent, Filter)) { WrappedTarget.WriteAsyncLogEvent(logEvent); } @@ -137,53 +138,22 @@ protected override void Write(AsyncLogEventInfo logEvent) /// protected override void Write(IList logEvents) { - var hasIgnoredLogEvents = false; - IList filterLogEvents = null; - var filterLogEvent = default(AsyncLogEventInfo); - for (var i = 0; i < logEvents.Count; ++i) - { - var logEvent = logEvents[i]; - - if (ShouldLogEvent(logEvent.LogEvent, Filter)) - { - if (hasIgnoredLogEvents && filterLogEvents == null) - { - if (filterLogEvent.LogEvent != null) - { - filterLogEvents = new List {filterLogEvent}; - filterLogEvent = default(AsyncLogEventInfo); - } - else - { - filterLogEvent = logEvent; - } - } - - filterLogEvents?.Add(logEvent); - } - else - { - if (!hasIgnoredLogEvents && i > 0) - { - filterLogEvents = logEvents.CreatePartialList(i); - } - hasIgnoredLogEvents = true; - logEvent.Continuation(null); - } - } - - if (!hasIgnoredLogEvents) - WrappedTarget.WriteAsyncLogEvents(logEvents); - else if (filterLogEvents != null) - WrappedTarget.WriteAsyncLogEvents(filterLogEvents); - else if (filterLogEvent.LogEvent != null) - WrappedTarget.WriteAsyncLogEvent(filterLogEvent); + var filterLogEvents = logEvents.FilterList(Filter, ShouldLogEvent); + WrappedTarget.WriteAsyncLogEvents(filterLogEvents); } - private static bool ShouldLogEvent(LogEventInfo logEvent, Filter filter) + private static bool ShouldLogEvent(AsyncLogEventInfo logEvent, Filter filter) { - var filterResult = filter.GetFilterResult(logEvent); - return filterResult != FilterResult.Ignore && filterResult != FilterResult.IgnoreFinal; + var filterResult = filter.GetFilterResult(logEvent.LogEvent); + if (filterResult != FilterResult.Ignore && filterResult != FilterResult.IgnoreFinal) + { + return true; + } + else + { + logEvent.Continuation(null); + return false; + } } private static ConditionBasedFilter CreateFilter(ConditionExpression value) @@ -192,8 +162,7 @@ private static ConditionBasedFilter CreateFilter(ConditionExpression value) { return null; } - - return new ConditionBasedFilter {Condition = value, DefaultFilterResult = FilterResult.Ignore}; + return new ConditionBasedFilter { Condition = value, DefaultFilterResult = FilterResult.Ignore }; } } } diff --git a/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs b/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs index ce6139e4e4..1ef0faaf35 100644 --- a/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs +++ b/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs @@ -165,7 +165,7 @@ protected override void Write(IList logEvents) else { InternalLogger.Trace("PostFilteringWrapper(Name={0}): Filter to apply: {1}", Name, resultFilter); - var resultBuffer = ApplyFilter(logEvents, resultFilter); + var resultBuffer = logEvents.FilterList(resultFilter, ApplyFilter); InternalLogger.Trace("PostFilteringWrapper(Name={0}): After filtering: {1} events.", Name, resultBuffer.Count); if (resultBuffer.Count > 0) { @@ -175,42 +175,18 @@ protected override void Write(IList logEvents) } } - /// - /// Apply the condition to the buffer - /// - /// - /// - /// - private static IList ApplyFilter(IList logEvents, ConditionExpression resultFilter) + private static bool ApplyFilter(AsyncLogEventInfo logEvent, ConditionExpression resultFilter) { - bool hasIgnoredLogEvents = false; - IList resultBuffer = null; - for (int i = 0; i < logEvents.Count; ++i) + object v = resultFilter.Evaluate(logEvent.LogEvent); + if (boxedTrue.Equals(v)) { - var logEvent = logEvents[i]; - object v = resultFilter.Evaluate(logEvent.LogEvent); - if (boxedTrue.Equals(v)) - { - if (hasIgnoredLogEvents && resultBuffer == null) - { - resultBuffer = new List(); - } - - resultBuffer?.Add(logEvent); - } - else - { - if (!hasIgnoredLogEvents && i > 0) - { - resultBuffer = logEvents.CreatePartialList(i); - } - hasIgnoredLogEvents = true; - // anything not passed down will be notified about successful completion - logEvent.Continuation(null); - } + return true; + } + else + { + logEvent.Continuation(null); + return false; } - - return resultBuffer ?? (hasIgnoredLogEvents ? ArrayHelper.Empty() : logEvents); } /// From d9ddff53e4273d575429c53815accb720b8b8dcd Mon Sep 17 00:00:00 2001 From: Julian Verdurmen <304NotModified@users.noreply.github.com> Date: Sun, 19 May 2019 23:50:23 +0200 Subject: [PATCH 9/9] docs and rename --- src/NLog/Internal/CollectionExtensions.cs | 7 ++++++- src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs | 2 +- src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/NLog/Internal/CollectionExtensions.cs b/src/NLog/Internal/CollectionExtensions.cs index a662f7adbb..85b82310e7 100644 --- a/src/NLog/Internal/CollectionExtensions.cs +++ b/src/NLog/Internal/CollectionExtensions.cs @@ -39,7 +39,12 @@ namespace NLog.Internal { internal static class CollectionExtensions { - public static IList FilterList([NotNull] this IList items, TState state, Func filter) + /// + /// Memory optimized filtering + /// + /// Passing state too avoid delegate capture and memory-allocations. + [NotNull] + public static IList Filter([NotNull] this IList items, TState state, Func filter) { var hasIgnoredLogEvents = false; IList filterLogEvents = null; diff --git a/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs b/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs index 30b6615c2a..0242a10734 100644 --- a/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs +++ b/src/NLog/Targets/Wrappers/FilteringTargetWrapper.cs @@ -138,7 +138,7 @@ protected override void Write(AsyncLogEventInfo logEvent) /// protected override void Write(IList logEvents) { - var filterLogEvents = logEvents.FilterList(Filter, ShouldLogEvent); + var filterLogEvents = logEvents.Filter(Filter, ShouldLogEvent); WrappedTarget.WriteAsyncLogEvents(filterLogEvents); } diff --git a/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs b/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs index 1ef0faaf35..8110bef2b7 100644 --- a/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs +++ b/src/NLog/Targets/Wrappers/PostFilteringTargetWrapper.cs @@ -165,7 +165,7 @@ protected override void Write(IList logEvents) else { InternalLogger.Trace("PostFilteringWrapper(Name={0}): Filter to apply: {1}", Name, resultFilter); - var resultBuffer = logEvents.FilterList(resultFilter, ApplyFilter); + var resultBuffer = logEvents.Filter(resultFilter, ApplyFilter); InternalLogger.Trace("PostFilteringWrapper(Name={0}): After filtering: {1} events.", Name, resultBuffer.Count); if (resultBuffer.Count > 0) {