2011-10-02 8 views
18

私は現在、数多くのクラスを持つJavaで大きなプロジェクトを作成しています。 メインクラスにロガーが設定されていて、正常に動作します。 すべてのクラスで1つのロガー(1つのコンソールアペンダーを使用)を使用できるようにします。 ロガーへの参照を別のクラスに渡そうとしましたが、正しく表示されません。さらに、メインで実行されていないクラスでテストを実行しているので、他のクラスでは初期化されていません。複数のクラスでlog4jを使用するには?

これを達成するための最良の方法は、異なるクラスから1つのログにログする方法です。クラス間の依存関係がなく、各クラスと独立してログを使用できますか?

答えて

16

私が正しく理解していれば、あなたは分で持っていることは次のとおりです。

public class Main { 
    public static final Logger LOGGER = Logger.getLogger(Main.class); 
} 

public class AnotherClass { 
    public void doSomething() { 
     Main.LOGGER.debug("value=" + value); 
    } 
} 

か、あなたはクラスのコンストラクタにロガーへの参照を渡します。

まず、あなたは同じように、単にLogger.getLoggerに渡された同じ値を使用して、1つのグローバルロガーを使用することができます。これはまったく同じロガーを使用しています

public class Main { 
    private static final Logger LOGGER = Logger.getLogger("GLOBAL"); 
} 

public class AnotherClass { 
    private final Logger LOGGER = Logger.getLogger("GLOBAL"); 

    public void doSomething() { 
     LOGGER.debug("value=" + value); 
    } 
} 

、Logger.getLoggerは両方の呼び出しで同じオブジェクトを返します。 。クラス間に依存関係がなくなり、これが機能します。

私はあなたのコメントから集まる他の事は、あなたがBasicConfigurator.configureを使用して(手で設定されていることである。ほとんどの時間は、これは必ずしも必要ではない、とあなたは、単にlog4j.propertiesかのlog4jを追加して設定を行う必要があります。 xmlをクラスパスに追加するEclipseでこれはsrc /(またはmavenを使用している場合はsrc/main/resources)に追加することで行いますjunitを使用している場合は、test/sourceディレクトリ(またはsrc/test/resources with maven)これは、クラス間で情報を渡す必要がないので、log4jを構成する長期的な方がはるかに優れています。

また、ロガーを使用することが推奨方法は、Logger.getLoggerにクラスを渡すことです()。その後log4j.propertiesで、1つのファイルに単一アペンダを設定することができ

public class Main { 
    private static final Logger LOGGER = Logger.getLogger(Main.class); 
    public static final main(String[] args) { 
     LOGGER.debug("started"); 
    } 
} 

public class AnotherClass { 
    private final Logger LOGGER = Logger.getLogger(this.getClass()); 

    public void doSomething() { 
     LOGGER.debug("value=" + value); 
    } 
} 

:この方法では、通常、はるかに便利なだけで一つのグローバルロガーを持つよりも、クラス名、に基づいて、あなたの出力をフィルタリングすることができます。

# Set root logger level to DEBUG and its only appender to A1. 
log4j.rootLogger=DEBUG, A1 

# A1 is set to be a ConsoleAppender. 
log4j.appender.A1=org.apache.log4j.ConsoleAppender 

# A1 uses PatternLayout. 
log4j.appender.A1.layout=org.apache.log4j.PatternLayout 
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n 

最後に、すべてのロガーを静的に宣言する必要はありません。これは、オブジェクト作成の [*]のロットを実行している場合にのみ顕著な違いになります。ロガーを非静的フィールドとして宣言すると、Logger.getLogger(this.getClass());を使用できます。その場合、クラスにロガーを追加すると、1行の切り取りと貼り付けになります。 Should I declare Log references static or not?を参照してください(残念ながらwikiページへのリンクが壊れています)が、slf4j pageにも説明があります。だから非常に良い理由がない限り、非静的フィールドを使用してください。

キャメロンは、可能であればslf4jを試してみる必要があると言います.1つのキラー機能があり、複数のログフレームワークを使用できます。

[*]と私はロットを意味します。

+0

私はまさにあなたが言及したように、Mainクラスのログだけが印刷されますが、他のメソッドのログは印刷されません。それを修正する方法 –

5

Your logger instances should typically be private, static and final。これにより、各クラスには、ログレコードが作成されたクラスを識別できるように、またクラス間でロガーインスタンスを渡す必要がなくなるように、クラスがロードされると独自のロガーインスタンスが作成されます(クラスがロードされると作成されます)。

+0

ここで、 "BasicConfigurator.configure();" メインメソッドのないクラスでは? – stdcall

+0

@Mellowcandleでは、すべてのクラスで 'BasicConfigurator.configure()'を呼び出す必要はありません。これは、あなたのアプリを初期化するクラスの主なメソッドでのみ行う必要があります。編集:['BasicConfigurator.configure'](http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/BasicConfigurator.html#configure%28%29)を使用してlog4j設定を作成し、 appendersとレイアウトで構成された機能的なlog4j.propertiesファイルがないときです。 –

+0

あなたは何をしなければならないのですか?いくつかのクラスで単体テストを実行する必要があります。いつ実行する必要がありますか? – stdcall

4

これを行う最も良い方法は、各クラスに独自のロガー(クラスの名前にちなんで命名)を持たせてから、すべてが同じアペンダーに追加されるように構成を設定することです。例えば

# Set root logger level to DEBUG and its only appender to A1. 
log4j.rootLogger=DEBUG, A1 

# A1 is set to be a ConsoleAppender. 
log4j.appender.A1=org.apache.log4j.ConsoleAppender 

# A1 uses PatternLayout. 
log4j.appender.A1.layout=org.apache.log4j.PatternLayout 
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n 

両方ABがするので、ルートロガーにログインします:

class A { 
    private static final Logger log = Logger.getLogger(A.class); 
} 

class B { 
    private static final Logger log = Logger.getLogger(B.class); 
} 

次に、あなたのlog4j.propertiesは、log4jのドキュメントの例のように見えることができます同じアペンダー(この場合はコンソール)。

これはあなたに必要なものを与えます:各クラスは独立していますが、それらはすべて同じログに書き込みます。また、log4j設定で各クラスのロギングレベルを変更できるという特典があります。

プロジェクトが初期の開発段階にある場合は、slf4jに移行することをお勧めします。 slf4jにはlog4jよりもいくつかの改良が施されているので、作業が少し楽になります。

+0

ここでは、 "BasicConfigurator.configure();"主な方法のないクラスでは? – stdcall

+2

@Mellowcandle:しないでください。 'log4j.properties'ファイルを使用してください。クラスパスに配置するだけで、log4jがそれを使用します。 –

+0

@CameronSkinnerまさにあなたが言及したように、Mainクラスのログだけがコンソールに表示され、他のメソッドのログは出力されません。どのように修正するのですか? –

1

あなたは(通常はクラス名をプリントアウトすることにより、それらを用いて構成されている)ログインするときにそれらが異なる振る舞いをしたいので、あなたが複数のロガーインスタンスを持っている理由があります。気にしない場合は、クラス内に単一のスタティックロガーインスタンスを作成し、その場所全体で使用することができます。単一ロガーを作成するには

、あなたは単に一点ロガーであることを静的ユーティリティロギングクラスを作成することができますので、我々はロガーパッケージを変更する必要がある場合、あなただけの、このクラスを更新します。

final public class Logger { 
    private static final org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger("Log"); 

    enum Level {Error, Warn, Fatal, Info, Debug} 

    private Logger() {/* do nothing */}; 

    public static void logError(Class clazz, String msg) { 
     log(Level.Error, clazz, msg, null); 
    } 

    public static void logWarn(Class clazz, String msg) { 
     log(Level.Warn, clazz, msg, null); 
    } 

    public static void logFatal(Class clazz, String msg) { 
     log(Level.Fatal, clazz, msg, null); 
    } 

    public static void logInfo(Class clazz, String msg) { 
     log(Level.Info, clazz, msg, null); 
    } 

    public static void logDebug(Class clazz, String msg) { 
     log(Level.Debug, clazz, msg, null); 
    } 


    public static void logError(Class clazz, String msg, Throwable throwable) { 
     log(Level.Error, clazz, msg, throwable); 
    } 


    public static void logWarn(Class clazz, String msg, Throwable throwable) { 
     log(Level.Warn, clazz, msg, throwable); 
    } 

    public static void logFatal(Class clazz, String msg, Throwable throwable) { 
     log(Level.Fatal, clazz, msg, throwable); 
    } 

    public static void logInfo(Class clazz, String msg, Throwable throwable) { 
     log(Level.Info, clazz, msg, throwable); 
    } 

    public static void logDebug(Class clazz, String msg, Throwable throwable) { 
     log(Level.Debug, clazz, msg, throwable); 
    } 

    private static void log(Level level, Class clazz, String msg, Throwable throwable) { 
     String message = String.format("[%s] : %s", clazz, msg); 
     switch (level) { 
      case Info: 
       logger.info(message, throwable); 
       break; 
      case Warn: 
       logger.warn(message, throwable); 
       break; 
      case Error: 
       logger.error(message, throwable); 
       break; 
      case Fatal: 
       logger.fatal(message, throwable); 
       break; 
      default: 
      case Debug: 
       logger.debug(message, throwable); 
     } 
    } 

} 
関連する問題