かずきのBlog@hatena

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

Enterprise Library 6のSemantic Logging Application Block + Reactive Extensions

Semantic Logging Application Blockのログですが、こいつはRxを使ってフィルタリングとかが出来ます。例えば、これまで作ってきたやつでInformation以上のログだけ表示するようにするには以下のような感じ。

// リスナー作って
var l = new ObservableEventListener();
// 監視するログの種類を設定して
l.EnableEvents(
    MyEventSource.Log,
    EventLevel.Verbose,
    MyEventSource.Keywords.Diagnostic | MyEventSource.Keywords.Lifecycle);
// LINQで色々できる!
l.Where(e => e.Schema.Level <= EventLevel.Informational)
    .LogToConsole();

まぁこの例だとEnableEventsでInformation渡せば済む話ですが…。ドキュメントには指定した条件でフラッシュするコードが例示されてました。引用しておきます。

public static IObservable<T> FlushOnTrigger<T>(
    this IObservable<T> stream, Func<T, bool> shouldFlush, int bufferSize) {  
    return Observable.Create<T>(observer =>
    {
        var buffer = new CircularBuffer<T>(bufferSize);
        var subscription = stream.Subscribe(newItem =>
            {
               if (shouldFlush(newItem))
               {
                   foreach (var buffered in buffer.TakeAll())
                   {
                       observer.OnNext(buffered);
                   }
                   observer.OnNext(newItem);
               }
               else
               {
                   buffer.Add(newItem);
               }
            },
            observer.OnError,
            observer.OnCompleted);
        return subscription;  
    });
}

引数でわたしたデリゲートがTrueになったタイミングでログの内容を後続に渡す感じですね。

var listener = new ObservableEventListener(); 
listener.EnableEvents(MyCompanyEventSource.Log,
    EventLevel.Informational,
    Keywords.All); 
listener.FlushOnTrigger(entry => entry.Schema.Level <= EventLevel.Error, bufferSize: 10)
    .LogToConsole();

こんな風に使うとエラーのあった直近10個のログだけを出すという、なんともありがたい感じになってます。これはいい・・・!(ドキュメントのコピーしただけですけど)

このほかには、指定した範囲の重要度とかだけに絞るとか1つのListenerから色々分派させることができそうです。