KEYCLOAK-16567 Optimize StackUtil class

This commit is contained in:
Hynek Mlnarik 2020-12-08 15:31:46 +01:00 committed by Hynek Mlnařík
parent 8e376aef51
commit f053675e50

View file

@ -1,5 +1,6 @@
package org.keycloak.common.util;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import org.jboss.logging.Logger;
@ -11,6 +12,8 @@ public class StackUtil {
private static final Logger LOG = Logger.getLogger("org.keycloak.STACK_TRACE");
private static final ConcurrentHashMap<String, Object> STACK_TRACE_OBJECTS = new ConcurrentHashMap<>();
/**
* Returns string representation of the stack trace of the current call
* without the call to the {@code getShortStackTrace} itself, and ignoring
@ -24,11 +27,11 @@ public class StackUtil {
* @return If the logger {@code org.keycloak.STACK_TRACE} is set to trace
* level, then returns stack trace, else returns empty {@link StringBuilder}
*/
public static StringBuilder getShortStackTrace() {
public static Object getShortStackTrace() {
return getShortStackTrace("\n ");
}
private static final Pattern IGNORED = Pattern.compile("^sun\\.|java\\.lang\\.reflect\\.");
private static final Pattern IGNORED = Pattern.compile("sun\\.|java\\.(lang|util|stream)\\.|org\\.jboss\\.logging.");
private static final StringBuilder EMPTY = new StringBuilder(0);
/**
@ -43,22 +46,43 @@ public class StackUtil {
* @return If the logger {@code org.keycloak.STACK_TRACE} is set to trace
* level, then returns stack trace, else returns empty {@link StringBuilder}
*/
public static StringBuilder getShortStackTrace(String prefix) {
public static Object getShortStackTrace(final String prefix) {
if (! isShortStackTraceEnabled()) return EMPTY;
StringBuilder sb = new StringBuilder();
StackTraceElement[] stackTrace = (new Throwable()).getStackTrace();
for (int endIndex = 2; endIndex < stackTrace.length; endIndex++) {
StackTraceElement st = stackTrace[endIndex];
if (IGNORED.matcher(st.getClassName()).find()) {
continue;
}
if (st.getClassName().startsWith("org.jboss.resteasy")) {
break;
}
sb.append(prefix).append(st);
Object res = STACK_TRACE_OBJECTS.get(prefix);
if (res == null) {
res = stackTraceObject(prefix);
// Do not synchronize. We don't care if the objects in the map get overridden, they are in the end the same.
STACK_TRACE_OBJECTS.put(prefix, res);
}
return sb;
return res;
}
private static Object stackTraceObject(final String prefix) {
return new Object() {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
StackTraceElement[] stackTrace = (new Throwable()).getStackTrace();
boolean stackTraceStarted = false;
for (int endIndex = 0; endIndex < stackTrace.length; endIndex++) {
StackTraceElement st = stackTrace[endIndex];
if (! stackTraceStarted) {
stackTraceStarted = (getClass().getName().equals(st.getClassName()));
endIndex++;
continue;
}
if (IGNORED.matcher(st.getClassName()).find()) {
continue;
}
if (st.getClassName().startsWith("org.jboss.resteasy")) {
break;
}
sb.append(prefix).append(st);
}
return sb.toString();
}
};
}
public static boolean isShortStackTraceEnabled() {