78

I am using log4j with tomcat. When I log exceptions in my JSPs, servlets:

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

I only get the first line of the exception, without a stacktrace.

17-Feb 17:37:45 ERROR AutoContrib:175 - Exception while publishing csv file: java.lang.ArrayIndexOutOfBoundsException

Not very helpful at all!

My log4j.properties file (/tomcat/common/classes/log4j.properties) looks like this:

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
Raedwald
  • 46,613
  • 43
  • 151
  • 237
Ryan
  • 3,924
  • 6
  • 46
  • 69
  • As far as I can see you are doing it all as it should be done... you should see all of the stacktrace in your log. Which version of log4j, Java and Tomcat are you using? – Manrico Corazzi Feb 19 '10 at 09:03
  • We're using tomcat 5.5.17 and log4j-1.2.14 (I think we'll upgrade to tc6 in the near future, but I am not sure that will make any difference?) – Ryan Feb 19 '10 at 09:05
  • You can view bellow thread. It has complete answer https://stackoverflow.com/a/51655824/3073945 – Md. Sajedul Karim Aug 02 '18 at 14:20
  • From recent news about log4jShell, this is now the least of my worries!... – Ryan Dec 17 '21 at 09:32

8 Answers8

114

Actually, it's probably due to a hotspot optimization: after a certain number of the same exception being thrown it stops printing out trace. This can be turned off with a VM arg, see:

From http://www.oracle.com/technetwork/java/javase/relnotes-139183.html :

The compiler in the server VM now provides correct stack backtraces for all "cold" built-in exceptions. For performance purposes, when such an exception is thrown a few times, the method may be recompiled. After recompilation, the compiler may choose a faster tactic using preallocated exceptions that do not provide a stack trace. To disable completely the use of preallocated exceptions, use this new flag: -XX:-OmitStackTraceInFastThrow.

More here:

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

naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259
minimo
  • 1,396
  • 1
  • 9
  • 9
29

There are two overloaded methods for error method.

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

if you use 1st method , which will only print the name of the Exception. if you use 2nd method, some message along with exception which will print complete stack trace similar to e.printStackTrace() method.

Venkatesh Boya
  • 564
  • 5
  • 11
27

What you have posted should display the stack trace as stated in the javadoc.

Note that if you don't include a message (and just call logger.error(ex)) then the stack trace is not logged.

Ahmed Ashour
  • 5,179
  • 10
  • 35
  • 56
objects
  • 8,637
  • 4
  • 30
  • 38
  • 3
    Ah. There it is. This is what was biting me. Logging an error doesn't print the stack trace. You need to log a message with the error to get that. – rbwhitaker May 10 '13 at 17:02
  • This was helpful. Thank you. Can we configure log4j so it display a full trace even if we just provide the exception object? – Charles Morin Mar 31 '17 at 13:38
7

Like answered by @Luhar above, I struggled with same thing and finally this worked for me; Good thing about this approach is we don't have to tinker with system level settings like JVM, Log4J since we never know it may lead to new unexpected surprise !

try {

...
..

} catch (Exception er) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        er.printStackTrace(new PrintStream(os));
        LOGGER.error(new String(os.toByteArray()));
        //LOGGER.error(er);
}
Ahmed Ashour
  • 5,179
  • 10
  • 35
  • 56
Rockoder
  • 746
  • 2
  • 11
  • 22
1

I don't see anything wrong with your config, so try to upgrade log4j to a newer (not necessarily the latest) version.

Though not the problem in this case, you'd better make your loggers private static final

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
1

I haven't used the fillStackTrace call, so I cannot comment if that will work. Another approach is to use a little method that returns the formatted text from an Exception.

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

In your logging code, you could write:

logger.error("An exception occurred: " + Utils.getStackTrace(e));
Luhar
  • 1,859
  • 2
  • 16
  • 23
1

You can add these lines of code in your catch block.

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);
}
madhu
  • 1,083
  • 3
  • 12
  • 31
-1

Using your code sample:

private static final Logger _log = Logger.getLogger(MyClass.class);
...
try{...} catch (Exception e) {
    //Change
    //_log.error("Error refreshing all prices", e);

   //To
    _log.error("Error refreshing all prices", e.fillInStackTrace());
}

You'll see all the stack trace displayed.

PS. Make Logger a singleton...(check my declaration) just after declaring public class MyClass {

Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
  • Thanks for the advice! I will try this now. BTW, for the singleton approach you can't use 'this' with the static getLoggger(). I guess I can use getLogger(MyClass.class) – Ryan Feb 19 '10 at 09:18
  • True Ryan!. It makes instantiation faster seeing that the singleton already exists after creation. – Buhake Sindi Feb 19 '10 at 09:22
  • ideally, he shouldn't need this – Bozho Feb 20 '10 at 10:49
  • 4
    that changes the stack trace to be the state of the current thread. It will no longer be the stack trace for the thrown exception – objects Feb 23 '10 at 22:43
  • That's correct, Definition of `fillInStackTrace()`: `Fills in the execution stack trace. This method records within this Throwable object information about the current state of the stack frames for the current thread.` and that's what we want. So recording all the stack frames from the thread that executed it. After all, Web apps especially are thread-executed, so that makes perfect sense. – Buhake Sindi Feb 24 '10 at 08:00
  • 2
    the stack trace of the thread is different from the stack trace of the exception. The stack trace of the exception shows where the exception occurred, the stack trace of the thread (in this case) shows where the exception was caught. – objects Feb 24 '10 at 08:45
  • I understand what you're saying @objects, `fillInStackTrace` also records the Cause of the exception. So you can ideally check in the cause to see where the fault lies. – Buhake Sindi Feb 24 '10 at 09:18
  • 1
    fillInStackTrace does not record the cause afaik, it (the cause) is set when the exception is created (fillInStackTrace is also called at that point) – objects Feb 24 '10 at 23:55