Diagnostics

Diagnostics

Bukkit/Paper BungeeCord Velocity Fabric NeoForge

MagicUtils diagnostics provide runtime self-checks that can be executed inside a live plugin or mod. The diagnostics service is built on top of MagicRuntime and ships with safe infrastructure-focused checks for runtime wiring, filesystem access, scheduler behavior, command registration exposure, and placeholder registry access.

Bootstrap Wiring

Enable diagnostics from the platform bootstrap builder:

java
BukkitBootstrap.RuntimeResult magic = BukkitBootstrap.forPlugin(plugin)        .enableCommands()        .enableDiagnostics()        .configureDiagnostics(registry -> {            registry.register(new MyDatabaseCheck());        })        .buildRuntime();DiagnosticsService diagnostics = magic.diagnosticsService();

The service is also available from the runtime container:

java
DiagnosticsService diagnostics =        magic.runtime().requireComponent(DiagnosticsService.class);

Running Checks

Execute the full report or a single suite:

java
DiagnosticReport safeReport = diagnostics.runAll(DiagnosticRunRequest.safe());DiagnosticReport standardReport = diagnostics.runSuite(        "magicutils.scheduler",        DiagnosticRunRequest.standard());

The built-in checks are registered through a magicutils-namespaced registry view, so their suite IDs are prefixed. Pass the full ID to runSuite(...):

  • magicutils.runtime
  • magicutils.filesystem
  • magicutils.config
  • magicutils.scheduler
  • magicutils.threading
  • magicutils.commands
  • magicutils.placeholders

Checks you register yourself through configureDiagnostics(...) receive the raw registry, so their suite() value is used as-is (no magicutils. prefix). Group your own checks under your own suite id, for example mymod.database.

SAFE mode avoids temp-file writes and reload probes. STANDARD mode enables reversible probes such as temp-file writes and config reloadability checks.

Writing A Custom Check

A DiagnosticCheck describes a single self-test: a stable id(), its suite(), a description(), the severity() that applies when it fails, the modes it supportedModes() runs in, and a run(...) that returns a DiagnosticResult (build one with DiagnosticResult.ok/warn/fail/skipped). The context exposes the live runtime() and workingDirectory().

java
public final class MyDatabaseCheck implements DiagnosticCheck {    @Override    public String id() {        return "mymod.database.reachable";    }    @Override    public String suite() {        return "mymod.database";    }    @Override    public String description() {        return "Database connection is reachable";    }    @Override    public DiagnosticSeverity severity() {        return DiagnosticSeverity.CRITICAL;    }    @Override    public EnumSet<DiagnosticMode> supportedModes() {        // read-only, so it runs in SAFE and STANDARD        return EnumSet.allOf(DiagnosticMode.class);    }    @Override    public CompletionStage<DiagnosticResult> run(DiagnosticContext context) {        boolean reachable = database.ping();        DiagnosticResult result = reachable                ? DiagnosticResult.ok(id(), suite(), severity(),                        "Database responded", Map.of())                : DiagnosticResult.fail(id(), suite(), severity(),                        "Database did not respond", Map.of(), null);        return CompletableFuture.completedFuture(result);    }}

Register it during bootstrap through configureDiagnostics(...) as shown above. supportedModes() lets you keep a probe out of SAFE runs: return EnumSet.of(DiagnosticMode.STANDARD) if the check writes or mutates anything.

Exporting Reports

Reports can be rendered to text or exported as JSON:

java
List<String> lines = DiagnosticReports.renderText(safeReport);Path exported = diagnostics.exportJson(safeReport);

The default export path is:

<configDir>/diagnostics/latest.json

Command Helper

Mount diagnostics into an existing command tree the same way you mount help:

java
MagicCommand admin = MagicCommand.<CommandSender>builder("admin")        .subCommand(HelpCommandSupport.createHelpSubCommand(                logger.getCore(),                registry::commandManager        ))        .subCommand(DiagnosticsCommandSupport.createDiagnosticsSubCommand(                logger.getCore(),                magic::diagnosticsService        ))        .build();

Supported command forms:

  • /plugin diagnostics
  • /plugin diagnostics safe
  • /plugin diagnostics standard
  • /plugin diagnostics export
  • /plugin diagnostics export standard
  • /plugin diagnostics suite magicutils.scheduler
  • /plugin diagnostics suite magicutils.scheduler standard