かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

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から色々分派させることができそうです。