2

私はEF5を使用しており、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は、すべてが合格するようにフィルターを定義していないためです。

「でも待って!」とあなたは言います。「流暢な構成でソースレベルのフィルターを設定しました!」

それは本当です-ある意味で。しかし、その名前にもかかわらず、Filterメソッドは実際のフィルターを作成しません(おそらくそうすべきです)!基本的には、が呼び出されたSourceLevelsときにのみチェックされる値を設定するだけです。Write流暢な構成の代わりに構成ファイルを使用する場合、構成ファイルでFilterは実際に名前が付けられswitchValueているため、それほど混乱することはありません。

したがってShouldLog、フィルタがないためtrueを返しますがWrite、に対するチェックのために実際には書き込みませんSourceLevels。これはかなり直感に反します。バージョン6でチェックを含めることができればいいのですがShouldLog?これは、trueを返す場合の目的を無効にし、ユーザーに高価なオブジェクトの束を作成させますが、最終的には、チェックShouldLogのためにメッセージがログに記録されることはありません。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がWarningに設定されている場合、情報の重大度がである場合はfalseが返されます。SourceLevelsLogEntry

アップデート

フィルタに関する問題の1つは、フィルタがグローバルであるため、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 に答える