2

I have long hierarchy of exceptions, one of it add long message with binary data. I can't change it in throw place, since it's in library. How can i truncate it, without losing another exceptions messages?

code example:

throw new RuntimeException("msg",
    new RuntimeException(generateLongErrorMessage(),
        new RuntimeException("short message",
            new RuntimeException("important message"))
    )
);

desired output:

Exception in thread "main" java.lang.RuntimeException: msg
    at xxx.excpetionMessageTruncator(Erofeev.java:18)
    at xxx.main(Erofeev.java:14)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.lang.RuntimeException: long message long message ...(truncated, original size: 100)
    ... 7 more
Caused by: java.lang.RuntimeException: short message
    ... 7 more
Caused by: java.lang.RuntimeException: important message
    ... 7 more
3
  • where do you catch this exception? Commented Apr 4, 2014 at 15:01
  • 2
    @radai, in my bloody enterprise project Commented Apr 4, 2014 at 15:07
  • 1
    i was aiming for something very much like mbred said below - if you know the code location where its caught you can rebuild the exception and strip out the long message, of just "peel" the outer layers and leave just the root cause. your only other option is a custom logger/appender Commented Apr 5, 2014 at 7:33

1 Answer 1

1

Update:

I see two different ways to do this, depending on your needs. I would prefer solution 2, as it is less invasive and allows all parts of the code to work with the complete exception.

1, one exception type only, no logger changes required:

Catch the exception and copy the whole stack exception by exception to set a shorter message:

private static RuntimeException truncate(RuntimeException rt) {
    Stack<Throwable> causeStack = new Stack<>();

    Throwable currentEx = rt;
    while(currentEx != null) {
            causeStack.push(currentEx);
            currentEx = currentEx.getCause();
    }

    RuntimeException newEx = null;
    while (!causeStack.isEmpty()) {
            Throwable t = causeStack.pop();
            newEx = new RuntimeException(truncateMessage(t.getMessage()), newEx);
            newEx.setStackTrace(t.getStackTrace());
    }

    return newEx;
}


private static String truncateMessage(String message) {
    if (message.length() < 25) {
        return message;
    }

    return message.substring(0, 25) + "...";
}

While you can use it on any type of exception, the result will always be a stack of runtime exceptions. If that is not desireable you can go with reflections + generics to create a new exception of the same type. If you only have combinations of message / cause inside the constructor this will be manageable, but keep in mind that there are custom expceptions as well.

2, Custom Exception Handler (if you are not able to catch the exception for whatever reason)

See http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.UncaughtExceptionHandler.html to set a threads exception handler. From there you can pass the exception to your logger. Then you can perform the truncation in the logger.

Sign up to request clarification or add additional context in comments.

3 Comments

but Throwable hasn't setMessage() method?
Sorry, scribbled it on my ipad. Changed it to a more complete solution.
it's look good, but you lose real exception class, i think it's matter

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.