Logs in invokeExceptionCaught have been made consistent and full

Motivation:

In case of exception in invokeExceptionCaught() only original exception passed to invokeExceptionCaught() will be logged on any log level.
+ AbstractChannelHandlerContext and CombinedChannelDuplexHandler log different exceptions.

Modifications:

Fix inconsistent logging code and add ability to see both stacktraces on DEBUG level.

Result:

Both handlers log now both original exception and thrown from invokeExceptionCaught. To see full stacktrace of exception thrown from invokeExceptionCaught DEBUG log level must be enabled.
This commit is contained in:
Dmitry Spikhalskiy 2016-06-08 16:51:34 +03:00 committed by Norman Maurer
parent b921f80057
commit 428c61673b
4 changed files with 76 additions and 30 deletions

View File

@ -0,0 +1,48 @@
/*
* Copyright 2016 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.util.internal;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
public final class ThrowableUtils {
/**
* <p>Gets the stack trace from a Throwable as a String.</p>
*
* @param throwable the <code>Throwable</code> to be examined
* @return the stack trace as generated by the exception's
* <code>printStackTrace(PrintWriter)</code> method
*/
public static String stackTraceToString(Throwable cause) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
PrintStream pout = new PrintStream(out);
cause.printStackTrace(pout);
pout.flush();
try {
return new String(out.toByteArray());
} finally {
try {
out.close();
} catch (IOException ignore) {
// ignore as should never happen
}
}
}
private ThrowableUtils() { }
}

View File

@ -16,13 +16,14 @@
package io.netty.channel;
import io.netty.buffer.ByteBufAllocator;
import io.netty.util.DefaultAttributeMap;
import io.netty.util.ResourceLeakHint;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.DefaultAttributeMap;
import io.netty.util.Recycler;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.ResourceLeakHint;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.internal.ThrowableUtils;
import io.netty.util.internal.ObjectUtil;
import io.netty.util.internal.StringUtil;
import io.netty.util.internal.SystemPropertyUtil;
@ -274,11 +275,18 @@ abstract class AbstractChannelHandlerContext extends DefaultAttributeMap
if (isAdded()) {
try {
handler().exceptionCaught(this, cause);
} catch (Throwable t) {
if (logger.isWarnEnabled()) {
} catch (Throwable error) {
if (logger.isDebugEnabled()) {
logger.debug(
"An exception {}" +
"was thrown by a user handler's exceptionCaught() " +
"method while handling the following exception:",
ThrowableUtils.stackTraceToString(error), cause);
} else if (logger.isWarnEnabled()) {
logger.warn(
"An exception was thrown by a user handler's " +
"exceptionCaught() method while handling the following exception:", cause);
"An exception '{}' [enable DEBUG level for full stacktrace] " +
"was thrown by a user handler's exceptionCaught() " +
"method while handling the following exception:", error, cause);
}
}
} else {

View File

@ -25,12 +25,10 @@ import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.FastThreadLocal;
import io.netty.util.internal.InternalThreadLocalMap;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.ThrowableUtils;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.util.Arrays;
@ -679,7 +677,7 @@ public final class ChannelOutboundBuffer {
} else {
logger.warn(
"Failed to mark a promise as success because it has failed already: {}, unnotified cause {}",
promise, stackTraceToString(err));
promise, ThrowableUtils.stackTraceToString(err));
}
}
}
@ -692,23 +690,7 @@ public final class ChannelOutboundBuffer {
} else {
logger.warn(
"Failed to mark a promise as failure because it hass failed already: {}, unnotified cause {}",
promise, stackTraceToString(err), cause);
}
}
}
private static String stackTraceToString(Throwable cause) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
PrintStream pout = new PrintStream(out);
cause.printStackTrace(pout);
pout.flush();
try {
return new String(out.toByteArray());
} finally {
try {
out.close();
} catch (IOException ignore) {
// ignore as should never happen
promise, ThrowableUtils.stackTraceToString(err), cause);
}
}
}

View File

@ -19,6 +19,7 @@ import io.netty.buffer.ByteBufAllocator;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.internal.ThrowableUtils;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
@ -142,10 +143,17 @@ public class CombinedChannelDuplexHandler<I extends ChannelInboundHandler, O ext
// as well
outboundHandler.exceptionCaught(outboundCtx, cause);
} catch (Throwable error) {
if (logger.isWarnEnabled()) {
if (logger.isDebugEnabled()) {
logger.debug(
"An exception {}" +
"was thrown by a user handler's exceptionCaught() " +
"method while handling the following exception:",
ThrowableUtils.stackTraceToString(error), cause);
} else if (logger.isWarnEnabled()) {
logger.warn(
"An exception was thrown by a user handler's " +
"exceptionCaught() method while handling the following exception:", error);
"An exception '{}' [enable DEBUG level for full stacktrace] " +
"was thrown by a user handler's exceptionCaught() " +
"method while handling the following exception:", error, cause);
}
}
} else {