You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

133 lines
5.3 KiB

10 months ago
using Microsoft.AspNetCore.Http.Extensions;
using Ocelot.RequestId;
using Serilog;
using System.Diagnostics;
using System.Text;
using Yitter.IdGenerator;
namespace HuiXin.Gateway.Ocelot.Middlewares
{
public class AccessLoggingMiddleware
{
private readonly RequestDelegate _next;
public AccessLoggingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var traceIdKey = DefaultRequestIdKey.Value;
var traceId = YitIdHelper.NextId().ToString();
context.TraceIdentifier = traceId;
context.Request.Headers[traceIdKey] = traceId;
var sw = Stopwatch.StartNew();
sw.Start();
var sb = new StringBuilder();
sb.AppendLine();
sb.AppendLine("-------------------Request Start-------------------");
sb.AppendLine(DateTime.Now.ToString());
sb.AppendLine($"追踪id:{traceId}");
sb.AppendLine($"地址:{context.Request.GetDisplayUrl()}");
sb.AppendLine("请求头:");
foreach (var header in context.Request.Headers)
{
sb.AppendLine($"{header.Key}:{header.Value}");
}
sb.AppendLine($"数据:{await GetRequestBody(context.Request)}");
sb.AppendLine("===================Request End===================");
Log.Information(sb.ToString());
sb.Clear();
//Copy a pointer to the original response body stream
var originalBodyStream = context.Response.Body;
//Create a new memory stream...
using var responseBody = new MemoryStream();
//...and use that for the temporary response body
context.Response.Body = responseBody;
//Continue down the Middleware pipeline, eventually returning to this class
await _next(context);
//Format the response from the server
//var response = await FormatResponse(context.Response);
sb.AppendLine();
sb.AppendLine("-------------------Response Start-------------------");
sb.AppendLine(DateTime.Now.ToString());
sb.AppendLine($"追踪id:{traceId}");
sb.AppendLine($"耗时:{sw.ElapsedMilliseconds}毫秒");
sb.AppendLine($"状态码:{context.Response.StatusCode}");
//sb.AppendLine("Headers: ");
//foreach (var header in context.Response.Headers)
//{
// sb.AppendLine($"{header.Key}:{header.Value}");
//}
sb.AppendLine($"数据:{await GetResponseBody(context.Response)}");
sb.AppendLine("===================Response End===================");
//Save log to chosen datastore
Log.Information(sb.ToString());
sb.Clear();
//Copy the contents of the new memory stream (which contains the response) to the original stream, which is then returned to the client.
await responseBody.CopyToAsync(originalBodyStream);
}
private static async Task<string> GetRequestBody(HttpRequest request)
{
request.EnableBuffering();
// Leave the body open so the next middleware can read it.
using var reader = new StreamReader(
request.Body,
encoding: Encoding.UTF8,
detectEncodingFromByteOrderMarks: false,
leaveOpen: true);
var body = await reader.ReadToEndAsync();
// Do some processing with body…
//var formattedRequest = $"{request.Scheme} {request.Host}{request.Path} {request.QueryString} {body}";
// Reset the request body stream position so the next middleware can read it
request.Body.Position = 0;
return body;
}
private static async Task<string> GetResponseBody(HttpResponse response)
{
//We need to read the response stream from the beginning...
response.Body.Seek(0, SeekOrigin.Begin);
//...and copy it into a string
string text = await new StreamReader(response.Body).ReadToEndAsync();
//We need to reset the reader for the response so that the client can read it.
response.Body.Seek(0, SeekOrigin.Begin);
//Return the string for the response, including the status code (e.g. 200, 404, 401, etc.)
//return $"{response.StatusCode}: {text}";
return text;
}
static AccessLoggingMiddleware()
{
// 创建 IdGeneratorOptions 对象,可在构造函数中输入 WorkerId:
var options = new IdGeneratorOptions();
// options.WorkerIdBitLength = 10; // 默认值6,限定 WorkerId 最大值为2^6-1,即默认最多支持64个节点。
// options.SeqBitLength = 6; // 默认值6,限制每毫秒生成的ID个数。若生成速度超过5万个/秒,建议加大 SeqBitLength 到 10。
// options.BaseTime = Your_Base_Time; // 如果要兼容老系统的雪花算法,此处应设置为老系统的BaseTime。
// ...... 其它参数参考 IdGeneratorOptions 定义。
// 保存参数(务必调用,否则参数设置不生效):
YitIdHelper.SetIdGenerator(options);
}
}
}