62

I am using Java's Logger class. I want to pass ex.printStackTrace() into Logger.log(loglevel, String), but printStackTrace() returns void. So I am not able to pass and print the stack trace of the exception.

Is there any way that I can convert void into String, or are there any other methods to print the whole stack trace of exceptions?

prmottajr
  • 1,816
  • 1
  • 13
  • 22
Surya Joseph
  • 661
  • 1
  • 5
  • 5

14 Answers14

69

You need to understand that void is actually nothingness. You cannot convert what is nothing. You might end up printing void as a string, but (trust me), you don't want that.

I think what you are looking for is

// assuming ex is your Exception object
logger.error(ex.getMessage(), ex);
// OR
Logger.log(errorLogLevel, ex.getMessage(), ex)

This will print the error message using the logger that you have configured. For more details, you can take a look at the java docs for Exception#getMessage()

Saif Asif
  • 5,516
  • 3
  • 31
  • 48
  • Thanks Saif Asif. I am able to log the whole stack trace now. – Surya Joseph Jul 14 '15 at 19:27
  • 22
    `logger.error()` is not `java.util.logging`, but I'm not going to downvote you because I am glad to discover `logger.log(Level, Exception, Supplier)` . Looks like Oracle have made `java.util.logging.Logger` seriously ugly! Since they were doing that, it's strange that they didn't take it further and create `logger.severe(String, Exception)` etc – Adam Oct 11 '17 at 12:56
  • 4
    The question asks for a solution using Java's Logger class. java.util.logging.Logger does not have a method called "error". I have downvoted this answer only because of that. – DAB Aug 28 '18 at 15:36
  • @Adam I agree that logger.error() looks ugly, but it is highly readable, and it is the way it is done in other simple languages like python, so it is not so terribly bad. – DGoiko Mar 14 '19 at 18:05
  • 4
    This is not answering the initial intention to print the stack trace to a logger, at all. getMessage() is not made for this. – A. Gille May 22 '20 at 12:28
  • 2
    So, the answer is: logger.log(Level.SEVERE, ex.getMessage(), ex); – Kenny Oct 14 '20 at 10:13
40

Use java.util.logging.Logger#log(Level, String, Throwable) and pass in ex as third argument like this:

LOGGER.log(Level.INFO, ex.getMessage(), ex);
Socowi
  • 25,550
  • 3
  • 32
  • 54
hzpz
  • 7,536
  • 1
  • 38
  • 44
27

Also another alternative would be:

import org.apache.commons.lang3.exception.ExceptionUtils;

log.error("Exception : " + ExceptionUtils.getStackTrace(exception));
RubioRic
  • 2,442
  • 4
  • 28
  • 35
Rutuja
  • 295
  • 3
  • 2
  • 2
    If you're refering to org.apache.commons.lang3.exception.ExceptionUtils, it's ExceptionUtils.getStackTrace(e) – JoschJava Sep 04 '18 at 15:46
13

There's an overloaded printStackTrace method that takes in a PrintWriter.

You can do something like this

Writer buffer = new StringWriter();
PrintWriter pw = new PrintWriter(buffer);
ex.printStackTrace(pw);
Logger.log(loglevel, buffer.toString());
NamingException
  • 2,388
  • 1
  • 19
  • 41
sleeloy
  • 131
  • 2
11

With below format you can have the stack trace:

java.util.logging.SimpleFormatter.format=%1$tF %1$tT [%4$-7s][%2$s] %5$s %6$s%n

The point in this pattern is %6$s. It will print the stack trace.

iman
  • 121
  • 1
  • 4
6

You can't convert void into String; no such conversion exists. void doesn't return anything back, so you have no value to retrieve.

What you probably want to do is get the message of the exception instead via ex.getMessage().

Makoto
  • 104,088
  • 27
  • 192
  • 230
4

You can use the getStackTrace() method to get an array of StackTraceElements, and generate a String from there. Otherwise, if just the final error message is sufficient, use the getMessage() method as suggested by Makoto.

To get the stack trace as a String from an array of StackTraceElement objects, you need to iterate over the array (taken from JDK7 source):

StringBuilder builder = new StringBuilder();
StackTraceElement[] trace = getOurStackTrace();
    for (StackTraceElement traceElement : trace)
        builder.append("\tat " + traceElement + "\n");

Another option is to use printStackTrace(PrintStream s), where you get to specify where you want the stacktrace to be printed:

ByteArrayOutputStream out1 = new ByteArrayOutputStream();
PrintStream out2 = new PrintStream(out1);
ex.printStackTrace(out2);
String message = out1.toString("UTF8");
Chthonic Project
  • 8,216
  • 1
  • 43
  • 92
  • 2
    Just use the apache commons ExceptionUtils library; no need to reinvent the wheel – beresfordt Jul 14 '15 at 19:11
  • 1. `String message = out1.toString("UTF8");` - compilation error, expected 0 parameterers, but got 1 2. It works correctly `out2.out.toString`. In case `out2.toString` -> 'PrintStream@hash' – Nikita Zamalyutdinov Nov 20 '19 at 12:04
2

You can use an ExceptionUtils if you need to see stacktrace without throwing Exception.

String stackTrace = ExceptionUtils.getStackTrace(new Exception("YourMessage"));
log.error(stackTrace);
Sathiamoorthy
  • 8,831
  • 9
  • 65
  • 77
Anton Tevs
  • 21
  • 2
1

you CAN convert stacktrace into String using below. If e is the exception object

StringWriter stringWriter= new StringWriter();
PrintWriter printWriter= new PrintWriter(stringWriter);
e.printStackTrace(printWriter);
String stackTraceAsString= stringWriter.toString(); 
Amit.rk3
  • 2,417
  • 2
  • 10
  • 16
1

Thank you all. I am able to log the stack trace details using

LOGGER.log(Level.INFO, ex.getMessage(),ex);
//ex is my exception object
AHiggins
  • 7,029
  • 6
  • 36
  • 54
Surya Joseph
  • 661
  • 1
  • 5
  • 5
0

As Makoto says, you probably want to do an ex.getMessage().

To further clarify, void means that there is nothing returned. You can't cast nothing into something :)

kotakotakota
  • 731
  • 8
  • 26
0

You can also use ExceptionUtils from apache library or below log statement

    try{
      doSomething();
    }
    catch(Exception e){
    log.error("Exception in method doSomething ",e);
    }
Saurabh
  • 7,525
  • 4
  • 45
  • 46
0

The previous suggestions all seem to just put the stack trace in the log without prefixing each line with the logger details. My suggestion below processes the stack trace elements and formats each line as a logger line:

log.error("{}", e.toString());
StackTraceElement[] stElements = e.getStackTrace();

log.error("(stacktrace) {}", e.toString());

for (StackTraceElement ste: stElements) {
    log.error("(stacktrace)     at {}.{}({}.java:{})", 
        new Object[] {ste.getClassName(), ste.getMethodName(), 
                      ste.getClassName(), ste.getLineNumber()});
}

Throwable thisThrowable = e;
boolean causedBy = true;
while (causedBy) {
    Throwable throwable = thisThrowable.getCause();
    if (throwable != null) {
        log.error("(stacktrace) Caused by: {}", throwable.toString());
        stElements = throwable.getStackTrace();
        for (StackTraceElement ste: stElements) {
            log.error("(stacktrace)     at {}.{}({}.java:{})", 
                 new Object[] {ste.getClassName(), ste.getMethodName(),                    
                               ste.getClassName(), ste.getLineNumber()});
        }
        thisThrowable = throwable;  // For the next caused-by check
    } else {
        log.error("(stacktrace) No Caused-by Exception");
        causedBy = false;  // No more caused-by Throwables, so end the loop
    }
}

Each line of the stack trace is prefixed with "(stacktrace)". This has the advantage of being able to filter them out when dumping log files, or to be able to find them easily.

hairysocks
  • 111
  • 7
0

With java.util.Arrays you can also solve this easily:

try {
    doSomething();
} catch (Exception e) {
    logger.error(Arrays.toString(e.getStackTrace()));
}

Arrays.toString(Object[] a) calls Object.toString() for each element or returns a String with "null" if the object is null. The elements are separated by a comma and a space. StackTraceElement implements toString(), so the array you get from e.getStackTrace() converts nicely.

gibhunter
  • 76
  • 2
  • 8