-
-
Save iamsingularity/266adb31acd68c9fad297d16ace75316 to your computer and use it in GitHub Desktop.
Owin Middleware Logging
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.IO; | |
using System.Threading.Tasks; | |
using Microsoft.Owin; | |
using NLog; // in this example, we use NLog | |
namespace net.github.gist.coenm | |
{ | |
public class LoggingMiddleware : OwinMiddleware | |
{ | |
private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); | |
public LoggingMiddleware(OwinMiddleware next) : base(next) | |
{ } | |
public override async Task Invoke(IOwinContext context) | |
{ | |
LogRequestResponseHelper.LogDebugRequest(Logger, context.Request); | |
var responseBody = ""; | |
if(Logger.IsTraceEnabled) //use trace for logging the response | |
{ | |
using (var captureResponseBody = new CaptureResponseBody(context)) | |
{ | |
await Next.Invoke(context); | |
responseBody = await captureResponseBody.GetBody(); | |
} | |
} | |
else | |
await Next.Invoke(context); | |
LogRequestResponseHelper.LogDebugResponse(Logger, context.Response); | |
if (Logger.IsTraceEnabled | |
&& !string.IsNullOrEmpty(context.Response.ContentType) && context.Response.ContentType.ToLower().StartsWith("application/json")) | |
LogRequestResponseHelper.LogTraceResponse(Logger, responseBody); | |
} | |
private class CaptureResponseBody : IDisposable | |
{ | |
// Response body is a write-only network stream by default for Katana hosts. | |
// You will need to replace context.Response.Body with a MemoryStream, | |
// read the stream, log the content and then copy the memory stream content | |
// back into the original network stream | |
private readonly Stream stream; | |
private readonly MemoryStream buffer; | |
public CaptureResponseBody(IOwinContext context) | |
{ | |
stream = context.Response.Body; | |
buffer = new MemoryStream(); | |
context.Response.Body = buffer; | |
} | |
public async Task<string> GetBody() | |
{ | |
buffer.Seek(0, SeekOrigin.Begin); | |
var reader = new StreamReader(buffer); | |
return await reader.ReadToEndAsync(); | |
} | |
public async void Dispose() | |
{ | |
await GetBody(); | |
// You need to do this so that the response we buffered | |
// is flushed out to the client application. | |
buffer.Seek(0, SeekOrigin.Begin); | |
await buffer.CopyToAsync(stream); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using Microsoft.Owin; | |
using NLog; // Using NLog in this example | |
namespace com.github.gist.coenm | |
{ | |
public static class LogRequestResponseHelper | |
{ | |
public static void LogDebugResponse(Logger logger, IOwinResponse response) | |
{ | |
if (!logger.IsDebugEnabled) | |
return; | |
MappedDiagnosticsContext.Clear(); | |
MappedDiagnosticsContext.Set("response.StatusCode", response.StatusCode.ToString()); | |
logger.Debug(String.Format("Response statuscode:'{0}'.", response.StatusCode)); | |
MappedDiagnosticsContext.Clear(); | |
} | |
public static void LogTraceResponse(Logger logger, string body) | |
{ | |
if (!logger.IsTraceEnabled) | |
return; | |
logger.Trace("Response body: {0}", body); | |
} | |
public static void LogDebugRequest(Logger logger, IOwinRequest request) | |
{ | |
if (!logger.IsDebugEnabled) | |
return; | |
MappedDiagnosticsContext.Clear(); | |
MappedDiagnosticsContext.Set("request.MediaType", request.MediaType); | |
MappedDiagnosticsContext.Set("request.Host", request.Host.ToString()); | |
MappedDiagnosticsContext.Set("request.ContentType", request.ContentType); | |
MappedDiagnosticsContext.Set("request.Scheme", request.Scheme); | |
MappedDiagnosticsContext.Set("request.Method", request.Method); | |
MappedDiagnosticsContext.Set("request.Path", request.Path.ToString()); | |
MappedDiagnosticsContext.Set("request.QueryString", request.QueryString.ToString()); | |
MappedDiagnosticsContext.Set("request.Accept", request.Accept); | |
var logMsg = string.Format("Request scheme:'{0}'; method:'{1}'; path:'{2}'; query:'{3}'; accept:'{4}'", | |
request.Scheme, | |
request.Method, | |
request.Path, | |
request.QueryString, | |
request.Accept); | |
logger.Debug(logMsg); | |
MappedDiagnosticsContext.Clear(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Linq; | |
using System.Net.Http.Formatting; | |
using System.Web.Http; | |
using Owin; | |
namespace com.github.gist.coen | |
{ | |
public class Startup | |
{ | |
private readonly Container container = new Container(); | |
public void Configuration(IAppBuilder appBuilder) | |
{ | |
// .... | |
appBuilder.Use<LoggingMiddleware>(); | |
// .... | |
} | |
} | |
} |
One more note: When used in a download scenario, reader.ReadToEndAsync (LoggingMiddleware line 59) reads the whole file downloaded into memory. This can fail with OutOfMemoryException if the file to download is big of size, e. g. 500 MB.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, great work. Helped a lot to resolve my problem. But one question:
LoggingMiddleware.cs Line 64, why do we need this inside Dispose method?