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;
}
}
}
}