Remove StackTraceSimplifier
Related issue: #2735 Motivation: When an application is under load and experiencing a lot of failure, the instantiation of DefaultExceptionEvent spends noticeable amount of time because of StackTraceSimplifier. Also, StackTraceSimplifier makes people sometimes confused because it hides the execution path partially. Modifications: Remove the use of StackTraceSimplifier Result: JVM spends much less time at Throwable.getStackTrace()
This commit is contained in:
parent
2b16d9f670
commit
8321035684
@ -17,8 +17,6 @@ package org.jboss.netty.channel;
|
||||
|
||||
import static org.jboss.netty.channel.Channels.*;
|
||||
|
||||
import org.jboss.netty.util.internal.StackTraceSimplifier;
|
||||
|
||||
/**
|
||||
* The default {@link ExceptionEvent} implementation.
|
||||
*/
|
||||
@ -39,7 +37,6 @@ public class DefaultExceptionEvent implements ExceptionEvent {
|
||||
}
|
||||
this.channel = channel;
|
||||
this.cause = cause;
|
||||
StackTraceSimplifier.simplify(cause);
|
||||
}
|
||||
|
||||
public Channel getChannel() {
|
||||
|
@ -15,8 +15,6 @@
|
||||
*/
|
||||
package org.jboss.netty.logging;
|
||||
|
||||
import org.jboss.netty.util.internal.StackTraceSimplifier;
|
||||
|
||||
/**
|
||||
* Creates an {@link InternalLogger} or changes the default factory
|
||||
* implementation. This factory allows you to choose what logging framework
|
||||
@ -37,13 +35,6 @@ import org.jboss.netty.util.internal.StackTraceSimplifier;
|
||||
public abstract class InternalLoggerFactory {
|
||||
private static volatile InternalLoggerFactory defaultFactory = new JdkLoggerFactory();
|
||||
|
||||
static {
|
||||
// Load the dependent classes in advance to avoid the case where
|
||||
// the VM fails to load the required classes because of too many open
|
||||
// files.
|
||||
StackTraceSimplifier.simplify(new Exception());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default factory. The initial default factory is
|
||||
* {@link JdkLoggerFactory}.
|
||||
@ -73,74 +64,7 @@ public abstract class InternalLoggerFactory {
|
||||
* Creates a new logger instance with the specified name.
|
||||
*/
|
||||
public static InternalLogger getInstance(String name) {
|
||||
final InternalLogger logger = getDefaultFactory().newInstance(name);
|
||||
return new InternalLogger() {
|
||||
|
||||
public void debug(String msg) {
|
||||
logger.debug(msg);
|
||||
}
|
||||
|
||||
public void debug(String msg, Throwable cause) {
|
||||
StackTraceSimplifier.simplify(cause);
|
||||
logger.debug(msg, cause);
|
||||
}
|
||||
|
||||
public void error(String msg) {
|
||||
logger.error(msg);
|
||||
}
|
||||
|
||||
public void error(String msg, Throwable cause) {
|
||||
StackTraceSimplifier.simplify(cause);
|
||||
logger.error(msg, cause);
|
||||
}
|
||||
|
||||
public void info(String msg) {
|
||||
logger.info(msg);
|
||||
}
|
||||
|
||||
public void info(String msg, Throwable cause) {
|
||||
StackTraceSimplifier.simplify(cause);
|
||||
logger.info(msg, cause);
|
||||
}
|
||||
|
||||
public boolean isDebugEnabled() {
|
||||
return logger.isDebugEnabled();
|
||||
}
|
||||
|
||||
public boolean isErrorEnabled() {
|
||||
return logger.isErrorEnabled();
|
||||
}
|
||||
|
||||
public boolean isInfoEnabled() {
|
||||
return logger.isInfoEnabled();
|
||||
}
|
||||
|
||||
public boolean isWarnEnabled() {
|
||||
return logger.isWarnEnabled();
|
||||
}
|
||||
|
||||
public void warn(String msg) {
|
||||
logger.warn(msg);
|
||||
}
|
||||
|
||||
public void warn(String msg, Throwable cause) {
|
||||
StackTraceSimplifier.simplify(cause);
|
||||
logger.warn(msg, cause);
|
||||
}
|
||||
|
||||
public boolean isEnabled(InternalLogLevel level) {
|
||||
return logger.isEnabled(level);
|
||||
}
|
||||
|
||||
public void log(InternalLogLevel level, String msg) {
|
||||
logger.log(level, msg);
|
||||
}
|
||||
|
||||
public void log(InternalLogLevel level, String msg, Throwable cause) {
|
||||
StackTraceSimplifier.simplify(cause);
|
||||
logger.log(level, msg, cause);
|
||||
}
|
||||
};
|
||||
return getDefaultFactory().newInstance(name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 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 org.jboss.netty.util.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.jboss.netty.channel.ChannelPipeline;
|
||||
import org.jboss.netty.channel.SimpleChannelHandler;
|
||||
import org.jboss.netty.util.DebugUtil;
|
||||
import org.jboss.netty.util.ThreadRenamingRunnable;
|
||||
|
||||
/**
|
||||
* Simplifies an exception stack trace by removing unnecessary
|
||||
* {@link StackTraceElement}s. Please note that the stack trace simplification
|
||||
* is disabled if {@linkplain DebugUtil debug mode} is turned on.
|
||||
*/
|
||||
public final class StackTraceSimplifier {
|
||||
|
||||
private static final boolean SIMPLIFY_STACK_TRACE = !DebugUtil.isDebugEnabled();
|
||||
private static final Pattern EXCLUDED_STACK_TRACE =
|
||||
Pattern.compile(
|
||||
"^org\\.jboss\\.netty\\." +
|
||||
"(util\\.(ThreadRenamingRunnable|internal\\.DeadLockProofWorker)" +
|
||||
"|channel\\.(SimpleChannel(Upstream|Downstream)?Handler|(Default|Static)ChannelPipeline.*))(\\$.*)?$");
|
||||
|
||||
/**
|
||||
* Removes unnecessary {@link StackTraceElement}s from the specified
|
||||
* exception. {@link ThreadRenamingRunnable}, {@link SimpleChannelHandler},
|
||||
* and {@link ChannelPipeline} implementations will be dropped from the
|
||||
* trace.
|
||||
*/
|
||||
public static void simplify(Throwable e) {
|
||||
if (!SIMPLIFY_STACK_TRACE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.getCause() != null) {
|
||||
simplify(e.getCause());
|
||||
}
|
||||
|
||||
StackTraceElement[] trace = e.getStackTrace();
|
||||
if (trace == null || trace.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Perhaps Netty bug. Let us not strip things out.
|
||||
if (EXCLUDED_STACK_TRACE.matcher(trace[0].getClassName()).matches()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<StackTraceElement> simpleTrace =
|
||||
new ArrayList<StackTraceElement>(trace.length);
|
||||
|
||||
simpleTrace.add(trace[0]);
|
||||
|
||||
// Remove unnecessary stack trace elements.
|
||||
for (int i = 1; i < trace.length; i ++) {
|
||||
if (EXCLUDED_STACK_TRACE.matcher(trace[i].getClassName()).matches()) {
|
||||
continue;
|
||||
}
|
||||
simpleTrace.add(trace[i]);
|
||||
}
|
||||
|
||||
e.setStackTrace(
|
||||
simpleTrace.toArray(new StackTraceElement[simpleTrace.size()]));
|
||||
}
|
||||
|
||||
private StackTraceSimplifier() {
|
||||
// Unused
|
||||
}
|
||||
}
|
@ -49,11 +49,6 @@ public class InternalLoggerFactoryTest {
|
||||
InternalLoggerFactory.setDefaultFactory(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnWrappedLogger() {
|
||||
assertNotSame(mock, InternalLoggerFactory.getInstance("mock"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsDebugEnabled() {
|
||||
expect(mock.isDebugEnabled()).andReturn(true);
|
||||
|
@ -1,118 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 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 org.jboss.netty.util.internal;
|
||||
|
||||
import static org.easymock.EasyMock.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.jboss.netty.buffer.ChannelBuffer;
|
||||
import org.jboss.netty.channel.Channel;
|
||||
import org.jboss.netty.channel.DefaultChannelPipeline;
|
||||
import org.jboss.netty.channel.SimpleChannelHandler;
|
||||
import org.jboss.netty.util.ThreadRenamingRunnable;
|
||||
import org.junit.Test;
|
||||
|
||||
public class StackTraceSimplifierTest {
|
||||
|
||||
@Test
|
||||
public void testBasicSimplification() {
|
||||
Exception e = new Exception();
|
||||
e.setStackTrace(new StackTraceElement[] {
|
||||
new StackTraceElement(ChannelBuffer.class.getName(), "a", null, 1),
|
||||
new StackTraceElement("com.example.Foo", "b", null, 1),
|
||||
new StackTraceElement(SimpleChannelHandler.class.getName(), "c", null, 1),
|
||||
new StackTraceElement(ThreadRenamingRunnable.class.getName(), "d", null, 1),
|
||||
});
|
||||
|
||||
StackTraceSimplifier.simplify(e);
|
||||
|
||||
StackTraceElement[] simplified = e.getStackTrace();
|
||||
assertEquals(2, simplified.length);
|
||||
assertEquals(ChannelBuffer.class.getName(), simplified[0].getClassName());
|
||||
assertEquals("com.example.Foo", simplified[1].getClassName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNestedSimplification() {
|
||||
Exception e1 = new Exception();
|
||||
e1.setStackTrace(new StackTraceElement[] {
|
||||
new StackTraceElement(ChannelBuffer.class.getName(), "a", null, 1),
|
||||
new StackTraceElement("com.example.Foo", "b", null, 1),
|
||||
new StackTraceElement(SimpleChannelHandler.class.getName(), "c", null, 1),
|
||||
new StackTraceElement(DefaultChannelPipeline.class.getName(), "d", null, 1),
|
||||
new StackTraceElement(ThreadRenamingRunnable.class.getName(), "e", null, 1),
|
||||
});
|
||||
|
||||
Exception e2 = new Exception(e1);
|
||||
e2.setStackTrace(new StackTraceElement[] {
|
||||
new StackTraceElement(Channel.class.getName(), "a", null, 1),
|
||||
new StackTraceElement("com.example.Bar", "b", null, 1),
|
||||
new StackTraceElement(SimpleChannelHandler.class.getName(), "c", null, 1),
|
||||
new StackTraceElement(DefaultChannelPipeline.class.getName(), "d", null, 1),
|
||||
new StackTraceElement(ThreadRenamingRunnable.class.getName(), "e", null, 1),
|
||||
});
|
||||
|
||||
StackTraceSimplifier.simplify(e2);
|
||||
|
||||
StackTraceElement[] simplified1 = e1.getStackTrace();
|
||||
assertEquals(2, simplified1.length);
|
||||
assertEquals(ChannelBuffer.class.getName(), simplified1[0].getClassName());
|
||||
assertEquals("com.example.Foo", simplified1[1].getClassName());
|
||||
|
||||
StackTraceElement[] simplified2 = e2.getStackTrace();
|
||||
assertEquals(2, simplified2.length);
|
||||
assertEquals(Channel.class.getName(), simplified2[0].getClassName());
|
||||
assertEquals("com.example.Bar", simplified2[1].getClassName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNettyBugDetection() {
|
||||
Exception e = new Exception();
|
||||
e.setStackTrace(new StackTraceElement[] {
|
||||
new StackTraceElement(DefaultChannelPipeline.class.getName(), "a", null, 1),
|
||||
new StackTraceElement(ChannelBuffer.class.getName(), "a", null, 1),
|
||||
new StackTraceElement("com.example.Foo", "b", null, 1),
|
||||
new StackTraceElement(SimpleChannelHandler.class.getName(), "c", null, 1),
|
||||
new StackTraceElement(ThreadRenamingRunnable.class.getName(), "d", null, 1),
|
||||
});
|
||||
|
||||
StackTraceSimplifier.simplify(e);
|
||||
|
||||
StackTraceElement[] simplified = e.getStackTrace();
|
||||
assertEquals(5, simplified.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyStackTrace() {
|
||||
Exception e = new Exception();
|
||||
e.setStackTrace(new StackTraceElement[0]);
|
||||
|
||||
StackTraceSimplifier.simplify(e);
|
||||
assertEquals(0, e.getStackTrace().length);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNullStackTrace() {
|
||||
Exception e = createNiceMock(Exception.class);
|
||||
expect(e.getStackTrace()).andReturn(null).anyTimes();
|
||||
replay(e);
|
||||
|
||||
StackTraceSimplifier.simplify(e);
|
||||
assertNull(e.getStackTrace());
|
||||
verify(e);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user