zoukankan      html  css  js  c++  java
  • .Net Core5.0使用中间件记录请求日志的注意事项

      前言:走进.net core5.0以后,我们会接触到中间件,中间件类似于程序的通道的一部分,也是进出程序所必须进过的一个环节。那么我们就可以利用中间件去记录程序所有相关的操作记录。

      1-Startup.cs配置中间件(注意中间件的放置位置,位置不同会影响日志数据的读取,也可能读不到想要的数据或抛出异常):

      我这里将中间件放到了路由中间件的下方(app.UseRouting())

    //启用日志中间件
    app.UseMiddleware<LogMiddleware>();

      

      2-创建日志分类特性:

    /// <summary>
        /// 日志特性类
        /// </summary>
        [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
        public class LogAttribute : Attribute
        {
            /// <summary>
            /// 日志类型
            /// </summary>
            public string LogType { get; set; }
    
            /// <summary>
            /// 指定创建人
            /// </summary>
            public string Creator { get; set; }
    
            /// <summary>
            /// 日志构造器
            /// </summary>
            /// <param name="logType">日志类型</param>
            public LogAttribute(string logType) : this(logType, null)
            {
            }
            /// <summary>
            /// 日志构造器
            /// </summary>
            /// <param name="logType">日志类型</param>
            public LogAttribute(string logType, string creator)
            {
                this.LogType = logType;
                this.Creator = creator;
            }
        }

      3-为方法添加合适的日志分类:

    [HttpPost]
    [Log(CrmLogType.ACTIVITY_COUPON_ADD)]
    public ActionResult AddCouponSave(VipCoupon vipCoupon, [FromServices] VipCouponRepository couponRepository)
    {
    }

      4-中间件核心代码(记录了request和response的结果响应,下面的代码并不完整,使用请调整):

    /// <summary>
        /// Log日志中间件
        /// </summary>
        public class LogMiddleware
        {
            private readonly RequestDelegate _next;
            private SystemOperationLogRepository _systemOperationLogRepository;
            private ILogger<LogMiddleware> _logger;
    
            public LogMiddleware(RequestDelegate next,
                SystemOperationLogRepository systemOperationLogRepository,
                ILogger<LogMiddleware> logger)
            {
                _next = next;
                this._systemOperationLogRepository = systemOperationLogRepository;
                this._logger = logger;
            }
    
            public async Task Invoke(HttpContext httpContext)
            {
                httpContext.Request.EnableBuffering();
    
                //这里会记录当前平台下所有方法上比较Log特性的操作日志
                Endpoint endpoint = httpContext.GetEndpoint();
                LogAttribute actionLogAttribute = endpoint?.Metadata.GetMetadata<LogAttribute>();
                if (actionLogAttribute != null)
                {
                    HttpRequest request = httpContext.Request;
                    HttpResponse response = httpContext.Response;
                    var originBody = response.Body;
                    using (var memoryStream = new MemoryStream())
                    {
                        response.Body = memoryStream;
                        await _next.Invoke(httpContext);
    
                        StreamReader requestStreamReader = null;
                        StreamReader responseStreamReader = null;
    
                        try
                        {
                            #region 获取request请求内容
    
                            string requestUrl = $"{request.Path.Value}{request.QueryString.Value}";
                            string requestContent = null;
    
                            if (request.HasFormContentType)
                            {
                                IFormCollection fromColl = request.Form;
                                requestContent += "{";
                                foreach (var item in fromColl)
                                {
                                    requestContent += $"{item.Key}:{item.Value},";
                                }
                                requestContent += requestContent.TrimEnd(',') + "}";
                            }
                            else if (request.HasJsonContentType())
                            {
                                request.Body.Seek(0, SeekOrigin.Begin);
                                requestStreamReader = new StreamReader(request.Body);
                                requestContent = await requestStreamReader.ReadToEndAsync();
                            }
    
                            #endregion
    
                            #region 获取response结果
    
                            JsonModel responseJsonModel = null;
                            memoryStream.Seek(0, SeekOrigin.Begin);
                            responseStreamReader = new StreamReader(memoryStream);
                            string responseBody = await responseStreamReader.ReadToEndAsync();
                            try
                            {
                                responseJsonModel = JsonHelper.ConvertStrToJson<JsonModel>(responseBody);
                            }
                            catch (Exception)
                            {
                            }
    
                            #endregion
    
                            #region 打印监控日志
    
                            ClaimsPrincipal user = httpContext.User;
                            string userName = actionLogAttribute.Creator;
                            if (userName.IsNullOrEmpty())
                            {
                                userName = user.FindFirst(ClaimTypes.Name)?.Value ?? "";
                            }
                            string logType = actionLogAttribute.LogType;
                            string logStatus = (responseJsonModel?.Success ?? false) ? "成功" : "失败";
                            string logContent = $"操作{logStatus}!操作内容:{requestContent}";
                            this._systemOperationLogRepository.AddSystemOperationLog(logType, logContent, requestUrl, userName);
    
                            #endregion
                        }
                        catch (Exception e)
                        {
                            this._logger.LogWarning(e, $"日志中间件出现异常,请及时处理:{e.Message}");
                        }
                        finally
                        {
                            #region 还原response流内容 && 释放资源
    
                            memoryStream.Seek(0, SeekOrigin.Begin);
                            await memoryStream.CopyToAsync(originBody);
                            response.Body = originBody;
                            response.Body.Seek(0, SeekOrigin.Begin);
    
                            if (responseStreamReader != null)
                            {
                                responseStreamReader.Close();
                                responseStreamReader.Dispose();
                            }
                            if (requestStreamReader != null)
                            {
                                requestStreamReader.Close();
                                requestStreamReader.Dispose();
                            }
                            request.Body.Close();
                            request.Body.Dispose();
    
                            #endregion
                        }
                    }
                }
                else
                {
                    await _next.Invoke(httpContext);
                }
            }
        }
    *感谢您的阅读。喜欢的、有用的就请大哥大嫂们高抬贵手“推荐一下”吧!你的精神 支持是博主强大的写作动力。欢迎转载!
    *博主的文章是自己平时开发总结的经验,由于博主的水平不高,不足和错误之处在所难免,希望大家能够批评指出。
    *我的博客: http://www.cnblogs.com/lxhbky/
  • 相关阅读:
    编写一个函数func(),将此函数的输入参数(int型)逆序输出显示,如54321 –> 12345,要求使用递归,并且函数体代码不超过8行
    java中两种单例模式
    springMVC配置freemarker 二(问题讨论篇)
    springMVC配置freemarker
    java中@value的环境配置
    java环境log4j日志环境的配置。
    websocket协议
    http报文和浏览器缓存机制
    详解网络连接
    编码总结
  • 原文地址:https://www.cnblogs.com/lxhbky/p/14608113.html
Copyright © 2011-2022 走看看