かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

Enterprise Library 6のSemantic Logging Application Blockで独自の出力先に出力する方法

過去分

はじめに

ログ関係のライブラリを使いこんでいくうちに出てくる要求として出力先をカスタマイズしたいというのはよくあると思います。Semantic Logging Application Blockでも当然そこは拡張できるように作られてるのでやってみました。

****Sinkというクラスを作る

Semantic Logging Application BlockはRxと相性がいいだけあって、ログの出力する人はEventEntryのIObserverです。OnNextを処理すればOKというわかりやすい設計。今回はコンソールに出すだけの簡単なものを作ってみました。フォーマッティングはIEventTextFormatterにお任せしてます。

// 独自の出力先
class MyConsoleSink : IObserver<EventEntry>
{
    private IEventTextFormatter formatter;
    public MyConsoleSink(IEventTextFormatter formatter = null)
    {
        this.formatter = formatter ?? new EventTextFormatter();
    }

    public void OnCompleted()
    {
    }

    public void OnError(Exception error)
    {
    }

    public void OnNext(EventEntry value)
    {
        // 値がわたってきたときだけ
        if (value == null)
        {
            return;
        }

        // formatterで整形して出力する
        using (var w = new StringWriter())
        {
            this.formatter.WriteEvent(value, w);
            Console.Write(w);
        }
    }
}

そして、IObservableと接続するための拡張メソッドを定義します。LogTo****という名前で作るのが一般的っぽいです。

// MyConsoleSink購読用拡張メソッド
static class MyConsoleSinkExtensions
{
    public static SinkSubscription<MyConsoleSink> LogToMyConsole(this IObservable<EventEntry> self, IEventTextFormatter formatter = null)
    {
        var sink = new MyConsoleSink(formatter);
        var d = self.Subscribe(sink);
        return new SinkSubscription<MyConsoleSink>(d, sink);
    }
}

Subscribeして、SinkSubscriptionというものを返すのがお約束っぽいのでそれに従ってます。Semantic Logging Application BlockのログがIObservableから発行されたものをIObserverで監視して出力するだけということがわかれば、間にRxのLINQ挟み込めるのも納得ですね。

使い方

// リスナー作って
var l = new ObservableEventListener();
// 監視するログの種類を設定して
l.EnableEvents(
    MyEventSource.Log,
    EventLevel.Verbose,
    MyEventSource.Keywords.Diagnostic | MyEventSource.Keywords.Lifecycle);
// 自前のログ出力先へ出力する
l.LogToMyConsole();

MyEventSource.Log.Start();
MyEventSource.Log.Query("select * from dual");
MyEventSource.Log.Stop();

とても簡単ですね。