.Net5 框架搭建(三):基于ExceptionFilter+NLog封装异常日志收集

前言

在我们项目开发测试过程中,有时候本地调试环境可能没问题,一部署到正式环境就可能出现各种问题,错误的原因各种各样,那么我们怎么准确的定位到错误呢,这时候就需要弄个可以监听这些业务功能的错误日志,但是又得要全局。这时候贴心的.net已经帮我们想到一种方案了,那就是Filter-过滤器,官网也叫筛选器,字面意思都差不多。

Filter-过滤器

Filter是延续ASP.NET MVC的产物,同样保留了五种的Filter,分别是Authorization Filter、Resource Filter、Action Filter、Exception Filter及Result Filter。 通过不同的Filter可以有效处理封包进出的加工。

更多细项介绍以及一些过滤器之间的优先级别可以参考官网文档:《ASP.NET Core 中的筛选器

自定义新建一个ExceptionFilter

GlobalExceptionsFilter.cs

using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;

namespace CuoDing.Core.Filter
{
    /// <summary>
    /// 全局异常错误日志
    /// </summary>
    public class GlobalExceptionsFilter : IExceptionFilter
    {
        private readonly IWebHostEnvironment _env;
        private readonly ILogger<GlobalExceptionsFilter> _logger;

        public GlobalExceptionsFilter(IWebHostEnvironment env, ILogger<GlobalExceptionsFilter> logger)
        {
            _env = env;
            _logger = logger;
        }

        public void OnException(ExceptionContext context)
        {
            var json = new JsonErrorResponse();

            json.Message = context.Exception.Message;//错误信息
            var errorAudit = "Unable to resolve service for";//特殊错误信息
            if (!string.IsNullOrEmpty(json.Message)&& json.Message.Contains(errorAudit))
            {
                json.Message = json.Message.Replace(errorAudit, $"(若新添加服务,需要重新编译项目){errorAudit}");
            }

            if (_env.IsDevelopment())
            {
                json.DevelopmentMessage = context.Exception.StackTrace;//堆栈信息
            }
            context.Result = new InternalServerErrorObjectResult(json);

            //输出错误日志信息
            //_logger.LogError(json.Message + WriteLog(json.Message, context.Exception));
            _logger.LogError(json.Message + string.Format("\r\n【自定义错误】:{0} \r\n【异常类型】:{1} \r\n【异常信息】:{2} \r\n【堆栈调用】:{3}", new object[] { json.Message,
                context.Exception.GetType().Name, context.Exception.Message, context.Exception.StackTrace }));


        }

    }
    public class InternalServerErrorObjectResult : ObjectResult
    {
        public InternalServerErrorObjectResult(object value) : base(value)
        {
            StatusCode = StatusCodes.Status500InternalServerError;
        }
    }
    //返回错误信息
    public class JsonErrorResponse
    {
        /// <summary>
        /// 生产环境的消息
        /// </summary>
        public string Message { get; set; }
        /// <summary>
        /// 开发环境的消息
        /// </summary>
        public string DevelopmentMessage { get; set; }
    }

}

注册过滤器

1、ServiceFilter 注册
在需要拦截的地方增加特性 [ServiceFilter(typeof(GlobalExceptionsFilter))] 并在ConfigureServices 中注册GlobalExceptionsFilter

 services.AddScoped(typeof(GlobalExceptionsFilter));

2、TypeFilter 注册
在需要拦截的地方增加特性 [TypeFilter(typeof(GlobalExceptionsFilter))] 此方式不需要在ConfigureServices 中注册

3、FilterFactory 注册
3.1编写Factory 类

    public class ExpertFilterFactory : Attribute,IFilterFactory
    {
        public bool IsReusable => true;
        public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
        {
            return serviceProvider.GetService(typeof(GlobalExceptionsFilter)) as IFilterMetadata;
        }
    }

3.2在需要拦截的地方增加特性 [ExpertFilterFactory] 并在ConfigureServices 中注册GlobalExceptionsFilter

services.AddScoped(typeof(GlobalExceptionsFilter));

4、全局注册
在ConfigureServices中注册

services.AddControllers(options =>
{
   //添加全局异常过滤器
   options.Filters.Add<GlobalExceptionsFilter>();
});

对AddControllers陌生的小伙伴可以看看这篇博友「7号南孚电池」写的文章,感觉介绍十分详细:《AddMvcCore,AddControllers,AddControllersWithViews,AddRazorPages的区别

加入Nlog记录日志信息

1、添加nuget包

    <PackageReference Include="NLog" Version="4.7.10" />
    <PackageReference Include="NLog.Web.AspNetCore" Version="4.12.0" />

2、添加nlog配置文件nlog.config

<?xml version="1.0" encoding="utf-8"?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" autoReload="true" internalLogLevel="Info">
  <!-- 启用.net core的核心布局渲染器 -->
  <extensions>
    <add assembly="NLog.Web.AspNetCore" />
  </extensions>
  <!-- 写入日志的目标配置 archiveAboveSize="102400" maxArchiveDays="60" -->
  <targets>
    <!-- 调试  -->
    <target xsi:type="File" name="debug" fileName="${basedir}/logs/debug-${shortdate}.log" layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" />
    <!-- 警告  -->
    <target xsi:type="File" name="warn" fileName="${basedir}/logs/warn-${shortdate}.log" layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" />
    <!-- 错误  -->
    <target xsi:type="File" name="error" fileName="${basedir}/logs/error-${shortdate}.log" layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" />
    <!-- 控制台  -->
    <target xsi:type="Console" name="console" layout="${message}" />
  </targets>
  <!-- 映射规则 -->
  <rules>
    <!-- 调试  -->
    <logger name="*" minlevel="Trace" maxlevel="Debug" writeTo="debug" />
    <!--<logger name="*" minlevel="Trace" writeTo="console" />-->
    <!-- 警告  -->
    <!--<logger name="*" minlevel="Info" maxlevel="Warn" writeTo="warn" />-->
    <!-- 错误  -->
    <logger name="*" minlevel="Error" maxlevel="Fatal" writeTo="error" />
    <!--跳过不重要的微软日志-->
    <logger name="Microsoft.*" maxlevel="Info" final="true" />
  </rules>
</nlog>

3、Program修改
注入Nlog

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .UseServiceProviderFactory(new AutofacServiceProviderFactory())//替换默认容器
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                }).UseNLog();  // NLog: 为依赖注入设置NLog

监听程序启动过程

        public static void Main(string[] args)
        {
            var logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
            try
            {
                logger.Debug("初始化 main");
                CreateHostBuilder(args).Build().Run();
            }
            catch (Exception exception)
            {
                //NLog: 捕获设置错误
                logger.Error(exception, "由于异常而停止程序");
                throw;
            }
            finally
            {
                // 确保在应用程序退出之前刷新并停止内部计时器/线程(避免Linux上出现分段错误)
                NLog.LogManager.Shutdown();
            }
        }

测试

测试一:
webapi项目运行
在这里插入图片描述
测试二:
把之前的autofac容器的方法暂时注释掉,用来测试之前接口报错信息
在这里插入图片描述
期望接口的结果:报错

重新编译运行项目,任意调用一个接口
在这里插入图片描述

日志也没问题,大功告成
在这里插入图片描述

完整代码已上传码云:https://gitee.com/shao-jiayong/cuo-ding

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hello,Mr.S

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值