diff --git a/src/Shared/Internal/HttpContextExtensions.cs b/src/Shared/Internal/HttpContextExtensions.cs
index 1d2b95ff..5fa13270 100644
--- a/src/Shared/Internal/HttpContextExtensions.cs
+++ b/src/Shared/Internal/HttpContextExtensions.cs
@@ -28,6 +28,22 @@ internal static HttpRequestBase TryGetRequest(this HttpContextBase context)
return null;
}
}
+
+ internal static HttpResponseBase TryGetResponse(this HttpContextBase context)
+ {
+ try
+ {
+ var response = context?.Response;
+ if (response == null)
+ InternalLogger.Debug("HttpContext Response Lookup returned null");
+ return response;
+ }
+ catch (HttpException ex)
+ {
+ InternalLogger.Debug(ex, "HttpContext Response Lookup failed.");
+ return null;
+ }
+ }
#else
internal static HttpRequest TryGetRequest(this HttpContext context)
{
@@ -36,6 +52,14 @@ internal static HttpRequest TryGetRequest(this HttpContext context)
InternalLogger.Debug("HttpContext Request Lookup returned null");
return request;
}
+
+ internal static HttpResponse TryGetResponse(this HttpContext context)
+ {
+ var response = context?.Response;
+ if (response == null)
+ InternalLogger.Debug("HttpContext Response Lookup returned null");
+ return response;
+ }
#endif
#if ASP_NET_CORE
diff --git a/src/Shared/LayoutRenderers/AspNetResponseStatusCodeRenderer.cs b/src/Shared/LayoutRenderers/AspNetResponseStatusCodeRenderer.cs
new file mode 100644
index 00000000..8a12f25a
--- /dev/null
+++ b/src/Shared/LayoutRenderers/AspNetResponseStatusCodeRenderer.cs
@@ -0,0 +1,42 @@
+using System.Text;
+using NLog.Config;
+using NLog.LayoutRenderers;
+using NLog.Web.Internal;
+
+namespace NLog.Web.LayoutRenderers
+{
+ ///
+ /// ASP.NET Response Status Code.
+ ///
+ /// Example usage of ${aspnet-response-statuscode}:
+ ///
+ ///
+ /// ${aspnet-response-statuscode} - Produces - 200.
+ ///
+ ///
+ [LayoutRenderer("aspnet-response-statuscode")]
+ [ThreadSafe]
+ public class AspNetResponseStatusCodeRenderer : AspNetLayoutRendererBase
+ {
+ ///
+ /// ASP.NET Http Response Status Code
+ ///
+ /// The to append the rendered data to.
+ /// Logging event.
+ protected override void DoAppend(StringBuilder builder, LogEventInfo logEvent)
+ {
+ var httpResponse = HttpContextAccessor.HttpContext.TryGetResponse();
+ if (httpResponse == null)
+ {
+ return;
+ }
+
+ int statusCode = httpResponse.StatusCode;
+
+ if (statusCode >= 100 && statusCode <= 599)
+ {
+ builder.Append(statusCode);
+ }
+ }
+ }
+}
diff --git a/tests/Shared/LayoutRenderers/AspNetResponseStatusCodeRendererTests.cs b/tests/Shared/LayoutRenderers/AspNetResponseStatusCodeRendererTests.cs
new file mode 100644
index 00000000..9d6e0360
--- /dev/null
+++ b/tests/Shared/LayoutRenderers/AspNetResponseStatusCodeRendererTests.cs
@@ -0,0 +1,49 @@
+using NLog.Web.LayoutRenderers;
+using NSubstitute;
+using Xunit;
+
+namespace NLog.Web.Tests.LayoutRenderers
+{
+ public class AspNetResponseStatusCodeRendererTests : LayoutRenderersTestBase
+ {
+ [Fact]
+ public void StatusCode_Set_Renderer()
+ {
+ // Arrange
+ var (renderer, httpContext) = CreateWithHttpContext();
+ httpContext.Response.StatusCode.Returns(200);
+
+ // Act
+ string result = renderer.Render(new LogEventInfo());
+
+ // Assert
+ Assert.Equal("200", result);
+ }
+
+ [Theory]
+ [InlineData(0, false)]
+ [InlineData(99, false)]
+ [InlineData(100, true)]
+ [InlineData(599, true)]
+ [InlineData(600, false)]
+ public void Only_Render_Valid_StatusCodes(int statusCode, bool shouldBeRendered)
+ {
+ // Arrange
+ var (renderer, httpContext) = CreateWithHttpContext();
+ httpContext.Response.StatusCode.Returns(statusCode);
+
+ // Act
+ string result = renderer.Render(new LogEventInfo());
+
+ // Assert
+ if (shouldBeRendered)
+ {
+ Assert.Equal($"{statusCode}", result);
+ }
+ else
+ {
+ Assert.Empty(result);
+ }
+ }
+ }
+}