2

我正在使用 EF 5 并尝试使用 ShouldLog 方法来确定是否会在实际记录 LogEntry 之前对其进行记录。我的问题是 ShouldLog 总是返回 true,即使我有一个过滤器来排除某些级别。过滤器有效且条目未记录,但 ShouldLog 似乎无效。

我正在像这样配置我的记录器:

internal static void ConfigureLogging(SourceLevels logLevel)
{
    var builder = new ConfigurationSourceBuilder();

    builder.ConfigureLogging()
        .LogToCategoryNamed("General")
        .WithOptions.SetAsDefaultCategory()
        .SendTo.FlatFile("Main log file")
        .FormatWith(
            new FormatterBuilder()
                .TextFormatterNamed("Text Formatter")
                .UsingTemplate("{timestamp(local:MM/dd/yyyy HH:mm:ss.fff)} [{severity}] {message}"))
        .Filter(logLevel) //Setting the source level filter
        .ToFile("log.txt");

    var configSource = new DictionaryConfigurationSource();
    builder.UpdateConfigurationWithReplace(configSource);
    EnterpriseLibraryContainer.Current
        = EnterpriseLibraryContainer.CreateDefaultContainer(configSource);
}

并像这样测试它:

ConfigureLogging(SourceLevels.Warning); //Do not allow Information level

var logEntry = new LogEntry { Message = "test", Severity = TraceEventType.Information };
var shouldLog = Logger.Writer.ShouldLog(logEntry);
Logger.Writer.Write(logEntry);

运行此代码后, shouldLog 变量为 true,但未写入任何日志条目。如果我将 SourceLevels.Information 传递给 ConfigureLogging 方法,我确实会收到写入日志的条目。难道我做错了什么?

4

1 回答 1

1

我不认为你做错了什么。但是,我承认这种行为有点奇怪。

如此处所述ShouldLog方法针对LogEntry. 返回 true的原因ShouldLog是您没有定义任何过滤器,所以一切都通过了。

“但是等等!”,你说。“我已经在fluent配置中设置了源级过滤器!”

这是真的——在某种意义上。但是,尽管它的名称,该Filter方法并没有创建一个实际的过滤器(也许它应该,虽然)!它基本上只是设置一个仅在被调用SourceLevels时才被检查的值Write。如果您使用配置文件而不是流利的配置,那么配置文件Filter中的实际名称是实际命名switchValue的,因此不会那么混乱。

所以ShouldLog返回 true,因为没有过滤器,但Write实际上没有写入,因为检查SourceLevels. 这是非常违反直觉的。如果在版本 6 中可以将检查包含在ShouldLog? 它违背了ShouldLogif 它返回 true 的目的,这会导致用户构造一堆昂贵的对象,但最终由于SourceLevels检查,消息永远不会被记录。

我检查了一下,看起来这种行为至少从第 4 版开始就存在了。

这种行为该怎么办?最简单的方法是添加自定义过滤器来执行SourceLevels检查:

public class SourceLevelFilter : LogFilter
{
    private SourceLevels level;

    public SourceLevelFilter(NameValueCollection nvc)
        : base("SourceLevelFilter")
    {
        if (!Enum.TryParse<SourceLevels>(nvc["Level"], out level))
        {
            throw new ArgumentOutOfRangeException(
                "Value " + nvc["Level"] + " is not a valid SourceLevels value");
        }
    }

    public override bool Filter(LogEntry log)
    {
        if (log == null) throw new ArgumentNullException("log");
        return ShouldLog(log.Severity);
    }

    public bool ShouldLog(TraceEventType eventType)
    {
        return ((((TraceEventType)level) & eventType) != (TraceEventType)0);
    }

    public SourceLevels SourceLevels
    {
        get { return level; }
    }
}

// ...

SourceLevels logLevel = SourceLevels.Warning;

var builder = new ConfigurationSourceBuilder();

builder.ConfigureLogging()
    .WithOptions
    .FilterCustom<SourceLevelFilter>("SourceLevelFilter", 
        new NameValueCollection() { { "Level", logLevel.ToString() } } )
    .LogToCategoryNamed("General")
    .WithOptions.SetAsDefaultCategory()
    .SendTo.FlatFile("Main log file")
    .FormatWith(
        new FormatterBuilder()
            .TextFormatterNamed("Text Formatter")
            .UsingTemplate("{timestamp(local:MM/dd/yyyy HH:mm:ss.fff)} [{severity}] {message}"))
    .Filter(logLevel) //Setting the source level filter
    .ToFile("log.txt");

现在将在其检查中ShouldLog合并该值,并在 SourceLevels 设置为警告时为信息严重性返回 false。SourceLevelsLogEntry

更新

过滤器可能遇到的一个问题是它们是全局的,因此您可能必须加强上面的过滤器才能将 SourceLevels 与 Category 一起存储。

如果您只想检查是否启用了警告,您可以检查特定的过滤器:

public bool IsWarningEnabled
{
    get
    {
        return writer.GetFilter<SourceLevelFilter>().ShouldLog(TraceEventType.Warning);
    }
}

另一种方法是在没有过滤器的情况下自己管理 SourceLevels。由于您正在编写通用日志包装器,因此我假设 SourceLevels 将通过您的包装器设置。您还谈到公开自己的方法,例如 IsDebugEnabled。如果是这样,那么您可以在包装器内部维护该知识并按需提供该检查。如果您将 EntLib LogWriters 返回给调用者,那么这可能会起作用,因为用户希望在 LogWriter 上调用 ShouldLog。虽然,您也可以在 LogWriter 上创建扩展方法(例如 IsWarningEnabled() )。

于 2012-01-10T05:32:24.083 回答