using System; using System.IO; using System.Linq; using System.Threading.Tasks; using System.Text; using System.Threading; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using System.Collections.Generic; using Rhea.Common; using System.Net; using Tiger.IBusiness; namespace Tiger.Api { /// /// 日志中间件 /// public class LogMiddleware { private readonly RequestDelegate _next; private static readonly object LogMiddlewareLock = new object(); /// /// 构造函数 /// /// public LogMiddleware(RequestDelegate next) { _next = next; } /// /// HttpContext响应 /// /// /// public async Task InvokeAsync(HttpContext context) { var hcLog = new HttpContextLog(LogMiddlewareLock);//new object());// hcLog.ID = $"{context.TraceIdentifier} at {DateTime.Now:yyyy/MM/dd HH:mm:ss.fff}"; hcLog.LocalHost = context.Request.Host.ToString(); hcLog.RemoteAddress = $"[{context.Connection.RemoteIpAddress}]:{context.Connection.RemotePort}"; HttpRequest request = context.Request; hcLog.Url = request.Path.ToString(); hcLog.HeaderDic = request.Headers.ToDictionary(k => k.Key, v => string.Join(";", v.Value.ToList())); hcLog.Method = request.Method; hcLog.ExcuteStartTime = DateTime.Now; if (hcLog.Url.StartsWith("/api") && !request.Method.ToLower().Equals("options")) { //获取Request.Body内容 if (request.Method.ToLower().Equals("post")) { request.EnableBuffering(); //启用多次读取 Stream stream = request.Body; byte[] buffer = new byte[request.ContentLength.Value]; await request.Body.ReadAsync(buffer, 0, buffer.Length); //_logInfo.RequestBody = Encoding.UTF8.GetString(buffer); hcLog.RequestBody = Encoding.Default.GetString(buffer); request.Body.Position = 0; } else if (request.Method.ToLower().Equals("get")) { hcLog.RequestBody = request.QueryString.Value; } //hcLog.LogRequest(); Task.Run(() => { hcLog.LogRequest(); }); // 响应完成记录时间和存入日志 context.Response.OnCompleted(() => { hcLog.ExcuteEndTime = DateTime.Now; //hcLog.LogResponse(); Task.Run(() => { hcLog.LogResponse(); }); return Task.CompletedTask; }); //获取Response.Body内容 var originalBodyStream = context.Response.Body; using (var responseBody = new MemoryStream()) { try { context.Response.Body = responseBody; await _next(context); responseBody.Position = 0; var responseContent = await new StreamReader(context.Response.Body).ReadToEndAsync(); hcLog.ResponseBody = responseContent; hcLog.Status = $"{((HttpStatusCode)context.Response.StatusCode).ToString()}[{context.Response.StatusCode.ToString()}]"; } catch (System.Exception ex) { Logger.Default.Fatal(ex, $"Request[{hcLog.ID}][{hcLog.RemoteAddress}][{hcLog.Url}]处理异常"); hcLog.ResponseBody = ex.Message; hcLog.Status = $"{HttpStatusCode.InternalServerError}[{(int)HttpStatusCode.InternalServerError}]"; } responseBody.Position = 0; await responseBody.CopyToAsync(originalBodyStream); } } else { await _next(context); } } } /// /// HttpContext 日志 /// public class HttpContextLog { /// /// 构造函数 /// /// public HttpContextLog(object writelock) { _writelock = writelock; } private object _writelock; /// /// ID /// public string ID { get; set; } /// /// LocalHost /// public string LocalHost { get; set; } /// /// RemoteAddress /// public string RemoteAddress { get; set; } /// /// Url /// public string Url { get; set; } /// /// Headers /// public IDictionary HeaderDic { get; set; } = new Dictionary(); /// /// Header /// public string Header { get => $"[{string.Join(",", this.HeaderDic.Select(i => "{" + $"\"{i.Key}\":\"{i.Value}\"" + "}"))}"; } /// /// Method /// public string Method { get; set; } /// /// RequestBody /// public string RequestBody { get; set; } /// /// ResponseBody /// public string ResponseBody { get; set; } /// /// Status /// public string Status { get; set; } /// /// ExcuteStartTime /// public DateTime ExcuteStartTime { get; set; } /// /// ExcuteEndTime /// public DateTime ExcuteEndTime { get; set; } /// /// ElapsedTime /// public double ElapsedTime { get => (ExcuteEndTime - ExcuteStartTime).TotalSeconds; } /// /// 重构ToString /// /// public override string ToString() { string headers = "[" + string.Join(",", this.HeaderDic.Select(i => "{" + $"\"{i.Key}\":\"{i.Value}\"" + "}")) + "]"; return $"Url: {this.Url},\r\nHeaders: {headers},\r\nMethod: {this.Method},\r\nRequestBody: {this.RequestBody},\r\nResponseBody: {this.ResponseBody},\r\nExcuteStartTime: {this.ExcuteStartTime.ToString("yyyy-MM-dd HH:mm:ss.fff")},\r\nExcuteEndTime: {this.ExcuteEndTime.ToString("yyyy-MM-dd HH:mm:ss.fff")}"; } /// /// RequestToString /// /// public string LogRequest() { lock (_writelock) { ConsoleExt.WriteLine($"Request Form Address {RemoteAddress}|ID: {ID}", ConsoleColor.Yellow); ConsoleExt.WriteLine("{"); ConsoleExt.Write($" Url: "); ConsoleExt.Write(Url, ConsoleColor.Green); ConsoleExt.Write($" (Method: "); ConsoleExt.Write(Method, ConsoleColor.Green); ConsoleExt.WriteLine(")"); ConsoleExt.Write($" Version: "); ConsoleExt.WriteLine((HeaderDic.ContainsKey("version_id") ? HeaderDic["version_id"] : ""), ConsoleColor.Green); ConsoleExt.Write($" RequestBody: "); ConsoleExt.WriteLine(RequestBody, ConsoleColor.Gray); ConsoleExt.Write($" ExcuteTime: "); ConsoleExt.WriteLine(ExcuteStartTime.ToString("yyyy-MM-dd HH:mm:ss.fff"), ConsoleColor.Gray); ConsoleExt.WriteLine("}"); ConsoleExt.WriteLine(""); var content = @$"Api Request: {ID} Request IP: {RemoteAddress} Method: {Method} {(HeaderDic.ContainsKey("version_id")? $" Version: {HeaderDic["version_id"]}" : "")} Url: {Url} RequestBody: {(!RequestBody.IsNullOrEmpty() && RequestBody.Length > 30000 ? RequestBody[..30000] + "......" : RequestBody)} ExcuteTime: {ExcuteStartTime:yyyy-MM-dd HH:mm:ss.fff}"; //Logger.Http.Info(content); Task.Run(() => { Logger.Http.Info(content); }); return content; } } /// /// ResponseToString /// /// public string LogResponse() { lock (_writelock) { ConsoleExt.WriteLine($"Response To Address {RemoteAddress}|ID: {ID}", ConsoleColor.Cyan); ConsoleExt.WriteLine("{"); ConsoleExt.Write($" Url: "); ConsoleExt.Write(Url, ConsoleColor.Green); ConsoleExt.Write($" (Method: "); ConsoleExt.Write(Method, ConsoleColor.Green); ConsoleExt.WriteLine(")"); ConsoleExt.Write($" Status: "); ConsoleExt.WriteLine(Status, ConsoleColor.Gray); ConsoleExt.Write($" ResponseBody: "); ConsoleExt.WriteLine(ResponseBody.Length > 1000 && !ResponseBody.Contains("Catch ApiAction Exception") && !ResponseBody.Contains("Catch Result Exception") ? ResponseBody[..1000] + "......" : ResponseBody, ((ResponseBody ?? "").Contains("\"IsSuccessed\":false") || (ResponseBody ?? "").Contains("\"StatusCode\":400")) ? ConsoleColor.Magenta : ConsoleColor.Gray); ConsoleExt.Write($" ElapsedTime: "); ConsoleExt.Write($"Total "); ConsoleExt.Write(ElapsedTime.ToString(), ConsoleColor.Green); ConsoleExt.WriteLine($" seconds", ConsoleColor.Gray); ConsoleExt.Write($" ExcuteTime: "); ConsoleExt.WriteLine(ExcuteEndTime.ToString("yyyy-MM-dd HH:mm:ss.fff"), ConsoleColor.Gray); ConsoleExt.WriteLine("}"); ConsoleExt.WriteLine(""); var content = @$"Api Response: {ID} Response IP: {RemoteAddress} Method: {Method} Url: {Url} Status: {Status} ResponseBody: {((ResponseBody.Length > 10000 && !ResponseBody.Contains("Catch ApiAction Exception") && !ResponseBody.Contains("Catch Result Exception")) ? ResponseBody[..10000] + "......" : (ResponseBody.Length > 30000 ? ResponseBody[..30000] + "......" : ResponseBody))} ElapsedTime: Total {ElapsedTime} seconds ExcuteTime: {ExcuteEndTime:yyyy-MM-dd HH:mm:ss.fff}"; //Logger.Http.Info(content); Task.Run(() => { Logger.Http.Info(content); }); return content; } } } }