diff --git a/README.md b/README.md index 6e639a89..1c9a6fb8 100644 --- a/README.md +++ b/README.md @@ -636,3 +636,42 @@ To set up the `Microsoft.Extensions.Logging` log filtering, you will need to edi ``` [Back to top](#akkahosting) + + +## Filtering Logs In Akka.NET + +In Akka.NET 1.5.21, we introduced [log filtering for log messages based on the LogSource or the content of a log message](https://getakka.net/articles/utilities/logging.html#filtering-log-messages). Depending on your coding style, you can use this feature in Akka.Hosting in several ways. + +1. Using The `LoggerConfigBuilder.WithLogFilter()` method. + + The `LoggerConfigBuilder.WithLogFilter()` method lets you set up the `LogFilterBuilder` + + ```csharp + builder.Services.AddAkka("MyActorSystem", configurationBuilder => + { + configurationBuilder + .ConfigureLoggers(loggerConfigBuilder => + { + loggerConfigBuilder.WithLogFilter(filterBuilder => + { + filterBuilder.ExcludeMessageContaining("Test"); + }); + }); + }); + ``` + +2. Setting the `loggerConfigBuilder.LogFilterBuilder` property directly. + + ```csharp + builder.Services.AddAkka("MyActorSystem", configurationBuilder => + { + configurationBuilder + .ConfigureLoggers(loggerConfigBuilder => + { + loggerConfigBuilder.LogFilterBuilder = new LogFilterBuilder(); + loggerConfigBuilder.LogFilterBuilder.ExcludeMessageContaining("Test"); + }); + }); + ``` + +[Back to top](#akkahosting) diff --git a/src/Akka.Hosting.API.Tests/verify/CoreApiSpec.ApproveCore.verified.txt b/src/Akka.Hosting.API.Tests/verify/CoreApiSpec.ApproveCore.verified.txt index 3699ed78..e5ddb84c 100644 --- a/src/Akka.Hosting.API.Tests/verify/CoreApiSpec.ApproveCore.verified.txt +++ b/src/Akka.Hosting.API.Tests/verify/CoreApiSpec.ApproveCore.verified.txt @@ -155,6 +155,7 @@ namespace Akka.Hosting public Akka.Hosting.DeadLetterOptions? DeadLetterOptions { get; set; } public Akka.Hosting.DebugOptions? DebugOptions { get; set; } public bool LogConfigOnStart { get; set; } + public Akka.Event.LogFilterBuilder? LogFilterBuilder { get; set; } public Akka.Event.LogLevel LogLevel { get; set; } [System.Obsolete("Use the WithDefaultLogMessageFormatter method instead")] public System.Type LogMessageFormatter { get; set; } @@ -163,6 +164,7 @@ namespace Akka.Hosting public Akka.Hosting.LoggerConfigBuilder ClearLoggers() { } public Akka.Hosting.LoggerConfigBuilder WithDefaultLogMessageFormatter() where T : Akka.Event.ILogMessageFormatter { } + public Akka.Hosting.LoggerConfigBuilder WithLogFilter(System.Action filterBuilder) { } } public static class LoggingExtensions { diff --git a/src/Akka.Hosting.Tests/HostingExtensionsSpec.cs b/src/Akka.Hosting.Tests/HostingExtensionsSpec.cs index 92c6cc33..2d6f991e 100644 --- a/src/Akka.Hosting.Tests/HostingExtensionsSpec.cs +++ b/src/Akka.Hosting.Tests/HostingExtensionsSpec.cs @@ -6,6 +6,8 @@ // ----------------------------------------------------------------------- using System; +using System.Linq; +using Akka.Event; using FluentAssertions; using FluentAssertions.Extensions; using Microsoft.Extensions.DependencyInjection; @@ -32,4 +34,20 @@ public void WithActorAskTimeoutInfiniteTest() builder.Configuration.HasValue.Should().BeTrue(); builder.Configuration.Value.GetString("akka.actor.ask-timeout").Should().Be("infinite"); } + + [Fact(DisplayName = "ConfigureLogger WithLogFilter should inject LogFilterSetup")] + public void ConfigureLoggerWithLogFilterSetupTest() + { + var builder = new AkkaConfigurationBuilder(new ServiceCollection(), "fake") + .ConfigureLoggers(logger => + { + logger.WithLogFilter(filterBuilder => + { + filterBuilder.ExcludeMessageContaining("Test"); + }); + }); + var filterSetup = builder.Setups.OfType().First(); + filterSetup.Filters.Length.Should().Be(1); + filterSetup.Filters.Any(f => f is RegexLogMessageFilter).Should().BeTrue(); + } } \ No newline at end of file diff --git a/src/Akka.Hosting.Tests/Logging/LoggerConfigBuilderSpecs.cs b/src/Akka.Hosting.Tests/Logging/LoggerConfigBuilderSpecs.cs index 38e178fa..034c16fb 100644 --- a/src/Akka.Hosting.Tests/Logging/LoggerConfigBuilderSpecs.cs +++ b/src/Akka.Hosting.Tests/Logging/LoggerConfigBuilderSpecs.cs @@ -5,8 +5,9 @@ // ----------------------------------------------------------------------- using System; +using System.Linq; using Akka.Configuration; -using Akka.Hosting.Logging; +using Akka.Event; using FluentAssertions; using Microsoft.Extensions.DependencyInjection; using Xunit; @@ -106,4 +107,42 @@ public void DeadLetterOptionsTest() }.ToString(); cfg.GetInt("akka.log-dead-letters").Should().Be(10); } + + [Fact(DisplayName = "WithLogFilter should populate the LogFilterBuilder property")] + public void WithLogFilterPropertyTest() + { + var akkaBuilder = new AkkaConfigurationBuilder(new ServiceCollection(), "test"); + var loggerConfigBuilder = new LoggerConfigBuilder(akkaBuilder) + .WithLogFilter(filterBuilder => + { + filterBuilder.ExcludeMessageContaining("Test"); + }); + loggerConfigBuilder.LogFilterBuilder.Should().NotBeNull(); + var filterSetup = loggerConfigBuilder.LogFilterBuilder!.Build(); + filterSetup.Filters.Length.Should().Be(1); + filterSetup.Filters.Any(f => f is RegexLogMessageFilter).Should().BeTrue(); + } + + [Fact(DisplayName = "WithLogFilter should append existing LogFilterBuilder property")] + public void WithLogFilterConcatTest() + { + var akkaBuilder = new AkkaConfigurationBuilder(new ServiceCollection(), "test"); + var loggerConfigBuilder = new LoggerConfigBuilder(akkaBuilder) + { + LogFilterBuilder = new LogFilterBuilder() + .ExcludeSourceContaining("Test") + }; + loggerConfigBuilder + .WithLogFilter(filterBuilder => + { + filterBuilder.ExcludeMessageContaining("Test"); + }); + + loggerConfigBuilder.LogFilterBuilder.Should().NotBeNull(); + var filterSetup = loggerConfigBuilder.LogFilterBuilder.Build(); + filterSetup.Filters.Length.Should().Be(2); + filterSetup.Filters.Any(f => f is RegexLogMessageFilter).Should().BeTrue(); + filterSetup.Filters.Any(f => f is RegexLogSourceFilter).Should().BeTrue(); + } + } \ No newline at end of file diff --git a/src/Akka.Hosting/LoggerConfigBuilder.cs b/src/Akka.Hosting/LoggerConfigBuilder.cs index 963c5375..853ed447 100644 --- a/src/Akka.Hosting/LoggerConfigBuilder.cs +++ b/src/Akka.Hosting/LoggerConfigBuilder.cs @@ -46,6 +46,8 @@ internal LoggerConfigBuilder(AkkaConfigurationBuilder builder) public DeadLetterOptions? DeadLetterOptions { get; set; } public DebugOptions? DebugOptions { get; set; } + + public LogFilterBuilder? LogFilterBuilder { get; set; } [Obsolete("Use the WithDefaultLogMessageFormatter method instead")] public Type LogMessageFormatter @@ -96,6 +98,13 @@ public LoggerConfigBuilder WithDefaultLogMessageFormatter() where T: ILogMess return this; } + public LoggerConfigBuilder WithLogFilter(Action filterBuilder) + { + LogFilterBuilder ??= new LogFilterBuilder(); + filterBuilder(LogFilterBuilder); + return this; + } + /// /// INTERNAL API /// @@ -108,7 +117,7 @@ internal void AddLogger(Type logger) _loggers.Add(logger); } - internal Config ToConfig() + private Config ToConfig() { var sb = new StringBuilder() .Append("akka.loglevel=").AppendLine(ParseLogLevel(LogLevel)) @@ -124,6 +133,15 @@ internal Config ToConfig() return ConfigurationFactory.ParseString(sb.ToString()); } + internal AkkaConfigurationBuilder Build(AkkaConfigurationBuilder builder) + { + builder.AddHoconConfiguration(ToConfig(), HoconAddMode.Prepend); + if (LogFilterBuilder is not null) + builder.AddSetup(LogFilterBuilder.Build()); + + return builder; + } + private static string ParseLogLevel(LogLevel logLevel) => logLevel switch { diff --git a/src/Akka.Hosting/Logging/LoggerFactoryLogger.cs b/src/Akka.Hosting/Logging/LoggerFactoryLogger.cs index 7eca8fcf..95d2bb11 100644 --- a/src/Akka.Hosting/Logging/LoggerFactoryLogger.cs +++ b/src/Akka.Hosting/Logging/LoggerFactoryLogger.cs @@ -24,7 +24,7 @@ public class LoggerFactoryLogger: ActorBase, IRequiresMessageQueue protected readonly ILoggingAdapter InternalLogger = Akka.Event.Logging.GetLogger(Context.System.EventStream, nameof(LoggerFactoryLogger)); private readonly ILoggerFactory _loggerFactory; - private ILogger _akkaLogger; + private readonly ILogger _akkaLogger; public LoggerFactoryLogger() { diff --git a/src/Akka.Hosting/LoggingExtensions.cs b/src/Akka.Hosting/LoggingExtensions.cs index e792c966..7c9cfb61 100644 --- a/src/Akka.Hosting/LoggingExtensions.cs +++ b/src/Akka.Hosting/LoggingExtensions.cs @@ -24,7 +24,7 @@ public static AkkaConfigurationBuilder ConfigureLoggers(this AkkaConfigurationBu { var setup = new LoggerConfigBuilder(builder); configurator(setup); - return builder.AddHoconConfiguration(setup.ToConfig(), HoconAddMode.Prepend); + return setup.Build(builder); } ///