你的位置:首页 > ASP.net教程

[ASP.net教程]NLog记录日志前拦截并执行前置任务(Filter另类用法)


以前写代码总喜欢自己造轮子,比如用的特别多的Logger.
但是发现自己写的Logger很多时候不够通用(比如持久层,可移植性),
于是乎在新项目构架中抛弃自己造的轮子使用开源的NLog;
 
首先不熟悉NLog的同学先移步到NLog官网 http://nlog-project.org , GitHub的托管地址 https://github.com/NLog/NLog 
NLog可能没有从java移植过来的log4net有名,但是贵在足够轻量 整洁,可扩展性很强等特点,并且作者持续更新
 
好了,基本知识补充了那么我们就切入正题了.
 
现在遇到一个棘手的场景,我们需要在记录日之前做很多自己想要做的事情,
比如发邮件&短信通知关键用户,广播给在线的运营人员,等等...


自己写的轮子是很好的实现了这个功能(通过发布订阅模式)
但是NLog刚接触不太了解它的拦截机制,于是乎查看了源码,发现IFilter这个接口,
IFilter顾名思义 就是筛选器的意思, 比如需要满足我们指定类型的的日志 或者 包含什么内容的日志 需要被记录
那么就必须使用它了, NLog为我们实现了 几个现成的Filter(WhenContainsFilter,WhenEqualFilter,等等)
这些Filter只是让我们断定是否需要记录日志用的.
那么怎么实现自己的需要的功能呢?
我们顺藤摸瓜,Filter 首先是记录日志判定的前置任务,那么我们也实现它就好了,
但是我们重载后只需要返回默认通过,通过前我们注入我们需要做的前置任务不就好了~
原理还是蛮简单的上代码:
首先我们定义一个注入接口,
 
  public interface ILoggerInject {    /// <summary>    /// 需要执行的Todo    /// </summary>    /// <param name="logEvent"></param>    void Todo(LogEventInfo logEvent);  }

  


然后我们实现一个ILoggerInject,比如下面的用来在调试的时候输出日志到调试面板
 
  public class DebugLoggerInject : ILoggerInject {    public void Todo(LogEventInfo logEvent)    {#if DEBUG      if (logEvent.Exception == null) { return; }      System.Diagnostics.Debug.WriteLine(logEvent.Message);#endif    }  }

  


接着就是我们的重头戏了, 实现一个自己的 Filter ,
 
  [Filter("inject")]  public class LoggerInjectFilter : LayoutBasedFilter {    /// <summary>    /// 加载的ILoggerInject    /// </summary>    [RequiredParameter]    public string Type { get; set; }    protected override FilterResult Check(LogEventInfo logEvent)    {      //拦截并且执行todo      GetLoggerInject()?.Todo(logEvent);       //返回默认的Neutral不阻塞日志的后置任务      return FilterResult.Neutral;    }     /// <summary>    /// 获取对应的Inject    /// </summary>    /// <returns></returns>    private ILoggerInject GetLoggerInject()    {       //这里使用缓存存储发现的ILoggerInject,提高性能      var cacheManager = EngineContext.Current.Resolve<ICacheManager>("cache_static");      return cacheManager.Get($"LoggerInjectFilter_{Type}", () =>      {        try        {            //这里使用容器或者反射找到运行时中实现的ILoggerInject          ILoggerInject task = null;          var type2 = System.Type.GetType(Type);          if (type2 != null)          {            object instance;            if (!EngineContext.Current.ContainerManager.TryResolve(type2, out instance))            {              //not resolved              instance = EngineContext.Current.ContainerManager.ResolveUnregistered(type2);              task = instance as ILoggerInject;            }          }          return task;        }        catch        {          //todo:          return null;        }      });    }  }

 


好了代码部分就大功告成了,
我们还需要在NLog的配置中配置好我们的Filter
注:XXX表示你的Filter存在的命名空间的DLL
 
 <extensions>  <add assembly="XXX"/> </extensions>   <rules>  <!-- 记录日志到数据库中 -->  <logger name="*" writeTo="database">   <filters>    <inject layout="*" type="XXX.Logging.DebugLoggerInject,XXX" />   </filters>  </logger> </rules>


 
然后调试代码运行
 
Logger.Error(new Exception("Hello NLog"));


 
我们就可以看到数据库记录日志前,我们的调试面板输出了Hello NLog
 
当然后续我们还需要注入其他的前置工作,只需要实现ILoggerInject并且如法炮制配置到filters中即可