.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);
            }
        }
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM