/** * If the specified throwable contains a fatal error in the throwable graph, such a fatal error will be thrown. Callers should ensure * that there are no catch statements that would catch an error in the stack as the fatal error here should go uncaught and be handled * by the uncaught exception handler that we install during bootstrap. If the specified throwable does indeed contain a fatal error, * the specified message will attempt to be logged before throwing the fatal error. If the specified throwable does not contain a fatal * error, this method is a no-op. * * @param maybeMessage the message to maybe log * @param maybeFatal the throwable that maybe contains a fatal error */ @SuppressWarnings("finally") private void maybeDie(final String maybeMessage, final Throwable maybeFatal) { ExceptionsHelper.maybeError(maybeFatal, logger).ifPresent(error -> { try { logger.error(maybeMessage, error); } finally { throw error; } }); }
/** * If the specified cause is an unrecoverable error, this method will rethrow the cause on a separate thread so that it can not be * caught and bubbles up to the uncaught exception handler. Note that the cause tree is examined for any {@link Error}. See * {@link #maybeError(Throwable, Logger)} for the semantics. * * @param throwable the throwable to possibly throw on another thread */ public static void maybeDieOnAnotherThread(final Throwable throwable) { ExceptionsHelper.maybeError(throwable, logger).ifPresent(error -> { /* * Here be dragons. We want to rethrow this so that it bubbles up to the uncaught exception handler. Yet, sometimes the stack * contains statements that catch any throwable (e.g., Netty, and the JDK futures framework). This means that a rethrow here * will not bubble up to where we want it to. So, we fork a thread and throw the exception from there where we are sure the * stack does not contain statements that catch any throwable. We do not wrap the exception so as to not lose the original cause * during exit. */ try { // try to log the current stack trace final String formatted = ExceptionsHelper.formatStackTrace(Thread.currentThread().getStackTrace()); logger.error("fatal error\n{}", formatted); } finally { new Thread( () -> { throw error; }) .start(); } }); }
|| e instanceof InterruptedException || e instanceof ExecutionException : e; final Optional<Error> maybeError = ExceptionsHelper.maybeError(e, logger); if (maybeError.isPresent()) {
/** * If the specified throwable contains a fatal error in the throwable graph, such a fatal error will be thrown. Callers should ensure * that there are no catch statements that would catch an error in the stack as the fatal error here should go uncaught and be handled * by the uncaught exception handler that we install during bootstrap. If the specified throwable does indeed contain a fatal error, the * specified message will attempt to be logged before throwing the fatal error. If the specified throwable does not contain a fatal * error, this method is a no-op. * * @param maybeMessage the message to maybe log * @param maybeFatal the throwable that maybe contains a fatal error */ @SuppressWarnings("finally") private void maybeDie(final String maybeMessage, final Throwable maybeFatal) { ExceptionsHelper.maybeError(maybeFatal, logger).ifPresent(error -> { try { logger.error(maybeMessage, error); } finally { throw error; } }); }
/** * If the specified throwable contains a fatal error in the throwable graph, such a fatal error will be thrown. Callers should ensure * that there are no catch statements that would catch an error in the stack as the fatal error here should go uncaught and be handled * by the uncaught exception handler that we install during bootstrap. If the specified throwable does indeed contain a fatal error, the * specified message will attempt to be logged before throwing the fatal error. If the specified throwable does not contain a fatal * error, this method is a no-op. * * @param maybeMessage the message to maybe log * @param maybeFatal the throwable that maybe contains a fatal error */ @SuppressWarnings("finally") private void maybeDie(final String maybeMessage, final Throwable maybeFatal) { ExceptionsHelper.maybeError(maybeFatal, logger).ifPresent(error -> { try { logger.error(maybeMessage, error); } finally { throw error; } }); }
/** * If the specified cause is an unrecoverable error, this method will rethrow the cause on a separate thread so that it can not be * caught and bubbles up to the uncaught exception handler. Note that the cause tree is examined for any {@link Error}. See * {@link #maybeError(Throwable, Logger)} for the semantics. * * @param throwable the throwable to possibly throw on another thread */ public static void maybeDieOnAnotherThread(final Throwable throwable) { ExceptionsHelper.maybeError(throwable, logger).ifPresent(error -> { /* * Here be dragons. We want to rethrow this so that it bubbles up to the uncaught exception handler. Yet, sometimes the stack * contains statements that catch any throwable (e.g., Netty, and the JDK futures framework). This means that a rethrow here * will not bubble up to where we want it to. So, we fork a thread and throw the exception from there where we are sure the * stack does not contain statements that catch any throwable. We do not wrap the exception so as to not lose the original cause * during exit. */ try { // try to log the current stack trace final String formatted = ExceptionsHelper.formatStackTrace(Thread.currentThread().getStackTrace()); logger.error("fatal error\n{}", formatted); } finally { new Thread( () -> { throw error; }) .start(); } }); }
/** * If the specified cause is an unrecoverable error, this method will rethrow the cause on a separate thread so that it can not be * caught and bubbles up to the uncaught exception handler. * * @param cause the throwable to test */ public static void maybeDie(final Throwable cause) { final Logger logger = ESLoggerFactory.getLogger(Netty4Utils.class); final Optional<Error> maybeError = ExceptionsHelper.maybeError(cause, logger); if (maybeError.isPresent()) { /* * Here be dragons. We want to rethrow this so that it bubbles up to the uncaught exception handler. Yet, Netty wraps too many * invocations of user-code in try/catch blocks that swallow all throwables. This means that a rethrow here will not bubble up * to where we want it to. So, we fork a thread and throw the exception from there where Netty can not get to it. We do not wrap * the exception so as to not lose the original cause during exit. */ try { // try to log the current stack trace final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); final String formatted = Arrays.stream(stackTrace).skip(1).map(e -> "\tat " + e).collect(Collectors.joining("\n")); logger.error("fatal error on the network layer\n{}", formatted); } finally { new Thread( () -> { throw maybeError.get(); }) .start(); } } }
|| e instanceof InterruptedException || e instanceof ExecutionException : e; final Optional<Error> maybeError = ExceptionsHelper.maybeError(e, logger); if (maybeError.isPresent()) {
|| e instanceof InterruptedException || e instanceof ExecutionException : e; final Optional<Error> maybeError = ExceptionsHelper.maybeError(e, ESLoggerFactory.getLogger(ThreadContext.class)); if (maybeError.isPresent()) {
ExceptionsHelper.maybeError(throwable, logger).ifPresent(error -> {