TraceKit.java

package space.sunqian.common.base.thread;

import space.sunqian.annotations.Nonnull;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * Utilities for tracing in the thread.
 *
 * @author sunqian
 */
public class TraceKit {

    /**
     * Returns the stack trace list of the current thread, starting at the method that invokes this method
     * ({@code TraceKit.stackTrace()}).
     * <p>
     * The list is a snapshot of the stack trace at the time of invocation. The first element at index {@code 0}
     * represents the <i>caller</i> of this method (the most recent method invocation). The last element of the list
     * represents the bottom of the stack, which is the least recent method invocation, typically is the {@code main()}
     * or {@link Thread#run()}.
     * <p>
     * The original stack trace info is come from {@link Thread#getStackTrace()}.
     *
     * @return the stack trace list of the current thread
     */
    public static @Nonnull List<@Nonnull StackTraceElement> stackTrace() {
        return stackTrace(Thread.currentThread());
    }

    /**
     * Returns the stack trace list of the specified thread, starting at the method that invokes this method
     * ({@code TraceKit.stackTrace()}).
     * <p>
     * The list is a snapshot of the stack trace at the time of invocation. The first element at index {@code 0}
     * represents the <i>caller</i> of this method (the most recent method invocation). The last element of the list
     * represents the bottom of the stack, which is the least recent method invocation, typically is the {@code main()}
     * or {@link Thread#run()}.
     * <p>
     * The original stack trace info is come from {@link Thread#getStackTrace()}.
     *
     * @param thread the specified thread
     * @return the stack trace list of the specified thread
     */
    public static @Nonnull List<@Nonnull StackTraceElement> stackTrace(@Nonnull Thread thread) {
        StackTraceElement[] elements = thread.getStackTrace();
        return parseStackTrace(elements);
    }

    private static @Nonnull List<@Nonnull StackTraceElement> parseStackTrace(
        @Nonnull StackTraceElement @Nonnull [] elements
    ) {
        int preIndex = -1;
        for (int i = 0; i < elements.length; i++) {
            StackTraceElement element = elements[i];
            if (TraceKit.class.getName().equals(element.getClassName())
                && "stackTrace".equals(element.getMethodName())) {
                preIndex = i;
            }
        }
        if (preIndex < 0) {
            return Collections.emptyList();
        }
        StackTraceElement[] actualElements = new StackTraceElement[elements.length - preIndex - 1];
        System.arraycopy(elements, preIndex + 1, actualElements, 0, actualElements.length);
        return Arrays.asList(actualElements);
    }

    private TraceKit() {
    }
}