Skip to content
This repository was archived by the owner on Feb 27, 2022. It is now read-only.

Commit 6b0778b

Browse files
authored
Merge pull request #2 from nblumhardt/dynamic-filters
Adds LoggingFilterSwitch
2 parents f5c723d + 21b4916 commit 6b0778b

File tree

4 files changed

+152
-0
lines changed

4 files changed

+152
-0
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Copyright 2013-2015 Serilog Contributors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using Serilog.Core;
16+
using Serilog.Events;
17+
using System;
18+
19+
namespace Serilog.Filters.Expressions
20+
{
21+
/// <summary>
22+
/// A log event filter that can be modified at runtime.
23+
/// </summary>
24+
public class LoggingFilterSwitch : ILogEventFilter
25+
{
26+
// Reference assignments are atomic. While this class makes
27+
// no attempt to synchronize Expression, ToString(), and IsIncluded(),
28+
// for any observer, this at least ensures they won't be permanently out-of-sync for
29+
// all observers.
30+
volatile Tuple<string, Func<LogEvent, object>> _filter;
31+
32+
/// <summary>
33+
/// Construct a <see cref="LoggingFilterSwitch"/>, optionally initialized
34+
/// with the <paramref name="expression"/>.
35+
/// </summary>
36+
/// <param name="expression">A filter expression against which log events will be tested.
37+
/// Only expressions that evaluate to <c>true</c> are included
38+
/// by the filter. A <c>null</c> expression will accept all
39+
/// events.</param>
40+
public LoggingFilterSwitch(string expression = null)
41+
{
42+
Expression = expression;
43+
}
44+
45+
/// <summary>
46+
/// A filter expression against which log events will be tested.
47+
/// Only expressions that evaluate to <c>true</c> are included
48+
/// by the filter. A <c>null</c> expression will accept all
49+
/// events.
50+
/// </summary>
51+
public string Expression
52+
{
53+
get
54+
{
55+
var filter = _filter;
56+
return filter?.Item1;
57+
}
58+
set
59+
{
60+
if (value == null)
61+
{
62+
_filter = null;
63+
}
64+
else
65+
{
66+
_filter = new Tuple<string, Func<LogEvent, object>>(
67+
value,
68+
FilterLanguage.CreateFilter(value));
69+
}
70+
}
71+
}
72+
73+
/// <inheritdoc/>
74+
public bool IsEnabled(LogEvent logEvent)
75+
{
76+
if (logEvent == null) throw new ArgumentNullException(nameof(logEvent));
77+
78+
var filter = _filter;
79+
80+
if (filter == null)
81+
return true;
82+
83+
return true.Equals(filter.Item2(logEvent));
84+
}
85+
86+
/// <inheritdoc/>
87+
public override string ToString()
88+
{
89+
var filter = _filter;
90+
return filter?.Item1 ?? "";
91+
}
92+
}
93+
}

src/Serilog.Filters.Expressions/LoggerFilterConfigurationExtensions.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,20 @@ public static LoggerConfiguration ByExcluding(this LoggerFilterConfiguration log
3838
var compiled = FilterLanguage.CreateFilter(expression);
3939
return loggerFilterConfiguration.ByExcluding(e => true.Equals(compiled(e)));
4040
}
41+
42+
/// <summary>
43+
/// Use a <see cref="LoggingFilterSwitch"/> to dynamically control filtering.
44+
/// </summary>
45+
/// <param name="loggerFilterConfiguration">Filter configuration.</param>
46+
/// <param name="switch">A <see cref="LoggingFilterSwitch"/> that can be used to dynamically control
47+
/// log filtering.</param>
48+
/// <returns>The underlying <see cref="LoggerConfiguration"/>.</returns>
49+
public static LoggerConfiguration ControlledBy(this LoggerFilterConfiguration loggerFilterConfiguration, LoggingFilterSwitch @switch)
50+
{
51+
if (loggerFilterConfiguration == null) throw new ArgumentNullException(nameof(loggerFilterConfiguration));
52+
if (@switch == null) throw new ArgumentNullException(nameof(@switch));
53+
54+
return loggerFilterConfiguration.With(@switch);
55+
}
4156
}
4257
}

test/Serilog.Filters.Expressions.Tests/FilterExpressionCompilerTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ public void FilterExpressionsEvaluateSubproperties()
104104
Some.InformationEvent("Checking out {@Cart}", new { Total = 20 }),
105105
Some.InformationEvent("Checking out {@Cart}", new { Total = 5 }));
106106
}
107+
107108
static void AssertFiltering(string expression, LogEvent match, params LogEvent[] noMatches)
108109
{
109110
var sink = new CollectingSink();
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using Serilog.Filters.Expressions.Tests.Support;
2+
using System.Linq;
3+
using Xunit;
4+
5+
namespace Serilog.Filters.Expressions.Tests
6+
{
7+
public class LoggingFilterSwitchTests
8+
{
9+
[Fact]
10+
public void WhenTheFilterExpressionIsModifiedTheFilterChanges()
11+
{
12+
var @switch = new LoggingFilterSwitch();
13+
var sink = new CollectingSink();
14+
15+
var log = new LoggerConfiguration()
16+
.Filter.ControlledBy(@switch)
17+
.WriteTo.Sink(sink)
18+
.CreateLogger();
19+
20+
var v11 = Some.InformationEvent("Adding {Volume} L", 11);
21+
22+
log.Write(v11);
23+
Assert.Same(v11, sink.SingleEvent);
24+
sink.Events.Clear();
25+
26+
@switch.Expression = "Volume > 12";
27+
28+
log.Write(v11);
29+
Assert.Equal(0, sink.Events.Count);
30+
31+
@switch.Expression = "Volume > 10";
32+
33+
log.Write(v11);
34+
Assert.Same(v11, sink.SingleEvent);
35+
sink.Events.Clear();
36+
37+
@switch.Expression = null;
38+
39+
log.Write(v11);
40+
Assert.Same(v11, sink.SingleEvent);
41+
}
42+
}
43+
}

0 commit comments

Comments
 (0)