diff --git a/src/SerilogWeb.Classic/Classic/ApplicationLifecycleModule.cs b/src/SerilogWeb.Classic/Classic/ApplicationLifecycleModule.cs index 09fdc57..02945a4 100644 --- a/src/SerilogWeb.Classic/Classic/ApplicationLifecycleModule.cs +++ b/src/SerilogWeb.Classic/Classic/ApplicationLifecycleModule.cs @@ -38,7 +38,7 @@ public static ILogger Logger get => Config.Logger; set => SerilogWebClassic.Configuration = new SerilogWebClassicConfiguration( isEnabled: Config.IsEnabled, - requestLoggingLevel: Config.RequestLoggingLevel, + logLevelEvaluator: Config.LogLevelEvaluator, requestFilter: Config.RequestFilter, formDataLoggingLevel: Config.FormDataLoggingLevel, customLogger: value, @@ -71,7 +71,7 @@ public static Func RequestFilter if (value == null) throw new ArgumentNullException(nameof(value)); SerilogWebClassic.Configuration = new SerilogWebClassicConfiguration( isEnabled: Config.IsEnabled, - requestLoggingLevel: Config.RequestLoggingLevel, + logLevelEvaluator: Config.LogLevelEvaluator, requestFilter: value, formDataLoggingLevel: Config.FormDataLoggingLevel, customLogger: Config.CustomLogger, @@ -98,7 +98,7 @@ public static LogPostedFormDataOption LogPostedFormData get => Config.LogPostedFormData; set => SerilogWebClassic.Configuration = new SerilogWebClassicConfiguration( isEnabled: Config.IsEnabled, - requestLoggingLevel: Config.RequestLoggingLevel, + logLevelEvaluator: Config.LogLevelEvaluator, requestFilter: Config.RequestFilter, formDataLoggingLevel: Config.FormDataLoggingLevel, customLogger: Config.CustomLogger, @@ -119,7 +119,7 @@ public static bool FilterPasswordsInFormData get => Config.FilterPasswordsInFormData; set => SerilogWebClassic.Configuration = new SerilogWebClassicConfiguration( isEnabled: Config.IsEnabled, - requestLoggingLevel: Config.RequestLoggingLevel, + logLevelEvaluator: Config.LogLevelEvaluator, requestFilter: Config.RequestFilter, formDataLoggingLevel: Config.FormDataLoggingLevel, customLogger: Config.CustomLogger, @@ -140,7 +140,7 @@ public static IEnumerable FilteredKeywordsInFormData get => Config.FilteredKeywordsInFormData; set => SerilogWebClassic.Configuration = new SerilogWebClassicConfiguration( isEnabled: Config.IsEnabled, - requestLoggingLevel: Config.RequestLoggingLevel, + logLevelEvaluator: Config.LogLevelEvaluator, requestFilter: Config.RequestFilter, formDataLoggingLevel: Config.FormDataLoggingLevel, customLogger: Config.CustomLogger, @@ -161,7 +161,7 @@ public static bool IsEnabled get => Config.IsEnabled; set => SerilogWebClassic.Configuration = new SerilogWebClassicConfiguration( isEnabled: value, - requestLoggingLevel: Config.RequestLoggingLevel, + logLevelEvaluator: Config.LogLevelEvaluator, requestFilter: Config.RequestFilter, formDataLoggingLevel: Config.FormDataLoggingLevel, customLogger: Config.CustomLogger, @@ -178,10 +178,9 @@ public static bool IsEnabled [Obsolete("Obsolete since v4.1 - Use SerilogWebClassic.Configure(cfg => cfg.LogAtLevel(level))")] public static LogEventLevel RequestLoggingLevel { - get => Config.RequestLoggingLevel; set => SerilogWebClassic.Configuration = new SerilogWebClassicConfiguration( isEnabled: Config.IsEnabled, - requestLoggingLevel: value, + logLevelEvaluator: (httpContext, elapsed) => value, requestFilter: Config.RequestFilter, formDataLoggingLevel: Config.FormDataLoggingLevel, customLogger: Config.CustomLogger, @@ -202,7 +201,7 @@ public static LogEventLevel FormDataLoggingLevel get => Config.FormDataLoggingLevel; set => SerilogWebClassic.Configuration = new SerilogWebClassicConfiguration( isEnabled: Config.IsEnabled, - requestLoggingLevel: Config.RequestLoggingLevel, + logLevelEvaluator: Config.LogLevelEvaluator, requestFilter: Config.RequestFilter, formDataLoggingLevel: value, customLogger: Config.CustomLogger, @@ -227,7 +226,7 @@ public static Func ShouldLogPostedFormData if (value == null) throw new ArgumentNullException(nameof(value)); SerilogWebClassic.Configuration = new SerilogWebClassicConfiguration( isEnabled: Config.IsEnabled, - requestLoggingLevel: Config.RequestLoggingLevel, + logLevelEvaluator: Config.LogLevelEvaluator, requestFilter: Config.RequestFilter, formDataLoggingLevel: Config.FormDataLoggingLevel, customLogger: Config.CustomLogger, diff --git a/src/SerilogWeb.Classic/Classic/SerilogWebClassicConfiguration.cs b/src/SerilogWeb.Classic/Classic/SerilogWebClassicConfiguration.cs index 8e5d789..fae60f0 100644 --- a/src/SerilogWeb.Classic/Classic/SerilogWebClassicConfiguration.cs +++ b/src/SerilogWeb.Classic/Classic/SerilogWebClassicConfiguration.cs @@ -18,7 +18,7 @@ internal sealed class SerilogWebClassicConfiguration internal SerilogWebClassicConfiguration( bool isEnabled, - LogEventLevel requestLoggingLevel, + Func logLevelEvaluator, Func requestFilter, LogEventLevel formDataLoggingLevel, ILogger customLogger, @@ -28,7 +28,7 @@ internal SerilogWebClassicConfiguration( IEnumerable filteredKeywordsInFormData) { IsEnabled = isEnabled; - RequestLoggingLevel = requestLoggingLevel; + LogLevelEvaluator = logLevelEvaluator; RequestFilter = requestFilter; FormDataLoggingLevel = formDataLoggingLevel; CustomLogger = customLogger; @@ -65,7 +65,7 @@ internal SerilogWebClassicConfiguration Edit(Func LogLevelEvaluator { get; } internal ILogger CustomLogger { get; } internal Func RequestFilter { get; } @@ -78,10 +78,10 @@ internal SerilogWebClassicConfiguration Edit(Func (CustomLogger ?? Log.Logger).ForContext(); - + internal Func FormLoggingStrategy { get; } - + /// /// Filters configured keywords from being logged /// diff --git a/src/SerilogWeb.Classic/Classic/SerilogWebClassicConfigurationBuilder.cs b/src/SerilogWeb.Classic/Classic/SerilogWebClassicConfigurationBuilder.cs index 43d6f60..331f0dd 100644 --- a/src/SerilogWeb.Classic/Classic/SerilogWebClassicConfigurationBuilder.cs +++ b/src/SerilogWeb.Classic/Classic/SerilogWebClassicConfigurationBuilder.cs @@ -17,7 +17,7 @@ public class SerilogWebClassicConfigurationBuilder private bool IsEnabled { get; set; } = true; - private LogEventLevel RequestLoggingLevel { get; set; } + private Func LogLevelEvaluator { get; set; } private ILogger CustomLogger { get; set; } private Func RequestFilter { get; set; } @@ -38,7 +38,7 @@ internal SerilogWebClassicConfigurationBuilder(SerilogWebClassicConfiguration co if (configToCopy == null) throw new ArgumentNullException(nameof(configToCopy)); CustomLogger = configToCopy.CustomLogger; IsEnabled = configToCopy.IsEnabled; - RequestLoggingLevel = configToCopy.RequestLoggingLevel; + LogLevelEvaluator = configToCopy.LogLevelEvaluator; RequestFilter = configToCopy.RequestFilter; FormDataLoggingLevel = configToCopy.FormDataLoggingLevel; LogPostedFormData = configToCopy.LogPostedFormData; @@ -51,7 +51,7 @@ private void Reset() { CustomLogger = null; IsEnabled = true; - RequestLoggingLevel = LogEventLevel.Information; + LogLevelEvaluator = (ctx, elapsed) => LogEventLevel.Information; RequestFilter = AlwaysFalse; ResetFormDataLogging(); } @@ -69,7 +69,7 @@ internal SerilogWebClassicConfiguration Build() { return new SerilogWebClassicConfiguration( isEnabled: IsEnabled, - requestLoggingLevel: RequestLoggingLevel, + logLevelEvaluator: LogLevelEvaluator, requestFilter: RequestFilter, formDataLoggingLevel: FormDataLoggingLevel, customLogger: CustomLogger, @@ -109,7 +109,18 @@ public SerilogWebClassicConfigurationBuilder Enable() /// A configuration object to allow chaining public SerilogWebClassicConfigurationBuilder LogAtLevel(LogEventLevel level) { - RequestLoggingLevel = level; + LogLevelEvaluator = (ctx, elapsed) => level; + return this; + } + + /// + /// Configure at which level HTTP requests are logged dynamically depending on the context + /// + /// Set the log level based on the current http context and total request time + /// A configuration object to allow chaining + public SerilogWebClassicConfigurationBuilder LogAtLevel(Func logLevelEvaluator) + { + LogLevelEvaluator = logLevelEvaluator; return this; } diff --git a/src/SerilogWeb.Classic/Classic/WebRequestLoggingHandler.cs b/src/SerilogWeb.Classic/Classic/WebRequestLoggingHandler.cs index 6c4e6ab..60bb63f 100644 --- a/src/SerilogWeb.Classic/Classic/WebRequestLoggingHandler.cs +++ b/src/SerilogWeb.Classic/Classic/WebRequestLoggingHandler.cs @@ -44,7 +44,7 @@ internal void OnLogRequest(SerilogWebClassicConfiguration configuration) var error = _application.Context.GetLastSerilogWebError() ?? _application.Server.GetLastError(); - var level = error != null || _application.Response.StatusCode >= 500 ? LogEventLevel.Error : configuration.RequestLoggingLevel; + var level = error != null || _application.Response.StatusCode >= 500 ? LogEventLevel.Error : configuration.LogLevelEvaluator(_application.Context, stopwatch.Elapsed); if (level == LogEventLevel.Error && error == null && _application.Context.AllErrors != null) { diff --git a/test/SerilogWeb.Classic.Tests/WebRequestLoggingHandlerTests.cs b/test/SerilogWeb.Classic.Tests/WebRequestLoggingHandlerTests.cs index 223d91b..8cc213d 100644 --- a/test/SerilogWeb.Classic.Tests/WebRequestLoggingHandlerTests.cs +++ b/test/SerilogWeb.Classic.Tests/WebRequestLoggingHandlerTests.cs @@ -86,6 +86,40 @@ public void RequestLoggingLevel(LogEventLevel requestLoggingLevel) Assert.Equal(requestLoggingLevel, evt.Level); } + [Theory] + [InlineData(LogEventLevel.Verbose)] + [InlineData(LogEventLevel.Debug)] + [InlineData(LogEventLevel.Information)] + [InlineData(LogEventLevel.Warning)] + [InlineData(LogEventLevel.Error)] + [InlineData(LogEventLevel.Fatal)] + public void RequestLogLevelEvaluator(LogEventLevel requestLoggingLevel) + { + SerilogWebClassic.Configure(cfg => cfg + .LogAtLevel((context, elapsed) => requestLoggingLevel) + ); + + TestContext.SimulateRequest(); + + var evt = LastEvent; + Assert.NotNull(evt); + Assert.Equal(requestLoggingLevel, evt.Level); + } + + [Fact] + public void DynamicRequestLogLevelEvaluator() + { + SerilogWebClassic.Configure(cfg => cfg + .LogAtLevel((context, elapsed) => elapsed.TotalMilliseconds > 3000 ? LogEventLevel.Warning : LogEventLevel.Information) + ); + + TestContext.SimulateRequest(sleepDurationMilliseconds: 4000); + + var evt = LastEvent; + Assert.NotNull(evt); + Assert.Equal(LogEventLevel.Warning, evt.Level); + } + [Fact] public void LogPostedFormData() {