Skip to content

Commit

Permalink
Add a callback on the reader options to expose the log filter switches
Browse files Browse the repository at this point in the history
Just like it was done for log level switches in #352.
  • Loading branch information
0xced committed May 5, 2023
1 parent 321156e commit d22b9fe
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 2 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,22 @@ Using this package you can also declare `LoggingFilterSwitch`-es in custom secti

Level updates to switches are also respected for a dynamic update.

Since version 4.0.0, filter switches are exposed through a callback on the reader options so that a reference can be kept:

```csharp
var filterSwitches = new Dictionary<string, ILoggingFilterSwitch>();
var options = new ConfigurationReaderOptions
{
OnFilterSwitchCreated = (switchName, filterSwitch) => filterSwitches[switchName] = filterSwitch
};
var logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration, options)
.CreateLogger();
ILoggingFilterSwitch filterSwitch = filterSwitches["$filterSwitch"];
```

### Nested configuration sections

Some Serilog packages require a reference to a logger configuration object. The sample program in this project illustrates this with the following entry configuring the _[Serilog.Sinks.Async](https://github.com/serilog/serilog-sinks-async)_ package to wrap the _[Serilog.Sinks.File](https://github.com/serilog/serilog-sinks-file)_ package. The `configure` parameter references the File sink configuration:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ void ProcessFilterSwitchDeclarations()
SetFilterSwitch(throwOnError: true);
SubscribeToFilterExpressionChanges();

_resolutionContext.AddFilterSwitch(switchName, filterSwitch);
var referenceName = _resolutionContext.AddFilterSwitch(switchName, filterSwitch);
_resolutionContext.ReaderOptions.OnFilterSwitchCreated?.Invoke(referenceName, filterSwitch);

void SubscribeToFilterExpressionChanges()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ public ConfigurationReaderOptions() : this(dependencyContext: null)
/// </summary>
public Action<string, LoggingLevelSwitch>? OnLevelSwitchCreated { get; init; }

/// <summary>
/// Called when a log filter switch is created while reading the <c>Serilog:FilterSwitches</c> section of the configuration.
/// The switch name includes the leading <c>$</c> character.
/// </summary>
public Action<string, ILoggingFilterSwitch>? OnFilterSwitchCreated { get; init; }

internal Assembly[]? Assemblies { get; }
internal DependencyContext? DependencyContext { get; }
internal ConfigurationAssemblySource? ConfigurationAssemblySource { get; }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace Serilog.Settings.Configuration;

/// <summary>
/// A log event filter that can be modified at runtime.
/// </summary>
/// <remarks>
/// Under the hood, the logging filter switch is either a <c>Serilog.Expressions.LoggingFilterSwitch</c> or a <c>Serilog.Filters.Expressions.LoggingFilterSwitch</c> instance.
/// </remarks>
public interface ILoggingFilterSwitch
{
/// <summary>
/// A filter expression against which log events will be tested.
/// Only expressions that evaluate to <c>true</c> are included by the filter. A <c>null</c> expression will accept all events.
/// </summary>
public string? Expression { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace Serilog.Settings.Configuration;

class LoggingFilterSwitchProxy
class LoggingFilterSwitchProxy : ILoggingFilterSwitch
{
readonly Action<string?> _setProxy;
readonly Func<string?> _getProxy;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1547,4 +1547,35 @@ public void TestLogLevelSwitchesCallback(string switchName)
var systemThreading = Assert.Contains("System.Threading", switches);
Assert.Equal(LogEventLevel.Debug, systemThreading.MinimumLevel);
}

[Theory]
[InlineData("$switch1", "$switch2")]
[InlineData("$switch1", "switch2")]
[InlineData("switch1", "$switch2")]
[InlineData("switch1", "switch2")]
public void TestLogFilterSwitchesCallback(string switch1Name, string switch2Name)
{
var json = $$"""
{
'Serilog': {
'FilterSwitches': {
'{{switch1Name}}': 'Prop = 1',
'{{switch2Name}}': 'Prop = 2'
}
}
}
""";

IDictionary<string, ILoggingFilterSwitch> switches = new Dictionary<string, ILoggingFilterSwitch>();
var readerOptions = new ConfigurationReaderOptions { OnFilterSwitchCreated = (name, filterSwitch) => switches[name] = filterSwitch };
ConfigFromJson(json, options: readerOptions);

Assert.Equal(2, switches.Count);

var switch1 = Assert.Contains("$switch1", switches);
Assert.Equal("Prop = 1", switch1.Expression);

var switch2 = Assert.Contains("$switch2", switches);
Assert.Equal("Prop = 2", switch2.Expression);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,12 @@ namespace Serilog.Settings.Configuration
public bool AllowInternalMethods { get; init; }
public bool AllowInternalTypes { get; init; }
public System.IFormatProvider? FormatProvider { get; init; }
public System.Action<string, Serilog.Settings.Configuration.ILoggingFilterSwitch>? OnFilterSwitchCreated { get; init; }
public System.Action<string, Serilog.Core.LoggingLevelSwitch>? OnLevelSwitchCreated { get; init; }
public string? SectionName { get; init; }
}
public interface ILoggingFilterSwitch
{
string? Expression { get; set; }
}
}

0 comments on commit d22b9fe

Please sign in to comment.