using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Logging; using Netmash.Logging.Api.Entities; using System; using System.Diagnostics; using System.IO; using System.Net; using System.Threading.Tasks; namespace Netmash.Logging.Api { public class RequestLoggingAttribute : ActionFilterAttribute { private readonly ILogger _logger; private readonly RequestLoggingConfiguration _requestLoggingConfiguration; public RequestLoggingAttribute(ILogger logger, RequestLoggingConfiguration requestLoggingConfiguration) { _logger = logger; _requestLoggingConfiguration = requestLoggingConfiguration; } public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { var stopWatch = new Stopwatch(); stopWatch.Start(); var uid = Guid.NewGuid(); var request = ((ControllerBase)context.Controller).Request; var requestUrl = request.Path; if (request.QueryString != null && request.QueryString.HasValue) requestUrl += request.QueryString.ToString(); var logContent = $"Start request {uid} for method {requestUrl}"; if (_requestLoggingConfiguration.LogBody && request.Method == WebRequestMethods.Http.Post) { var requestBody = await GetRequestBody(request); logContent += $" with body {requestBody}"; } _logger.LogInformation(logContent); var resultContext = await next(); stopWatch.Stop(); if (resultContext.Exception != null) _logger.LogError(resultContext.Exception, $"Request {uid} for method {requestUrl} failed - {resultContext.Exception.Message}"); _logger.LogInformation($"End request {uid} for method {requestUrl}"); _logger.LogDebug($"Request {uid} duration: {stopWatch.ElapsedMilliseconds:N0} ms"); } private async Task GetRequestBody(HttpRequest request) { if (request.ContentLength == 0) return "-"; using (var body = new StreamReader(request.Body)) { body.BaseStream.Seek(0, SeekOrigin.Begin); var bodyStr = await body.ReadToEndAsync(); return bodyStr; } } } }