using Microsoft.AspNetCore.Connections; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using System; using System.Diagnostics; using System.IO; using System.Net; using System.Text; using System.Threading.Tasks; namespace FastGithub.ReverseProxy { /// /// 请求日志中间件 /// sealed class RequestLoggingMiddleware { private readonly ILogger logger; /// /// 请求日志中间件 /// /// public RequestLoggingMiddleware(ILogger logger) { this.logger = logger; } /// /// 执行请求 /// /// /// /// public async Task InvokeAsync(HttpContext context, RequestDelegate next) { var stopwatch = Stopwatch.StartNew(); try { await next(context); } finally { stopwatch.Stop(); } var request = context.Request; var response = context.Response; var message = $"{request.Method} {request.Scheme}://{request.Host}{request.Path} responded {response.StatusCode} in {stopwatch.Elapsed.TotalMilliseconds} ms"; var client = context.Connection.RemoteIpAddress; if (IPAddress.Loopback.Equals(client) == false) { message = $"{client} {message}"; } var exception = context.GetForwarderErrorFeature()?.Exception; if (exception == null) { this.logger.LogInformation(message); } else if (IsError(exception)) { this.logger.LogError($"{message}{Environment.NewLine}{exception}"); } else { this.logger.LogWarning($"{message}{Environment.NewLine}{GetMessage(exception)}"); } } /// /// 是否为错误 /// /// /// private static bool IsError(Exception exception) { if (exception is OperationCanceledException) { return false; } if (exception is IOException ioException && ioException.InnerException is ConnectionAbortedException) { return false; } return true; } /// /// 获取异常信息 /// /// /// private static string GetMessage(Exception exception) { var ex = exception; var builder = new StringBuilder(); while (ex != null) { var type = ex.GetType(); builder.Append(type.Namespace).Append(".").Append(type.Name).Append(": ").AppendLine(ex.Message); ex = ex.InnerException; } return builder.ToString(); } } }