.NET 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負責初始化程序集中的Filterapp

public sealed class FilterFactory
{
    private static TypeDictionary _filters = new TypeDictionary();

    static FilterFactory()
    {
        foreach (Assembly a in ExtensionUtils.GetExtensionAssemblies())
        {
            AddFiltersFromAssembly(a, "");
        }
    }

反射初始化的方式和上篇的LayoutRender沒有差異debug

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

只是簡單的從初始化好的_filters字典裏面取出便可,若是發現沒有,就會嘗試反射建立調試

執行

仍是在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就不須要再輸出了。code

TargetWithFilterChain 是包裝Target的關鍵類型:get

internal class TargetWithFilterChain
{
    private Target _target;
    private FilterCollection _filterChain;
    private TargetWithFilterChain _next;

    public TargetWithFilterChain(Target a, FilterCollection filterChain)
    {
        _target = a;
        _filterChain = filterChain;
    }

這個類型的實現很簡單,就是將Target和FilterChain打包放在一塊兒。string

InternalLogger

這裏值得注意的細節是InternalLogger記錄了內部一些詳情,當咱們須要的時候直接開啓InternalLogger調試日誌組件的工做過程。it

咱們對於InternalLogger的要求是不要影響正常程序的運行過程,僅僅在調試日誌組件功能的時候使用,所以裏面的代碼犧牲異常也保證安全。io

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 "";
    }
}
相關文章
相關標籤/搜索