From 5d0088f23d5c854510f9e5679f33b1eec8d8adaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Drahom=C3=ADr=20Karch=C5=88=C3=A1k?= <drahomir.karchnak@nic.cz> Date: Thu, 28 Jul 2016 16:54:48 +0200 Subject: [PATCH] #421 WIP First use of Sentry/Raven for crash reporting... --- build.gradle | 1 + core/build.gradle | 1 + core/src/cz/nic/tablexia/Tablexia.java | 12 ++ core/src/cz/nic/tablexia/TablexiaRaven.java | 121 ++++++++++++++++++++ 4 files changed, 135 insertions(+) create mode 100644 core/src/cz/nic/tablexia/TablexiaRaven.java diff --git a/build.gradle b/build.gradle index e7ed8bb50..7b7048c0e 100644 --- a/build.gradle +++ b/build.gradle @@ -400,6 +400,7 @@ project(":core") { compile "com.badlogicgames.gdx:gdx-freetype:$gdxVersion" compile "com.google.guava:guava:$guavaVersion" + compile 'com.getsentry.raven:raven:7.5.0' testCompile "junit:junit:4.11" testCompile "com.badlogicgames.gdx:gdx-backend-headless:$gdxVersion" diff --git a/core/build.gradle b/core/build.gradle index 6894b0f57..5a9c469ff 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -43,6 +43,7 @@ task writeTablexiaBuildConfig { " public final static Integer TABLEXIA_SERVER_PORT = ${project.hasProperty('TABLEXIA_SERVER_PORT') ? "$TABLEXIA_SERVER_PORT" : "null"};\n" + " public final static String TABLEXIA_SERVER_SECRET = ${project.hasProperty('TABLEXIA_SERVER_SECRET') ? "\"$TABLEXIA_SERVER_SECRET\"" : "null"};\n" + " public final static String FLURRY_KEY = ${project.hasProperty('TABLEXIA_FLURRY_KEY') ? "\"$TABLEXIA_FLURRY_KEY\"" : "null"};\n" + + " public final static String SENTRY_DSN_KEY = ${project.hasProperty('TABLEXIA_SENTRY_DSN_KEY') ? "\"$TABLEXIA_SENTRY_DSN_KEY\"" : "null"};\n" + "\n" + "}", BUILD_CONFIG_FILE_ENCODING) } diff --git a/core/src/cz/nic/tablexia/Tablexia.java b/core/src/cz/nic/tablexia/Tablexia.java index 8b809e02e..af66524ce 100644 --- a/core/src/cz/nic/tablexia/Tablexia.java +++ b/core/src/cz/nic/tablexia/Tablexia.java @@ -5,6 +5,8 @@ import com.badlogic.gdx.graphics.GL30; import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.actions.Actions; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; +import com.getsentry.raven.connection.EventSendFailureCallback; +import com.getsentry.raven.event.Event; import net.engio.mbassy.bus.error.IPublicationErrorHandler; import net.engio.mbassy.bus.error.PublicationError; @@ -68,6 +70,7 @@ public class Tablexia extends TablexiaApplication { private static IConnectionManager connectionManager; private final SQLConnectionType sqlConnectionType; +// private final Raven raven; private MenuController menuController; private TablexiaButton backButton; private boolean backButtonVisibility; @@ -111,6 +114,15 @@ public class Tablexia extends TablexiaApplication { Log.err(ApplicationBus.class, error.getMessage(), error.getCause()); } }); + + TablexiaRaven.start(); + TablexiaRaven.enableCrashReporting(); + TablexiaRaven.addEventSendFailureCallback(new EventSendFailureCallback() { + @Override + public void onFailure(Event event, Exception exception) { + Log.info(getClass(), "Event failure!"); + } + }); } private void loadingComplete() { diff --git a/core/src/cz/nic/tablexia/TablexiaRaven.java b/core/src/cz/nic/tablexia/TablexiaRaven.java new file mode 100644 index 000000000..edee5019b --- /dev/null +++ b/core/src/cz/nic/tablexia/TablexiaRaven.java @@ -0,0 +1,121 @@ +package cz.nic.tablexia; + +import com.badlogic.gdx.Gdx; +import com.getsentry.raven.DefaultRavenFactory; +import com.getsentry.raven.Raven; +import com.getsentry.raven.connection.Connection; +import com.getsentry.raven.connection.EventSendFailureCallback; +import com.getsentry.raven.dsn.Dsn; +import com.getsentry.raven.event.Event; +import com.getsentry.raven.event.EventBuilder; +import com.getsentry.raven.event.interfaces.ExceptionInterface; + +import java.util.HashSet; +import java.util.Set; + +/** + * Created by drahomir on 7/28/16. + */ +public class TablexiaRaven { + // TABLEXIA RAVEN FACTORY + private class TablexiaRavenFactory extends DefaultRavenFactory { + private EventSendFailureCallback eventSendFailureCallback; + + public Raven ravenInstance(String DSN, EventSendFailureCallback callback) { + eventSendFailureCallback = callback; + return createRavenInstance(new Dsn(DSN)); + } + + @Override + protected Connection createConnection(Dsn dsn) { + Connection connection = super.createConnection(dsn); + + if(eventSendFailureCallback != null) connection.addEventSendFailureCallback(eventSendFailureCallback); + + return connection; + } + } + + //TABLEXIA RAVEN //TODO Refactor + private static TablexiaRaven instance; + + private final EventSendFailureCallback DEFAULT_SEND_EVENT_FAILURE_CALLBACK = new EventSendFailureCallback() { + @Override + public void onFailure(Event event, Exception exception) { + //Calls all registered callbacks + for(EventSendFailureCallback eventSendFailureCallback : sendFailureCallbacks) eventSendFailureCallback.onFailure(event, exception); + } + }; + + private Set<EventSendFailureCallback> sendFailureCallbacks; + private Raven raven; + + private TablexiaRaven(String DSN) { + this.raven = new TablexiaRavenFactory().ravenInstance(DSN, DEFAULT_SEND_EVENT_FAILURE_CALLBACK); + this.sendFailureCallbacks = new HashSet<EventSendFailureCallback>(); + + Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { + @Override + public void uncaughtException(Thread t, Throwable e) { + sendExceptionEvent(t, e); + } + }); + } + + public static void start() { + if(TablexiaBuildConfig.SENTRY_DSN_KEY == null) { + return; + } + + if(instance != null) { + return; + } + + instance = new TablexiaRaven(TablexiaBuildConfig.SENTRY_DSN_KEY); + } + + private static boolean isStarted() { + return instance != null; + } + + //TODO - Must be called after start method which is not good + public static void enableCrashReporting() { + if(!isStarted()) { + return; + } + + Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { + @Override + public void uncaughtException(Thread t, Throwable e) { + instance.sendExceptionEvent(t, e); + } + }); + } + + //TODO - Use this for saving storing events in DB and sending 'em later + //TODO - Must be called after start method which is not good + public static void addEventSendFailureCallback(EventSendFailureCallback eventSendFailureCallback) { + if(!isStarted()) { + return; + } + + if(eventSendFailureCallback != null) { + if(!instance.sendFailureCallbacks.contains(eventSendFailureCallback)) instance.sendFailureCallbacks.add(eventSendFailureCallback); + } + } + + private void sendExceptionEvent(Thread t, Throwable e) { + EventBuilder eventBuilder = new EventBuilder() + .withMessage(e.getMessage()) + .withSentryInterface(new ExceptionInterface(e)) + .withTag("Platform", Gdx.app.getType().toString()) + .withTag("Version", TablexiaBuildConfig.VERSION_NAME) + .withExtra("Language", TablexiaSettings.getInstance().getLocale().toString()) + .withExtra("UserInfo", TablexiaSettings.getInstance().getSelectedUser()) + .withExtra("UserUUID", TablexiaSettings.getInstance().getSelectedUser().getUuid()) + .withLevel(Event.Level.ERROR); + + raven.runBuilderHelpers(eventBuilder); + raven.sendEvent(eventBuilder.build()); + } +} \ No newline at end of file -- GitLab