using System; using System.IO; namespace WebApi.Restful.Middlewares { public class MemoryWrappedHttpResponseStream : MemoryStream { private Stream _innerStream; public MemoryWrappedHttpResponseStream(Stream innerStream) { this._innerStream = innerStream ?? throw new ArgumentNullException(nameof(innerStream)); } public override void Flush() { this._innerStream.Flush(); base.Flush(); } public override void Write(byte[] buffer, int offset, int count) { base.Write(buffer, offset, count); this._innerStream.Write(buffer, offset, count); } protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) { this._innerStream.Dispose(); } } public override void Close() { base.Close(); this._innerStream.Close(); } } }
using Exceptionless; using gateway.api; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; namespace WebApi.Restful.Middlewares {
/// <summary> /// 请求日志记录中间件 /// </summary> public class RequestLoggingMiddleware { private readonly RequestDelegate _next; private readonly ILogger _logger; public RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger) { _next = next; _logger = logger; } public async Task Invoke(HttpContext context) { context.TraceIdentifier = Guid.NewGuid().ToString("N"); var request = context.Request; await RequestEnableRewindAsync(request).ConfigureAwait(false); var encoding = GetRequestEncoding(request); var requestContent = await ReadStreamAsync(request.Body, encoding).ConfigureAwait(false); WritLog(context, JsonConvert.SerializeObject(requestContent)); await ResponseEnableRewindAsync(context.Response); context.Response.OnCompleted(ResponseCompletedCallback, context); await _next(context); } private async Task ResponseCompletedCallback(object obj) { if (obj is HttpContext context) { var response = await ResponseReadStreamAsync(context.Response);
//记录日志 //ExceptionlessClient.Default.CreateLog(JsonConvert.SerializeObject(response)).AddTags(context.TraceIdentifier).Submit(); } } private async Task<string> ResponseReadStreamAsync(HttpResponse response) { if (response.Body.Length > 0) { response.Body.Seek(0, SeekOrigin.Begin); var encoding = GetEncoding(response.ContentType); var retStr = await ReadStreamAsync(response.Body, encoding, false).ConfigureAwait(false); return retStr; } return null; } private async Task<string> ReadStreamAsync(Stream stream, Encoding encoding, bool forceSeekBeginZero = true) { using (StreamReader sr = new StreamReader(stream, encoding, true, 1024, true))//这里注意Body部分不能随StreamReader一起释放 { var str = await sr.ReadToEndAsync(); if (forceSeekBeginZero) { stream.Seek(0, SeekOrigin.Begin);//内容读取完成后需要将当前位置初始化,否则后面的InputFormatter会无法读取 } return str; } } private void WritLog(HttpContext context, string body) { var request = context.Request; try { Task.Factory.StartNew(() => { LogMode logMode = new LogMode { Body = body, CententLength = request.ContentLength, CententType = request.ContentType, Headers = JsonConvert.SerializeObject(request.Headers), Host = request.Host.Host, Method = request.Method, Path = request.Path, Query = JsonConvert.SerializeObject(request.Query) };
// 记录日志 // ExceptionlessClient.Default.CreateLog(JsonConvert.SerializeObject(logMode)).AddTags(context.TraceIdentifier).Submit(); }); } catch (Exception ex) {
//记录日志 //ex.ToExceptionless().Submit(); } } private async Task ResponseEnableRewindAsync(HttpResponse response) { if (!response.Body.CanRead || !response.Body.CanSeek) { response.Body = new MemoryWrappedHttpResponseStream(response.Body); } } private async Task RequestEnableRewindAsync(HttpRequest request) { if (!request.Body.CanSeek) { request.EnableBuffering(); await request.Body.DrainAsync(CancellationToken.None); request.Body.Seek(0L, SeekOrigin.Begin); } } private async Task<string> ReadStreamAsync(Stream stream, Encoding encoding) { using (StreamReader sr = new StreamReader(stream, encoding, true, 1024, true))//这里注意Body部分不能随StreamReader一起释放 { var str = await sr.ReadToEndAsync(); stream.Seek(0, SeekOrigin.Begin);//内容读取完成后需要将当前位置初始化,否则后面的InputFormatter会无法读取 return str; } } private Encoding GetRequestEncoding(HttpRequest request) { var requestContentType = request.ContentType; var requestMediaType = requestContentType == null ? default(MediaType) : new MediaType(requestContentType); var requestEncoding = requestMediaType.Encoding; if (requestEncoding == null) { requestEncoding = Encoding.UTF8; } return requestEncoding; } private Encoding GetEncoding(string contentType) { var mediaType = contentType == null ? default(MediaType) : new MediaType(contentType); var encoding = mediaType.Encoding; if (encoding == null) { encoding = Encoding.UTF8; } return encoding; } public class LogMode { public string Body { get; set; } public long? CententLength { get; set; } public string CententType { get; set; } public string Headers { get; set; } public string Host { get; set; } public string Method { get; set; } public string Path { get; set; } public string Query { get; set; } } private Dictionary<string, IEnumerable<string>> GetHeaders(HttpRequestMessage request) { var result = new Dictionary<string, IEnumerable<string>>(); foreach (var pair in request.Headers) { result.Add(pair.Key, pair.Value); } return result; } } }