設計の観点から、ロギングのベストプラクティスは何ですか?[閉まっている]


11

現在作業中のアプリケーションにロギングを追加したい。以前にロギングを追加しましたが、ここでは問題ではありません。

しかし、オブジェクト指向言語の設計の観点から、OOPとパターンに従うロギングのベストプラクティスは何ですか?

注:私は現在C#でこれを行っているので、C#の例は明らかに歓迎されています。また、JavaとRubyの例をご覧ください。


編集:私はlog4netを使用しています。プラグインするのに最適な方法がわからないだけです。

回答:


6

私がお勧めするベストプラクティスは、独自にローリングするのではなく、log4jを使用することです。(JavaからC#とRubyの両方に移植されているため、興味のある3つの言語すべてに適用されます。)

そのマニュアルページを読むと、他のベストプラクティスがいくつか見つかります。軽量であること、アプリケーションの外部で構成可能であること、アプリケーションのさまざまな部分のロギングを個別にオン/オフできることなど。


5

私が働いている場所では、多くの.NETデスクトップアプリを作成しています。通常、コンポーネントに2つのイベントを実装します。1つは情報のロギング用で、もう1つは例外のロギング用です(ただし、個別のイベントを発生させる代わりに例外を発生させます。状況によって異なります)。このアーキテクチャを使用すると、どのライブラリもロギングの実装方法や情報の使用方法、保存方法、処理方法を知る必要がありません。次に、アプリケーションに適切な方法でロギングイベントを処理させます。数年前、このアーキテクチャにより、MS Enterprise Libraryのログ作成からBitFactoryのログ作成コンポーネントへの切り替えが非常に簡単になりました。


イベント/オブザーバーパターンを使用するための+1:オブザーバーを変更し、ログを変更しました
Matthieu M.

2

C#でこれを行っているので、NLogとElMAHを確認することをお勧めします。NUGETを使用して非常に簡単にインストールできます。あなたがより多くの情報を得ることができるように、私は以下にそれらへのいくつかのリンクを置きました。

  • Elmah:http ://code.google.com/p/elmah/
  • NLog:http ://nlog-project.org/
  • Nuget:http ://nuget.codeplex.com/

2

個人的には、選択したロギングフレームワーク(私の場合は.NETで作業しているためEntlib)を使用し、ロギング用のAOPアスペクトを作成します。

その後、メソッド/プロパティ/クラス/名前空間を属性付けし、ソースを乱雑にすることなくそれらにロギングを追加できます。


非常に興味深いように思えますが、ログに記録できる内容と、ログがどのように情報を収集するかについては予約があります(つまり、「単なる」メソッドのインストルメンテーション以上のものです)。このアプローチの実際の例を見て、何ができて何ができないかを見てみたいと思います。特に、私は新しいアプリを始めたばかりで、これをどこで/どこまで運ぶことができるかを見たいと思っています。
マルジャンヴェネマ

@marjan Venema:ポストシャープドキュメントには、メソッドの開始/終了を記録する側面の例があります。doc.sharpcrafters.com/postsharp/2.0/##PostSharp.chm/html/…Post sharpの場合、ビルド時に属性からコードをソースに織り込むため、他の人が行うようにパフォーマンスに影響を与えません。
スティーブンエバーズ

1

私が現在取り組んでいるシステムは、イベント駆動型のアーキテクチャとメッセージングを使用しているため、システム内のほとんどのアクションはコマンドの結果であり、イベント(標準のデリゲートイベントではなく、ディスパッチされるDTOクラスとして)になります。ロギングの処理を唯一の目的とするイベントハンドラを添付します。この設計により、自分自身を繰り返す必要がなくなり、既存のコードを変更して機能を追加/変更する必要もなくなります。

以下に、アプリケーションの狭いセクション(インポート元の特定のコンテンツソースに関するもの)からすべてのイベントを記録するログクラスの例を示します。

頻繁に何をどのように記録するかについて考えを変えるように見えるため、これが必ずしもベストプラクティスであるとは言いません。ログを使用して問題を診断する必要があるたびに、記録する情報。

ただし、適切な情報を(特にCtrl-F /検索可能な方法で)記録することが最も重要な部分です。

2番目に重要な部分は、ロギングコードをメインロジックから遠ざけることです。これにより、メソッドがく長くなり、非常に複雑なります。

public class MctLogger :
    IEventHandler<StoryImported>,
    IEventHandler<StoryScanned>,
    IEventHandler<SourceDirectoryMissing>,
    IEventHandler<SourceDirectoryAccessError>,
    IEventHandler<CannotCreateScannedStoryDirectory>,
    IEventHandler<CannotReadStoryDocument>,
    IEventHandler<StorySkippedPastCutoff>,
    IEventHandler<StorySkippedDuplicateUniqueId>,
    IEventHandler<StorySkippedByFilter>
{

    public void Observe(StoryImported e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StoryImported");
        log.Info("Story Unique ID: {Story.UniqueId}, Content ID: {ContentId}, Title: {Story.Headline}".SmartFormat(e));
    }

    public void Observe(StoryScanned e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StoryScanned");
        log.Info("Story Unique ID: {Story.UniqueId}, File: {FilePath}, Title: {Story.Headline}".SmartFormat(e));
    }

    public void Observe(SourceDirectoryMissing e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.SourceDirectoryMissing");
        log.Error("Directory: " + e.Directory);
    }

    public void Observe(SourceDirectoryAccessError e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.SourceDirectoryAccessError");
        log.Error(e.Exception, "Exception: " + e.Exception.Message);
    }

    public void Observe(CannotCreateScannedStoryDirectory e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.CannotCreateScannedStoryDirectory");
        log.Error(e.Exception, "Directory: {Directory}, Exception: {Exception.Message}".SmartFormat(e));
    }

    public void Observe(CannotReadStoryDocument e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.CannotReadStoryDocument");
        if (e.Exception == null) {
            log.Warn("File: {FilePath}".SmartFormat(e));
        }
        else {
            log.Warn(e.Exception, "File: {FilePath}, Exception: {Exception.Message}".SmartFormat(e));
        }
    }

    public void Observe(StorySkippedPastCutoff e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StorySkippedPastCutoff");
        log.Warn("Story Unique ID: {Story.UniqueId}, File: {FilePath}, Title: {Story.Headline}".SmartFormat(e));
    }

    public void Observe(StorySkippedDuplicateUniqueId e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StorySkippedDuplicateUniqueId");
        log.Warn("Story Unique ID: {Story.UniqueId}, File: {FilePath}, Title: {Story.Headline}".SmartFormat(e));
    }

    public void Observe(StorySkippedByFilter e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StorySkippedByFilter");
        log.Warn("Story Unique ID: {Story.UniqueId}, Reason: {Reason}, File: {FilePath}, Title: {Story.Headline}".SmartFormat(e));
    }
}

1

他の人が言ったようにlog4jlog4netまたは他の適切に構築されたロギングフレームワークを使用します。

私は、コードのロギングがビジネスロジックの邪魔になることを本当に嫌う傾向があります。それが私が使用する理由ですLog4PostSharp。つまり、アスペクト指向プログラミングを使用して、次のようなメソッドに注釈を付けることができます。

[Log(LogLevel.Info, "Counting characters.")]
int CountCharacters(string arg) 
{
    return arg.Length;
}

または、次のようなアセンブリのすべてのメソッド:

[assembly: Log(AttributeTargetTypes = "*", 
 EntryLevel = LogLevel.Debug, ExitLevel = LogLevel.Debug, 
 ExceptionLevel = LogLevel.Error)]

0

フレームワークがこれを行うかどうかはわかりませんが、設計の観点から、主に3つのカテゴリにログインする必要がある情報をモデル化します。

  1. メソッドレベルのトレース
  2. 例外ログ
  3. 追加の実行時情報開発者は、実行時障害(または実行時のみの状況に関連する動作)の場合の調査に不可欠であると考えています。

最初の2つのカテゴリについては、私の理想的なロギングフレームワークは、ポストビルドプロセスとして開発者に透過的に処理する必要があります。次のように、ロギングをアセンブリに宣言的に追加すると便利です。

Trace YourNamespace.* [public methods|constructors]
{  # options
   ignore trivial methods,
   format: "{time stamp}: {method name}({parameter list})",
   condition: "{Context.Instance.UserID in (12432,23432)}",
}

Exception YourNamespace.Program.Main [unhandled exceptions]
{
  format: "{time stamp}: {Context.Instance.UserId} {exception}",
  action: die,  # options are throw, swallow,
}

3番目のカテゴリでは、プログラマは1つ以上の専用の「ロギング」メソッドを作成し、最初のカテゴリのトレースを活用できます。ロギングメソッドは、トレースルールを適用できるスタブポイントを提供するだけです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.