ULS ログのヒント

ULS ログのヒント

2011 年 2 月 4 日更新: http://blogs.msdn.com/b/sharepoint_jp/archive/2011/03/21/uls-2.aspx にある更新された例を参照することをお勧めします。新しい例の方が機能が向上しています。

最近のプロジェクトに ULS ログを追加したときに、ちょっとした気になる副作用があることに気付きました。 ULS ログで領域が "Unknown" と表示されました。 これの一部については他の場所で取り上げられていることは知っていますが、これに対処する最も都合のよい方法を見つけたのでいち早く投稿しておくことにします (他の解決策のいくつかよりは明らかに優れています)。 1 つ指摘しておきたいのは、ここで説明することをまったく行いたくない場合は、ベスト プラクティス チームが CodePlex に掲載しているログ フレームワークが行ってくれます。 しかし、私はたいていできる限り自分でコードを書くので、ここで解決策を簡単に説明します。

まず最初に、ほとんどの SDK ドキュメントは新しい SPDiagnosticsCategory の作成の概念に有効であるということです。 クラスの新しいインスタンス用のコンストラクターでは、カテゴリ名を指定でき、そのようにすると、使用するカスタム カテゴリ名が ULS ログのカテゴリ列に表示されます。 通常、独自のカスタム ログを使用する場合は、カスタム領域をカスタム カテゴリと連携させることも考えます。 残念ながら、SDK でこれを行うのはかなり面倒です。なぜなら、簡単なコンストラクターを使用して新しい領域を作成して使用することはできず、SPDiagnosticsServiceBase を継承する独自のクラスを作成する必要があるためです。

これらをまとめて実装するために私が選んだ方法は、ログ クラスと診断サービス基本クラスの両方を含む 1 つの CS ファイルを作成するというものです。 まず最初に診断基本クラスです。以下にクラス全体を示し、後で要点を説明します。

    public class SteveDiagnosticService : SPDiagnosticsServiceBase

    {

        private const string LOG_AREA = "Steve Area";

        public enum LogCategories

        {

            SteveCategory

        }

        public SteveDiagnosticService()

            : base("Steve Diagnostics Service", SPFarm.Local)

        {

        }

        public SteveDiagnosticService(string name, SPFarm parent)

            : base(name, parent)

        {

        }

        protected override bool HasAdditionalUpdateAccess()

        {

            return true;

        }

        public static SteveDiagnosticService Local

        {

            get

            {

                return SPDiagnosticsServiceBase.GetLocal<SteveDiagnosticService>();

            }

        }

        public void LogMessage(ushort id, LogCategories LogCategory, TraceSeverity traceSeverity,

            string message, params object[] data)

        {

            if (traceSeverity != TraceSeverity.None)

            {

                SPDiagnosticsCategory category

                 = Local.Areas[LOG_AREA].Categories[LogCategory.ToString()];

                Local.WriteTrace(id, category, traceSeverity, message, data);

            }

        }

        protected override IEnumerable<SPDiagnosticsArea> ProvideAreas()

        {

            List<SPDiagnosticsCategory> categories = new List<SPDiagnosticsCategory>();

            categories.Add(new SPDiagnosticsCategory(

  LogCategories.SteveCategory.ToString(),

             TraceSeverity.Medium, EventSeverity.Information));

            SPDiagnosticsArea area = new SPDiagnosticsArea(

             LOG_AREA, 0, 0, false, categories);

            List<SPDiagnosticsArea> areas = new List<SPDiagnosticsArea>();

            areas.Add(area);

            return areas;

        }

    }

 

興味深い部分を見ていくことにします。

private const string LOG_AREA = "Steve Area";

ここでは、ULS ログに書き込む領域の名前を定義しています。

public enum LogCategories

{

SteveCategory

}  

これは、カスタム領域に追加するカテゴリのリストです。 この例ではこの領域で使用するカテゴリは 1 つだけですが、複数の領域を使用する場合はこの列挙の内容を拡張するだけで済みます。

public void LogMessage(ushort id, LogCategories LogCategory, TraceSeverity traceSeverity,

string message, params object[] data)

{

if (traceSeverity != TraceSeverity.None)

{

SPDiagnosticsCategory category

= Local.Areas[LOG_AREA].Categories[LogCategory.ToString()];

Local.WriteTrace(id, category, traceSeverity, message, data);

}

}

 

これは実装する 2 つの重要なメソッドのうちの 1 つで、ULS ログに実際に書き込みます。 1 行目では、SPDiagnosticCategory を取得し、そのときに属している領域を参照します。 2 行目では、ローカル SPDiagnosticsServiceBase クラスで基本クラスのメソッドを呼び出し、ULS ログに書き込みます。その一部として、領域と関連付けられているカテゴリを渡します。

protected override IEnumerable<SPDiagnosticsArea> ProvideAreas()

{

List<SPDiagnosticsCategory> theCategories = new List<SPDiagnosticsCategory>();

theCategories.Add(new SPDiagnosticsCategory(

  LogCategories.SteveCategory.ToString(),

             TraceSeverity.Medium, EventSeverity.Information));

SPDiagnosticsArea theArea = new SPDiagnosticsArea(

             LOG_AREA, 0, 0, false, theCategories);

List<SPDiagnosticsArea> theArea = new List<SPDiagnosticsArea>();

theArea.Add(area);

return theArea;

}

 

このオーバーライドでは、SharePoint にすべてのカスタム領域を返します。 この例では、独自の領域のみを使用するので、返すのはそれだけです。 また、前記のように、この領域で使用しているカスタム カテゴリは 1 つだけです。 複数のカスタム カテゴリを使用する場合は、1) 前に説明した列挙にそれを追加し、2) このメソッドで定義している theCategories リスト インスタンスにそれぞれを追加します。

これにより、カスタム領域を追加すると、ULS ログの適切な列にそれが表示されます。 ログ クラスの実装も同じように簡単です。次にその主要部分を示し、あとで簡単に説明します。

    public class Log

    {

        private const int LOG_ID = 11100;

    public static void WriteLog(string Message, TraceSeverity TraceLogSeverity)

        {

            try

            {

           // この簡単な例では、常に同じカテゴリを使用する

              // もちろんメソッドのパラメーターとして渡すこともできる

              // SteveDiagnosticService を呼び出すときに使用する

                SteveDiagnosticService.Local.LogMessage(LOG_ID,

                    SteveDiagnosticService.LogCategories.SteveCategory,

                    TraceLogSeverity, Message, null);

            }

            catch (Exception writeEx)

            {

                // 無視する

                Debug.WriteLine(writeEx.Message);

            }

        }

    }

 

このコードは参照しているメソッドから簡単に実装できます。 WriteLog は静的メソッドなので、コードは単に Log.WriteLog("This is my error message", TraceSeverity.Medium); などとなります。 この例では、ULS ログに、領域が "Steve Area"、カテゴリが "SteveCategory"、メッセージが "This is my error message" のエントリを作成します。

これはローカライズされたブログ投稿です。原文の記事は、「Tips for ULS Logging」をご覧ください。