Set up crash reporting for Guava's EventBuses

- Added GuavaEventBusHijacker to access an inexplicably package-private
constructor in EventBus
- Added and utilized ReportingEventBus that reports caught exceptions
This commit is contained in:
OLEGSHA 2021-01-07 00:13:18 +03:00
parent c919ffc8ce
commit 1bba20504d
4 changed files with 77 additions and 2 deletions

View File

@ -22,10 +22,11 @@ import org.lwjgl.glfw.GLFW;
import com.google.common.eventbus.EventBus;
import ru.windcorp.progressia.client.graphics.input.*;
import ru.windcorp.progressia.common.util.crash.ReportingEventBus;
public class InputHandler {
private static final EventBus INPUT_EVENT_BUS = new EventBus("Input");
private static final EventBus INPUT_EVENT_BUS = ReportingEventBus.create("Input");
// KeyEvent

View File

@ -40,6 +40,7 @@ import ru.windcorp.progressia.client.graphics.input.bus.InputBus;
import ru.windcorp.progressia.client.graphics.input.bus.InputListener;
import ru.windcorp.progressia.common.util.Named;
import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.common.util.crash.ReportingEventBus;
public class Component extends Named {
@ -455,7 +456,7 @@ public class Component extends Named {
public void addListener(Object listener) {
if (eventBus == null) {
eventBus = new EventBus(getName());
eventBus = ReportingEventBus.create(getName());
}
eventBus.register(listener);

View File

@ -0,0 +1,55 @@
package ru.windcorp.progressia.common.hacks;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.SubscriberExceptionHandler;
import com.google.common.util.concurrent.MoreExecutors;
import ru.windcorp.progressia.common.util.crash.CrashReports;
/**
* This class had to be written because there is not legal way to instantiate a non-async
* {@link EventBus} with both a custom identifier and a custom exception handler. Which
* is a shame. Guava maintainers know about the issue but have rejected solutions multiple
* times <em>without a clearly stated reason</em>; looks like some dirty reflection will
* have to do.
* @author javapony
*/
public class GuavaEventBusHijacker {
public static final Constructor<EventBus> THE_CONSTRUCTOR;
public static final Method DISPATCHER__PER_THREAD_DISPATCH_QUEUE;
static {
try {
Class<?> dispatcherClass = Class.forName("com.google.common.eventbus.Dispatcher");
THE_CONSTRUCTOR = EventBus.class.getDeclaredConstructor(
String.class, Executor.class, dispatcherClass, SubscriberExceptionHandler.class
);
THE_CONSTRUCTOR.setAccessible(true);
DISPATCHER__PER_THREAD_DISPATCH_QUEUE = dispatcherClass.getDeclaredMethod("perThreadDispatchQueue");
DISPATCHER__PER_THREAD_DISPATCH_QUEUE.setAccessible(true);
} catch (Exception e) {
throw CrashReports.report(e, "Something went horribly wrong when setting up EventBus hijacking. Has Guava updated?");
}
}
public static EventBus newEventBus(String identifier, SubscriberExceptionHandler exceptionHandler) {
try {
return THE_CONSTRUCTOR.newInstance(
identifier,
MoreExecutors.directExecutor(),
DISPATCHER__PER_THREAD_DISPATCH_QUEUE.invoke(null),
exceptionHandler
);
} catch (Exception e) {
throw CrashReports.report(e, "Something went horribly wrong when hijacking EventBus. Has Guava updated?");
}
}
}

View File

@ -0,0 +1,18 @@
package ru.windcorp.progressia.common.util.crash;
import com.google.common.eventbus.EventBus;
import ru.windcorp.progressia.common.hacks.GuavaEventBusHijacker;
public class ReportingEventBus {
private ReportingEventBus() {}
public static EventBus create(String identifier) {
return GuavaEventBusHijacker.newEventBus(identifier, (throwable, context) -> {
// Makes sense to append identifier to messageFormat because different EventBuses are completely unrelated
throw CrashReports.crash(throwable, "Unexpected exception in EventBus " + identifier);
});
}
}