ロガーはプライベートスタティックかどうか


103

ロガーを静的に宣言する必要がありますか?通常、ロガーの宣言には2つのタイプがあります。

    保護されたログログ=新しいLog4JLogger(aClass.class);

または

    プライベート静的ログログ=新しいLog4JLogger(aClass.class);

どちらを使用する必要がありますか?両方の長所と短所は何ですか?


1
ロギングは分野横断的な関心事です。アスペクトを使用してください。
デイブジャービス

4
staticクラスごとに1つの参照です。非静的は、インスタンスごとに1つの参照です(+初期化)。したがって、場合によっては、インスタンスが大量にあると、後者がメモリに大きな影響を与えることがあります。頻繁に使用するオブジェクトで非静的を使用しないでください。私は常に静的バージョンを使用しています。(大文字に する必要がありますLOG
QUITあり-Anony-Mousse

2
すでに提案されているように、AOPと注釈を使用します。例:jcabi.com/jcabi-aspects/annotation-loggable.html
yegor256

1
RobertHumeは、静的なバージョンがされた定数を使用しました。それが大文字でなければならない理由です。
QUITあり-Anony-Mousse 2017年

2
いいえ、それprivate static final Log logは小文字でなければなりません。ロガーは定数ではなく、ロガーは静的な最終オブジェクトです(変更可能)。個人的にはいつも使っていますlogger
osundblad

回答:


99

非静的形式の利点は、正しいクラス名が使用されることを心配せずに、次のように(抽象的な)基本クラスで宣言できることです。

protected Log log = new Log4JLogger(getClass());

ただし、その欠点は、クラスのインスタンスごとにまったく新しいロガーインスタンスが作成されることです。これ自体は高価ではありませんが、かなりのオーバーヘッドが追加されます。これを避けたい場合は、static代わりにフォームを使用します。しかしその欠点はgetClass()、静的コンテキストでは使用できないため、ロガーの構築中に正しいクラス名が使用されるように、個々のクラスごとに宣言し、すべてのクラスで注意する必要があることです。ただし、平均的なIDEでは、このためのオートコンプリートテンプレートを作成できます。たとえばlogger+ ctrl+space

一方、すでにインスタンス化されたロガーをキャッシュするファクトリーによってロガーを取得する場合、非静的フォームを使用してもオーバーヘッドはそれほど増えません。たとえば、Log4jにLogManagerはこの目的のためのがあります。

protected Log log = LogManager.getLogger(getClass());

6
abstract Log getLogger();抽象クラスで宣言します。このメソッドを実装して、特定のインスタンスの静的ロガーを返します。private final static Log LOG = LogManager.getLogger(Clazz.class);IDEクラステンプレートに追加します。
QUITあり-Anony-Mousse

2
slf4jの場合:protected Logger log = LoggerFactory.getLogger(getClass());
Markus Pscheidt 2014

3
@BalusC getClass()をgetLoggerメソッドに渡す際の問題は、現在のインスタンスのクラスを返すことです。通常、ロギングがコードがあるクラスに関連付けられることがより望ましいです。たとえば、ログコードがクラスParentにある場合、実行中のインスタンスがParentのサブクラスであるクラスChildのインスタンスであっても、ログをParentに関連付ける必要があります。getClass()を使用すると、誤って子に関連付けられます
18

@inor:「正しくない」?クラスを抽象化したくない場合は、最初に継承されたgetClass()を使用しないでください。ロジックが正確に実行されたサブクラスの情報を明らかにするので、それが正しくて便利であると考える開発者がいます。
BalusC

2
@ BalusC getLogger(getClass())を実行すると、常にサブクラスの名前が誤ってログに記録されます。ログクラスは常にgetLogger(Clazz.class)を実行して、クラスClazzのコードによって作成されたログを関連付ける必要があります。どのサブクラスが実行されているか(たとえば、SubClazzがClazzを拡張している)を知りたい開発者は、SubClazz:getLogger(SubClazz.class)で次のように実行する必要があります。
2018年

44

以前は、すべてのロガーは静的である必要があると思っていました。ただし、wiki.apache.orgのこの記事では、クラスローダーのリークに関して、いくつかの重要なメモリの問題を取り上げています。ロガーを静的として宣言すると、宣言したクラス(および関連するクラスローダー)が、共有クラスローダーを使用するJ2EEコンテナーでガベージコレクションされなくなります。アプリケーションを何度も再デプロイすると、PermGenエラーが発生します。

ロガーを非静的として宣言する以外に、このクラスローダーのリークの問題を回避する方法はありません。


4
静的フィールドにもメモリリークの問題があると思いました。他の人が言ったように、非静的にはパフォーマンスの問題があるかもしれません。では、理想的な方法は何ですか?
リャン2013年

@piepera参照した記事で説明されている主な問題は、「プライベートスタティックログログ=を使用するクラスが、複数の祖先の祖先にあるClassLoaderを介してデプロイされている場合を考慮して、各アプリケーションのロギングレベルを制御する機能です。独立した「アプリケーション」。この特定の状況ではアプリケーションに「共通グラウンド」があり、その「共通グラウンド」でクラスのロギングレベルが決定され、そうです、それはすべてのアプリケーションに当てはまるので、問題とは思われません...このクラスは、これらのアプリケーションの外部に[ロード]されることに留意してください
18

17

最も重要な違いは、それがログファイルにどのように影響するかです。ログはどのカテゴリに移動しますか?

  • 最初の選択では、サブクラスのログはスーパークラスのカテゴリになります。それは私には直感に反しているようです。
  • 最初のケースのバリアントがあります:

    保護されたログログ=新しいLog4JLogger(getClass());

    その場合、ログカテゴリは、ログに記録されたコードがどのオブジェクトで動作していたかを示します。

  • 2番目の選択肢(プライベートスタティック)では、ログカテゴリはログコードを含むクラスです。したがって、通常は、ログに記録されていることを実行しているクラスです。

私はその最後のオプションを強くお勧めします。他のソリューションと比較して、次の利点があります。

  • ログとコードの間には直接的な関係があります。ログメッセージの送信元を簡単に見つけることができます。
  • ロギングレベルを調整する必要がある場合(これはカテゴリごとに行われます)、それは通常、特定のクラスによって書かれた特定のメッセージに関心がある(または関心がない)ためです。カテゴリがメッセージを書き込んでいるクラスではない場合、レベルを調整するのが難しくなります。
  • 静的メソッドでログインできます
  • ロガーはクラスごとに1回だけ初期化(またはルックアップ)する必要があるため、作成されたインスタンスごとではなく、起動時に初期化する必要があります。

また、欠点もあります。

  • メッセージを記録するすべてのクラスで宣言する必要があります(スーパークラスロガーを再利用しないでください)。
  • ロガーを初期化するときは、正しいクラス名を付けるように注意する必要があります。(しかし、良いIDEはあなたのためにそれを処理します)。

4

制御の反転を使用して、ロガーをコンストラクターに渡します。クラス内にロガーを作成すると、単体テストで時間の悪魔が生まれます。あなたはユニットテストを書いていますね?


5
作成しているロギングを調べる単体テストは、無用で非常に壊れやすい音を生成します。
マイケル

1
テスト対象のシステムに応じた有用性。時々、ロギングがあなたがアクセスできるすべてのものです。
ウェインアレン

@Wayne Allenは、単体テストを実行しているとき、当然、テスト結果も持っています。単体テストはするがテスト結果がないという状況を示唆していますか?ログしかない?
2018

クラス内にロガーを作成しても問題は発生しません。クラスが独自のロガーを作成するためにUTに困難な簡単な例を示すことができますか?
2018

1
承知しました。メールを送信するロガーはどうですか。テストを実行するたびにそれを実行する必要はありません。さらに、副作用をどのように主張しますか?
ウェインアレン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.