diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index b3a3edeaa..fab70eb15 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -42,6 +42,8 @@ object Versions { const val SPOTIFY_COMPLETABLE_FUTURES = "0.3.6" + const val SENTRY = "8.0.0-alpha.2" + // tests const val EXPRESSIBLE_JUNIT = "1.3.6" const val GROOVY_ALL = "3.0.22" diff --git a/eternalcore-core/build.gradle.kts b/eternalcore-core/build.gradle.kts index 46f8c7993..632153d2d 100644 --- a/eternalcore-core/build.gradle.kts +++ b/eternalcore-core/build.gradle.kts @@ -98,4 +98,8 @@ eternalShadow { // caffeine library("com.github.ben-manes.caffeine:caffeine:${Versions.CAFFEINE}") libraryRelocate("com.github.benmanes.caffeine"); + + // sentry + library("io.sentry:sentry:${Versions.SENTRY}") + libraryRelocate("io.sentry") } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/EternalCore.java b/eternalcore-core/src/main/java/com/eternalcode/core/EternalCore.java index 7b8c20fd8..79a2bd310 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/EternalCore.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/EternalCore.java @@ -13,6 +13,7 @@ import com.eternalcode.core.publish.Publisher; import com.eternalcode.core.publish.event.EternalInitializeEvent; import com.eternalcode.core.publish.event.EternalShutdownEvent; +import io.sentry.Sentry; import net.dzikoysk.cdn.entity.Contextual; import org.bukkit.Server; import org.bukkit.plugin.Plugin; diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/bridge/litecommand/LiteCommandsSetup.java b/eternalcore-core/src/main/java/com/eternalcode/core/bridge/litecommand/LiteCommandsSetup.java index bf46256e6..cd52d8fe1 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/bridge/litecommand/LiteCommandsSetup.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/bridge/litecommand/LiteCommandsSetup.java @@ -1,5 +1,6 @@ package com.eternalcode.core.bridge.litecommand; +import com.eternalcode.core.bridge.sentry.SentryLiteCommandExceptionHandler; import com.eternalcode.core.injector.annotations.Bean; import com.eternalcode.core.injector.annotations.component.BeanSetup; import com.eternalcode.core.injector.bean.BeanFactory; @@ -33,7 +34,8 @@ class LiteCommandsSetup implements Subscriber { .commands(liteCommandsAnnotations) .extension(new LiteAdventurePlatformExtension(audiencesProvider), extension -> extension .serializer(miniMessage) - ); + ) + .exception(Throwable.class, new SentryLiteCommandExceptionHandler(server.getLogger())); } @Bean diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/bridge/litecommand/argument/DurationArgument.java b/eternalcore-core/src/main/java/com/eternalcode/core/bridge/litecommand/argument/DurationArgument.java index fe0edd36e..f4c085736 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/bridge/litecommand/argument/DurationArgument.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/bridge/litecommand/argument/DurationArgument.java @@ -11,11 +11,12 @@ import dev.rollczi.litecommands.invocation.Invocation; import dev.rollczi.litecommands.suggestion.SuggestionContext; import dev.rollczi.litecommands.suggestion.SuggestionResult; +import org.bukkit.command.CommandSender; + import java.time.Duration; import java.time.format.DateTimeParseException; import java.util.Arrays; import java.util.List; -import org.bukkit.command.CommandSender; @LiteArgument(type = Duration.class) class DurationArgument extends AbstractViewerArgument { diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/bridge/sentry/SentryLiteCommandExceptionHandler.java b/eternalcore-core/src/main/java/com/eternalcode/core/bridge/sentry/SentryLiteCommandExceptionHandler.java new file mode 100644 index 000000000..e11fb1fc4 --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/bridge/sentry/SentryLiteCommandExceptionHandler.java @@ -0,0 +1,25 @@ +package com.eternalcode.core.bridge.sentry; + +import dev.rollczi.litecommands.handler.exception.ExceptionHandler; +import dev.rollczi.litecommands.handler.result.ResultHandlerChain; +import dev.rollczi.litecommands.invocation.Invocation; +import io.sentry.Sentry; +import org.bukkit.command.CommandSender; + +import java.util.logging.Logger; + + +public class SentryLiteCommandExceptionHandler implements ExceptionHandler { + + private final Logger logger; + + public SentryLiteCommandExceptionHandler(Logger logger) { + this.logger = logger; + } + + @Override + public void handle(Invocation invocation, Throwable t, ResultHandlerChain resultHandlerChain) { + Sentry.captureException(t); + this.logger.severe("An error occurred while executing the command: " + t.getMessage()); + } +} diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/bridge/sentry/SentrySetup.java b/eternalcore-core/src/main/java/com/eternalcode/core/bridge/sentry/SentrySetup.java new file mode 100644 index 000000000..0c9e06082 --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/bridge/sentry/SentrySetup.java @@ -0,0 +1,90 @@ +package com.eternalcode.core.bridge.sentry; + +import com.eternalcode.core.configuration.implementation.PluginConfiguration; +import com.eternalcode.core.injector.DependencyInjectorException; +import com.eternalcode.core.injector.annotations.Inject; +import com.eternalcode.core.injector.annotations.component.BeanSetup; +import com.eternalcode.core.injector.bean.BeanException; +import com.eternalcode.core.publish.Subscribe; +import com.eternalcode.core.publish.Subscriber; +import com.eternalcode.core.publish.event.EternalInitializeEvent; +import com.google.common.collect.ImmutableList; +import dev.rollczi.litecommands.LiteCommandsException; +import io.papermc.lib.PaperLib; +import io.sentry.Sentry; +import org.bukkit.Server; +import org.bukkit.plugin.Plugin; +import org.xml.sax.SAXException; + +import javax.xml.parsers.ParserConfigurationException; +import java.net.MalformedURLException; +import java.nio.file.FileSystemException; +import java.sql.SQLException; +import java.time.format.DateTimeParseException; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutionException; + +@BeanSetup +class SentrySetup implements Subscriber { + + private static final List> LOADER_OR_INJECTOR_EXCEPTIONS = List.of( + ReflectiveOperationException.class, + FileSystemException.class, + SAXException.class, + BeanException.class, + NoClassDefFoundError.class, + MalformedURLException.class, + ParserConfigurationException.class, + DependencyInjectorException.class + ); + + private static final List> DATABASE_EXCEPTIONS = ImmutableList.of( + SQLException.class, + ExecutionException.class + ); + + private static final List> LITECOMMANDS_EXCEPTIONS = ImmutableList.of( + LiteCommandsException.class, + DateTimeParseException.class + ); + + + private final PluginConfiguration config; + + @Inject + SentrySetup(PluginConfiguration config) { + this.config = config; + } + + @Subscribe(EternalInitializeEvent.class) + public void onInitialize(Plugin plugin, Server server) { + if (this.config.sentryEnabled) { + Sentry.init(options -> { + options.setDsn("https://4bf366d0d9f1da00162b9e629a80be52@o4505014505177088.ingest.us.sentry.io/4506093905051648"); + options.setTracesSampleRate(0.75); + options.setRelease(plugin.getDescription().getVersion()); + options.setEnvironment(PaperLib.getEnvironment().getName()); + options.setTag("plugins", Arrays.stream(server.getPluginManager().getPlugins()).toList().toString()); + options.setTag("serverVersion", server.getVersion()); + options.setBeforeSend((event, hint) -> { + Throwable throwable = event.getThrowable(); + + if (throwable != null) { + if (LOADER_OR_INJECTOR_EXCEPTIONS.stream().anyMatch(exception -> exception.isInstance(throwable))) { + event.setFingerprints(List.of("loader_or_injector")); + } + else if (DATABASE_EXCEPTIONS.stream().anyMatch(exception -> exception.isInstance(throwable))) { + event.setFingerprints(List.of("database")); + } + else if (LITECOMMANDS_EXCEPTIONS.stream().anyMatch(exception -> exception.isInstance(throwable))) { + event.setFingerprints(List.of("litecommands")); + } + } + + return event; + }); + }); + } + } +} diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/configuration/implementation/PluginConfiguration.java b/eternalcore-core/src/main/java/com/eternalcode/core/configuration/implementation/PluginConfiguration.java index 24db4bc7c..24f3b652c 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/configuration/implementation/PluginConfiguration.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/configuration/implementation/PluginConfiguration.java @@ -6,15 +6,13 @@ import com.eternalcode.core.feature.afk.AfkSettings; import com.eternalcode.core.feature.automessage.AutoMessageSettings; import com.eternalcode.core.feature.chat.ChatSettings; +import com.eternalcode.core.feature.helpop.HelpOpSettings; import com.eternalcode.core.feature.jail.JailSettings; import com.eternalcode.core.feature.randomteleport.RandomTeleportSettings; import com.eternalcode.core.feature.randomteleport.RandomTeleportType; -import com.eternalcode.core.feature.helpop.HelpOpSettings; import com.eternalcode.core.feature.spawn.SpawnSettings; -import com.eternalcode.core.injector.annotations.component.ConfigurationFile; import com.eternalcode.core.feature.teleportrequest.TeleportRequestSettings; -import java.util.LinkedHashMap; -import java.util.Set; +import com.eternalcode.core.injector.annotations.component.ConfigurationFile; import net.dzikoysk.cdn.entity.Contextual; import net.dzikoysk.cdn.entity.Description; import net.dzikoysk.cdn.entity.Exclude; @@ -25,7 +23,9 @@ import java.io.File; import java.time.Duration; +import java.util.LinkedHashMap; import java.util.Map; +import java.util.Set; @ConfigurationFile public class PluginConfiguration implements ReloadableConfig { @@ -43,6 +43,10 @@ public class PluginConfiguration implements ReloadableConfig { "#", }) + @Description({ "", "# Whether Sentry - the real-time error tracking system should be enabled", + "# We strongly recommend leaving this option on true, as it helps us fixing bugs faster."}) + public boolean sentryEnabled = true; + @Description("# Whether the player should receive information about new plugin updates upon joining the server") public boolean shouldReceivePluginUpdates = true; diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/database/DatabaseManager.java b/eternalcore-core/src/main/java/com/eternalcode/core/database/DatabaseManager.java index a51f09174..7b438283c 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/database/DatabaseManager.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/database/DatabaseManager.java @@ -8,6 +8,7 @@ import com.j256.ormlite.jdbc.DataSourceConnectionSource; import com.j256.ormlite.support.ConnectionSource; import com.zaxxer.hikari.HikariDataSource; +import io.sentry.Sentry; import java.io.File; import java.sql.SQLException; @@ -95,6 +96,7 @@ public void close() { this.connectionSource.close(); } catch (Exception exception) { + Sentry.captureException(exception); exception.printStackTrace(); } } @@ -112,6 +114,7 @@ public Dao getDao(Class type) { return (Dao) dao; } catch (SQLException exception) { + Sentry.captureException(exception); throw new RuntimeException(exception); } } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/database/DatabaseManagerSetup.java b/eternalcore-core/src/main/java/com/eternalcode/core/database/DatabaseManagerSetup.java index 3e77f542c..cdd0c2494 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/database/DatabaseManagerSetup.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/database/DatabaseManagerSetup.java @@ -1,11 +1,12 @@ package com.eternalcode.core.database; import com.eternalcode.core.configuration.implementation.PluginConfiguration; -import com.eternalcode.core.publish.Subscriber; -import com.eternalcode.core.publish.event.EternalShutdownEvent; import com.eternalcode.core.injector.annotations.Bean; import com.eternalcode.core.injector.annotations.component.BeanSetup; import com.eternalcode.core.publish.Subscribe; +import com.eternalcode.core.publish.Subscriber; +import com.eternalcode.core.publish.event.EternalShutdownEvent; +import io.sentry.Sentry; import java.io.File; import java.sql.SQLException; @@ -22,6 +23,7 @@ DatabaseManager databaseManager(PluginConfiguration pluginConfiguration, Logger databaseManager.connect(); } catch (SQLException exception) { + Sentry.captureException(exception); logger.severe("Could not connect to database! Some functions may not work properly!"); throw new RuntimeException(exception); } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/database/wrapper/AbstractRepositoryOrmLite.java b/eternalcore-core/src/main/java/com/eternalcode/core/database/wrapper/AbstractRepositoryOrmLite.java index 420fb3234..3b4e56a8c 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/database/wrapper/AbstractRepositoryOrmLite.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/database/wrapper/AbstractRepositoryOrmLite.java @@ -3,6 +3,7 @@ import com.eternalcode.commons.scheduler.Scheduler; import com.eternalcode.core.database.DatabaseManager; import com.j256.ormlite.dao.Dao; +import io.sentry.Sentry; import panda.std.function.ThrowingFunction; import java.sql.SQLException; @@ -62,6 +63,7 @@ protected CompletableFuture action(Class type, ThrowingFunction completableFuture.complete(action.apply(dao)); } catch (Throwable throwable) { + Sentry.captureException(throwable); completableFuture.completeExceptionally(throwable); } }); diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/essentials/mob/ButcherArgument.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/essentials/mob/ButcherArgument.java index fd07a13a2..ae8deefb4 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/essentials/mob/ButcherArgument.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/essentials/mob/ButcherArgument.java @@ -4,12 +4,12 @@ import com.eternalcode.core.configuration.implementation.PluginConfiguration; import com.eternalcode.core.injector.annotations.Inject; import com.eternalcode.core.injector.annotations.lite.LiteArgument; -import com.eternalcode.multification.notice.NoticeBroadcast; import com.eternalcode.core.notice.NoticeService; import com.eternalcode.core.translation.Translation; import com.eternalcode.core.translation.TranslationManager; import com.eternalcode.core.viewer.Viewer; import com.eternalcode.core.viewer.ViewerService; +import com.eternalcode.multification.notice.NoticeBroadcast; import dev.rollczi.litecommands.argument.Argument; import dev.rollczi.litecommands.argument.parser.ParseResult; import dev.rollczi.litecommands.invocation.Invocation; diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/ignore/IgnoreRepositoryOrmLite.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/ignore/IgnoreRepositoryOrmLite.java index 7531dc581..d74d2becf 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/ignore/IgnoreRepositoryOrmLite.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/ignore/IgnoreRepositoryOrmLite.java @@ -13,6 +13,7 @@ import com.j256.ormlite.stmt.DeleteBuilder; import com.j256.ormlite.table.DatabaseTable; import com.j256.ormlite.table.TableUtils; +import io.sentry.Sentry; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -53,6 +54,7 @@ public CompletableFuture isIgnored(UUID by, UUID target) { return uuids.contains(target) || uuids.contains(IGNORE_ALL); } catch (ExecutionException exception) { + Sentry.captureException(exception); throw new RuntimeException(exception); } }); @@ -70,6 +72,7 @@ public CompletableFuture ignore(UUID by, UUID target) { } } catch (ExecutionException exception) { + Sentry.captureException(exception); throw new RuntimeException(exception); } }); diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/injector/DependencyInjector.java b/eternalcore-core/src/main/java/com/eternalcode/core/injector/DependencyInjector.java index 027f81d01..5a4098461 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/injector/DependencyInjector.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/injector/DependencyInjector.java @@ -2,6 +2,7 @@ import com.eternalcode.core.injector.annotations.Inject; import com.eternalcode.core.injector.bean.BeanException; +import io.sentry.Sentry; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; @@ -47,9 +48,11 @@ public Object invokeMethod(Object instance, Method method, Object... additionalD return method.invoke(instance, parameters); } catch (BeanException beanException) { + Sentry.captureException(beanException); throw new DependencyInjectorException("Failed to invoke method " + method.getName() + " in " + declaringClass.getName() + "!", beanException, declaringClass); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException exception) { + Sentry.captureException(exception); throw new DependencyInjectorException(exception, declaringClass); } } @@ -85,9 +88,11 @@ private T newInstance(Constructor constructor, Object... additionalDepend return constructor.newInstance(parameters); } catch (BeanException beanException) { + Sentry.captureException(beanException); throw new DependencyInjectorException("Failed to create a new instance of " + declaringClass.getName() + "!", beanException, declaringClass); } catch (InvocationTargetException | InstantiationException | IllegalAccessException exception) { + Sentry.captureException(exception); throw new DependencyInjectorException(exception, declaringClass); } } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/injector/bean/LazyFieldBeanCandidate.java b/eternalcore-core/src/main/java/com/eternalcode/core/injector/bean/LazyFieldBeanCandidate.java index 2db597b2e..2c026b4fa 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/injector/bean/LazyFieldBeanCandidate.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/injector/bean/LazyFieldBeanCandidate.java @@ -1,5 +1,7 @@ package com.eternalcode.core.injector.bean; +import io.sentry.Sentry; + import java.lang.reflect.Field; public class LazyFieldBeanCandidate extends LazyBeanCandidate { @@ -15,7 +17,10 @@ public LazyFieldBeanCandidate(Object instance, Field field) { return field.get(instance); } catch (IllegalAccessException exception) { - throw new BeanException("Cannot access field " + field.getName() + " of " + instance.getClass().getName(), exception, field.getType()); + String message = "Cannot access field " + field.getName() + " of " + instance.getClass().getName(); + Sentry.captureException(exception); + Sentry.captureMessage(message); + throw new BeanException(message, exception, field.getType()); } }); this.field = field; diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/util/ReflectUtil.java b/eternalcore-core/src/main/java/com/eternalcode/core/util/ReflectUtil.java index cf3e98b69..248ba660a 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/util/ReflectUtil.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/util/ReflectUtil.java @@ -2,6 +2,7 @@ import com.google.common.base.Preconditions; import com.google.common.reflect.ClassPath; +import io.sentry.Sentry; import java.io.IOException; import java.util.ArrayList; @@ -45,6 +46,7 @@ public static List> scanClasses(String packageToScan, ClassLoader class return loadedClasses; } catch (IOException | ClassNotFoundException exception) { + Sentry.captureException(exception); throw new RuntimeException(exception); } } diff --git a/eternalcore-docs-api/build.gradle.kts b/eternalcore-docs-api/build.gradle.kts index a9a61d867..76b9bbabf 100644 --- a/eternalcore-docs-api/build.gradle.kts +++ b/eternalcore-docs-api/build.gradle.kts @@ -7,4 +7,6 @@ dependencies { compileOnly("com.google.guava:guava:${Versions.GUAVA}") compileOnly("com.google.code.gson:gson:${Versions.GSON}") compileOnly("dev.rollczi:litecommands-framework:${Versions.LITE_COMMANDS}") + + implementation("io.sentry:sentry:${Versions.SENTRY}") } diff --git a/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/reflect/PackageUtil.java b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/reflect/PackageUtil.java index a05fd6268..1bd4915c8 100644 --- a/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/reflect/PackageUtil.java +++ b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/reflect/PackageUtil.java @@ -1,6 +1,7 @@ package com.eternalcode.annotations.scan.reflect; import com.google.common.reflect.ClassPath; +import io.sentry.Sentry; import java.io.IOException; import java.util.ArrayList; @@ -34,6 +35,7 @@ private static Result resolvePackageStack(Package packageToSearch, ClassLoader c continue; } catch (NoClassDefFoundError error) { + Sentry.captureException(error); continue; } } @@ -46,6 +48,7 @@ private static Result resolvePackageStack(Package packageToSearch, ClassLoader c Class.forName(info.getName(), false, classLoader); } catch (NoClassDefFoundError error) { + Sentry.captureException(error); continue; } @@ -65,6 +68,7 @@ private static Result resolvePackageStack(Package packageToSearch, ClassLoader c return new Result(packageStack, loadedPackages); } catch (IOException | ClassNotFoundException exception) { + Sentry.captureException(exception); throw new RuntimeException(exception); } } diff --git a/eternalcore-docs-generate/src/main/java/com/eternalcode/annotations/scan/GenerateDocs.java b/eternalcore-docs-generate/src/main/java/com/eternalcode/annotations/scan/GenerateDocs.java index 9576f572a..88ce23234 100644 --- a/eternalcore-docs-generate/src/main/java/com/eternalcode/annotations/scan/GenerateDocs.java +++ b/eternalcore-docs-generate/src/main/java/com/eternalcode/annotations/scan/GenerateDocs.java @@ -6,6 +6,7 @@ import com.eternalcode.annotations.scan.feature.FeatureScanResolver; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import io.sentry.Sentry; import java.io.FileWriter; import java.io.IOException; @@ -38,6 +39,7 @@ public static void main(String[] args) throws ClassNotFoundException { gson.toJson(featureResults, fileWriter); } catch (IOException exception) { + Sentry.captureException(exception); exception.printStackTrace(); } @@ -45,6 +47,7 @@ public static void main(String[] args) throws ClassNotFoundException { gson.toJson(commandResults, fileWriter); } catch (IOException exception) { + Sentry.captureException(exception); exception.printStackTrace(); } } diff --git a/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/EternalCoreWrapper.java b/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/EternalCoreWrapper.java index e0cbc13b0..969b883ec 100644 --- a/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/EternalCoreWrapper.java +++ b/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/EternalCoreWrapper.java @@ -1,5 +1,6 @@ package com.eternalcode.core.loader; +import io.sentry.Sentry; import org.bukkit.plugin.Plugin; import java.lang.reflect.Constructor; @@ -25,6 +26,7 @@ public void enable(Plugin plugin) { this.eternalCore = eternalCoreConstructor.newInstance(plugin); } catch (InvocationTargetException exception) { + Sentry.captureException(exception); if (exception.getCause() instanceof RuntimeException runtimeException) { throw runtimeException; } @@ -32,6 +34,7 @@ public void enable(Plugin plugin) { throw new RuntimeException("Can not enable EternalCore: ", exception.getCause()); } catch (IllegalAccessException | NoSuchMethodException | InstantiationException exception) { + Sentry.captureException(exception); throw new RuntimeException(exception); } } @@ -47,6 +50,7 @@ public void disable() { } } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException exception) { + Sentry.captureException(exception); throw new RuntimeException(exception); } } @@ -58,6 +62,7 @@ public static EternalCoreWrapper create(ClassLoader loader) { return new EternalCoreWrapper(eternalCoreClass); } catch (ClassNotFoundException exception) { + Sentry.captureException(exception); throw new RuntimeException(exception); } } diff --git a/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/classloader/IsolatedClassLoaderImpl.java b/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/classloader/IsolatedClassLoaderImpl.java index 0179e866d..34e4fc391 100644 --- a/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/classloader/IsolatedClassLoaderImpl.java +++ b/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/classloader/IsolatedClassLoaderImpl.java @@ -25,6 +25,8 @@ package com.eternalcode.core.loader.classloader; +import io.sentry.Sentry; + import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; @@ -58,6 +60,7 @@ public void addPath(Path path) { this.addURL(requireNonNull(path, "path").toUri().toURL()); } catch (MalformedURLException e) { + Sentry.captureException(e); throw new IllegalArgumentException(e); } } @@ -68,8 +71,9 @@ public void close() { super.close(); } catch (IOException ioException) { + Sentry.captureException(ioException); throw new RuntimeException(ioException); } } -} \ No newline at end of file +} diff --git a/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/classloader/URLClassLoaderAccessor.java b/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/classloader/URLClassLoaderAccessor.java index e95eee974..1c7a3cd48 100644 --- a/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/classloader/URLClassLoaderAccessor.java +++ b/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/classloader/URLClassLoaderAccessor.java @@ -25,6 +25,8 @@ package com.eternalcode.core.loader.classloader; +import io.sentry.Sentry; + import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.MalformedURLException; @@ -60,6 +62,7 @@ public void addJarToClasspath(Path file) { this.addURL(file.toUri().toURL()); } catch (MalformedURLException exception) { + Sentry.captureException(exception); throw new RuntimeException(exception); } } @@ -81,6 +84,7 @@ private static class ReflectionURLClassLoaderAccessor extends URLClassLoaderAcce addUrlMethod.setAccessible(true); } catch (Exception e) { + Sentry.captureException(e); addUrlMethod = null; } ADD_URL_METHOD = addUrlMethod; @@ -100,6 +104,7 @@ public void addURL(URL url) { ADD_URL_METHOD.invoke(super.classLoader, url); } catch (ReflectiveOperationException e) { + Sentry.captureException(e); URLClassLoaderAccessor.throwError(e); } } @@ -123,6 +128,7 @@ private static class UnsafeURLClassLoaderAccessor extends URLClassLoaderAccessor unsafe = (sun.misc.Unsafe) unsafeField.get(null); } catch (Throwable throwable) { + Sentry.captureException(throwable); unsafe = null; } UNSAFE = unsafe; @@ -147,6 +153,7 @@ private static boolean isSupported() { pathURLs = (Collection) fetchField(ucp.getClass(), ucp, "path"); } catch (Throwable throwable) { + Sentry.captureException(throwable); unopenedURLs = null; pathURLs = null; } diff --git a/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/dependency/DependencyDownloader.java b/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/dependency/DependencyDownloader.java index b279270d0..750d3e5ed 100644 --- a/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/dependency/DependencyDownloader.java +++ b/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/dependency/DependencyDownloader.java @@ -2,6 +2,7 @@ import com.eternalcode.core.loader.repository.Repository; import com.google.common.io.ByteStreams; +import io.sentry.Sentry; import java.io.FileNotFoundException; import java.io.IOException; @@ -34,6 +35,7 @@ public Path downloadDependency(Dependency dependency) { return this.tryDownloadDependency(dependency); } catch (URISyntaxException exception) { + Sentry.captureException(exception); throw new DependencyException(exception); } } @@ -54,6 +56,7 @@ private Path tryDownloadDependency(Dependency dependency) throws URISyntaxExcept return path; } catch (DependencyException exception) { + Sentry.captureException(exception); exceptions.add(exception); } } @@ -76,9 +79,11 @@ private Path downloadJarAndSave(Repository repository, Dependency dependency, Pa Files.write(file, bytes, StandardOpenOption.CREATE); } catch (FileNotFoundException | NoSuchFileException fileNotFoundException) { + Sentry.captureException(fileNotFoundException); throw new DependencyException("Dependency not found for repositoru: " + dependency.toMavenJar(repository).toString()); } catch (IOException e) { + Sentry.captureException(e); throw new DependencyException(e); } diff --git a/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/dependency/DependencyLoaderImpl.java b/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/dependency/DependencyLoaderImpl.java index 306b85a4e..ec6afb12d 100644 --- a/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/dependency/DependencyLoaderImpl.java +++ b/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/dependency/DependencyLoaderImpl.java @@ -7,8 +7,9 @@ import com.eternalcode.core.loader.relocation.Relocation; import com.eternalcode.core.loader.relocation.RelocationHandler; import com.eternalcode.core.loader.repository.Repository; - import com.spotify.futures.CompletableFutures; +import io.sentry.Sentry; + import java.io.File; import java.io.IOException; import java.net.URL; @@ -43,13 +44,13 @@ public DependencyLoaderImpl(Logger logger, File dataFolder, List rep this.localRepository = Repository.localRepository(localRepositoryPath); List allRepositories = new ArrayList<>(); - allRepositories.add(localRepository); + allRepositories.add(this.localRepository); allRepositories.addAll(repositories); this.executor = Executors.newCachedThreadPool(); this.logger = logger; - this.pomXmlScanner = new PomXmlScanner(allRepositories, localRepository); - this.downloadDependency = new DependencyDownloader(logger, localRepository, allRepositories); + this.pomXmlScanner = new PomXmlScanner(allRepositories, this.localRepository); + this.downloadDependency = new DependencyDownloader(logger, this.localRepository, allRepositories); this.relocationHandler = RelocationHandler.create(this); } @@ -91,7 +92,7 @@ public DependencyLoadResult load(IsolatedClassLoader loader, List de return new DependencyLoadEntry(dependency, downloadedDependencyPath); } - Path relocatedDependency = this.relocationHandler.relocateDependency(localRepository, downloadedDependencyPath, dependency, relocations); + Path relocatedDependency = this.relocationHandler.relocateDependency(this.localRepository, downloadedDependencyPath, dependency, relocations); return new DependencyLoadEntry(dependency, relocatedDependency); }, this.executor); @@ -117,6 +118,7 @@ public void close() { this.relocationHandler.close(); } catch (Exception exception) { + Sentry.captureException(exception); throw new DependencyException("Failed to close relocation handler", exception); } } @@ -129,6 +131,7 @@ private Path setupCacheDirectory(File dataFolder) { catch (FileAlreadyExistsException ignored) { } catch (IOException ioException) { + Sentry.captureException(ioException); throw new DependencyException("Unable to create " + LOCAL_REPOSITORY_PATH + " directory", ioException); } diff --git a/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/pom/PomXmlScanner.java b/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/pom/PomXmlScanner.java index 60f265548..88aa18e7c 100644 --- a/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/pom/PomXmlScanner.java +++ b/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/pom/PomXmlScanner.java @@ -3,6 +3,16 @@ import com.eternalcode.core.loader.dependency.Dependency; import com.eternalcode.core.loader.dependency.DependencyCollector; import com.eternalcode.core.loader.repository.Repository; +import io.sentry.Sentry; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -14,14 +24,6 @@ import java.util.Collections; import java.util.List; import java.util.Optional; -import javax.xml.XMLConstants; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; public class PomXmlScanner implements DependencyScanner { @@ -38,6 +40,7 @@ public class PomXmlScanner implements DependencyScanner { DOCUMENT_BUILDER_FACTORY.setExpandEntityReferences(false); } catch (ParserConfigurationException exception) { + Sentry.captureException(exception); throw new RuntimeException("Failed to configure XML parser", exception); } } @@ -85,6 +88,7 @@ private Optional> tryReadDependency(Dependency dependency, Repo return Optional.of(dependencies); } catch (IOException | SAXException | ParserConfigurationException | URISyntaxException exception) { + Sentry.captureException(exception); return Optional.empty(); } } @@ -112,6 +116,7 @@ private boolean isEmpty(File file) { return Files.size(file.toPath()) == 0; } catch (IOException exception) { + Sentry.captureException(exception); return true; } } diff --git a/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/relocation/RelocationHandler.java b/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/relocation/RelocationHandler.java index aa4682b34..7bdf501a5 100644 --- a/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/relocation/RelocationHandler.java +++ b/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/relocation/RelocationHandler.java @@ -30,8 +30,9 @@ import com.eternalcode.core.loader.dependency.DependencyException; import com.eternalcode.core.loader.dependency.DependencyLoadResult; import com.eternalcode.core.loader.dependency.DependencyLoaderImpl; - import com.eternalcode.core.loader.repository.Repository; +import io.sentry.Sentry; + import java.io.File; import java.io.IOException; import java.lang.reflect.Constructor; @@ -108,6 +109,7 @@ private Path relocate(Path input, Path output, List relocations) { this.jarRelocatorRunMethod.invoke(relocator); } catch (InstantiationException | IllegalAccessException | InvocationTargetException | IOException exception) { + Sentry.captureException(exception); throw new DependencyException("Failed to create JarRelocator instance", exception); } @@ -130,6 +132,7 @@ public static RelocationHandler create(DependencyLoaderImpl dependencyLoaderImpl return new RelocationHandler(classLoader, jarRelocatorConstructor, jarRelocatorRunMethod); } catch (ClassNotFoundException | NoSuchMethodException exception) { + Sentry.captureException(exception); throw new DependencyException(exception); } } diff --git a/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/repository/Repository.java b/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/repository/Repository.java index 92881480c..aec04d167 100644 --- a/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/repository/Repository.java +++ b/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/repository/Repository.java @@ -1,5 +1,7 @@ package com.eternalcode.core.loader.repository; +import io.sentry.Sentry; + import java.net.MalformedURLException; import java.nio.file.Path; @@ -33,6 +35,7 @@ public static Repository localRepository(Path repositoryFolder) { return Repository.of(repositoryFolder.toUri().toURL().toString()); } catch (MalformedURLException exception) { + Sentry.captureException(exception); throw new RuntimeException(exception); } } diff --git a/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/resource/ResourceLocator.java b/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/resource/ResourceLocator.java index 56ad0078b..f11da9b3d 100644 --- a/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/resource/ResourceLocator.java +++ b/eternalcore-plugin/src/main/java/com/eternalcode/core/loader/resource/ResourceLocator.java @@ -1,5 +1,7 @@ package com.eternalcode.core.loader.resource; +import io.sentry.Sentry; + import java.io.File; import java.net.MalformedURLException; import java.net.URI; @@ -33,6 +35,7 @@ public File toFile() { return new File(this.url.toURI()); } catch (URISyntaxException exception) { + Sentry.captureException(exception); throw new RuntimeException(exception); } } @@ -46,6 +49,7 @@ public static ResourceLocator fromURI(URI uri) { return new ResourceLocator(uri.toURL()); } catch (MalformedURLException exception) { + Sentry.captureException(exception); throw new RuntimeException(exception); } } @@ -59,6 +63,7 @@ public static ResourceLocator fromFile(File file) { return new ResourceLocator(file.toURI().toURL()); } catch (MalformedURLException exception) { + Sentry.captureException(exception); throw new RuntimeException(exception); } } @@ -68,6 +73,7 @@ public static ResourceLocator fromString(String string) { return new ResourceLocator(new URL(string)); } catch (MalformedURLException exception) { + Sentry.captureException(exception); throw new RuntimeException(exception); } }