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
|
{
|
/// <summary>
|
/// 日志中间件
|
/// </summary>
|
public class LogMiddleware
|
{
|
private readonly RequestDelegate _next;
|
private static readonly object LogMiddlewareLock = new object();
|
|
/// <summary>
|
/// 构造函数
|
/// </summary>
|
/// <param name="next"></param>
|
public LogMiddleware(RequestDelegate next)
|
{
|
_next = next;
|
}
|
|
/// <summary>
|
/// HttpContext响应
|
/// </summary>
|
/// <param name="context"></param>
|
/// <returns></returns>
|
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);
|
}
|
}
|
}
|
|
/// <summary>
|
/// HttpContext 日志
|
/// </summary>
|
public class HttpContextLog
|
{
|
/// <summary>
|
/// 构造函数
|
/// </summary>
|
/// <param name="writelock"></param>
|
public HttpContextLog(object writelock)
|
{
|
_writelock = writelock;
|
}
|
private object _writelock;
|
/// <summary>
|
/// ID
|
/// </summary>
|
public string ID { get; set; }
|
/// <summary>
|
/// LocalHost
|
/// </summary>
|
public string LocalHost { get; set; }
|
/// <summary>
|
/// RemoteAddress
|
/// </summary>
|
public string RemoteAddress { get; set; }
|
/// <summary>
|
/// Url
|
/// </summary>
|
public string Url { get; set; }
|
/// <summary>
|
/// Headers
|
/// </summary>
|
public IDictionary<string, string> HeaderDic { get; set; } = new Dictionary<string, string>();
|
/// <summary>
|
/// Header
|
/// </summary>
|
public string Header { get => $"[{string.Join(",", this.HeaderDic.Select(i => "{" + $"\"{i.Key}\":\"{i.Value}\"" + "}"))}"; }
|
/// <summary>
|
/// Method
|
/// </summary>
|
public string Method { get; set; }
|
/// <summary>
|
/// RequestBody
|
/// </summary>
|
public string RequestBody { get; set; }
|
/// <summary>
|
/// ResponseBody
|
/// </summary>
|
public string ResponseBody { get; set; }
|
/// <summary>
|
/// Status
|
/// </summary>
|
public string Status { get; set; }
|
/// <summary>
|
/// ExcuteStartTime
|
/// </summary>
|
public DateTime ExcuteStartTime { get; set; }
|
/// <summary>
|
/// ExcuteEndTime
|
/// </summary>
|
public DateTime ExcuteEndTime { get; set; }
|
/// <summary>
|
/// ElapsedTime
|
/// </summary>
|
public double ElapsedTime { get => (ExcuteEndTime - ExcuteStartTime).TotalSeconds; }
|
/// <summary>
|
/// 重构ToString
|
/// </summary>
|
/// <returns></returns>
|
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")}";
|
}
|
/// <summary>
|
/// RequestToString
|
/// </summary>
|
/// <returns></returns>
|
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;
|
}
|
}
|
/// <summary>
|
/// ResponseToString
|
/// </summary>
|
/// <returns></returns>
|
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;
|
}
|
}
|
}
|
}
|