Upstream NLog/NLog state of the touched files before 229644059f
This commit is contained in:
commit
94b7d9de1f
8 files changed
+911
No files matched your search
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// Copyright (c) 2004-2024 Jaroslaw Kowalski <jaak@jkowalski.net>, 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.Filters
|
||||
{
|
||||
using NLog.Conditions;
|
||||
|
||||
/// <summary>
|
||||
/// Matches when the specified condition is met.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Conditions are expressed using a simple language.
|
||||
/// </remarks>
|
||||
/// <seealso href="https://github.com/NLog/NLog/wiki/Conditions">Documentation on NLog Wiki</seealso>
|
||||
[Filter("when")]
|
||||
public class ConditionBasedFilter : Filter
|
||||
{
|
||||
internal static readonly ConditionBasedFilter Empty = new ConditionBasedFilter();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the condition expression.
|
||||
/// </summary>
|
||||
/// <docgen category='Filtering Options' order='10' />
|
||||
public ConditionExpression Condition { get; set; } = ConditionLiteralExpression.Null;
|
||||
|
||||
internal FilterResult FilterDefaultAction { get; set; } = FilterResult.Neutral;
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override FilterResult Check(LogEventInfo logEvent)
|
||||
{
|
||||
var val = Condition?.Evaluate(logEvent);
|
||||
return ConditionExpression.BoxedTrue.Equals(val) ? Action : FilterDefaultAction;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// Copyright (c) 2004-2024 Jaroslaw Kowalski <jaak@jkowalski.net>, 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.Filters
|
||||
{
|
||||
using NLog.Config;
|
||||
|
||||
/// <summary>
|
||||
/// An abstract filter class. Provides a way to eliminate log messages
|
||||
/// based on properties other than logger name and log level.
|
||||
/// </summary>
|
||||
[NLogConfigurationItem]
|
||||
public abstract class Filter
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Filter" /> class.
|
||||
/// </summary>
|
||||
protected Filter()
|
||||
{
|
||||
Action = FilterResult.Neutral;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the action to be taken when filter matches.
|
||||
/// </summary>
|
||||
/// <docgen category='Filtering Options' order='10' />
|
||||
public FilterResult Action { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the result of evaluating filter against given log event.
|
||||
/// </summary>
|
||||
/// <param name="logEvent">The log event.</param>
|
||||
/// <returns>Filter result.</returns>
|
||||
internal FilterResult GetFilterResult(LogEventInfo logEvent)
|
||||
{
|
||||
return Check(logEvent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether log event should be logged or not.
|
||||
/// </summary>
|
||||
/// <param name="logEvent">Log event.</param>
|
||||
/// <returns>
|
||||
/// <see cref="FilterResult.Ignore"/> - if the log event should be ignored<br/>
|
||||
/// <see cref="FilterResult.Neutral"/> - if the filter doesn't want to decide<br/>
|
||||
/// <see cref="FilterResult.Log"/> - if the log event should be logged<br/>
|
||||
/// .</returns>
|
||||
protected abstract FilterResult Check(LogEventInfo logEvent);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// Copyright (c) 2004-2024 Jaroslaw Kowalski <jaak@jkowalski.net>, 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.Filters
|
||||
{
|
||||
using NLog.Layouts;
|
||||
|
||||
/// <summary>
|
||||
/// A base class for filters that are based on comparing a value to a layout.
|
||||
/// </summary>
|
||||
public abstract class LayoutBasedFilter : Filter
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LayoutBasedFilter" /> class.
|
||||
/// </summary>
|
||||
protected LayoutBasedFilter()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the layout to be used to filter log messages.
|
||||
/// </summary>
|
||||
/// <value>The layout.</value>
|
||||
/// <docgen category='Filtering Options' order='10' />
|
||||
public Layout Layout { get; set; } = Layout.Empty;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
//
|
||||
// Copyright (c) 2004-2024 Jaroslaw Kowalski <jaak@jkowalski.net>, 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.Filters
|
||||
{
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Matches when the calculated layout contains the specified substring.
|
||||
/// This filter is deprecated in favor of <c><when /></c> which is based on <a href="https://github.com/NLog/NLog/wiki/Conditions">conditions</a>.
|
||||
/// </summary>
|
||||
[Filter("whenContains")]
|
||||
public class WhenContainsFilter : LayoutBasedFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to ignore case when comparing strings.
|
||||
/// </summary>
|
||||
/// <docgen category='Filtering Options' order='10' />
|
||||
public bool IgnoreCase { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the substring to be matched.
|
||||
/// </summary>
|
||||
/// <docgen category='Filtering Options' order='10' />
|
||||
public string Substring { get; set; } = string.Empty;
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override FilterResult Check(LogEventInfo logEvent)
|
||||
{
|
||||
StringComparison comparisonType = IgnoreCase
|
||||
? StringComparison.OrdinalIgnoreCase
|
||||
: StringComparison.Ordinal;
|
||||
string result = Layout.Render(logEvent);
|
||||
if (!string.IsNullOrEmpty(Substring) && result.IndexOf(Substring, comparisonType) >= 0)
|
||||
{
|
||||
return Action;
|
||||
}
|
||||
|
||||
return FilterResult.Neutral;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
//
|
||||
// Copyright (c) 2004-2024 Jaroslaw Kowalski <jaak@jkowalski.net>, 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.Filters
|
||||
{
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Matches when the calculated layout is equal to the specified substring.
|
||||
/// This filter is deprecated in favor of <c><when /></c> which is based on <a href="https://github.com/NLog/NLog/wiki/Conditions">conditions</a>.
|
||||
/// </summary>
|
||||
[Filter("whenEqual")]
|
||||
public class WhenEqualFilter : LayoutBasedFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to ignore case when comparing strings.
|
||||
/// </summary>
|
||||
/// <docgen category='Filtering Options' order='10' />
|
||||
public bool IgnoreCase { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a string to compare the layout to.
|
||||
/// </summary>
|
||||
/// <docgen category='Filtering Options' order='10' />
|
||||
public string CompareTo { get; set; } = string.Empty;
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override FilterResult Check(LogEventInfo logEvent)
|
||||
{
|
||||
StringComparison comparisonType = IgnoreCase
|
||||
? StringComparison.OrdinalIgnoreCase
|
||||
: StringComparison.Ordinal;
|
||||
string result = Layout.Render(logEvent);
|
||||
if (result.Equals(CompareTo, comparisonType))
|
||||
{
|
||||
return Action;
|
||||
}
|
||||
|
||||
return FilterResult.Neutral;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
//
|
||||
// Copyright (c) 2004-2024 Jaroslaw Kowalski <jaak@jkowalski.net>, 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.Filters
|
||||
{
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Matches when the calculated layout does NOT contain the specified substring.
|
||||
/// This filter is deprecated in favor of <c><when /></c> which is based on <a href="https://github.com/NLog/NLog/wiki/Conditions">conditions</a>.
|
||||
/// </summary>
|
||||
[Filter("whenNotContains")]
|
||||
public class WhenNotContainsFilter : LayoutBasedFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the substring to be matched.
|
||||
/// </summary>
|
||||
/// <docgen category='Filtering Options' order='10' />
|
||||
public string Substring { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to ignore case when comparing strings.
|
||||
/// </summary>
|
||||
/// <docgen category='Filtering Options' order='10' />
|
||||
public bool IgnoreCase { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override FilterResult Check(LogEventInfo logEvent)
|
||||
{
|
||||
StringComparison comparison = IgnoreCase
|
||||
? StringComparison.OrdinalIgnoreCase
|
||||
: StringComparison.Ordinal;
|
||||
string result = Layout.Render(logEvent);
|
||||
if (!string.IsNullOrEmpty(Substring) && result.IndexOf(Substring, comparison) < 0)
|
||||
{
|
||||
return Action;
|
||||
}
|
||||
|
||||
return FilterResult.Neutral;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// Copyright (c) 2004-2024 Jaroslaw Kowalski <jaak@jkowalski.net>, 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.Filters
|
||||
{
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Matches when the calculated layout is NOT equal to the specified substring.
|
||||
/// This filter is deprecated in favor of <c><when /></c> which is based on <a href="https://github.com/NLog/NLog/wiki/Conditions">conditions</a>.
|
||||
/// </summary>
|
||||
[Filter("whenNotEqual")]
|
||||
public class WhenNotEqualFilter : LayoutBasedFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WhenNotEqualFilter" /> class.
|
||||
/// </summary>
|
||||
public WhenNotEqualFilter()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a string to compare the layout to.
|
||||
/// </summary>
|
||||
/// <docgen category='Filtering Options' order='10' />
|
||||
public string CompareTo { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to ignore case when comparing strings.
|
||||
/// </summary>
|
||||
/// <docgen category='Filtering Options' order='10' />
|
||||
public bool IgnoreCase { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override FilterResult Check(LogEventInfo logEvent)
|
||||
{
|
||||
StringComparison comparisonType = IgnoreCase
|
||||
? StringComparison.OrdinalIgnoreCase
|
||||
: StringComparison.Ordinal;
|
||||
string result = Layout.Render(logEvent);
|
||||
if (!result.Equals(CompareTo, comparisonType))
|
||||
{
|
||||
return Action;
|
||||
}
|
||||
|
||||
return FilterResult.Neutral;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,414 @@
|
||||
//
|
||||
// Copyright (c) 2004-2024 Jaroslaw Kowalski <jaak@jkowalski.net>, 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.Filters
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
using NLog.Internal;
|
||||
|
||||
/// <summary>
|
||||
/// Matches when the result of the calculated layout has been repeated a moment ago
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <a href="https://github.com/NLog/NLog/wiki/WhenRepeated-Filter">See NLog Wiki</a>
|
||||
/// </remarks>
|
||||
/// <seealso href="https://github.com/NLog/NLog/wiki/WhenRepeated-Filter">Documentation on NLog Wiki</seealso>
|
||||
[Filter("whenRepeated")]
|
||||
public class WhenRepeatedFilter : LayoutBasedFilter
|
||||
{
|
||||
private const int MaxInitialRenderBufferLength = 16384;
|
||||
|
||||
/// <summary>
|
||||
/// How long before a filter expires, and logging is accepted again
|
||||
/// </summary>
|
||||
/// <docgen category='Filtering Options' order='10' />
|
||||
public int TimeoutSeconds { get; set; } = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Max length of filter values, will truncate if above limit
|
||||
/// </summary>
|
||||
/// <docgen category='Filtering Options' order='10' />
|
||||
public int MaxLength { get; set; } = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// Applies the configured action to the initial logevent that starts the timeout period.
|
||||
/// Used to configure that it should ignore all events until timeout.
|
||||
/// </summary>
|
||||
/// <docgen category='Filtering Options' order='10' />
|
||||
public bool IncludeFirst { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Max number of unique filter values to expect simultaneously
|
||||
/// </summary>
|
||||
/// <docgen category='Filtering Options' order='100' />
|
||||
public int MaxFilterCacheSize { get; set; } = 50000;
|
||||
|
||||
/// <summary>
|
||||
/// Default number of unique filter values to expect, will automatically increase if needed
|
||||
/// </summary>
|
||||
/// <docgen category='Filtering Options' order='100' />
|
||||
public int DefaultFilterCacheSize { get; set; } = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// Insert FilterCount value into <see cref="LogEventInfo.Properties"/> when an event is no longer filtered
|
||||
/// </summary>
|
||||
/// <docgen category='Filtering Options' order='10' />
|
||||
public string FilterCountPropertyName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Append FilterCount to the <see cref="LogEventInfo.Message"/> when an event is no longer filtered
|
||||
/// </summary>
|
||||
/// <docgen category='Filtering Options' order='10' />
|
||||
public string FilterCountMessageAppendFormat { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Reuse internal buffers, and doesn't have to constantly allocate new buffers
|
||||
/// </summary>
|
||||
/// <docgen category='Filtering Options' order='100' />
|
||||
[Obsolete("No longer used, and always returns true. Marked obsolete on NLog 5.0")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public bool OptimizeBufferReuse { get => _optimizeBufferReuse ?? true; set => _optimizeBufferReuse = value ? true : (bool?)null; }
|
||||
private bool? _optimizeBufferReuse;
|
||||
|
||||
/// <summary>
|
||||
/// Default buffer size for the internal buffers
|
||||
/// </summary>
|
||||
/// <docgen category='Filtering Options' order='100' />
|
||||
public int OptimizeBufferDefaultLength { get; set; } = 1000;
|
||||
|
||||
private readonly ReusableBuilderCreator ReusableLayoutBuilder = new ReusableBuilderCreator();
|
||||
|
||||
private readonly Dictionary<FilterInfoKey, FilterInfo> _repeatFilter = new Dictionary<FilterInfoKey, FilterInfo>(1000);
|
||||
private readonly Stack<KeyValuePair<FilterInfoKey, FilterInfo>> _objectPool = new Stack<KeyValuePair<FilterInfoKey, FilterInfo>>(1000);
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether log event should be logged or not. In case the LogEvent has just been repeated.
|
||||
/// </summary>
|
||||
/// <param name="logEvent">Log event.</param>
|
||||
/// <returns>
|
||||
/// <see cref="FilterResult.Ignore"/> - if the log event should be ignored<br/>
|
||||
/// <see cref="FilterResult.Neutral"/> - if the filter doesn't want to decide<br/>
|
||||
/// <see cref="FilterResult.Log"/> - if the log event should be logged<br/>
|
||||
/// .</returns>
|
||||
protected override FilterResult Check(LogEventInfo logEvent)
|
||||
{
|
||||
FilterResult filterResult = FilterResult.Neutral;
|
||||
bool obsoleteFilter = false;
|
||||
|
||||
lock (_repeatFilter)
|
||||
{
|
||||
using (var targetBuilder = ReusableLayoutBuilder.Allocate())
|
||||
{
|
||||
if (targetBuilder.Result.Capacity != OptimizeBufferDefaultLength)
|
||||
{
|
||||
// StringBuilder.Equals only works when StringBuilder.Capacity is the same
|
||||
if (OptimizeBufferDefaultLength < MaxInitialRenderBufferLength)
|
||||
{
|
||||
OptimizeBufferDefaultLength = MaxLength;
|
||||
while (OptimizeBufferDefaultLength < targetBuilder.Result.Capacity && OptimizeBufferDefaultLength < MaxInitialRenderBufferLength)
|
||||
{
|
||||
OptimizeBufferDefaultLength *= 2;
|
||||
}
|
||||
}
|
||||
targetBuilder.Result.Capacity = OptimizeBufferDefaultLength;
|
||||
}
|
||||
|
||||
FilterInfoKey filterInfoKey = RenderFilterInfoKey(logEvent, targetBuilder.Result);
|
||||
|
||||
if (!_repeatFilter.TryGetValue(filterInfoKey, out var filterInfo))
|
||||
{
|
||||
filterInfo = CreateFilterInfo(logEvent);
|
||||
if (filterInfo.StringBuffer != null)
|
||||
{
|
||||
filterInfo.StringBuffer.ClearBuilder();
|
||||
int length = Math.Min(targetBuilder.Result.Length, MaxLength);
|
||||
for (int i = 0; i < length; ++i)
|
||||
filterInfo.StringBuffer.Append(targetBuilder.Result[i]);
|
||||
}
|
||||
filterInfo.Refresh(logEvent.Level, logEvent.TimeStamp, 0);
|
||||
_repeatFilter.Add(new FilterInfoKey(filterInfo.StringBuffer, filterInfoKey.StringValue, filterInfoKey.StringHashCode), filterInfo);
|
||||
obsoleteFilter = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IncludeFirst)
|
||||
{
|
||||
obsoleteFilter = filterInfo.IsObsolete(logEvent.TimeStamp, TimeoutSeconds);
|
||||
}
|
||||
|
||||
filterResult = RefreshFilterInfo(logEvent, filterInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore the first log-event, and wait until next timeout expiry
|
||||
if (IncludeFirst && obsoleteFilter)
|
||||
{
|
||||
filterResult = Action;
|
||||
}
|
||||
|
||||
return filterResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses object pooling, and prunes stale filter items when the pool runs dry
|
||||
/// </summary>
|
||||
private FilterInfo CreateFilterInfo(LogEventInfo logEvent)
|
||||
{
|
||||
FilterInfo reusableObject;
|
||||
if (_objectPool.Count == 0 && _repeatFilter.Count > DefaultFilterCacheSize)
|
||||
{
|
||||
int aggressiveTimeoutSeconds = _repeatFilter.Count > MaxFilterCacheSize ? TimeoutSeconds * 2 / 3 : TimeoutSeconds;
|
||||
PruneFilterCache(logEvent, Math.Max(1, aggressiveTimeoutSeconds));
|
||||
if (_repeatFilter.Count > MaxFilterCacheSize)
|
||||
{
|
||||
PruneFilterCache(logEvent, Math.Max(1, TimeoutSeconds / 2));
|
||||
}
|
||||
}
|
||||
|
||||
if (_objectPool.Count == 0)
|
||||
{
|
||||
reusableObject = new FilterInfo(new StringBuilder(OptimizeBufferDefaultLength));
|
||||
}
|
||||
else
|
||||
{
|
||||
reusableObject = _objectPool.Pop().Value;
|
||||
// StringBuilder.Equals only works when StringBuilder.Capacity is the same
|
||||
if (reusableObject.StringBuffer != null && reusableObject.StringBuffer.Capacity != OptimizeBufferDefaultLength)
|
||||
{
|
||||
reusableObject.StringBuffer.Capacity = OptimizeBufferDefaultLength;
|
||||
}
|
||||
}
|
||||
|
||||
return reusableObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove stale filter-value from the cache, and fill them into the pool for reuse
|
||||
/// </summary>
|
||||
private void PruneFilterCache(LogEventInfo logEvent, int aggressiveTimeoutSeconds)
|
||||
{
|
||||
foreach (var filterPair in _repeatFilter)
|
||||
{
|
||||
if (filterPair.Value.IsObsolete(logEvent.TimeStamp, aggressiveTimeoutSeconds))
|
||||
{
|
||||
_objectPool.Push(filterPair);
|
||||
}
|
||||
}
|
||||
foreach (var filterPair in _objectPool)
|
||||
{
|
||||
_repeatFilter.Remove(filterPair.Key);
|
||||
}
|
||||
if (_repeatFilter.Count * 2 > DefaultFilterCacheSize && DefaultFilterCacheSize < MaxFilterCacheSize)
|
||||
{
|
||||
DefaultFilterCacheSize *= 2;
|
||||
}
|
||||
while (_objectPool.Count != 0 && _objectPool.Count > DefaultFilterCacheSize)
|
||||
{
|
||||
_objectPool.Pop();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the Log Event into a filter value, that is used for checking if just repeated
|
||||
/// </summary>
|
||||
private FilterInfoKey RenderFilterInfoKey(LogEventInfo logEvent, StringBuilder targetBuilder)
|
||||
{
|
||||
if (targetBuilder != null)
|
||||
{
|
||||
Layout.Render(logEvent, targetBuilder);
|
||||
if (targetBuilder.Length > MaxLength)
|
||||
targetBuilder.Length = MaxLength;
|
||||
return new FilterInfoKey(targetBuilder, null);
|
||||
}
|
||||
string value = Layout.Render(logEvent);
|
||||
if (value.Length > MaxLength)
|
||||
value = value.Substring(0, MaxLength);
|
||||
return new FilterInfoKey(null, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Repeated LogEvent detected. Checks if it should activate filter-action
|
||||
/// </summary>
|
||||
private FilterResult RefreshFilterInfo(LogEventInfo logEvent, FilterInfo filterInfo)
|
||||
{
|
||||
if (filterInfo.HasExpired(logEvent.TimeStamp, TimeoutSeconds) || logEvent.Level > filterInfo.LogLevel)
|
||||
{
|
||||
int filterCount = filterInfo.FilterCount;
|
||||
if (filterCount > 0 && filterInfo.IsObsolete(logEvent.TimeStamp, TimeoutSeconds))
|
||||
{
|
||||
filterCount = 0;
|
||||
}
|
||||
|
||||
filterInfo.Refresh(logEvent.Level, logEvent.TimeStamp, 0);
|
||||
|
||||
if (filterCount > 0)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(FilterCountPropertyName))
|
||||
{
|
||||
if (!logEvent.Properties.TryGetValue(FilterCountPropertyName, out var otherFilterCount))
|
||||
{
|
||||
logEvent.Properties[FilterCountPropertyName] = filterCount;
|
||||
}
|
||||
else if (otherFilterCount is int i)
|
||||
{
|
||||
filterCount = Math.Max(i, filterCount);
|
||||
logEvent.Properties[FilterCountPropertyName] = filterCount;
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrEmpty(FilterCountMessageAppendFormat) && logEvent.Message != null)
|
||||
{
|
||||
logEvent.Message += string.Format(FilterCountMessageAppendFormat, filterCount.ToString(System.Globalization.CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
|
||||
return FilterResult.Neutral;
|
||||
}
|
||||
filterInfo.Refresh(logEvent.Level, logEvent.TimeStamp, filterInfo.FilterCount + 1);
|
||||
return Action;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filter Value State (mutable)
|
||||
/// </summary>
|
||||
private sealed class FilterInfo
|
||||
{
|
||||
public FilterInfo(StringBuilder stringBuilder)
|
||||
{
|
||||
StringBuffer = stringBuilder;
|
||||
}
|
||||
|
||||
public void Refresh(LogLevel logLevel, DateTime logTimeStamp, int filterCount)
|
||||
{
|
||||
if (filterCount == 0)
|
||||
{
|
||||
LastLogTime = logTimeStamp;
|
||||
LogLevel = logLevel;
|
||||
}
|
||||
else if (LogLevel is null || logLevel.Ordinal > LogLevel.Ordinal)
|
||||
{
|
||||
LogLevel = logLevel;
|
||||
}
|
||||
LastFilterTime = logTimeStamp;
|
||||
FilterCount = filterCount;
|
||||
}
|
||||
|
||||
public bool IsObsolete(DateTime logEventTime, int timeoutSeconds)
|
||||
{
|
||||
if (FilterCount == 0)
|
||||
{
|
||||
return HasExpired(logEventTime, timeoutSeconds);
|
||||
}
|
||||
return (logEventTime - LastFilterTime).TotalSeconds > timeoutSeconds && HasExpired(logEventTime, timeoutSeconds * 2);
|
||||
}
|
||||
|
||||
public bool HasExpired(DateTime logEventTime, int timeoutSeconds)
|
||||
{
|
||||
return (logEventTime - LastLogTime).TotalSeconds > timeoutSeconds;
|
||||
}
|
||||
|
||||
public StringBuilder StringBuffer { get; }
|
||||
public LogLevel? LogLevel { get; private set; }
|
||||
private DateTime LastLogTime { get; set; }
|
||||
private DateTime LastFilterTime { get; set; }
|
||||
public int FilterCount { get; private set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filter Lookup Key (immutable)
|
||||
/// </summary>
|
||||
private
|
||||
#if !NETFRAMEWORK
|
||||
readonly
|
||||
#endif
|
||||
struct FilterInfoKey : IEquatable<FilterInfoKey>
|
||||
{
|
||||
private readonly StringBuilder? _stringBuffer;
|
||||
public readonly string? StringValue;
|
||||
public readonly int StringHashCode;
|
||||
|
||||
public FilterInfoKey(StringBuilder? stringBuffer, string? stringValue, int? stringHashCode = null)
|
||||
{
|
||||
_stringBuffer = stringBuffer;
|
||||
StringValue = stringValue;
|
||||
if (stringHashCode.HasValue)
|
||||
{
|
||||
StringHashCode = stringHashCode.Value;
|
||||
}
|
||||
else if (stringBuffer != null)
|
||||
{
|
||||
int hashCode = stringBuffer.Length.GetHashCode();
|
||||
int hashCodeCount = Math.Min(stringBuffer.Length, 100);
|
||||
for (int i = 0; i < hashCodeCount; ++i)
|
||||
hashCode = hashCode ^ stringBuffer[i].GetHashCode();
|
||||
StringHashCode = hashCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
StringHashCode = stringValue is null ? 0 : StringComparer.Ordinal.GetHashCode(stringValue);
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return StringHashCode;
|
||||
}
|
||||
|
||||
public bool Equals(FilterInfoKey other)
|
||||
{
|
||||
if (StringValue != null)
|
||||
{
|
||||
return string.Equals(StringValue, other.StringValue, StringComparison.Ordinal);
|
||||
}
|
||||
if (_stringBuffer != null && other._stringBuffer != null)
|
||||
{
|
||||
// StringBuilder.Equals only works when StringBuilder.Capacity is the same
|
||||
if (_stringBuffer.Capacity != other._stringBuffer.Capacity)
|
||||
{
|
||||
return _stringBuffer.EqualTo(other._stringBuffer);
|
||||
}
|
||||
return _stringBuffer.Equals(other._stringBuffer);
|
||||
}
|
||||
return ReferenceEquals(_stringBuffer, other._stringBuffer) && ReferenceEquals(StringValue, other.StringValue);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is FilterInfoKey key && Equals(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user