From 8a60d9a3eaf8a7c8001acb1e3a8a229b0bf2750e Mon Sep 17 00:00:00 2001 From: zhaozhenjing Date: Mon, 15 Sep 2025 10:16:10 +0800 Subject: [PATCH] =?UTF-8?q?[INIT]=E4=B8=8A=E4=BC=A0log=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Helpers/Logs/ApiHelper.cs | 85 +++++++++ .../Helpers/Logs/ILogHandler.cs | 20 ++ .../Helpers/Logs/LogHandler.cs | 175 ++++++++++++++++++ 3 files changed, 280 insertions(+) create mode 100644 src/5.shared/ATS.NonCustodial.AdminUi/Helpers/Logs/ApiHelper.cs create mode 100644 src/5.shared/ATS.NonCustodial.AdminUi/Helpers/Logs/ILogHandler.cs create mode 100644 src/5.shared/ATS.NonCustodial.AdminUi/Helpers/Logs/LogHandler.cs diff --git a/src/5.shared/ATS.NonCustodial.AdminUi/Helpers/Logs/ApiHelper.cs b/src/5.shared/ATS.NonCustodial.AdminUi/Helpers/Logs/ApiHelper.cs new file mode 100644 index 0000000..4ecfe89 --- /dev/null +++ b/src/5.shared/ATS.NonCustodial.AdminUi/Helpers/Logs/ApiHelper.cs @@ -0,0 +1,85 @@ +using ATS.NonCustodial.Application.Contracts.Interfaces.Admins.Api; +using ATS.NonCustodial.Application.Contracts.Interfaces.Admins.Api.Output; +using ATS.NonCustodial.Shared.Common.Attributes; +using ATS.NonCustodial.Shared.Common.UnifiedResults; +using ATS.NonCustodial.Shared.Extensions; + +namespace ATS.NonCustodial.AdminUi.Helpers.Logs +{ + /// + /// Api帮助类 + /// + /// Author:mxg + /// CreatedTimed:2022-05-18 09:46 AM + [SingleInstance] + public class ApiHelper + { + #region Identity + + private List _apis; + private static readonly object LockObject = new(); + private readonly IApiService _apiService; + + public ApiHelper(IApiService apiService) + { + _apiService = apiService; + } + + #endregion Identity + + /// + /// 主要是在Action 操作的时候添加操作日志时候用 + /// + /// + public List GetApis() + { + if (_apis != null && _apis.Any()) return _apis; + + lock (LockObject) + { + if (_apis != null && _apis.Any()) return _apis; + + _apis = new List(); + + var apis = ((ResultOutput>)_apiService.GetListAsync("").Result) + .Data + .Select(a => new + { + a.Id, + a.ParentId, + a.Label, + a.Path + }); + + foreach (var api in apis) + { + var parentLabel = apis.FirstOrDefault(a => a.Id == api.ParentId)?.Label; + + _apis.Add(new ApiHelperDto + { + Label = parentLabel.NotNull() ? $"{parentLabel} / {api.Label}" : api.Label, + Path = api.Path?.ToLower().Trim('/') + }); + } + + return _apis; + } + } + } + + /// + /// + /// + public class ApiHelperDto + { + /// + /// 接口名称 + /// + public string Label { get; set; } + + /// + /// 接口地址 + /// + public string Path { get; set; } + } +} \ No newline at end of file diff --git a/src/5.shared/ATS.NonCustodial.AdminUi/Helpers/Logs/ILogHandler.cs b/src/5.shared/ATS.NonCustodial.AdminUi/Helpers/Logs/ILogHandler.cs new file mode 100644 index 0000000..3eacae8 --- /dev/null +++ b/src/5.shared/ATS.NonCustodial.AdminUi/Helpers/Logs/ILogHandler.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Mvc.Filters; + +namespace ATS.NonCustodial.AdminUi.Helpers.Logs +{ + /// + /// 操作日志处理接口 + /// + /// Author:mxg + /// CreatedTimed:2022-05-18 09:46 AM + public interface ILogHandler + { + /// + /// 写操作日志 + /// + /// + /// + /// + Task LogAsync(ActionExecutingContext context, ActionExecutionDelegate next); + } +} \ No newline at end of file diff --git a/src/5.shared/ATS.NonCustodial.AdminUi/Helpers/Logs/LogHandler.cs b/src/5.shared/ATS.NonCustodial.AdminUi/Helpers/Logs/LogHandler.cs new file mode 100644 index 0000000..267a1e7 --- /dev/null +++ b/src/5.shared/ATS.NonCustodial.AdminUi/Helpers/Logs/LogHandler.cs @@ -0,0 +1,175 @@ +using ATS.NonCustodial.Application.Contracts.Interfaces.Logs.OprationLog; +using ATS.NonCustodial.Application.Contracts.Interfaces.Logs.OprationLog.Input; +using ATS.NonCustodial.AuditLogging.AuditLoggings.Services; +using ATS.NonCustodial.Shared.Common.UnifiedResults; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using System.Diagnostics; +using System.Reflection; + +namespace ATS.NonCustodial.AdminUi.Helpers.Logs +{ + /// + /// 控制器操作日志记录 ==> 操作日志处理 + /// + /// Author:mxg + /// CreatedTimed:2022-05-18 09:46 AM + public class LogHandler : ILogHandler + { + #region Identity + + private readonly ILogger _logger; + private readonly ApiHelper _apiHelper; + private readonly IOperationLogService _operationLogService; + private readonly IAuditEventLogger _auditEventLogger; + + public LogHandler( + ILogger logger, + ApiHelper apiHelper, + IOperationLogService operationLogService, + IAuditEventLogger auditEventLogger + ) + { + _logger = logger; + _apiHelper = apiHelper; + _operationLogService = operationLogService; + _auditEventLogger = auditEventLogger; + } + + #endregion Identity + + /// + /// + /// + /// + /// + /// + public async Task LogAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + var sw = new Stopwatch(); + sw.Start(); + //调用接口 + var actionExecutedContext = await next(); + sw.Stop(); + + try + { + //接口Type + var controllerType = (context.ActionDescriptor as ControllerActionDescriptor)?.ControllerTypeInfo.AsType().GetSummary(); + + //方法信息 + var controllerAction = (context.ActionDescriptor as ControllerActionDescriptor)?.MethodInfo.GetSummary(); + + var input = new OprationLogAddInput + { + ApiLabel = $"{controllerType}/{controllerAction}".Trim('/'), + ApiMethod = context.HttpContext.Request.Method.ToLower(), + ApiPath = context.ActionDescriptor.AttributeRouteInfo?.Template?.ToLower(), + ElapsedMilliseconds = sw.ElapsedMilliseconds, + Params = JsonConvert.SerializeObject(context.ActionArguments) + }; + + if (actionExecutedContext.Result is ObjectResult { Value: IResultOutput res }) + { + input.Status = res.Success; + input.Msg = res.Msg; + } + + #region 设置参数 + + //switch (context.HttpContext.Request.Method) + //{ + // case "GET": + // case "DELETE": + // input.Params = context.HttpContext.Request.Path; + // break; + // case "PUT": + // case "POST": + // context.HttpContext.Request.EnableBuffering(); + // context.HttpContext.Request.Body.Position = 0; + // StreamReader reader = new StreamReader(context.HttpContext.Request.Body, Encoding.UTF8); + // input.Params = reader.ReadToEndAsync().GetAwaiter().GetResult(); + // context.HttpContext.Request.Body.Position = 0; + // break; + // default: break; + //} + //if (input.Params is { Length: > 1024 }) + //{ + // input.Params = input.Params.Substring(0, 1021) + "..."; + //} + + #endregion 设置参数 + + #region 设置返回值 + + try + { + if (actionExecutedContext.Exception != null && !actionExecutedContext.ExceptionHandled) + { + input.Exception = actionExecutedContext.Exception.StackTrace; + } + } + catch (Exception ex) + { + input.Exception = ex.StackTrace; + throw; + } + finally + { + if (input.Exception is { Length: > 2048 }) + { + input.Exception = input.Exception.Substring(0, 2045) + "..."; + } + + if (actionExecutedContext != null) + { + input.Result = actionExecutedContext.Result switch + { + ObjectResult objectResult => JsonConvert.SerializeObject(objectResult.Value), + JsonResult jsonResult => JsonConvert.SerializeObject(jsonResult.Value), + ContentResult contentResult => contentResult.Content, + _ => input.Result + }; + if (input.Result is { Length: > 2048 }) + { + input.Result = input.Result.Substring(0, 2045) + "..."; + } + } + } + + #endregion 设置返回值 + + //接口名称 + //input.ApiLabel = _apiHelper.GetApis().FirstOrDefault(a => a.Path == input.ApiPath)?.Label; + + //添加操作日志 + await _operationLogService.AddAsync(input); + + #region 添加审计日志 + + //var apiAuditLog = new CustomizedLogEvent() + //{ + // Category = nameof(CustomizedLogEvent), + // SubjectType = AuditSubjectTypes.machine, + // SubjectName = Environment.MachineName, + // SubjectIdentifier = Environment.MachineName, + // Action = new { Method = input.ApiPath, Class = context.Controller.ToString() } + //}; + //await _auditEventLogger.LogEventAsync(apiAuditLog, options => + //{ + // options.UseDefaultSubject = false; + // options.UseDefaultAction = false; + //}); + + #endregion 添加审计日志 + } + catch (Exception ex) + { + _logger.LogError("操作日志插入异常:{@ex}", ex); + } + } + } +} \ No newline at end of file