読者です 読者をやめる 読者になる 読者になる

銀の光と碧い空

クラウドなインフラとC#なアプリ開発の狭間にいるエンジニアの日々

EnterpriseLibrary 6のSemantic Logging Application Block (SLAB) で Out-of-Process なログ出力を試してみる

数か月前にこういうセッションをして紹介したSLABですが、

肝心の導入の仕方とか使い方は説明しないままでした。また、 id:okazuki 先生がわかりやすい SLABの解説を書いてくださっています。

EnterpriseLibrary 6のSemantic Logging Application Blockの感想 - かずきのBlog@hatena

id:okazuki 先生は In-Process なログ出力を扱っていましたが、WebアプリだとやはりOut-of-Process の方が好ましいことが多いと判断しています。というわけで、 SLABの Out-of-Process (OOB) を試してみたいと思います。今回はNugetで公開されているライブラリを取得してきて動かしてみるところまでです。

SLABのOOBはNugetで配布されていますが、C# (などの)VisualStudioプロジェクトに追加して使うのではなく、単体のツールとして動きます。そのためセットアップもちょっと変わった方法になります*1

まず、ドライブ直下に「OOB」などといった適当なフォルダを作ります*2。そして、NuGet Gallery | Home からNugetをダウンロードして、「.nuget\Nuget.exe」に置いておきます。 ここからはPowerShellでセットアップしていきます。以下のコマンドを実行してNugetから EnterpriseLibrary.SemanticLogging.Service をlibフォルダ以下にダウンロードします。

.\.nuget\nuget.exe install EnterpriseLibrary.SemanticLogging.Service  -OutputDirectory lib

これで終わり。と思いきや、もう一度依存するライブラリをNugetから取得しないといけないので次のコマンドを実行します。

.\lib\EnterpriseLibrary.SemanticLogging.Service.2.0.1406.1\tools\install-packages.ps1 -autoAcceptTerms

こんな風にダウンロードが完了します。「Press ENTER key to finish...」とあるので適当に押して終わりましょう。

f:id:tanaka733:20140725193424p:plain

さて、ここで勘のいい方は気づいたかもしれませんが、-autoAcceptTerms オプションを指定しているのにもかかわらずユーザーからの入力を求めています。つまり、このツールの展開を自動化する場合には、ここのユーザー入力がネックになってしまいます... 回避策はなくはないのですが、本家に修正してもらうのがいいと思いますので、Issueを上げています。

Semantic Logging Application Block - View Issue #51: Please avoid force user-input in install-packages.ps1

さて、toolsフォルダ 以下に必要なものがダウンロードされているので見てみましょう。dll や SQLファイルのほかに、SemanticLogging-svc.exe と SemanticLogging-svc.xml があると思いますが、これが本体のexeと設定ファイルになります。

SemanticLogging-svc.xml を開くと flatFileSink とか書かれたXML要素があるはずです。ここで、どのような出力(Sink)を使うかと、その設定、入力を指定します。 今回は最初から用意されている ConsoleSink というSinkを使ってみましょう。 SemanticLogging-svc.xml を以下のように編集します。

<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns="http://schemas.microsoft.com/practices/2013/entlib/semanticlogging/etw"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://schemas.microsoft.com/practices/2013/entlib/semanticlogging/etw SemanticLogging-svc.xsd">
  
  <traceEventService/>
  <sinks>

    <consoleSink name="ConsoleEventSink">
      <sources>
        <eventSource name="My" level="LogAlways" />
      </sources>
      <eventTextFormatter header="+=========================================+"/>
    </consoleSink>    
  </sinks>

</configuration>

consoleSink 要素の中のsourcesが取得するSLABのイベントソースです。今回はテスト用にログを発生させるので、とりあえず"My"という名前にしておきました。 テスト用のログはこんな風なプログラムで実行しました。

using System;
using System.Diagnostics.Tracing;
using System.Threading;

namespace ConsoleApplication11
{
    class Program
    {
        static void Main(string[] args)
        {
            var log = MyEventSource.Log;
            var random = new Random();
            while (true)
            {   
                log.Login("user" + random.Next(100));
                Thread.Sleep(TimeSpan.FromSeconds(1));
            }
        }
    }

    [EventSource(Name = "My")]
    public sealed class MyEventSource : EventSource
    {
        public class Keywords
        {
            public const EventKeywords Perf = (EventKeywords)1;
        }

        public class Tasks
        {
            public const EventTask Login = (EventTask)1;
        }

        private readonly static MyEventSource log = new MyEventSource();
        private MyEventSource() { }
        public static MyEventSource Log { get { return log; } }

        [Event(201, Level = EventLevel.Informational, Keywords = Keywords.Perf,
            Message = "Login: {0}", Task = Tasks.Login, Version = 1)]
        public void Login(string user)
        {
            WriteEvent(201, user);
        }

    }
}

書いたコンソールアプリを起動しておきます。

それでは、 SemanticLogging-svc.exe を実行します。PowerShellコンソールを管理者権限で開きます。引数つけずに実行するとヘルプが出ます。

Enterprise Library Semantic Logging Service v2.0.1406.1
Microsoft Enterprise Library
Microsoft Corporation


[ -i | -install ]               Install as a Windows Service.
[ -u | -uninstall ]             Uninstall the Windows Service.
[ -s | -start ]                 Start or install and start the service.
[ -c | -console ]               Run as a console application.
[ -h | -help | -? ]             Display list of arguments
[ -a=type | -account=type]      Specifies the account type. Accepted values are User, LocalSystem, and LocalService. De
ault is LocalService.

サービスとしてセットアップできますが、今回はコンソールアプリとして動かしてみましょう。 "SemanticLogging-svc.exe -c" と実行してみます。

+=========================================+
EventId : 201, Level : Informational, Message : Login: user19, Payload : [user :
 user19] , EventName : LoginInfo, Timestamp : 2014-07-25T12:51:22.9527575Z, Proc
essId : 6684, ThreadId : 7232

+=========================================+
EventId : 201, Level : Informational, Message : Login: user46, Payload : [user :
 user46] , EventName : LoginInfo, Timestamp : 2014-07-25T12:51:23.9530479Z, Proc
essId : 6684, ThreadId : 7232

+=========================================+
EventId : 201, Level : Informational, Message : Login: user8, Payload : [user :
user8] , EventName : LoginInfo, Timestamp : 2014-07-25T12:51:24.9534321Z, Proces
sId : 6684, ThreadId : 7232

+=========================================+
EventId : 201, Level : Informational, Message : Login: user27, Payload : [user :
 user27] , EventName : LoginInfo, Timestamp : 2014-07-25T12:51:25.9541017Z, Proc
essId : 6684, ThreadId : 7232

+=========================================+
EventId : 201, Level : Informational, Message : Login: user19, Payload : [user :
 user19] , EventName : LoginInfo, Timestamp : 2014-07-25T12:51:26.9549686Z, Proc
essId : 6684, ThreadId : 7232

+=========================================+
EventId : 201, Level : Informational, Message : Login: user70, Payload : [user :
 user70] , EventName : LoginInfo, Timestamp : 2014-07-25T12:51:27.9557676Z, Proc
essId : 6684, ThreadId : 7232

EventSourceから出力したイベントを consoleSink で取得できましたね。Payload にはメソッドの引数が含まれていますが、これとは別にログが発生したTimestampも含まれています。

*1:ほかにも方法はあると思いますが一例として

*2:この後ファイルパスが長くなっていくのでドライブ直下がお勧めです