diff --git a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs index a8ec777..f1708ce 100644 --- a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs +++ b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs @@ -32,6 +32,7 @@ class RequestLoggingMiddleware readonly Func> _getMessageTemplateProperties; readonly ILogger? _logger; readonly bool _includeQueryInRequestPath; + readonly bool _addElapsedToHttpContext; static readonly LogEventProperty[] NoProperties = []; public RequestLoggingMiddleware(RequestDelegate next, DiagnosticContext diagnosticContext, RequestLoggingOptions options) @@ -45,6 +46,7 @@ public RequestLoggingMiddleware(RequestDelegate next, DiagnosticContext diagnost _messageTemplate = new MessageTemplateParser().Parse(options.MessageTemplate); _logger = options.Logger?.ForContext(); _includeQueryInRequestPath = options.IncludeQueryInRequestPath; + _addElapsedToHttpContext = options.AddElapsedToHttpContext; _getMessageTemplateProperties = options.GetMessageTemplateProperties; } @@ -82,6 +84,11 @@ bool LogCompletion(HttpContext httpContext, DiagnosticContextCollector collector if (!logger.IsEnabled(level)) return false; + if (_addElapsedToHttpContext) + { + httpContext.Items.Add(RequestLoggingOptions.HttpContextItemsElapsedKey, elapsedMs); + } + _enrichDiagnosticContext?.Invoke(_diagnosticContext, httpContext); if (!collector.TryComplete(out var collectedProperties, out var collectedException)) diff --git a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingOptions.cs b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingOptions.cs index fe9c1ab..b7937ec 100644 --- a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingOptions.cs +++ b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingOptions.cs @@ -41,6 +41,11 @@ static IEnumerable DefaultGetMessageTemplateProperties(HttpCon new LogEventProperty("StatusCode", new ScalarValue(statusCode)), new LogEventProperty("Elapsed", new ScalarValue(elapsedMs)) ]; + + /// + /// The key used to add the ElapsedMs value to Items collection + /// + public const string HttpContextItemsElapsedKey = "Serilog.AspNetCore.ElapsedMs"; /// /// Gets or sets the message template. The default value is @@ -81,6 +86,11 @@ static IEnumerable DefaultGetMessageTemplateProperties(HttpCon /// public bool IncludeQueryInRequestPath { get; set; } + /// + /// Add the elapsed millisecond value to the Items collection before invoking EnrichDiagnosticContext + /// + public bool AddElapsedToHttpContext { get; set; } + /// /// A function to specify the values of the MessageTemplateProperties. /// diff --git a/test/Serilog.AspNetCore.Tests/SerilogWebHostBuilderExtensionsTests.cs b/test/Serilog.AspNetCore.Tests/SerilogWebHostBuilderExtensionsTests.cs index 61ea07a..8d84553 100644 --- a/test/Serilog.AspNetCore.Tests/SerilogWebHostBuilderExtensionsTests.cs +++ b/test/Serilog.AspNetCore.Tests/SerilogWebHostBuilderExtensionsTests.cs @@ -63,7 +63,29 @@ public async Task RequestLoggingMiddlewareShouldEnrich() Assert.Equal("GET", completionEvent.Properties["RequestMethod"].LiteralValue()); Assert.True(completionEvent.Properties.ContainsKey("Elapsed")); } + + [Fact] + public async Task RequestLoggingMiddlewareShouldEnrichWithElapsed() + { + var (sink, web) = Setup(options => + { + options.AddElapsedToHttpContext = true; + options.EnrichDiagnosticContext += (diagnosticContext, httpContext) => + { + var elapsedValue = (double)(httpContext.Items[RequestLoggingOptions.HttpContextItemsElapsedKey] ?? -0.1); + diagnosticContext.Set("ElapsedValue", elapsedValue); + }; + }); + await web.CreateClient().GetAsync("/resource"); + + Assert.NotEmpty(sink.Writes); + + var completionEvent = sink.Writes.First(logEvent => Matching.FromSource()(logEvent)); + + Assert.True((double)completionEvent.Properties["ElapsedValue"].LiteralValue()! > 0); + } + [Fact] public async Task RequestLoggingMiddlewareShouldEnrichWithCustomisedProperties() {