Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 16 additions & 7 deletions core/src/main/java/dev/faststats/ErrorHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -154,29 +155,37 @@ private static List<String> collapseConsecutiveDuplicates(final List<String> lin
return result;
}

public static boolean isSameLoader(final ClassLoader loader, final Throwable error) {
return isSameLoader(loader, error, Collections.newSetFromMap(new IdentityHashMap<>()));
public static boolean isSameLoader(final Thread thread, final ClassLoader loader, final Throwable error) {
return isSameLoader(thread, loader, error, Collections.newSetFromMap(new IdentityHashMap<>()));
}

private static boolean isSameLoader(final ClassLoader loader, @Nullable final Throwable error, final Set<Throwable> visited) {
private static boolean isSameLoader(final Thread thread, final ClassLoader loader, @Nullable final Throwable error, final Set<Throwable> visited) {
if (error == null || !visited.add(error)) return false;

final var stackTrace = error.getStackTrace();
if (stackTrace == null || stackTrace.length == 0)
return isSameLoader(loader, error.getCause(), visited);
return isSameLoader(thread, loader, error.getCause(), visited);

final var firstNonLibraryIndex = findFirstNonLibraryFrameIndex(stackTrace);
if (firstNonLibraryIndex == -1) return isSameLoader(loader, error.getCause(), visited);
if (firstNonLibraryIndex == -1) return isSameLoader(thread, loader, error.getCause(), visited);

final var framesToCheck = Math.min(5, stackTrace.length - firstNonLibraryIndex);

for (var i = 0; i < framesToCheck; i++) {
final var frame = stackTrace[firstNonLibraryIndex + i];
if (isLibraryFrame(frame.getClassName())) continue;
if (!isFromLoader(frame, loader)) return isSameLoader(loader, error.getCause(), visited);
if (!isFromLoader(frame, loader)) return isSameLoader(thread, loader, error.getCause(), visited);
}

return true;
return classLoadersMatch(thread.getContextClassLoader(), loader);
}

private static boolean classLoadersMatch(@Nullable final ClassLoader first, @Nullable final ClassLoader second) {
if (Objects.equals(first, second)) return true;
if (first == null || second == null) return false;
if (classLoadersMatch(first.getParent(), second)) return true;
if (classLoadersMatch(first, second.getParent())) return true;
return false;
}

private static int findFirstNonLibraryFrameIndex(final StackTraceElement[] stackTrace) {
Expand Down
21 changes: 18 additions & 3 deletions core/src/main/java/dev/faststats/ErrorTracker.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@
*/
public sealed interface ErrorTracker permits SimpleErrorTracker {
/**
* Creates a context-aware error tracker policy.
* Creates a context-aware error tracker policy for the current class loader.
*
* @return the error tracker policy
* @see #contextAware(ClassLoader)
* @since 0.24.0
*/
@Contract(value = " -> new", pure = true)
static ErrorTracker contextAware() {
return contextAware(ErrorTracker.class.getClassLoader());
return contextAware(Thread.currentThread().getContextClassLoader());
}

/**
Expand Down Expand Up @@ -256,6 +257,20 @@ default ErrorTracker anonymize(@RegExp final String pattern, final String replac
*/
@Contract(pure = true)
static boolean isSameLoader(final ClassLoader loader, final Throwable error) {
return ErrorHelper.isSameLoader(loader, error);
return ErrorHelper.isSameLoader(Thread.currentThread(), loader, error);
}

/**
* Checks if the error occurred in the same class loader as the provided loader and thread.
*
* @param thread the thread
* @param loader the class loader
* @param error the error
* @return whether the error occurred in the same class loader
* @since 0.23.0
*/
@Contract(pure = true)
static boolean isSameLoader(final Thread thread, final ClassLoader loader, final Throwable error) {
return ErrorHelper.isSameLoader(thread, loader, error);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ private static void handleUncaughtException(final Thread thread, final Throwable
for (final var tracker : DISPATCHER_TRACKERS) {
try {
final var loader = tracker.attachedLoader();
if (loader != null && !ErrorHelper.isSameLoader(loader, error)) continue;
if (loader != null && !ErrorHelper.isSameLoader(thread, loader, error)) continue;
tracker.trackError(error).handled(false);
tracker.getContextErrorHandler().ifPresent(handler -> handler.accept(loader, error));
} catch (final Throwable t) {
Expand Down
Loading