c# - 企业框架日志记录 - ShouldLog 不适用于 SourceLevel 过滤器

标签 c# .net enterprise-library logging-application-block

我正在使用 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 变量为真,但未写入任何日志条目。相反,如果我将 SourceLevels.Information 传递给 ConfigureLogging 方法,我确实会在我的日志中写入一个条目。我做错了什么吗?

最佳答案

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

如前所述here ShouldLog 方法根据 LogEntry 查询所有已配置的过滤器。 ShouldLog 返回 true 的原因是您没有定义任何过滤器,所以一切都通过了。

“等等!”,你说。 “我已经在流畅的配置中设置了源级过滤器!”

从某种意义上说,这是真的。但是,尽管它的名称是 Filter 方法,但它并没有创建一个实际的过滤器(不过也许它应该创建)!它基本上只是设置一个 SourceLevels 值,只有在调用 Write 时才会检查该值。如果您使用配置文件而不是流畅的配置,那么在配置文件中 Filter 实际命名为 switchValue 所以它不会那么困惑。

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

我检查了一下,看起来这种行为至少从第 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 值,并在设置 SourceLevels 时为具有信息严重性的 LogEntry 返回 false警告。

更新

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

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

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

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

关于c# - 企业框架日志记录 - ShouldLog 不适用于 SourceLevel 过滤器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8794380/

相关文章:

.net - ASP.NET : How can I get the domain name without any subdomains?

.net - 在 .NET 中,如何限制对私有(private)方法的访问?

c# - Enterprise Library Unity 和数据访问 block

.net - 企业库应用程序 block 还是自制框架?

c# - 使用正则表达式获取每个反斜杠之间的字符串

c# - 系统参数异常 : The encoded string can only be used for a password

c# - 如何从内容页面的代码后面更改母版页的背景?

c# - 为什么我的 SqlCacheDependency HasChanged 返回 false 但几乎是在更改为 true 之后立即返回?

c# - Web Api 调用未在 JSON 响应中返回 __type

asp.net - 在 ASP.NET 中使用企业库异常处理应用程序 block - 代码审查