HTTP Response Body Capture - NLog/NLog.Web GitHub Wiki
⚠️ HTTP Logging can potentially log personally identifiable information (PII). Consider the risk and avoid logging sensitive information.
Render the posted body, e.g. FORM or Ajax POST
Platforms Supported: All
Remarks
- Will buffer the input-stream (if allowed) and capture the posted-body as string-value in the HttpContext Items Dictionary.
- .NET6 introduces UseHttpLogging that also supports logging of HTTP Response Body.
ASP.NET Core Requirements
- NLog.Web.AspNetCore 5.1.0+
- Register
NLogResponseBodyMiddleware
as middleware in theConfigure
method ofStartup
class
Description
If you are using NLog.Web.AspNetCore, you may need to capture the HTTP response body. The library already supports the capture of the HTTP request body via the included NLogRequestPostedBodyMiddleware and the aspnet-request-posted-body layout renderer. We can capture the response body in a similar method with a similar middleware.
We have decided to include this in source code form only, as this requires the use of a NuGet package that NLog.Web.AspNetCore does not normally use, Microsoft.IO.RecyclableMemoryStream. The reason this library is utilized is in order to use a pool of MemoryStreams instead of constantly creating and destroying MemoryStream instances where one instance is required per response body capture.
The middleware, and its corresponding options class, are provided as attachments. There is an explanation of the options and usage below.
// needed for capture of the HTTP response body with an API Controller.
// The options default to only logging a maximum of 30KB.
// Also, only content types starting with ‘text/‘, or those ending with ‘xml’, ‘html’, ‘json’, or content types
// that have the word ‘charset’ are logged, since we desire to log strings and not binary content
// Those can be overridden in the options if necessary. But typically the default options should be adequate.
app.UseMiddleware<NLog.Web.NLogResponseBodyMiddleware>
(new NLog.Web.NLogResponseBodyMiddlewareOptions());
Full Example:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
// needed for HTTP response body with an API Controller.
app.UseMiddleware<NLog.Web.NLogResponseBodyMiddleware>(
new NLog.Web.NLogResponseBodyMiddlewareOptions());
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
NLogResponseBodyMiddleware Options
-
int MaxContentLength
- The maximum request posted body that will be captured. Defaults to 30 KB.
-
IList<KeyValuePair<string,string>> AllowContentTypes
- The Key is the prefix value such as ‘text’.
- The Value is the suffix value such as ‘html’.
- The default contents of this property are:
'application/', 'json'
'application/', 'xml'
'application/', 'html'
'text/', ''
'', 'charset'
-
Predicate<HttpContext> ShouldCapture()
- This indicates if the response body should be saved to a MemoryStream before continuing to the caller
- By default this method returns true
- At this point we do not know the response body content length since the logic that creates the response can not been executed at this point.
-
Predicate<HttpContext> ShouldRetain()
- This indicates if the contents of the MemoryStream, once captured, should be saved into a key/value pair in HttpContext.Items to be logged later.
- The key is 'nlog-aspnet-response-body'
- By default this method returns true if
- The content length is not null and is <= MaxContentLength
- The content type must match one of the entries in the AllowContentTypes List.
- For a match the ContentType must StartsWith the Key, case insensitive, and also have an IndexOf the Value, case insensitive.
- An empty string for the Key or for the Value acts as a wildcard match.
- The method has the HttpContext as the parameter, so a user wishing to override this property should have all the properties required to implement an override.