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 list
To add Inspector to the plugin you must:
- Add Inspector as a dependency to the project
- Modify main plugin class
- Change main class in
plugin.yml
to new
Also, for more coverage, you should:
- Change all usages of
BukkitRunnable
toTrackedBukkitRunnable
- Wrap
CommandExecutor
withTrackedCommandExecutor
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();
}
}