/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.toolkit.modules.statistics.utils;
import java.util.regex.Pattern;
/**
* A utility class to create compact single-line stacktrace strings. A typical use case for these is using them as a statistics counter
* argument, resulting in a statistic about how frequently a code location is called from which code paths.
*
* @author Robert Mischke
*/
public final class CompactStacktraceBuilder {
private final Pattern matchPattern;
private final String separator;
private final boolean includeMethodNames;
/**
* Creates an instance with a regular expression defining the class names to include (see below), using a default separator (currently
* "<"), and including method names.
*
* @param matchRegexp a regular expression that each stack trace element's class must match to be included; all other elements are
* omitted, while still adding the separators that would glue them together, which shows how many stacktrace steps were skipped
*/
public CompactStacktraceBuilder(String matchRegexp) {
this(matchRegexp, "<", true);
}
/**
* Creates an instance with a regular expression defining the class names to include (see below), and a custom separator that is used to
* join the stacktrace steps.
*
* @param matchRegexp a regular expression that each stack trace element's class must match to be included; all other elements are
* omitted, while still adding the separators that would glue them together, which shows how many stacktrace steps were skipped
* @param separator a string used to "glue" the stack trace element's class names together
* @param includeMethodNames whether to include method names in the output, or just the line numbers
*/
public CompactStacktraceBuilder(String matchRegexp, String separator, boolean includeMethodNames) {
this.matchPattern = Pattern.compile(matchRegexp);
this.separator = separator;
this.includeMethodNames = includeMethodNames;
}
/**
* Returns a compact, single-line stacktrace representation. Its exact content is defined by the constructor arguments used. Common
* aspects are omitting package and method names, ie logging only class names and line numbers, and truncating the stack trace when a
* certain class pattern is met or not met anymore.
*
* @return .
*/
public String getSingleLineStacktrace() {
return getSingleLineStacktrace(1); // semantically, this should be 0, but must be 1 to exclude the zero-args method itself
}
/**
* Returns a compact, single-line stacktrace representation. Its exact content is defined by the constructor arguments used. Common
* aspects are omitting package and method names, ie logging only class names and line numbers, and truncating the stack trace when a
* certain class pattern is met or not met anymore.
*
* @param skipInitial the number of initial stacktrace steps to skip; useful if the call is made in an utility class which should not
* appear in the generated output
* @return .
*/
public String getSingleLineStacktrace(int skipInitial) {
StringBuilder buffer = new StringBuilder();
final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
for (int p = skipInitial + 1; p < stackTrace.length; p++) {
final StackTraceElement traceStep = stackTrace[p];
final String className = traceStep.getClassName();
if (buffer.length() != 0) {
buffer.append(separator);
}
if (!matchPattern.matcher(className).matches()) {
continue; // the separator was still added, marking how many steps were skipped
}
buffer.append(className.substring(className.lastIndexOf(".") + 1)); // also works for root package
if (includeMethodNames) {
buffer.append(".");
buffer.append(traceStep.getMethodName());
}
buffer.append(":");
buffer.append(traceStep.getLineNumber());
}
return buffer.toString();
}
}