以前写代码总喜欢自己造轮子,比如用的特别多的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中即可
原标题:NLog记录日志前拦截并执行前置任务(Filter另类用法)
关键词: