178

Say you catch an exception and get the following on the standard output (like, say, the console) if you do a e.printStackTrace() :

java.io.FileNotFoundException: so.txt
        at java.io.FileInputStream.<init>(FileInputStream.java)
        at ExTest.readMyFile(ExTest.java:19)
        at ExTest.main(ExTest.java:7)

Now I want to send this instead to a logger like, say, log4j to get the following:

31947 [AWT-EventQueue-0] ERROR Java.io.FileNotFoundException: so.txt
32204 [AWT-EventQueue-0] ERROR    at java.io.FileInputStream.<init>(FileInputStream.java)
32235 [AWT-EventQueue-0] ERROR    at ExTest.readMyFile(ExTest.java:19)
32370 [AWT-EventQueue-0] ERROR    at ExTest.main(ExTest.java:7)

How can I do this?

try {
   ...
} catch (Exception e) {
    final String s;
    ...  // <-- What goes here?
    log.error( s );
}
Erick Robertson
  • 32,125
  • 13
  • 69
  • 98
SyntaxT3rr0r
  • 27,745
  • 21
  • 87
  • 120

11 Answers11

292

You pass the exception directly to the logger, e.g.

try {
   ...
} catch (Exception e) {
    log.error( "failed!", e );
}

It's up to log4j to render the stack trace.

skaffman
  • 398,947
  • 96
  • 818
  • 769
  • 39
    The logger takes an object for its first argument and will toString() it. However the second argument has to be a Throwable and displays the stack trace. – Peter Lawrey Dec 03 '10 at 16:50
  • 2
    I never know what to stuff into the first String, usually I just end up doing `log.error(e.getLocalizedMessage(), e)` which is totally redundant. Does it handle a null for the first argument? – Mark Peters Dec 03 '10 at 16:52
  • 7
    @Mark: Try to give it a message which is more pertinent to the context than the exception's message, e.g. what was it actually trying to do at the time? – skaffman Dec 03 '10 at 16:53
  • 3
    @Mark Peters, A good example could be to log the arguments to the current method as the message, or - for a FileNotFound exception the full name of the path which was tried to be opened. Anything that can help you find out what is wrong - just think you cannot debug the situation. – Thorbjørn Ravn Andersen Dec 03 '10 at 17:01
  • I agree with Thorbjørn Ravn Andersen. One of the most useful things to do with ever changing webapps is to print out the SQL on all database operations. If you put plenty of newlines in to have each part on a seperate line, your database client will tell you exactly where the error is if it you paste it in and execute it. – Steve Aug 06 '11 at 16:58
  • 1
    @skaffman: Actually I am using `log4j-1.2.8.jar` and I wanted to print all `stackTrace` on my log file so I tried like above you mentioned but is is printing on my log file only `nullPointerException`. I was used on my code `e.printStackTrace()` it prints all trace. Why this Kolavery ? – Yubaraj Sep 10 '13 at 11:22
  • Log4j allows you to configure the depth of stack trace added to the logs. If you execute the stack-trace yourself then you bypass this configurable value. Note on spewing SQL: if you are using prepared statements you may not have access to a "paste-able complete SQL command". Calling toString on an Oracle prepared statement, for instance, does not return SQL. – ChrisCantrell Jun 20 '16 at 20:09
  • You apparently need to include the message with your log or it doesn't work: https://stackoverflow.com/a/2307917/1545084 – Gladclef May 24 '17 at 16:44
15

If you want to log a stacktrace without involving an exception just do this:

String message = "";

for(StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) {                         
    message = message + System.lineSeparator() + stackTraceElement.toString();
}   
log.warn("Something weird happened. I will print the the complete stacktrace even if we have no exception just to help you find the cause" + message);
borjab
  • 11,149
  • 6
  • 71
  • 98
13

You can also get stack trace as string via ExceptionUtils.getStackTrace.

See: ExceptionUtils.java

I use it only for log.debug, to keep log.error simple.

Alex
  • 8,093
  • 6
  • 49
  • 79
ktsujister
  • 471
  • 5
  • 12
10

The answer from skaffman is definitely the correct answer. All logger methods such as error(), warn(), info(), debug() take Throwable as a second parameter:

try {
...
 } catch (Exception e) {
logger.error("error: ", e);
}

However, you can extract stacktrace as a String as well. Sometimes it could be useful if you wish to take advantage of formatting feature using "{}" placeholder - see method void info(String var1, Object... var2); In this case say you have a stacktrace as String, then you can actually do something like this:

try {
...
 } catch (Exception e) {
String stacktrace = TextUtils.getStacktrace(e);
logger.error("error occurred for usename {} and group {}, details: {}",username, group, stacktrace);
}

This will print parametrized message and the stacktrace at the end the same way it does for method: logger.error("error: ", e);

I actually wrote an open source library that has a Utility for extraction of a stacktrace as a String with an option to smartly filter out some noise out of stacktrace. I.e. if you specify the package prefix that you are interested in your extracted stacktrace would be filtered out of some irrelevant parts and leave you with very consized info. Here is the link to the article that explains what utilities the library has and where to get it (both as maven artifacts and git sources) and how to use it as well. Open Source Java library with stack trace filtering, Silent String parsing Unicode converter and Version comparison See the paragraph "Stacktrace noise filter"

Michael Gantman
  • 7,315
  • 2
  • 19
  • 36
7

Just because it happened to me and can be useful. If you do this

try {
   ...
} catch (Exception e) {
    log.error( "failed! {}", e );
}

you will get the header of the exception and not the whole stacktrace. Because the logger will think that you are passing a String. Do it without {} as skaffman said

iberbeu
  • 15,295
  • 5
  • 27
  • 48
  • 1
    Surely you will get whole stack trace here, however the {} will be printed verbatim too (without any substitution)? – k1eran Feb 25 '15 at 14:24
  • 1
    don't be so sure my friend! It didn't work to me, I got only the header. It could depend on the version of log4j though – iberbeu Feb 25 '15 at 16:27
  • @iberbeu is right because `Throwable.toString()` doesn't return a stacktrace. (Assuming you are using a logger that knows what do to with '{}'.) –  Jan 09 '19 at 19:56
4

In Log4j 2, you can use Logger.catching() to log a stacktrace from an exception that was caught.

    try {
        String msg = messages[messages.length];
        logger.error("An exception should have been thrown");
    } catch (Exception ex) {
        logger.catching(ex);
    }
mbonness
  • 1,612
  • 1
  • 18
  • 20
  • You can also print a stack trace without an exception, with: `logger.catching(new Throwable());` – Jamie Oct 28 '21 at 15:23
  • is the idea we're logging a stack trace without a `String message`? Why would we do this instead of `log.error("message", ex)`? – Geoff Langenderfer Dec 12 '22 at 21:31
  • The idea is you want to log that you caught and swallowed an exception with no other information. If you want to add an error message string then you would use logger.error as you said. – mbonness Dec 14 '22 at 13:13
2

This answer may be not related to the question asked but related to title of the question.

public class ThrowableTest {

    public static void main(String[] args) {

        Throwable createdBy = new Throwable("Created at main()");
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        PrintWriter pw = new PrintWriter(os);
        createdBy.printStackTrace(pw);
        try {
            pw.close();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        logger.debug(os.toString());
    }
}

OR

public static String getStackTrace (Throwable t)
{
    StringWriter stringWriter = new StringWriter();
    PrintWriter  printWriter  = new PrintWriter(stringWriter);
    t.printStackTrace(printWriter);
    printWriter.close();    //surprise no IO exception here
    try {
        stringWriter.close();
    }
    catch (IOException e) {
    }
    return stringWriter.toString();
}

OR

StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
for(StackTraceElement stackTrace: stackTraceElements){
    logger.debug(stackTrace.getClassName()+ "  "+ stackTrace.getMethodName()+" "+stackTrace.getLineNumber());
}
Kanagavelu Sugumar
  • 18,766
  • 20
  • 94
  • 101
0

this would be good log4j error/exception logging - readable by splunk/other logging/monitoring s/w. everything is form of key-value pair. log4j would get the stack trace from Exception obj e

    try {
          ---
          ---
    } catch (Exception e) {
        log.error("api_name={} method={} _message=\"error description.\" msg={}", 
                  new Object[]{"api_name", "method_name", e.getMessage(), e});
    }
src3369
  • 1,839
  • 2
  • 17
  • 18
0
Try this:

catch (Throwable t) {
    logger.error("any message" + t);
    StackTraceElement[] s = t.getStackTrace();
    for(StackTraceElement e : s){
        logger.error("\tat " + e);
    }   
}
0

You can use bellow code:

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class LogWriterUtility {
    Logger log;

    public LogWriterUtility(Class<?> clazz) {
        log = LogManager.getLogger(clazz);
    }

public void errorWithAnalysis( Exception exception) {

        String message="No Message on error";
        StackTraceElement[] stackTrace = exception.getStackTrace();
        if(stackTrace!=null && stackTrace.length>0) {
            message="";
            for (StackTraceElement e : stackTrace) {
                message += "\n" + e.toString();
            }
        }
        log.error(message);


    }

}

Here you can just call : LogWriterUtility.errorWithAnalysis( YOUR_EXCEPTION_INSTANCE);

It will print stackTrace into your log.

Md. Sajedul Karim
  • 6,749
  • 3
  • 61
  • 87
-2

Create this class:

public class StdOutErrLog {

private static final Logger logger = Logger.getLogger(StdOutErrLog.class);

public static void tieSystemOutAndErrToLog() {
    System.setOut(createLoggingProxy(System.out));
    System.setErr(createLoggingProxy(System.err));
}

public static PrintStream createLoggingProxy(final PrintStream realPrintStream) {
    return new PrintStream(realPrintStream) {
        public void print(final String string) {
            logger.info(string);
        }
        public void println(final String string) {
            logger.info(string);
        }
    };
}
}

Call this in your code

StdOutErrLog.tieSystemOutAndErrToLog();
Nazik
  • 8,696
  • 27
  • 77
  • 123