Level.FINEログメッセージが表示されないのはなぜですか?


110

状態のJavaDocsjava.util.logging.Level


降順のレベルは次のとおりです。

  • SEVERE (最高値)
  • WARNING
  • INFO
  • CONFIG
  • FINE
  • FINER
  • FINEST (最低値)

ソース

import java.util.logging.*;

class LoggingLevelsBlunder {

    public static void main(String[] args) {
        Logger logger = Logger.getAnonymousLogger();
        logger.setLevel(Level.FINER);
        System.out.println("Logging level is: " + logger.getLevel());
        for (int ii=0; ii<3; ii++) {
            logger.log(Level.FINE, ii + " " + (ii*ii));
            logger.log(Level.INFO, ii + " " + (ii*ii));
        }
    }
}

出力

Logging level is: FINER
Jun 11, 2011 9:39:23 PM LoggingLevelsBlunder main
INFO: 0 0
Jun 11, 2011 9:39:24 PM LoggingLevelsBlunder main
INFO: 1 1
Jun 11, 2011 9:39:24 PM LoggingLevelsBlunder main
INFO: 2 4
Press any key to continue . . .

問題文

私の例ではLevelFINERに設定しているため、ループごとに2つのメッセージが表示されることを期待していました。代わりに、ループごとに1つのメッセージが表示されます(Level.FINEメッセージがありません)。

質問

FINEFINERまたは、FINEST)出力を表示するには何を変更する必要がありますか?

更新(ソリューション)

Vineet Reynoldsの回答のおかげで、このバージョンは私の期待どおりに機能します。3つのINFOメッセージと3つのメッセージが表示されFINEます。

import java.util.logging.*;

class LoggingLevelsBlunder {

    public static void main(String[] args) {
        Logger logger = Logger.getAnonymousLogger();
        // LOG this level to the log
        logger.setLevel(Level.FINER);

        ConsoleHandler handler = new ConsoleHandler();
        // PUBLISH this level
        handler.setLevel(Level.FINER);
        logger.addHandler(handler);

        System.out.println("Logging level is: " + logger.getLevel());
        for (int ii=0; ii<3; ii++) {
            logger.log(Level.FINE, ii + " " + (ii*ii));
            logger.log(Level.INFO, ii + " " + (ii*ii));
        }
    }
}

10
INFO以上の場合、コンソールにメッセージが2回出力されるように見えます。最初は匿名ロガー、次にその親であるグローバルロガーで、デフォルトではConsoleHandlerもINFOに設定されています。グローバルロガーを無効にするには、次のコード行を追加する必要があります。logger.setUseParentHandlers(false);
2014年

私はダブルスに関するminsコメントを確認したいだけです。.setUseParentHandlers(false);を使用しない限り、2つの出力が得られます。
xpagesbeast 2018年

回答:


124

ロガーはメッセージのみをログに記録します。つまり、ログレコード(またはログリクエスト)を作成します。ハンドラーが処理する宛先にメッセージを発行しません。ロガーのレベルを設定すると、そのレベル以上に一致するログレコードのみが作成されます。

を使用している可能性がConsoleHandlerあります(出力がSystem.errまたはファイルの場所を推測できませんでしたが、前者であると想定しています)。これは、デフォルトでレベルのログレコードを発行しますLevel.INFOLevel.FINER希望する結果を得るために、このハンドラーを構成して、レベル以上のログレコードを公開する必要があります。

基本的な設計を理解するために、Java Logging Overviewガイドを読むことをお勧めします。このガイドでは、ロガーとハンドラーの概念の違いについて説明しています。

ハンドラーレベルの編集

1.構成ファイルの使用

java.util.loggingプロパティファイル(デフォルトではのlogging.propertiesファイルJRE_HOME/lib)を変更して、ConsoleHandlerのデフォルトレベルを変更できます。

java.util.logging.ConsoleHandler.level = FINER

2.実行時にハンドラーを作成する

グローバル構成が上書きされる可能性があるため、これはお勧めできません。コードベース全体でこれを使用すると、ロガー構成が管理できなくなる可能性があります。

Handler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.FINER);
Logger.getAnonymousLogger().addHandler(consoleHandler);

2
ありがとう。これでうまくいきました。私が最初にとても混乱していた理由がわかりました。以前はロギングレベルで作業していましたが、そのときの実装では、すべてのログメッセージを単にに関係なく表示されるリストにドロップしましたHandler
Andrew Thompson

3
どういたしまして。そして、ええ、デザインは1つが、単にファイルに文字列をダンプしたロガーを書いてきた場合など、コンソール、あなたに取得しない
Vineetレイノルズ

7
また、グローバルJREライブラリのlogging.propertiesの変更は管理可能ですか?
James Anderson、

2
ロガー自体のレベルは、ハンドラーのレベルよりも制限が少ない必要があることに注意してください。ログを記録する前に、Javaはロガーとハンドラの間の最大レベルをチェックします。したがって、handler.setLevel(Level.FINER);のみを設定すると、デフォルトのロガーレベルはLevel.INFOであるため、何も表示されません。FINER、FINEST、またはALLに設定する必要があります。logger.setLevel(Level.ALL);と言います。
Jeff_Alieffson 2015年

これは、デフォルトの環境で匿名の名前付きロガーを使用する場合でも、ワンライナーとして問題を解決すると思います:Logger.getGlobal().getParent().getHandlers()[0].setLevel(Level.FINER);
Mark Jeronimus

27

なぜ

java.util.loggingには、デフォルトでに設定されているルートロガーと、デフォルトでに設定されLevel.INFOているConsoleHandlerがアタッチされていLevel.INFOます。 FINEはより小さいためINFO、デフォルトでは細かいメッセージは表示されません。


解決策1

たとえば、パッケージ名から、またはを使用してLogger.getGlobal()、アプリケーション全体のロガーを作成し、それに独自のConsoleLoggerをフックします。次に、(より高いレベルのメッセージの重複出力を回避するために)ルートロガーにシャットダウンを依頼するか、ログをルートに転送ないようロガーに依頼します。

public static final Logger applog = Logger.getGlobal();
...

// Create and set handler
Handler systemOut = new ConsoleHandler();
systemOut.setLevel( Level.ALL );
applog.addHandler( systemOut );
applog.setLevel( Level.ALL );

// Prevent logs from processed by default Console handler.
applog.setUseParentHandlers( false ); // Solution 1
Logger.getLogger("").setLevel( Level.OFF ); // Solution 2

解決策2

または、ルートロガーのバーを下げることもできます。

あなたはコードでそれらを設定することができます:

Logger rootLog = Logger.getLogger("");
rootLog.setLevel( Level.FINE );
rootLog.getHandlers()[0].setLevel( Level.FINE ); // Default console handler

または、ログ構成ファイルを使用している場合は、それを使用します。

.level = FINE
java.util.logging.ConsoleHandler.level = FINE

グローバルレベルを下げると、一部のSwingコンポーネントやJavaFXコンポーネントなどのコアライブラリからのメッセージが表示されるようになります。この場合、あなたは設定可能フィルターないあなたのプログラムからのメッセージをフィルタリングするためにルートロガーに。


applog.setUseParentHandlers(false)これらのコードは私に役立ちます。
aolphn

4

なぜ私のJavaロギングが機能しないのですか

は、ログインが期待どおりに機能しない理由を解明するのに役立つjarファイルを提供します。インストールされているロガーとハンドラー、および設定されているレベルとロギング階層のどのレベルの完全なダンプを提供します。


これはコメントであり、回答ではありません。
hfontanez

4

なぜ

@Sheepyが述べたように、これが機能しない理由java.util.logging.Loggerは、デフォルトでルートロガーがLevel.INFOあり、ConsoleHandlerそのルートロガーに接続されている場合もデフォルトでになっているためLevel.INFOです。そのため、見るためにFINEFINERまたはFINEST)出力を、あなたは、ルートロガーのデフォルト値を設定し、そのために必要ConsoleHandlerLevel.FINE次のように:

Logger.getLogger("").setLevel(Level.FINE);
Logger.getLogger("").getHandlers()[0].setLevel(Level.FINE);


アップデートの問題(解決策)

@minsで述べたように、メッセージはコンソールで2回INFO以上表示されます。最初は匿名ロガー、次にその親であるルートロガーで、デフォルトでConsoleHandler設定さINFOれています。ルートロガーを無効にするには、次のコード行を追加する必要があります:logger.setUseParentHandlers(false);

@Sheepyによって言及されたルートロガーのデフォルトのコンソールハンドラーによってログが処理されないようにする他の方法があります。例:

Logger.getLogger("").getHandlers()[0].setLevel( Level.OFF );

ただしLogger.getLogger("").setLevel( Level.OFF );、ルートロガーに直接渡されたメッセージのみをブロックし、子ロガーからのメッセージはブロックしないため、機能しません。仕組みを説明するためにLogger Hierarchy、次の図を描きます。

ここに画像の説明を入力してください

public void setLevel(Level newLevel)このロガーによって記録されるメッセージレベルを指定するログレベルを設定します。この値より低いメッセージレベルは破棄されます。レベル値Level.OFFを使用して、ロギングをオフにすることができます。新しいレベルがnullの場合、このノードは特定の(null以外の)レベル値を持つ最も近い祖先からそのレベルを継承する必要があることを意味します。


0

私は実際の問題を見つけましたが、それはどの回答にも記載されていませんでした。私の単体テストの一部は、ロギング初期化コードを同じテストスイート内で複数回実行させ、後のテストでロギングをめちゃくちゃにしていました。


0

他のバリアントを試しましたが、これは適切な場合があります

    Logger logger = Logger.getLogger(MyClass.class.getName());        
    Level level = Level.ALL;
    for(Handler h : java.util.logging.Logger.getLogger("").getHandlers())    
        h.setLevel(level);
    logger.setLevel(level);
// this must be shown
    logger.fine("fine");
    logger.info("info");

0

このソリューションは、保守性と変更の設計に関して、私にはよく見えます。

  1. リソースプロジェクトフォルダーに埋め込むロギングプロパティファイルを作成し、jarファイルに含めます。

    # Logging
    handlers = java.util.logging.ConsoleHandler
    .level = ALL
    
    # Console Logging
    java.util.logging.ConsoleHandler.level = ALL
  2. コードからプロパティファイルをロードします。

    public static java.net.URL retrieveURLOfJarResource(String resourceName) {
       return Thread.currentThread().getContextClassLoader().getResource(resourceName);
    }
    
    public synchronized void initializeLogger() {
       try (InputStream is = retrieveURLOfJarResource("logging.properties").openStream()) {
          LogManager.getLogManager().readConfiguration(is);
       } catch (IOException e) {
          // ...
       }
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.