[{"data":1,"prerenderedAt":312},["ShallowReactive",2],{"docs-\u002Fmodules\u002Fdiagnostics":3},{"id":4,"title":5,"body":6,"description":302,"extension":303,"meta":304,"navTitle":305,"navigation":306,"path":307,"rawbody":308,"seo":309,"stem":310,"__hash__":311},"docs\u002Fmodules\u002Fdiagnostics.md","Diagnostics",{"type":7,"value":8,"toc":293},"minimark",[9,13,17,26,31,34,44,47,53,57,60,66,77,116,135,145,149,194,200,216,220,223,229,232,240,244,247,253,256],[10,11,5],"h1",{"id":12},"diagnostics",[14,15],"platform-badges",{":platforms":16},"[\"bukkit\",\"bungee\",\"velocity\",\"fabric\",\"neoforge\"]",[18,19,20,21,25],"p",{},"MagicUtils diagnostics provide runtime self-checks that can be executed inside a\nlive plugin or mod. The diagnostics service is built on top of ",[22,23,24],"code",{},"MagicRuntime","\nand ships with safe infrastructure-focused checks for runtime wiring,\nfilesystem access, scheduler behavior, command registration exposure, and\nplaceholder registry access.",[27,28,30],"h2",{"id":29},"bootstrap-wiring","Bootstrap Wiring",[18,32,33],{},"Enable diagnostics from the platform bootstrap builder:",[35,36,42],"pre",{"className":37,"code":39,"language":40,"meta":41},[38],"language-java","BukkitBootstrap.RuntimeResult magic = BukkitBootstrap.forPlugin(plugin)\n        .enableCommands()\n        .enableDiagnostics()\n        .configureDiagnostics(registry -> {\n            registry.register(new MyDatabaseCheck());\n        })\n        .buildRuntime();\n\nDiagnosticsService diagnostics = magic.diagnosticsService();\n","java","",[22,43,39],{"__ignoreMap":41},[18,45,46],{},"The service is also available from the runtime container:",[35,48,51],{"className":49,"code":50,"language":40,"meta":41},[38],"DiagnosticsService diagnostics =\n        magic.runtime().requireComponent(DiagnosticsService.class);\n",[22,52,50],{"__ignoreMap":41},[27,54,56],{"id":55},"running-checks","Running Checks",[18,58,59],{},"Execute the full report or a single suite:",[35,61,64],{"className":62,"code":63,"language":40,"meta":41},[38],"DiagnosticReport safeReport = diagnostics.runAll(DiagnosticRunRequest.safe());\nDiagnosticReport standardReport = diagnostics.runSuite(\n        \"magicutils.scheduler\",\n        DiagnosticRunRequest.standard()\n);\n",[22,65,63],{"__ignoreMap":41},[18,67,68,69,72,73,76],{},"The built-in checks are registered through a ",[22,70,71],{},"magicutils","-namespaced registry\nview, so their suite IDs are prefixed. Pass the full ID to ",[22,74,75],{},"runSuite(...)",":",[78,79,80,86,91,96,101,106,111],"ul",{},[81,82,83],"li",{},[22,84,85],{},"magicutils.runtime",[81,87,88],{},[22,89,90],{},"magicutils.filesystem",[81,92,93],{},[22,94,95],{},"magicutils.config",[81,97,98],{},[22,99,100],{},"magicutils.scheduler",[81,102,103],{},[22,104,105],{},"magicutils.threading",[81,107,108],{},[22,109,110],{},"magicutils.commands",[81,112,113],{},[22,114,115],{},"magicutils.placeholders",[18,117,118,119,122,123,126,127,130,131,134],{},"Checks you register yourself through ",[22,120,121],{},"configureDiagnostics(...)"," receive the raw\nregistry, so their ",[22,124,125],{},"suite()"," value is used as-is (no ",[22,128,129],{},"magicutils."," prefix). Group\nyour own checks under your own suite id, for example ",[22,132,133],{},"mymod.database",".",[18,136,137,140,141,144],{},[22,138,139],{},"SAFE"," mode avoids temp-file writes and reload probes. ",[22,142,143],{},"STANDARD"," mode enables\nreversible probes such as temp-file writes and config reloadability checks.",[27,146,148],{"id":147},"writing-a-custom-check","Writing A Custom Check",[18,150,151,152,155,156,159,160,162,163,166,167,170,171,174,175,178,179,182,183,186,187,190,191,134],{},"A ",[22,153,154],{},"DiagnosticCheck"," describes a single self-test: a stable ",[22,157,158],{},"id()",", its ",[22,161,125],{},",\na ",[22,164,165],{},"description()",", the ",[22,168,169],{},"severity()"," that applies when it fails, the modes it\n",[22,172,173],{},"supportedModes()"," runs in, and a ",[22,176,177],{},"run(...)"," that returns a ",[22,180,181],{},"DiagnosticResult","\n(build one with ",[22,184,185],{},"DiagnosticResult.ok\u002Fwarn\u002Ffail\u002Fskipped","). The context exposes the\nlive ",[22,188,189],{},"runtime()"," and ",[22,192,193],{},"workingDirectory()",[35,195,198],{"className":196,"code":197,"language":40,"meta":41},[38],"public final class MyDatabaseCheck implements DiagnosticCheck {\n    @Override\n    public String id() {\n        return \"mymod.database.reachable\";\n    }\n\n    @Override\n    public String suite() {\n        return \"mymod.database\";\n    }\n\n    @Override\n    public String description() {\n        return \"Database connection is reachable\";\n    }\n\n    @Override\n    public DiagnosticSeverity severity() {\n        return DiagnosticSeverity.CRITICAL;\n    }\n\n    @Override\n    public EnumSet\u003CDiagnosticMode> supportedModes() {\n        \u002F\u002F read-only, so it runs in SAFE and STANDARD\n        return EnumSet.allOf(DiagnosticMode.class);\n    }\n\n    @Override\n    public CompletionStage\u003CDiagnosticResult> run(DiagnosticContext context) {\n        boolean reachable = database.ping();\n        DiagnosticResult result = reachable\n                ? DiagnosticResult.ok(id(), suite(), severity(),\n                        \"Database responded\", Map.of())\n                : DiagnosticResult.fail(id(), suite(), severity(),\n                        \"Database did not respond\", Map.of(), null);\n        return CompletableFuture.completedFuture(result);\n    }\n}\n",[22,199,197],{"__ignoreMap":41},[18,201,202,203,205,206,208,209,211,212,215],{},"Register it during bootstrap through ",[22,204,121],{}," as shown above.\n",[22,207,173],{}," lets you keep a probe out of ",[22,210,139],{}," runs: return\n",[22,213,214],{},"EnumSet.of(DiagnosticMode.STANDARD)"," if the check writes or mutates anything.",[27,217,219],{"id":218},"exporting-reports","Exporting Reports",[18,221,222],{},"Reports can be rendered to text or exported as JSON:",[35,224,227],{"className":225,"code":226,"language":40,"meta":41},[38],"List\u003CString> lines = DiagnosticReports.renderText(safeReport);\nPath exported = diagnostics.exportJson(safeReport);\n",[22,228,226],{"__ignoreMap":41},[18,230,231],{},"The default export path is:",[35,233,238],{"className":234,"code":236,"language":237,"meta":41},[235],"language-text","\u003CconfigDir>\u002Fdiagnostics\u002Flatest.json\n","text",[22,239,236],{"__ignoreMap":41},[27,241,243],{"id":242},"command-helper","Command Helper",[18,245,246],{},"Mount diagnostics into an existing command tree the same way you mount help:",[35,248,251],{"className":249,"code":250,"language":40,"meta":41},[38],"MagicCommand admin = MagicCommand.\u003CCommandSender>builder(\"admin\")\n        .subCommand(HelpCommandSupport.createHelpSubCommand(\n                logger.getCore(),\n                registry::commandManager\n        ))\n        .subCommand(DiagnosticsCommandSupport.createDiagnosticsSubCommand(\n                logger.getCore(),\n                magic::diagnosticsService\n        ))\n        .build();\n",[22,252,250],{"__ignoreMap":41},[18,254,255],{},"Supported command forms:",[78,257,258,263,268,273,278,283,288],{},[81,259,260],{},[22,261,262],{},"\u002Fplugin diagnostics",[81,264,265],{},[22,266,267],{},"\u002Fplugin diagnostics safe",[81,269,270],{},[22,271,272],{},"\u002Fplugin diagnostics standard",[81,274,275],{},[22,276,277],{},"\u002Fplugin diagnostics export",[81,279,280],{},[22,281,282],{},"\u002Fplugin diagnostics export standard",[81,284,285],{},[22,286,287],{},"\u002Fplugin diagnostics suite magicutils.scheduler",[81,289,290],{},[22,291,292],{},"\u002Fplugin diagnostics suite magicutils.scheduler standard",{"title":41,"searchDepth":294,"depth":294,"links":295},3,[296,298,299,300,301],{"id":29,"depth":297,"text":30},2,{"id":55,"depth":297,"text":56},{"id":147,"depth":297,"text":148},{"id":218,"depth":297,"text":219},{"id":242,"depth":297,"text":243},"The MagicUtils diagnostics service: built-in runtime checks, custom diagnostics, JSON export, and command helpers for health and support.","md",{},null,true,"\u002Fmodules\u002Fdiagnostics","---\ntitle: Diagnostics\ndescription: 'The MagicUtils diagnostics service: built-in runtime checks, custom diagnostics, JSON export, and command helpers for health and support.'\n---\n\n# Diagnostics\n\n:platform-badges{:platforms='[\"bukkit\",\"bungee\",\"velocity\",\"fabric\",\"neoforge\"]'}\n\nMagicUtils diagnostics provide runtime self-checks that can be executed inside a\nlive plugin or mod. The diagnostics service is built on top of `MagicRuntime`\nand ships with safe infrastructure-focused checks for runtime wiring,\nfilesystem access, scheduler behavior, command registration exposure, and\nplaceholder registry access.\n\n## Bootstrap Wiring\n\nEnable diagnostics from the platform bootstrap builder:\n\n```java\nBukkitBootstrap.RuntimeResult magic = BukkitBootstrap.forPlugin(plugin)\n        .enableCommands()\n        .enableDiagnostics()\n        .configureDiagnostics(registry -> {\n            registry.register(new MyDatabaseCheck());\n        })\n        .buildRuntime();\n\nDiagnosticsService diagnostics = magic.diagnosticsService();\n```\n\nThe service is also available from the runtime container:\n\n```java\nDiagnosticsService diagnostics =\n        magic.runtime().requireComponent(DiagnosticsService.class);\n```\n\n## Running Checks\n\nExecute the full report or a single suite:\n\n```java\nDiagnosticReport safeReport = diagnostics.runAll(DiagnosticRunRequest.safe());\nDiagnosticReport standardReport = diagnostics.runSuite(\n        \"magicutils.scheduler\",\n        DiagnosticRunRequest.standard()\n);\n```\n\nThe built-in checks are registered through a `magicutils`-namespaced registry\nview, so their suite IDs are prefixed. Pass the full ID to `runSuite(...)`:\n\n- `magicutils.runtime`\n- `magicutils.filesystem`\n- `magicutils.config`\n- `magicutils.scheduler`\n- `magicutils.threading`\n- `magicutils.commands`\n- `magicutils.placeholders`\n\nChecks you register yourself through `configureDiagnostics(...)` receive the raw\nregistry, so their `suite()` value is used as-is (no `magicutils.` prefix). Group\nyour own checks under your own suite id, for example `mymod.database`.\n\n`SAFE` mode avoids temp-file writes and reload probes. `STANDARD` mode enables\nreversible probes such as temp-file writes and config reloadability checks.\n\n## Writing A Custom Check\n\nA `DiagnosticCheck` describes a single self-test: a stable `id()`, its `suite()`,\na `description()`, the `severity()` that applies when it fails, the modes it\n`supportedModes()` runs in, and a `run(...)` that returns a `DiagnosticResult`\n(build one with `DiagnosticResult.ok\u002Fwarn\u002Ffail\u002Fskipped`). The context exposes the\nlive `runtime()` and `workingDirectory()`.\n\n```java\npublic final class MyDatabaseCheck implements DiagnosticCheck {\n    @Override\n    public String id() {\n        return \"mymod.database.reachable\";\n    }\n\n    @Override\n    public String suite() {\n        return \"mymod.database\";\n    }\n\n    @Override\n    public String description() {\n        return \"Database connection is reachable\";\n    }\n\n    @Override\n    public DiagnosticSeverity severity() {\n        return DiagnosticSeverity.CRITICAL;\n    }\n\n    @Override\n    public EnumSet\u003CDiagnosticMode> supportedModes() {\n        \u002F\u002F read-only, so it runs in SAFE and STANDARD\n        return EnumSet.allOf(DiagnosticMode.class);\n    }\n\n    @Override\n    public CompletionStage\u003CDiagnosticResult> run(DiagnosticContext context) {\n        boolean reachable = database.ping();\n        DiagnosticResult result = reachable\n                ? DiagnosticResult.ok(id(), suite(), severity(),\n                        \"Database responded\", Map.of())\n                : DiagnosticResult.fail(id(), suite(), severity(),\n                        \"Database did not respond\", Map.of(), null);\n        return CompletableFuture.completedFuture(result);\n    }\n}\n```\n\nRegister it during bootstrap through `configureDiagnostics(...)` as shown above.\n`supportedModes()` lets you keep a probe out of `SAFE` runs: return\n`EnumSet.of(DiagnosticMode.STANDARD)` if the check writes or mutates anything.\n\n## Exporting Reports\n\nReports can be rendered to text or exported as JSON:\n\n```java\nList\u003CString> lines = DiagnosticReports.renderText(safeReport);\nPath exported = diagnostics.exportJson(safeReport);\n```\n\nThe default export path is:\n\n```text\n\u003CconfigDir>\u002Fdiagnostics\u002Flatest.json\n```\n\n## Command Helper\n\nMount diagnostics into an existing command tree the same way you mount help:\n\n```java\nMagicCommand admin = MagicCommand.\u003CCommandSender>builder(\"admin\")\n        .subCommand(HelpCommandSupport.createHelpSubCommand(\n                logger.getCore(),\n                registry::commandManager\n        ))\n        .subCommand(DiagnosticsCommandSupport.createDiagnosticsSubCommand(\n                logger.getCore(),\n                magic::diagnosticsService\n        ))\n        .build();\n```\n\nSupported command forms:\n\n- `\u002Fplugin diagnostics`\n- `\u002Fplugin diagnostics safe`\n- `\u002Fplugin diagnostics standard`\n- `\u002Fplugin diagnostics export`\n- `\u002Fplugin diagnostics export standard`\n- `\u002Fplugin diagnostics suite magicutils.scheduler`\n- `\u002Fplugin diagnostics suite magicutils.scheduler standard`\n",{"title":5,"description":302},"modules\u002Fdiagnostics","MEMQE1XqnNkEjfN73NHpC8kIg2hNgVdQAuKdyWDd488",1783944487964]