Inspector helps developers to track all exceptions and crashes of theirs plugins. It automatically sends reports to a developer with all needed information about an environment.
It sends not sensitive data:
- Plugin name and version
- Version of Inspector
- Exception stacktrace
- Unique ID of server (it can't be used to determine who sent a report, it used only to determine that "two reports sent from same server")
Also, it sends some sensitive data that can be disabled from sending:
- Server core and version
- List of plugins with versions
NOTE: Inspector filters all tracked exceptions from console to not bother server owners. All plugin-related logs will be saved to log file in the plugin folder.
- samples: Samples of usage Inspector
- inspector-sentry-reporter: Report exceptions to Sentry (recommended reporter)
- inspector-discord-reporter: Send reports to Discord channel
This is not a plugin and can't be installed with copying to plugins directory.
You can disable sending of information about server core and installed plugins in the inspector.yml that stored in a directory of each plugin that uses Inspector.
Also, you can configure it globally in plugins/Inspector/config.yml.
Reporter:
enabled: true
# Here you can choose what you want to send
data:
core: true # Info about server core
plugins: true # Plugins listTo add Inspector to the plugin you must:
- Add Inspector as a dependency to the project
- Modify main plugin class
- Change main class in
plugin.ymlto new
Also, for more coverage, you should:
- Change all usages of
BukkitRunnabletoTrackedBukkitRunnable - Wrap
CommandExecutorwithTrackedCommandExecutor
plugins {
// Add shadow plugin to shade inspector
// See: http://imperceptiblethoughts.com/shadow/
id 'com.github.johnrengelman.shadow' version '7.0.0'
}
// Inspector is published at Maven Central
repositories {
mavenCentral()
}
shadowJar {
// Exclude dependencies bundled into Spigot from resulting JAR
dependencies {
exclude(dependency("com.google.code.gson:gson:.*"))
exclude(dependency("org.jetbrains:annotations:.*"))
}
// Remove some extra files from resulting JAR
exclude("DebugProbesKt.bin")
exclude("META-INF/proguard/**") // If you don't use proguard
exclude("META-INF/native-image/**")
// To avoid possible conflicts we should relocate embedded dependencies to own unique package
// Here we use manual relocating, but easiest (and slower) variant is use automatically relocating.
// Read more: https://imperceptiblethoughts.com/shadow/configuration/relocation/#automatically-relocating-dependencies
def shadowPackage = "shadow.[PLACE_HERE_YOUR_PLUGIN_PACKAGE]"
relocate "ru.endlesscode.inspector", "${shadowPackage}.inspector"
relocate "kotlinx", "${shadowPackage}.kotlinx"
relocate "kotlin", "${shadowPackage}.kotlin"
// If you use inspector-sentry-reporter:
relocate "io.sentry", "${shadowPackage}.sentry"
// If you use inspector-discord-reporter:
relocate "com.github.kittinunf", "${shadowPackage}.kittinunf"
// Enable shadowJar minimization to reduce plugin size.
// Read more: https://imperceptiblethoughts.com/shadow/configuration/minimizing/
minimize()
}
// Automatically run shadowJar making on assemble
tasks.assemble.dependsOn tasks.shadowJar
// Here you can change preferred version of inspector
ext.inspectorVerson = "0.12.1"
// Add Inspector as dependency
// 'inspector-bukkit' - implementation of Inspector for Bukkit.
// 'inspector-sentry-reporter' - reporter that we want to use (read above about available reporters)
dependencies {
implementation "ru.endlesscode.inspector:inspector-bukkit:$inspectorVerson"
implementation "ru.endlesscode.inspector:inspector-sentry-reporter:$inspectorVerson"
implementation "ru.endlesscode.inspector:sentry-bukkit:$inspectorVerson" // If you want SentryBukkitIntegration
}First, your current main plugin class should extend PluginLifecycle instead of JavaPlugin.
For example, this code:
public class MyPlugin extends JavaPlugin {
// ...
// onEnable, onDisable, etc.
// ...
}must become:
public class MyPlugin extends PluginLifecycle {
// ...
// onEnable, onDisable, etc.
// ...
}If you're doing anything that requires access to plugin's methods in a constructor, you will get UninitializedPropertyAccessException.
To avoid this problem, override method init() and do the work within:
public class MyPlugin extends PluginLifecycle {
@Override
public void init() {
// do some work, using plugin's methods
}
}Next, you must create the new class extending TrackedPlugin that will be used as main plugin class and link it with the lifecycle.
Also, you must override method createReporter().
The created reporter will be used for reporting errors.
Example:
public class MyTrackedPlugin extends TrackedPlugin {
public MyTrackedPlugin() {
super(MyPlugin.class); // Pass here lifecycle class
}
@Override
public Reporter createReporter() {
String dsn = "[YOUR_DSN_HERE]";
// Note that you should add needed reporter as dependency first.
return new SentryReporter.Builder()
.setDsn(dsn)
// If you want more detailed reports, add this, but you also should
// add `sentry-bukkit` dependency before
.addIntegration(new SentryBukkitIntegration(this))
.focusOn(this) // Reporter will be focused on this plugin
.build();
}
}