core中间件全局日志
参考学习项目zradmin
在Configure中配置请求参数缓存
//使可以多次多去body内容 app.Use((context, next) => { context.Request.EnableBuffering(); return next();//请求通道走向下一步 });
在ConfigureServices配置中间件
services.AddMvc(options => { options.Filters.Add(typeof(GlobalActionMonitor));//全局注册 })
中间件
public class GlobalActionMonitor : ActionFilterAttribute { static readonly Logger logger = LogManager.GetCurrentClassLogger(); private ISysOperLogService OperLogService; public GlobalActionMonitor(ISysOperLogService operLogService) { OperLogService = operLogService; } /// <summary> /// Action请求前 /// </summary> /// <param name="context"></param> /// <param name="next"></param> /// <returns></returns> public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { ApiResult response = new(); response.Code = (int)ResultCode.PARAM_ERROR; var values = context.ModelState.Values; foreach (var item in values) { foreach (var err in item.Errors) { if (err.ErrorMessage.Contains("JSON")) { return next(); } if (!string.IsNullOrEmpty(response.Msg)) { response.Msg += " | "; } response.Msg += err.ErrorMessage; } } if (!string.IsNullOrEmpty(response.Msg)) { logger.Info($"请求参数错误,{response.Msg}"); context.Result = new JsonResult(response); } return base.OnActionExecutionAsync(context, next); } /// <summary> /// OnActionExecuted是在Action中的代码执行之后运行的方法。 /// </summary> /// <param name="context"></param> public override void OnResultExecuted(ResultExecutedContext context) { if (context.ActionDescriptor is not ControllerActionDescriptor controllerActionDescriptor) return; //获得注解信息 LogAttribute logAttribute = GetLogAttribute(controllerActionDescriptor); if (logAttribute == null) return; try { string method = context.HttpContext.Request.Method.ToUpper(); // 获取当前的用户 string userName = context.HttpContext.GetName(); string jsonResult = string.Empty; if (context.Result is ContentResult result && result.ContentType == "application/json") { jsonResult = result.Content.Replace("\r\n", "").Trim(); } if (context.Result is JsonResult result2) { jsonResult = result2.Value?.ToString(); } //获取当前执行方法的类名 //string className = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name; //获取当前成员的名称 //string methodName = System.Reflection.MethodBase.GetCurrentMethod().Name; string controller = context.RouteData.Values["Controller"].ToString(); string action = context.RouteData.Values["Action"].ToString(); string ip = HttpContextExtension.GetClientUserIp(context.HttpContext); var ip_info = IpTool.Search(ip); SysOperLog sysOperLog = new() { status = 0, operName = userName, operIp = ip, operUrl = HttpContextExtension.GetRequestUrl(context.HttpContext), requestMethod = method, jsonResult = jsonResult, operLocation = ip_info.Province + " " + ip_info.City, method = controller + "." + action + "()", //Elapsed = _stopwatch.ElapsedMilliseconds, operTime = DateTime.Now }; HttpContextExtension.GetRequestValue(context.HttpContext, sysOperLog); if (logAttribute != null) { sysOperLog.title = logAttribute?.Title; sysOperLog.businessType = (int)logAttribute?.BusinessType; sysOperLog.operParam = logAttribute.IsSaveRequestData ? sysOperLog.operParam : ""; sysOperLog.jsonResult = logAttribute.IsSaveResponseData ? sysOperLog.jsonResult : ""; } LogEventInfo ei = new(LogLevel.Info, "GlobalActionMonitor", ""); ei.Properties["jsonResult"] = !HttpMethods.IsGet(method) ? jsonResult : ""; ei.Properties["requestParam"] = sysOperLog.operParam; ei.Properties["user"] = userName; logger.Log(ei); OperLogService.InsertOperlog(sysOperLog); } catch (Exception ex) { logger.Error(ex, $"记录操作日志出错了#{ex.Message}"); } } private LogAttribute GetLogAttribute(ControllerActionDescriptor controllerActionDescriptor) { var attribute = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true) .FirstOrDefault(a => a.GetType().Equals(typeof(LogAttribute))); return (LogAttribute)attribute; } }
方法上的日志特性
/// <summary> /// 自定义操作日志记录注解 /// </summary> public class LogAttribute : System.Attribute { public string Title { get; set; } public BusinessType BusinessType { get; set; } /// <summary> /// 是否保存请求数据 /// </summary> public bool IsSaveRequestData { get; set; } = true; /// <summary> /// 是否保存返回数据 /// </summary> public bool IsSaveResponseData { get; set; } = true; public LogAttribute() { } public LogAttribute(string name) { Title = name; } public LogAttribute(string name, BusinessType businessType, bool saveRequestData = true, bool saveResponseData = true) { Title = name; BusinessType = businessType; IsSaveRequestData = saveRequestData; IsSaveResponseData = saveResponseData; } }
使用方式
上下网络获取
/// <summary> /// HttpContext扩展类 /// </summary> public static class HttpContextExtension { /// <summary> /// 是否是ajax请求 /// </summary> /// <param name="request"></param> /// <returns></returns> public static bool IsAjaxRequest(this HttpRequest request) { if (request == null) { throw new ArgumentNullException(nameof(request)); } //return request.Headers.ContainsKey("X-Requested-With") && // request.Headers["X-Requested-With"].Equals("XMLHttpRequest"); return request.Headers["X-Requested-With"] == "XMLHttpRequest" || (request.Headers != null && request.Headers["X-Requested-With"] == "XMLHttpRequest"); } /// <summary> /// 获取客户端IP /// </summary> /// <param name="context"></param> /// <returns></returns> public static string GetClientUserIp(this HttpContext context) { if (context == null) return ""; var result = context.Request.Headers["X-Forwarded-For"].FirstOrDefault(); if (string.IsNullOrEmpty(result)) { result = context.Connection.RemoteIpAddress.ToString(); } if (string.IsNullOrEmpty(result) || result.Contains("::1")) result = "127.0.0.1"; result = result.Replace("::ffff:", "127.0.0.1"); result = IsIP(result) ? result : "127.0.0.1"; return result; } public static bool IsIP(string ip) { return Regex.IsMatch(ip, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$"); } public static long GetUId(this HttpContext context) { var uid = context.User.FindFirstValue(ClaimTypes.PrimarySid); return !string.IsNullOrEmpty(uid) ? long.Parse(uid) : 0; } public static string GetName(this HttpContext context) { var uid = context.User?.Identity?.Name; return uid; } public static bool IsAdmin(this HttpContext context) { long id = GetUId(context); return id == 1; } /// <summary> /// ClaimsIdentity /// </summary> /// <param name="context"></param> /// <returns></returns> public static IEnumerable<ClaimsIdentity> GetClaims(this HttpContext context) { return context.User?.Identities; } //public static int GetRole(this HttpContext context) //{ // var roleid = context.User.FindFirstValue(ClaimTypes.Role) ?? "0"; // return int.Parse(roleid); //} public static string GetUserAgent(this HttpContext context) { return context.Request.Headers["User-Agent"]; } /// <summary> /// 获取请求令牌 /// </summary> /// <param name="context"></param> /// <returns></returns> public static string GetToken(this HttpContext context) { return context.Request.Headers["Authorization"]; } public static ClientInfo GetClientInfo(this HttpContext context) { var str = GetUserAgent(context); var uaParser = Parser.GetDefault(); ClientInfo c = uaParser.Parse(str); return c; } public static string GetRequestUrl(this HttpContext context) { return context != null ? context.Request.Path.Value : ""; } /// <summary> /// 设置请求参数 /// </summary> /// <param name="operLog"></param> /// <param name="context"></param> public static void GetRequestValue(this HttpContext context, SysOperLog operLog) { string reqMethod = operLog.requestMethod; string param; if (HttpMethods.IsPost(reqMethod) || HttpMethods.IsPut(reqMethod)) { context.Request.Body.Seek(0, SeekOrigin.Begin); using var reader = new StreamReader(context.Request.Body, Encoding.UTF8); //需要使用异步方式才能获取 param = reader.ReadToEndAsync().Result; } else { param = context.Request.QueryString.Value.ToString(); } operLog.operParam = param; } }
这样一个全局异常就搞定了