org.apache.brooklyn.util.javalang.StackTraceSimplifier Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of brooklyn-utils-common Show documentation
Show all versions of brooklyn-utils-common Show documentation
Utility classes and methods developed for Brooklyn but not dependendent on Brooklyn or much else
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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.apache.brooklyn.util.javalang;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import com.google.common.annotations.Beta;
import com.google.common.collect.ImmutableSet;
/**
* Utility class for cleaning up stacktraces.
*/
public class StackTraceSimplifier {
/** comma-separated prefixes (not regexes) */
public static final String DEFAULT_BLACKLIST_SYSTEM_PROPERTY_NAME = "org.apache.brooklyn.util.javalang.StackTraceSimplifier.blacklist";
private static final Collection DEFAULT_BLACKLIST;
static {
ImmutableSet.Builder blacklist = ImmutableSet.builder();
blacklist.addAll(Arrays.asList(
System.getProperty(DEFAULT_BLACKLIST_SYSTEM_PROPERTY_NAME,
"java.," +
"javax.," +
"jdk.," +
"sun.," +
"groovy.," +
"org.codehaus.groovy.," +
"gjdk.groovy.,"
).split("(\\s|,)+")));
DEFAULT_BLACKLIST = blacklist.build();
}
private static final StackTraceSimplifier DEFAULT_INSTACE = newInstance();
private final Collection blacklist;
protected StackTraceSimplifier() {
this(true);
}
protected StackTraceSimplifier(boolean includeDefaultBlacklist, String ...packages) {
ImmutableSet.Builder blacklistB = ImmutableSet.builder();
if (includeDefaultBlacklist)
blacklistB.addAll(DEFAULT_BLACKLIST);
blacklistB.add(packages);
blacklist = blacklistB.build();
}
public static StackTraceSimplifier newInstance() {
return new StackTraceSimplifier();
}
public static StackTraceSimplifier newInstance(String ...additionalBlacklistPackagePrefixes) {
return new StackTraceSimplifier(true, additionalBlacklistPackagePrefixes);
}
public static StackTraceSimplifier newInstanceExcludingOnly(String ...blacklistPackagePrefixes) {
return new StackTraceSimplifier(false, blacklistPackagePrefixes);
}
/** @return whether the given element is useful, that is, not in the blacklist */
public boolean isUseful(StackTraceElement el) {
for (String s: blacklist){
if (el.getClassName().startsWith(s)) return false;;
// gets underscores in some contexts ?
if (el.getClassName().replace('_', '.').startsWith(s)) return false;
}
return true;
}
/** @return new list containing just the {@link #isUseful(StackTraceElement)} stack trace elements */
public List clean(Iterable st) {
List result = new LinkedList();
for (StackTraceElement element: st){
if (isUseful(element)){
result.add(element);
}
}
return result;
}
/** @return new array containing just the {@link #isUseful(StackTraceElement)} stack trace elements */
public StackTraceElement[] clean(StackTraceElement[] st) {
List result = clean(Arrays.asList(st));
return result.toArray(new StackTraceElement[result.size()]);
}
/** @return first {@link #isUseful(StackTraceElement)} stack trace elements, or null */
public StackTraceElement firstUseful(StackTraceElement[] st) {
return nthUseful(0, st);
}
/** @return (n+1)th {@link #isUseful(StackTraceElement)} stack trace elements (ie 0 is {@link #firstUseful(StackTraceElement[])}), or null */
public StackTraceElement nthUseful(int n, StackTraceElement[] st) {
for (StackTraceElement element: st){
if (isUseful(element)) {
if (n==0)
return element;
n--;
}
}
return null;
}
/** {@link #clean(StackTraceElement[])} the given throwable instance, returning the same instance for convenience */
public T cleaned(T t) {
t.setStackTrace(clean(t.getStackTrace()));
return t;
}
// ---- statics
/** static convenience for {@link #isUseful(StackTraceElement)} */
public static boolean isStackTraceElementUseful(StackTraceElement el) {
return DEFAULT_INSTACE.isUseful(el);
}
/** static convenience for {@link #clean(Iterable)} */
public static List cleanStackTrace(Iterable st) {
return DEFAULT_INSTACE.clean(st);
}
/** static convenience for {@link #clean(StackTraceElement[])} */
public static StackTraceElement[] cleanStackTrace(StackTraceElement[] st) {
return DEFAULT_INSTACE.clean(st);
}
/** static convenience for {@link #cleaned(Throwable)} */
public static T cleanedStackTrace(T t) {
return DEFAULT_INSTACE.cleaned(t);
}
public static String toString(Throwable t) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
t.printStackTrace(pw);
return sw.getBuffer().toString();
}
/** returns the number of times the calling method occurs elsewhere in the stack trace;
* 0 if no recursion, 1 if it has cycled three times, etc. */
@Beta // useful to track down things like https://github.com/apache/incubator-brooklyn/pull/489
public static int getRecursiveCallCount() {
StackTraceElement[] t = cleanStackTrace(new Throwable().getStackTrace());
Iterator ti = Arrays.asList(t).iterator();
ti.next();
if (!ti.hasNext()) return 0;
// t0 is the caller
StackTraceElement t0 = ti.next();
String l0 = t0.getClassName()+"."+t0.getMethodName()+"("+t0.getFileName()+")";
int count = 0;
while (ti.hasNext()) {
StackTraceElement ta = ti.next();
String li = ta.getClassName()+"."+ta.getMethodName()+"("+ta.getFileName()+")";
// if we have something in a different method, then something back in the method
// from which the recursive check came, then return true
if (li.equals(l0)) count++;
}
return count;
}
}