web-dev-qa-db-ja.com

log4jが例外のスタックトレースを出力しない

Tomcatでlog4jを使用しています。 JSP、サーブレットで例外をログに記録すると:

private Logger _log = Logger.getLogger(this.getClass());
...
try{...} catch (Exception e) {
    _log.error("Error refreshing all prices", e);
}

スタックトレースなしで、例外の最初の行のみを取得します。

2月17日17:37:45エラーAutoContrib:175-csvファイルの公開中の例外:Java.lang.ArrayIndexOutOfBoundsException

まったく役に立たない!

私のlog4j.propertiesファイル(/Tomcat/common/classes/log4j.properties)は次のようになります。

log4j.appender.stdout=org.Apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.Apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{dd-MMM HH:mm:ss} %5p %c{1}:%L - %m%n
log4j.appender.stdout.threshold=info

log4j.appender.file=org.Apache.log4j.RollingFileAppender
log4j.appender.file.maxFileSize=5000KB
log4j.appender.file.maxBackupIndex=10
log4j.appender.file.File=${catalina.home}/logs/web.log
log4j.appender.file.layout=org.Apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{dd-MMM HH:mm:ss} %5p %c{1}:%L - %m%n
log4j.appender.file.threshold=info

log4j.rootLogger=debug, stdout, file
66
Ryan

実際には、ホットスポットの最適化が原因である可能性があります。同じ例外が一定回数スローされると、トレースの出力が停止します。これはVM argでオフにできます。以下を参照してください:

http://www.Oracle.com/technetwork/Java/javase/relnotes-139183.html から:

サーバーのコンパイラVMは、すべての「コールド」組み込み例外に対して正しいスタックバックトレースを提供するようになりました。パフォーマンスの目的で、このような例外が数回スローされると、メソッドが再コンパイルされます。再コンパイル後、コンパイラは、スタックトレースを提供しない事前割り当て例外を使用して、より高速な戦術を選択する場合があります事前割り当て例外の使用を完全に無効にするには、次の新しいフラグを使用します。

詳細はこちら:

http://jawspeak.com/2010/05/26/hotspot-caused-exceptions-to-lose-their-stack-traces-in-production-and-the-fix/

76
minimo

投稿した内容には、 javadoc に記載されているスタックトレースが表示されます。

メッセージを含めない(そして単にlogger.error(ex)を呼び出す)場合、スタックトレースはログに記録されないことに注意してください。

21
objects

Errorメソッドには2つのオーバーロードメソッドがあります。

  1. logger.error(ex);
  2. logger.error("some oops string ", ex);

1番目のメソッドを使用する場合、例外の名前のみが出力されます。 2番目のメソッドを使用する場合、e.printStackTrace()メソッドに類似した完全なスタックトレースを出力する例外とともにメッセージが表示されます。

15
Venkatesh Boya

上記の@Luharが答えたように、私は同じことで苦労しました。このアプローチの良い点は、JVM、Log4Jなどのシステムレベル設定をいじる必要がないことです。これは、予期しない新しい驚きにつながる可能性があることがわからないからです。

try {

...
..

} catch (Exception er) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        er.printStackTrace(new PrintStream(os));
        LOGGER.error(new String(os.toByteArray()));
        //LOGGER.error(er);
}
6
Rockoder

あなたの設定に何の問題も見られないので、アップグレードしてみてくださいlog4jより新しい(必ずしも最新ではない)バージョンに。

この場合は問題ありませんが、ロガーを作成することをお勧めしますprivate static final

1
Bozho

FillStackTrace呼び出しを使用したことがないため、それが機能するかどうかについてコメントすることはできません。別のアプローチは、例外から書式設定されたテキストを返す小さなメソッドを使用することです。

public static String getStackTrace(Exception e)
{
    StringWriter sWriter = new StringWriter();
    PrintWriter pWriter = new PrintWriter(sWriter);
    e.printStackTrace(pWriter);
    return sWriter.toString();
}

ロギングコードでは、次のように記述できます。

logger.error("An exception occurred: " + Utils.getStackTrace(e));
1
Luhar

これらのコード行をcatchブロックに追加できます。

catch (SQLException e) {
            CharArrayWriter cw = new CharArrayWriter();
            PrintWriter w = new PrintWriter(cw);
            e.printStackTrace(w);
            w.close();
            String trace = cw.toString();

    log.error("This is complete stacktrace", trace);
}
0
madhu