转载

NLog详解(四) - filter

我们将版本向前切换到20051025,这期的关注点是filter。我们在使用日志的时候可能希望加上一些过滤器,在满足某些特定条件的时候才输出。举个简单的使用方式如下:

<nlog>  <targets><target name='debug' type='Debug' layout='${basedir} ${message}' /></targets>  <rules>   <logger name='*' minlevel='Debug' appendTo='debug'>   <filters>    <whenContains layout='${message}' substring='zzz' action='Ignore' />   </filters>   </logger>  </rules> </nlog> 

初始化

FilterFactory负责初始化程序集中的Filter

public sealed class FilterFactory {  private static TypeDictionary _filters = new TypeDictionary();  static FilterFactory()  {   foreach (Assembly a in ExtensionUtils.GetExtensionAssemblies())   {    AddFiltersFromAssembly(a, "");   }  } 

反射初始化的方式和上篇的LayoutRender没有差别

 public static void AddFiltersFromAssembly(Assembly theAssembly, string prefix) {  try  {   InternalLogger.Debug("AddFiltersFromAssembly('{0}')", theAssembly.FullName);   foreach (Type t in theAssembly.GetTypes())   {    FilterAttribute[]attributes = (FilterAttribute[])t.GetCustomAttributes(typeof(FilterAttribute), false);    if (attributes != null)    {     foreach (FilterAttribute attr in attributes)     {      AddFilter(prefix + attr.Name, t);     }    }   }  }  catch (Exception ex)  {   InternalLogger.Error("Failed to add filters from '" + theAssembly.FullName + "': {0}", ex);  } } 

加载配置文件中的Filter

NLog详解(四) - filter

只是简单的从初始化好的_filters字典里面取出即可,如果发现没有,就会尝试反射创建

NLog详解(四) - filter

执行

NLog详解(四) - filter

还是在 LoggerImplWrite 方法中以链式的方式嵌入

for (TargetWithFilterChain awf = targets; awf != null; awf = awf.Next) {  Target app = awf.Target;  try  {   FilterCollection filterChain = awf.FilterChain;   FilterResult result = FilterResult.Neutral;   for (int i = 0; i < filterChain.Count; ++i)   {    Filter f = filterChain[i];    result = f.Check(logMessage);    if (result != FilterResult.Neutral)     break;   }   if (result == FilterResult.Ignore)   {    if (InternalLogger.IsDebugEnabled)    {     InternalLogger.Debug("{0}.{1} Rejecting message because of a filter.", logger.Name, level);    }    continue;   }  } 

这里可以看到,如果filter 的result 是 Ignore ,该Message的Target就不需要再输出了。

TargetWithFilterChain 是包装Target的关键类型:

internal class TargetWithFilterChain {  private Target _target;  private FilterCollection _filterChain;  private TargetWithFilterChain _next;  public TargetWithFilterChain(Target a, FilterCollection filterChain)  {   _target = a;   _filterChain = filterChain;  } 

这个类型的实现很简单,就是将Target和FilterChain打包放在一起。

InternalLogger

这里值得注意的细节是 InternalLogger 记录了内部一些详情,当我们需要的时候直接开启 InternalLogger 调试日志组件的工作过程。

NLog详解(四) - filter

我们对于 InternalLogger 的要求是不要影响正常程序的运行过程,仅仅在调试日志组件功能的时候使用,因此里面的代码牺牲异常也保证安全。

static InternalLogger() {  try  {   switch (ConfigurationSettings.AppSettings["nlog.internalLogToConsole"].ToLower())   {    case "false":     LogToConsole = false;     break;    case "true":     LogToConsole = true;     break;    default:     if (EnvironmentHelper.GetSafeEnvironmentVariable("NLOG_INTERNAL_LOG_TO_CONSOLE") != null)     {      LogToConsole = true;     }     break;   }   string levelString = ConfigurationSettings.AppSettings["nlog.internalLogLevel"];   if (levelString == null || levelString.Length == 0)    levelString = EnvironmentHelper.GetSafeEnvironmentVariable("NLOG_INTERNAL_LOG_LEVEL");   if (levelString != null && levelString.Length > 0)    LogLevel = LogLevel.FromString(EnvironmentHelper.GetSafeEnvironmentVariable("NLOG_INTERNAL_LOG_LEVEL"));   LogFile = ConfigurationSettings.AppSettings["nlog.internalLogFile"];   if (LogFile == null)    LogFile = EnvironmentHelper.GetSafeEnvironmentVariable("NLOG_INTERNAL_LOG_FILE");   Info("NLog internal logger initialized.");  }  catch {} } 

可以看到 InternalLogger 的开启不依赖于原来的配置文件结构,默认不输出,以及取环境变量处理的也非常小心。

public static string GetSafeEnvironmentVariable(string name) {  try  {   string s = Environment.GetEnvironmentVariable(name);   if (s == "")    return null;   else    return s;  }  catch (SecurityException)  {   return "";  } } 
正文到此结束
Loading...