125 lines
5.1 KiB
C#
125 lines
5.1 KiB
C#
using IRaCIS.Core.API._PipelineExtensions.Serilog;
|
||
using IRaCIS.Core.Domain.Share;
|
||
using Microsoft.AspNetCore.Builder;
|
||
using Microsoft.AspNetCore.Hosting;
|
||
using Microsoft.AspNetCore.Http;
|
||
using Serilog;
|
||
using System.Linq;
|
||
using UAParser;
|
||
|
||
namespace IRaCIS.Core.API
|
||
{
|
||
|
||
|
||
public static class SerilogConfig
|
||
{
|
||
|
||
public static void UseSerilogConfig(this IApplicationBuilder app, IWebHostEnvironment env)
|
||
{
|
||
app.UseMiddleware<RequestResponseLoggingMiddleware>();
|
||
|
||
// 从 DI 容器中获取 Parser 实例
|
||
var uaParser = app.ApplicationServices.GetRequiredService<Parser>();
|
||
|
||
app.UseSerilogRequestLogging(opts
|
||
=>
|
||
{
|
||
|
||
opts.MessageTemplate = "{FullName} {UserType} {UserIp} {Host} {RequestMethod} {RequestPath}{QueryString} {RequestBody} {OS} {Browser} {DeviceType} responded {StatusCode} in {Elapsed:0.0000} ms";
|
||
|
||
opts.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>
|
||
{
|
||
|
||
var request = httpContext.Request;
|
||
|
||
// Set all the common properties available for every request
|
||
diagnosticContext.Set("Host", request.Host.Value);
|
||
|
||
|
||
// Only set it if available. You're not sending sensitive data in a querystring right?!
|
||
|
||
diagnosticContext.Set("QueryString", request.QueryString.Value ?? "");
|
||
|
||
|
||
diagnosticContext.Set("FullName", httpContext?.User?.FindFirst(JwtIRaCISClaimType.FullName)?.Value);
|
||
|
||
diagnosticContext.Set("UserType", httpContext?.User?.FindFirst(JwtIRaCISClaimType.UserTypeShortName)?.Value);
|
||
|
||
var clientIp = httpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault() ??
|
||
httpContext.Connection.RemoteIpAddress?.ToString();
|
||
|
||
if (clientIp.StartsWith("::ffff:"))
|
||
{
|
||
clientIp = clientIp.Substring(7); // 移除前缀
|
||
}
|
||
|
||
diagnosticContext.Set("UserIp", clientIp);
|
||
|
||
|
||
// ==================== 新增:解析 User-Agent ====================
|
||
try
|
||
{
|
||
var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
|
||
|
||
if (!string.IsNullOrEmpty(userAgent))
|
||
{
|
||
var clientInfo = uaParser.Parse(userAgent);
|
||
|
||
diagnosticContext.Set("OS", clientInfo.OS.ToString());
|
||
diagnosticContext.Set("Browser", clientInfo.UA.ToString());
|
||
//diagnosticContext.Set("DeviceType", clientInfo.Device.ToString());
|
||
diagnosticContext.Set("DeviceType", userAgent.Contains("Mobile") ? "Mobile": "Desktop");
|
||
|
||
}
|
||
else
|
||
{
|
||
diagnosticContext.Set("OS", "Unknown");
|
||
diagnosticContext.Set("Browser", "Unknown");
|
||
diagnosticContext.Set("DeviceType", "Unknown");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
// 解析失败时记录异常,但不要影响主流程
|
||
diagnosticContext.Set("OS", "ParseError");
|
||
diagnosticContext.Set("Browser", "ParseError");
|
||
diagnosticContext.Set("DeviceType", "ParseError");
|
||
}
|
||
// ==============================================================
|
||
|
||
#region 非必要不记录
|
||
//diagnosticContext.Set("Protocol", request.Protocol);
|
||
//diagnosticContext.Set("Scheme", request.Scheme);
|
||
//// Retrieve the IEndpointFeature selected for the request
|
||
//var endpoint = httpContext.GetEndpoint();
|
||
//if (endpoint is object) // endpoint != null
|
||
//{
|
||
// diagnosticContext.Set("EndpointName", endpoint.DisplayName);
|
||
//}
|
||
// Set the content-type of the Response at this point
|
||
//diagnosticContext.Set("ContentType", httpContext.Response.ContentType);
|
||
#endregion
|
||
|
||
|
||
#region old 未用
|
||
//这种获取的Ip不准 配置服务才行
|
||
//diagnosticContext.Set("RequestIP", httpContext.Connection.RemoteIpAddress.ToString());
|
||
|
||
//这种方式可以,但是serilog提供了 就不用了
|
||
//diagnosticContext.Set("TestIP", httpContext.GetUserIp());
|
||
|
||
//这种方式不行 读取的body为空字符串 必须在中间件中读取
|
||
//diagnosticContext.Set("RequestBody", await ReadRequestBody(httpContext.Request));
|
||
//diagnosticContext.Set("RequestBody", RequestPayload);
|
||
#endregion
|
||
|
||
|
||
};
|
||
});
|
||
|
||
|
||
|
||
}
|
||
}
|
||
}
|