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:
parent
b921f80057
commit
428c61673b
@ -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() { }
|
||||||
|
}
|
@ -16,13 +16,14 @@
|
|||||||
package io.netty.channel;
|
package io.netty.channel;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBufAllocator;
|
import io.netty.buffer.ByteBufAllocator;
|
||||||
import io.netty.util.DefaultAttributeMap;
|
|
||||||
import io.netty.util.ResourceLeakHint;
|
|
||||||
import io.netty.util.Attribute;
|
import io.netty.util.Attribute;
|
||||||
import io.netty.util.AttributeKey;
|
import io.netty.util.AttributeKey;
|
||||||
|
import io.netty.util.DefaultAttributeMap;
|
||||||
import io.netty.util.Recycler;
|
import io.netty.util.Recycler;
|
||||||
import io.netty.util.ReferenceCountUtil;
|
import io.netty.util.ReferenceCountUtil;
|
||||||
|
import io.netty.util.ResourceLeakHint;
|
||||||
import io.netty.util.concurrent.EventExecutor;
|
import io.netty.util.concurrent.EventExecutor;
|
||||||
|
import io.netty.util.internal.ThrowableUtils;
|
||||||
import io.netty.util.internal.ObjectUtil;
|
import io.netty.util.internal.ObjectUtil;
|
||||||
import io.netty.util.internal.StringUtil;
|
import io.netty.util.internal.StringUtil;
|
||||||
import io.netty.util.internal.SystemPropertyUtil;
|
import io.netty.util.internal.SystemPropertyUtil;
|
||||||
@ -274,11 +275,18 @@ abstract class AbstractChannelHandlerContext extends DefaultAttributeMap
|
|||||||
if (isAdded()) {
|
if (isAdded()) {
|
||||||
try {
|
try {
|
||||||
handler().exceptionCaught(this, cause);
|
handler().exceptionCaught(this, cause);
|
||||||
} catch (Throwable t) {
|
} 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(
|
logger.warn(
|
||||||
"An exception was thrown by a user handler's " +
|
"An exception '{}' [enable DEBUG level for full stacktrace] " +
|
||||||
"exceptionCaught() method while handling the following exception:", cause);
|
"was thrown by a user handler's exceptionCaught() " +
|
||||||
|
"method while handling the following exception:", error, cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -25,12 +25,10 @@ import io.netty.util.ReferenceCountUtil;
|
|||||||
import io.netty.util.concurrent.FastThreadLocal;
|
import io.netty.util.concurrent.FastThreadLocal;
|
||||||
import io.netty.util.internal.InternalThreadLocalMap;
|
import io.netty.util.internal.InternalThreadLocalMap;
|
||||||
import io.netty.util.internal.PlatformDependent;
|
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.InternalLogger;
|
||||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
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.ByteBuffer;
|
||||||
import java.nio.channels.ClosedChannelException;
|
import java.nio.channels.ClosedChannelException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -679,7 +677,7 @@ public final class ChannelOutboundBuffer {
|
|||||||
} else {
|
} else {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
"Failed to mark a promise as success because it has failed already: {}, unnotified cause {}",
|
"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 {
|
} else {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
"Failed to mark a promise as failure because it hass failed already: {}, unnotified cause {}",
|
"Failed to mark a promise as failure because it hass failed already: {}, unnotified cause {}",
|
||||||
promise, stackTraceToString(err), cause);
|
promise, ThrowableUtils.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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import io.netty.buffer.ByteBufAllocator;
|
|||||||
import io.netty.util.Attribute;
|
import io.netty.util.Attribute;
|
||||||
import io.netty.util.AttributeKey;
|
import io.netty.util.AttributeKey;
|
||||||
import io.netty.util.concurrent.EventExecutor;
|
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.InternalLogger;
|
||||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||||
|
|
||||||
@ -142,10 +143,17 @@ public class CombinedChannelDuplexHandler<I extends ChannelInboundHandler, O ext
|
|||||||
// as well
|
// as well
|
||||||
outboundHandler.exceptionCaught(outboundCtx, cause);
|
outboundHandler.exceptionCaught(outboundCtx, cause);
|
||||||
} catch (Throwable error) {
|
} 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(
|
logger.warn(
|
||||||
"An exception was thrown by a user handler's " +
|
"An exception '{}' [enable DEBUG level for full stacktrace] " +
|
||||||
"exceptionCaught() method while handling the following exception:", error);
|
"was thrown by a user handler's exceptionCaught() " +
|
||||||
|
"method while handling the following exception:", error, cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user