Lotus Expeditor Toolkit バージョン 6.2
オペレーティング・システム: Linux on x86、Windows


Java.util.logging のベスト・プラクティス

JSR47 の使用に関するベスト・プラクティスのセットを、以下に示します。
  1. ロガーを取得するための優れた方法はありますか ?
    各クラスで以下のパターンを使用して、JSR47 ロガーを取得できます。
    private static final String CLAZZ_NAME = MyClass.class.getName();
    private static final String PKG = MyClass.class.getPackage().getName();
    private static Logger _logger = Logger.getLogger(PKG);

    MyClass を実際のクラス名に置き換えて、 同じ名前のプロパティー・ファイルがパッケージのリーフ・ノードとして存在することを確認してください。

    注: CLAZZ_NAME 定義はロガー初期化には不要ですが、すべての logp() ロギングとトレースの呼び出しに使用します。示されているとおりにセットアップしてください。
    注: このパターンを使用する場合は、後でパッケージの名前を変更するときに注意してください。
  2. LogManager.getLogger("com.ibm.rcp.mypackage"); を使用するだけではどうですか?

    java.util.logging.LogManager.getLogger(String name) は、一致する名前がすでに存在する場合には、その名前をロガーに返します。 その他の場合は、ヌルを返します。 クラスのインスタンス化の順序は決められていないので、クラスが初期化されるときに指定のロガーが存在する保証はありません。 現時点の順序と後の順序とでは異なる場合があります。 そのため、Logger クラスにあるゲット・メソッドを使用して、 Logger が確実に戻されるようにする必要があります。 LogManager または Logger のどちらを使用してロガーを取得するとしても、指定されたロガーのインスタンスが VM 内で一度に複数存在することはありません。

  3. ロガーのログ・レベルはどのようにして変更できますか ?
    LogManager は、 ファイル <workspace>/.config/rcpinstall.properties の値に基づいて初期化されます。 そこで、ロガーのレベルを設定できます。 例えば、パッケージ com.ibm.rcp.mypackage 内にある自分のコードに対する ログ項目をすべて表示するには、次のストリングを追加します。
    com.ibm.rcp.mypackage.level=FINEST

    rcpinstall.properties 内のデフォルト値を SEVERE に変更すると、他の JSR47 ロガーからの SEVERE レベル・メッセージだけを受け取ることができます。

    また、Lotus® Expeditor の OSGi コンソール機能を活用すると、ロギング・レベルを動的に変更できます。そのためには、-console を起動に追加し、setlogrlev コマンドと getlogrlev コマンドをここで記されているように利用します。

    setlogrlev osgi コンソール・コマンドを使用すると、JSR47 を使用可能な Lotus Expeditor コンポーネントのトレースを行えます。このコマンドについてのヘルプを以下に記します。
    • setlogrlev <logger> (level) - ロガーを指定のレベルに設定します。デフォルトは、FINEST です。
    • getlogrlev <logger> - 指定のロガーの現行レベルを戻します。
    以下の例は、com.ibm.rcp.core.internal.pd.manager ロガーに対して FINEST レベルでのトレースを有効にする詳しい方法を示しています。
    osgi> setlogrlev com.ibm.rcp.core.internal.pd.manager
  4. 自分のログはどこにありますか ?

    システム・ログは、<workspace>¥logs¥error-log-0.xml にあります。 n は数字の 0 (現行ログ)、または前回実行したときのログを示す 1 です。

    システム・トレース・ファイルは、<workspace>¥logs¥trace-log-0.xml にあります。 n は数字の 0 (現行ログ)、または前回実行したときのログを示す 1 です。

    ログ・ファイルとトレース・ファイルの詳細については、InfoCenter の Lotus Expeditor の「トラブルシューティングおよびサポート」の『クライアント・デスクトップのトラブルシューティング』セクションを参照してください。

  5. 「保護されたロギング」とは何であり、なぜそれが必要ですか ?
    「保護されたロギング」は、 ログ・ステートメントが出力されるかどうかをそれを実行する前に検査するためのパターンです。 ロガーは自ら初期検査を実行して、このメッセージが確実にログ・イベント・ハンドラーに送信されるようにしますが、ロガー・ガーダーに到達するためにはすべてのパラメーターが最初に解決される必要があります。場合によっては、パラメーターを解決するには複雑な操作やストリング操作が必要になる場合があります。そのような場合、ログまたはトレースの呼び出しを行う前に、Java™ コードに明示的な保護を追加することをお勧めします。以下の例は、ログ・メッセージのパラメーター解決の一部として複雑なストリング操作を必要とするロギング・メッセージを示しています。
                if(_logger.isLoggable(WARNING)){
                    _logger.logp(WARNING,CLAZZ_NAME, METHOD,
                         Nls.bind("warn.unable.to.get.preference",
                       new Object[]{pid,key}));
               }
    次のコード・サンプルは、『保護されたロギング』を必要としない簡単なストリング連結を例示しています。
       private boolean methodP(String param1, String param2) {         
    		logger.entering(CLAZZ_NAME,METHOD, param1 + "," + param2);
    }
    前述の例では、param1param2 がストリングであると想定されています。こうしたパラメーターがストリング・オブジェクトではなく、複雑な toString() 実装がなされている場合、保護されたロギングは推奨されていません。
    表 1. 保護されたロギングの例と説明
    保護すべきか? 理由
    _logger.logp( Level.SEVERE, CLAZZ_NAME, METHOD, NLS.bind( Messages.MessageKey, new Object[] { element[i].getContributor().getName() } ), exception ); いいえ SEVERE メッセージは必ずログに記録されます。
    _logger.logp( Level.WARNING, CLAZZ_NAME, METHOD, Messages.MessageKey2 ); いいえ 警告メッセージをログに記録する簡単な呼び出し
    _logger.logp( Level.INFO, CLAZZ_NAME, METHOD, NLS.bind( Messages.MessageKey, new Object[] { element[i].getContributor().getName(), createReportFromExtension( element[i] ) }, exception ) はい createReportFromExtension は、メッセージ内で置換するオブジェクトを生成するためにかなり作業を実行する必要があります。
    _logger.entering( CLAZZ_NAME, METHOD ) いいえ _logger.entering はレベル検査を実行し、その結果コードの読み取りが簡単になります。

    String result = "something"

    ...

    _logger.exiting( CLAZZ_NAME, METHOD, result )

    いいえ _logger.exiting はレベル検査を実行し、その結果コードの読み取りが簡単になります。

    ...

    _logger.exiting( CLAZZ_NAME, METHOD, result )

    いいえ 結果オブジェクトでは、ロギング・レベルが有効でない限りは、ストリングへの変換は行われません。

    SomeObject result = getFromSomeplace();

    ...

    _logger.exiting( CLAZZ_NAME, METHOD, result.toString() )

    はい toString() 操作によって大規模なストリングが作成されるので、終了メソッドの呼び出し前にそうしたストリングを解決し、大規模なストリング操作を回避するために保護検査を実行する必要があります。
    注: パラメーターに toString() メソッドが組み込まれていないのであれば、この呼び出しでは保護は必要とされません。結果は exiting() 署名と一致し、java.util.logging によって提供される組み込み保護になるからです。
  6. 各ロギング・レベルを使用する際の指針は何ですか ?

    INFO

    行う: コンポーネントの通常の操作を表し、他のコード・セグメントで発生する可能性のある問題を解決するために役立つイベントに対して、INFO を使用します。 例えば、インストール操作の完了を検証した後に、以下のメッセージがランチャーからログに記録されます。
    インストール操作が完了しました。

    行わない: INFO をデバッグ情報、プログラム実行のトレース、頻繁に繰り返す可能性のあるイベントのために使用したり、関連するイベントでの問題の原因判別に役立つのでない限り、確認するだけの目的で使用することはしません。

    WARNING

    行う: WARNING は、通常の操作に有害な影響を与えても、ほとんどの操作が実行し続けることを妨げないような問題が発生したときに使用します。 その良い例は、プロビジョニングからの次のメッセージです。
    URL EXPEDITOR.png のページ・ファイルの検索に失敗しました。

    行わない: WARNING は、その問題によって機能の使用が完全にまたはかなり除去される場合、 または機能の低下を示していない情報メッセージのためには使用しません。

    SEVERE

    行う: SEVERE は、ある機能がほとんどまたは完全に失われるようなイベントを示すために使用します。 SEVERE メッセージの例としては、plugin_customization.ini を 読み取ることができない場合にプラットフォーム・プラグインによって書き込まれる次のものがあります。
    プラグイン・カスタマイズ・ファイルのロード中にエラーが生じました。

    行わない: SEVERE は、機能のすべてまたはほとんどが引き続き使用可能な場合、または問題が一時的なものである場合には使用しません。

  7. トレースはどのように行われるか ? 開発者専用のトレースの場合は ?

    トレースは、デフォルトでは使用不可になっています。 トレースは、開発者、品質工学の担当者、およびサポート担当者が使用するためのものです。

    トレースのレベルには、FINE、FINER、および FINEST の 3 つがあります。

    FINE: このレベルは、問題を理解またはデバッグしようとするときに、システムの流れや状態を説明する有意のイベントに対して使用します。 これらは通常、オブジェクト作成のレベルで、エラーとならない例外などのキャッチ文節です。

    FINER: FINER レベルのメッセージを生成する Logger メソッドのセットがあります。 それらは、entering(...)、exitin(..)、finer(..)、および throwing(..) です。
    • entry および exit は、メソッドの入り口および出口に使用します。
    • finer は、fine で期待されるよりも詳細ではあっても、 メソッドの出入り口ではないトレースや、例外のスローの前に使用されるトレースに使用できます。
    • throwing は、例外をスローまたは再スローする直前に使用します。

    FINEST: FINEST は、通常は開発者用またはデバッグ用のトレースとなります。 これは開発の際に、システムの動作を詳細なレベルで理解しようと試みるとき、 およびコードのリリース後に難解な問題を診断しようと試みるときに使用されます。

    トレースは、開発中も開発後も価値あるツールとなります。 トレースは動的な使用可能化をサポートする必要があり、java.util.logging.Logger API を使用して実行される必要があります。 経験法則によれば、開発時に価値あるものは、後になってからもその価値は失われません。 println または printStackTrace は動的な使用可能化やレベル管理をサポートしていないのでかなり使い勝手が悪く、問題判別のためにシステム・トレース・ファイルを使用するのにこれらを使用しようとすると、多くの場合思うようにできないかもしれません。

  8. ロギング例外をどのように処理すべきですか ?
    すべての例外は、ロギング・ステートメントに記述される必要があります。 その例外が些細 (ささい) なものだったり再スローされている場合を除いて、通常これは WARNING または SEVERE レベルとなります。 その他の指針には、以下のものがあります。
    • 例外を含むログ項目についての特定のメッセージを常に提供します。 そのメッセージでは、例外の影響について説明します。
    • メッセージではなく、例外をログに記録します。 自分で設定したものでなければ、メッセージが理解可能であること、または存在することさえ保証されていません。
    • 例外の発生時に printStackTrace を呼び出さないでください。 これはロガーの役割です。ロガーは、オートノミックなどが例外に反応できるような方法でこれを行います。
    • 例外をキャッチしてから新しい例外をスローする場合 (上手に記述された API ではよく生じる)、キャッチした例外をスローした例外の原因として使用する必要があります。 この場合、関係者はみな同じ指針に従うことを前提に、キャッチした例外をログに記録しないでください。
    • ときには、その情報がユーザーに役立つ可能性があると思われる場合、 別の例外をスローする予定であっても最初の例外をログに記録する価値があることもあります。
  9. ロギングの例としてどんなものがありますか ?
    次の 2 つのコード例は、一般的なロギング・パターンです。
      _logger.logp(Level.INFO, CLAZZ_NAME, METHOD,
    "Messages.PROCESS_RECS");
    以下は、ログに記録することが必要な例外の場合です。
    _logger.logp(Level.SEVERE,CLAZZ_NAME,METHOD,Messages,RCP_XML_PROCESSING_ERROR
        throwable);
  10. トレースの例としてどんなものがありますか ?

    以下のコード例は、トレースを例示しています。

    トレース例 1:
    if (_logger.isLoggable(Level.FINE)) 
            	            	_logger.logp(CLASS_NAME_METHOD,"Setting activities for page 
                               " + _model.getName() + ":");    	 
    }

    前述の例では、_model.getName() 呼び出しにおいて、1 つのストリングを単に戻すだけでなく、より複雑な処理が必要であると想定されています。1 つのストリングだけが戻るのであれば、この場合には保護は必要ありません。

    トレース例 2:
    	private GUID methodX(URL url, IProgressMonitor pM, boolean overrideCache) {
    
              final String METHOD="methodX";
    		if (logger.isLoggable(Level.FINER)) {
    			logger.entering(CLASSNAME, METHOD, url==
                                 null?"null":url.toExternalForm());
    		}
    		…
    	}
    この例では、他の引数はデバッグの際にあまり役立たないので、入り口で URL だけがログに記録されます。アプリケーションがロードされない場合、部分的に計算され、部分的に破損した URL の問題によることが多いので、ロード呼び出しに渡されている URL を正確に知ることはとても役立ちます。 また、これは private メソッドです。 この private メソッドを呼び出すことで多くの public メソッドがそれぞれのジョブを行うので、 public 呼び出しを使用して URL を何回もログに記録する代わりに、これによりロギングをこのメソッドに集中させることができます。
    		logger.exiting(CLASSNAME, METHOD, res);

    "exiting" 呼び出しでは、このメソッドから返される結果もログに記録されます。 これもまた、障害が生じた場合に何が問題であるかを判別するためのデバッグを行う際に、とても役立ちます。

    トレース例 3:
    public void showApplication(URL url, String pageId, IProgressMonitor 
              progressMonitor)
    		 throws IllegalArgumentException, CompositeApplicationException {
    
        final String METHOD="showApplication";
    		if (logger.isLoggable(Level.FINER)) {
    			logger.entering(CLASSNAME, 
    				
        METHOD, 
    				new Object[] {url, pageId, progressMonitor});
    		}
    } catch (RuntimeException e) {
    			logger.logp(Level.SEVERE,CLASS NAME, METHOD
    Messages.PORTAL APP JOB UPDATE ERROR, e);
    			throw new CompositeApplicationException(e);
    		}
  11. ロガー・レベルをキャッシュに入れる必要がありますか ?

    呼び出しを保護する必要が生じるたびにレベルを調べるよりも、ロガーのレベルを実行中に一度だけ調べてからキャッシュに入れられたそのレベルを参照する方が良さそうに思えるかもしれません。 しかし、この方法では OSGi コマンド・プロンプトからの更新などロガー・レベルの構成に対する動的な更新にコードが対応しなくなることがあるため、これは勧められていません。



ライブラリー | サポート | ホーム | 教育 | ご利用条件 |

最終更新日: 2008 年 10 月 21 日
© Copyright IBM Corporation 2006, 2008. All Rights Reserved.
この Information Center では Eclipse™ (http://www.eclipse.org)
が採用されています。