[{"data":1,"prerenderedAt":597},["ShallowReactive",2],{"docs-\u002Fmodules\u002Flogger":3},{"id":4,"title":5,"body":6,"description":587,"extension":588,"meta":589,"navTitle":590,"navigation":591,"path":592,"rawbody":593,"seo":594,"stem":595,"__hash__":596},"docs\u002Fmodules\u002Flogger.md","Logger",{"type":7,"value":8,"toc":568},"minimark",[9,13,17,21,26,46,89,99,102,108,114,120,126,130,137,142,148,152,158,162,169,175,179,185,191,195,201,216,219,225,229,250,256,259,327,331,337,348,352,358,387,394,398,404,410,413,417,425,443,451,454,484,488,499,505,511,514,518,521,539,542,548,551],[10,11,5],"h1",{"id":12},"logger",[14,15],"platform-badges",{":platforms":16},"[\"bukkit\",\"bungee\",\"velocity\",\"fabric\",\"neoforge\"]",[18,19,20],"p",{},"MagicUtils logger builds on Adventure components and provides a consistent API\nfor console and chat output, with optional localisation, internal placeholders,\nand external placeholder engines.",[22,23,25],"h2",{"id":24},"why-a-logger-built-on-adventure","Why a logger built on Adventure",[18,27,28,29,33,34,37,38,41,42,45],{},"Every platform speaks a different dialect of \"styled text\": Bukkit has legacy\n",[30,31,32],"code",{},"&","\u002F",[30,35,36],{},"§"," colour codes and ",[30,39,40],{},"ChatColor",", Fabric\u002FNeoForge use Minecraft's own ",[30,43,44],{},"Text",",\nVelocity and BungeeCord have their own component types. Writing colourful output\nthat works everywhere normally means branching per platform.",[18,47,48,49,56,57,62,63,66,67,66,70,73,74,78,79,66,82,66,85,88],{},"MagicUtils logs in ",[50,51,55],"a",{"href":52,"rel":53},"https:\u002F\u002Fdocs.advntr.dev\u002F",[54],"nofollow","Kyori Adventure"," components. You\ncan author them with ",[50,58,61],{"href":59,"rel":60},"https:\u002F\u002Fdocs.advntr.dev\u002Fminimessage\u002Fformat.html",[54],"MiniMessage",",\nthe modern tag syntax (",[30,64,65],{},"\u003Cgreen>",", ",[30,68,69],{},"\u003Cgradient>",[30,71,72],{},"\u003Chover>","), ",[75,76,77],"strong",{},"or"," with familiar\nlegacy colour codes (",[30,80,81],{},"&a",[30,83,84],{},"&l",[30,86,87],{},"&#ff8800",") — both are accepted and legacy\ncodes are converted to MiniMessage automatically, so you can mix styles or paste\nexisting coloured strings:",[90,91,97],"pre",{"className":92,"code":94,"language":95,"meta":96},[93],"language-java","logger.info(\"\u003Cgreen>New\u003C\u002Fgreen> and \u003Cgold>old\u003C\u002Fgold> styles\");\nlogger.info(\"&aNew&r and &6old&r styles\");   \u002F\u002F same result\n","java","",[30,98,94],{"__ignoreMap":96},[18,100,101],{},"One string renders correctly on every platform, in chat and in the console, and\nthe same call can localise, resolve placeholders, and honour per-logger prefixes.",[18,103,104,107],{},[75,105,106],{},"Before"," (raw Bukkit, colour codes, console vs player split):",[90,109,112],{"className":110,"code":111,"language":95,"meta":96},[93],"String msg = ChatColor.translateAlternateColorCodes('&', \"&aReady&r, &e\" + count + \"&r loaded\");\nBukkit.getConsoleSender().sendMessage(msg);\nplayer.sendMessage(msg);\n",[30,113,111],{"__ignoreMap":96},[18,115,116,119],{},[75,117,118],{},"After"," (MagicUtils, one call, MiniMessage, any platform):",[90,121,124],{"className":122,"code":123,"language":95,"meta":96},[93],"logger.info()\n        .toAll()\n        .args(count)\n        .send(\"\u003Cgreen>Ready\u003C\u002Fgreen>, \u003Cyellow>{0}\u003C\u002Fyellow> loaded\");\n",[30,125,123],{"__ignoreMap":96},[22,127,129],{"id":128},"setup","Setup",[18,131,132,133,136],{},"The recommended path is to obtain the logger from a bootstrap result or\n",[30,134,135],{},"MagicRuntime",".",[138,139,141],"h3",{"id":140},"bukkitpaper","Bukkit\u002FPaper",[90,143,146],{"className":144,"code":145,"language":95,"meta":96},[93],"BukkitBootstrap.RuntimeResult magic = BukkitBootstrap.forPlugin(plugin)\n        .buildRuntime();\n\nLogger logger = magic.logger();\n",[30,147,145],{"__ignoreMap":96},[138,149,151],{"id":150},"fabric","Fabric",[90,153,156],{"className":154,"code":155,"language":95,"meta":96},[93],"FabricBootstrap.RuntimeResult magic = FabricBootstrap.forMod(\"mymod\", () -> server)\n        .buildRuntime();\n\nLogger logger = magic.logger();\n",[30,157,155],{"__ignoreMap":96},[138,159,161],{"id":160},"velocity","Velocity",[18,163,164,165,168],{},"Velocity bootstrap returns ",[30,166,167],{},"LoggerCore"," directly:",[90,170,173],{"className":171,"code":172,"language":95,"meta":96},[93],"VelocityBootstrap.RuntimeResult magic = VelocityBootstrap.forPlugin(proxy, plugin, \"MyPlugin\", dataDirectory)\n        .buildRuntime();\n\nLoggerCore logger = magic.logger();\n",[30,174,172],{"__ignoreMap":96},[138,176,178],{"id":177},"neoforge-custom-platforms","NeoForge \u002F Custom Platforms",[18,180,181,182,184],{},"NeoForge and custom platforms typically wire ",[30,183,167],{}," manually:",[90,186,189],{"className":187,"code":188,"language":95,"meta":96},[93],"Platform platform = new NeoForgePlatformProvider();\nConfigManager configManager = new ConfigManager(platform);\nLoggerCore logger = new LoggerCore(platform, configManager, this, \"MyMod\");\n",[30,190,188],{"__ignoreMap":96},[22,192,194],{"id":193},"basic-usage","Basic Usage",[90,196,199],{"className":197,"code":198,"language":95,"meta":96},[93],"logger.info(\"\u003Cgreen>Ready.\u003C\u002Fgreen>\");\nlogger.warn(\"Slow query detected\");\nlogger.error(\"Database unavailable\");\nlogger.success(\"Migration complete\");\nlogger.debug(\"Cache miss for {key}\");\n",[30,200,198],{"__ignoreMap":96},[18,202,203,204,207,208,211,212,215],{},"Each level also has form-string overloads (",[30,205,206],{},"info(format, args...)",") and variants\nthat target the console (",[30,209,210],{},"infoConsole(...)",") or every audience (",[30,213,214],{},"infoAll(...)",").\nThe logger accepts MiniMessage markup and can target console, chat, or both.",[18,217,218],{},"Send a plain broadcast to every online player and the console:",[90,220,223],{"className":221,"code":222,"language":95,"meta":96},[93],"logger.broadcast(\"\u003Cgold>Server restarting in 60s\u003C\u002Fgold>\");\n",[30,224,222],{"__ignoreMap":96},[22,226,228],{"id":227},"log-builder","Log Builder",[18,230,231,232,66,235,238,239,66,242,245,246,249],{},"Start a builder with ",[30,233,234],{},"log()",[30,236,237],{},"noPrefix()",", or any level (",[30,240,241],{},"info()",[30,243,244],{},"success()",",\n...), chain the targeting\u002Fformatting calls, then ",[30,247,248],{},"send(...)",":",[90,251,254],{"className":252,"code":253,"language":95,"meta":96},[93],"logger.info()\n        .toConsole()\n        .noPrefix()\n        .send(\"\u003Cyellow>Reloaded\u003C\u002Fyellow>\");\n\nlogger.log()\n        .to(playerAudience)\n        .args(playerName, count)\n        .send(\"\u003Cgreen>{0} claimed {1} rewards\u003C\u002Fgreen>\");\n",[30,255,253],{"__ignoreMap":96},[18,257,258],{},"Builder methods:",[260,261,262,274,285,292,305,315,321],"ul",{},[263,264,265,66,268,66,271],"li",{},[30,266,267],{},"target(LogTarget.CHAT | CONSOLE | BOTH)",[30,269,270],{},"toConsole()",[30,272,273],{},"toAll()",[263,275,276,66,279,66,282],{},[30,277,278],{},"to(audience)",[30,280,281],{},"toAudiences(collection)",[30,283,284],{},"recipient(audience)",[263,286,287,66,289],{},[30,288,237],{},[30,290,291],{},"prefixMode(PrefixMode.FULL | SHORT | CUSTOM | NONE)",[263,293,294,297,298,66,301,304],{},[30,295,296],{},"args(Object...)"," for ",[30,299,300],{},"{0}",[30,302,303],{},"{1}",", ... substitution",[263,306,307,310,311,314],{},[30,308,309],{},"placeholders(Map)"," for named ",[30,312,313],{},"{key}"," tokens",[263,316,317,320],{},[30,318,319],{},"withResolvers(TagResolver...)"," for custom MiniMessage tags",[263,322,323,326],{},[30,324,325],{},"send(message, placeholders...)"," to render and dispatch",[22,328,330],{"id":329},"prefixed-loggers","Prefixed Loggers",[90,332,335],{"className":333,"code":334,"language":95,"meta":96},[93],"PrefixedLogger db = logger.withPrefix(\"database\", \"[DB]\");\ndb.info(\"Connected\");\n",[30,336,334],{"__ignoreMap":96},[18,338,339,340,343,344,347],{},"Each prefixed logger gets its own entry under ",[30,341,342],{},"sub-loggers"," in ",[30,345,346],{},"logger.{ext}","\nfor enable or disable toggles.",[22,349,351],{"id":350},"prefix-modes","Prefix Modes",[18,353,354,355,249],{},"Prefix rendering is controlled by ",[30,356,357],{},"PrefixMode",[260,359,360,366,372,381],{},[263,361,362,365],{},[30,363,364],{},"FULL"," -> full plugin\u002Fmod name",[263,367,368,371],{},[30,369,370],{},"SHORT"," -> short name from config",[263,373,374,377,378],{},[30,375,376],{},"CUSTOM"," -> ",[30,379,380],{},"setCustomPrefix(...)",[263,382,383,386],{},[30,384,385],{},"NONE"," -> no prefix",[18,388,389,391,392,136],{},[30,390,5],{}," delegates these controls to the underlying ",[30,393,167],{},[22,395,397],{"id":396},"runtime-integration","Runtime Integration",[18,399,400,401,403],{},"When you already have ",[30,402,135],{},", the logger is a shared typed component:",[90,405,408],{"className":406,"code":407,"language":95,"meta":96},[93],"MagicRuntime runtime = magic.runtime();\nLoggerCore loggerCore = runtime.requireComponent(LoggerCore.class);\n",[30,409,407],{"__ignoreMap":96},[18,411,412],{},"That makes it easy to pass the logger into reloadable services or register\nnamed runtime resources that log through the same config and placeholder setup.",[22,414,416],{"id":415},"logger-configuration","Logger Configuration",[18,418,419,422,423,136],{},[30,420,421],{},"LoggerConfig"," is stored as ",[30,424,346],{},[260,426,427,430,437],{},[263,428,429],{},"Bukkit: plugin config directory",[263,431,432,433,436],{},"Fabric: ",[30,434,435],{},"config\u002F\u003Cmodid>\u002F"," by default",[263,438,439,440],{},"Velocity \u002F custom platforms: resolved through the active ",[30,441,442],{},"Platform",[18,444,445,446,450],{},"See ",[50,447,449],{"href":448},"logger-config","Logger Config"," for a full key reference.",[18,452,453],{},"Key sections:",[260,455,456,461,466,475,480],{},[263,457,458],{},[30,459,460],{},"prefix",[263,462,463],{},[30,464,465],{},"defaults",[263,467,468,471,472],{},[30,469,470],{},"chat"," \u002F ",[30,473,474],{},"console",[263,476,477],{},[30,478,479],{},"help",[263,481,482],{},[30,483,342],{},[22,485,487],{"id":486},"localisation","Localisation",[18,489,490,491,494,495,498],{},"Attach a ",[30,492,493],{},"LanguageManager"," to enable ",[30,496,497],{},"@key"," lookups:",[90,500,503],{"className":501,"code":502,"language":95,"meta":96},[93],"logger.setLanguageManager(languageManager);\nlogger.info(\"@myplugin.ready\");\n",[30,504,502],{"__ignoreMap":96},[18,506,507,508,510],{},"The logger resolves the key through the attached ",[30,509,493],{}," and then\nrenders the result as MiniMessage.",[18,512,513],{},"Bootstrap helpers bind the language manager automatically when language support\nis enabled.",[22,515,517],{"id":516},"internal-and-external-placeholders","Internal And External Placeholders",[18,519,520],{},"Logger messages pass through both:",[522,523,524,536],"ol",{},[263,525,526,297,529,531,532,535],{},[30,527,528],{},"MagicPlaceholders",[30,530,313],{}," and ",[30,533,534],{},"{namespace:key}"," tokens.",[263,537,538],{},"Platform-specific external placeholder engines.",[18,540,541],{},"Examples:",[90,543,546],{"className":544,"code":545,"language":95,"meta":96},[93],"logger.info(\"Balance: {economy:balance}\");\nlogger.info(\"Hello {player}\");\n",[30,547,545],{"__ignoreMap":96},[18,549,550],{},"Platform integrations:",[260,552,553,556,559],{},[263,554,555],{},"Bukkit logger installs the PlaceholderAPI bridge and a Bukkit external\nplaceholder engine.",[263,557,558],{},"Fabric logger installs Text Placeholder API \u002F MiniPlaceholders \u002F PB4 support\nwhen those mods are present.",[263,560,561,563,564,567],{},[30,562,167],{}," also supports a custom ",[30,565,566],{},"ExternalPlaceholderEngine"," for custom\nplatforms.",{"title":96,"searchDepth":569,"depth":569,"links":570},3,[571,573,579,580,581,582,583,584,585,586],{"id":24,"depth":572,"text":25},2,{"id":128,"depth":572,"text":129,"children":574},[575,576,577,578],{"id":140,"depth":569,"text":141},{"id":150,"depth":569,"text":151},{"id":160,"depth":569,"text":161},{"id":177,"depth":569,"text":178},{"id":193,"depth":572,"text":194},{"id":227,"depth":572,"text":228},{"id":329,"depth":572,"text":330},{"id":350,"depth":572,"text":351},{"id":396,"depth":572,"text":397},{"id":415,"depth":572,"text":416},{"id":486,"depth":572,"text":487},{"id":516,"depth":572,"text":517},"The Adventure-based MagicUtils logger core: rich formatting, sub-loggers, and consistent styling across every supported platform.","md",{},null,true,"\u002Fmodules\u002Flogger","---\ntitle: Logger\ndescription: 'The Adventure-based MagicUtils logger core: rich formatting, sub-loggers, and consistent styling across every supported platform.'\n---\n\n# Logger\n\n:platform-badges{:platforms='[\"bukkit\",\"bungee\",\"velocity\",\"fabric\",\"neoforge\"]'}\n\nMagicUtils logger builds on Adventure components and provides a consistent API\nfor console and chat output, with optional localisation, internal placeholders,\nand external placeholder engines.\n\n## Why a logger built on Adventure\n\nEvery platform speaks a different dialect of \"styled text\": Bukkit has legacy\n`&`\u002F`§` colour codes and `ChatColor`, Fabric\u002FNeoForge use Minecraft's own `Text`,\nVelocity and BungeeCord have their own component types. Writing colourful output\nthat works everywhere normally means branching per platform.\n\nMagicUtils logs in [Kyori Adventure](https:\u002F\u002Fdocs.advntr.dev\u002F) components. You\ncan author them with [MiniMessage](https:\u002F\u002Fdocs.advntr.dev\u002Fminimessage\u002Fformat.html),\nthe modern tag syntax (`\u003Cgreen>`, `\u003Cgradient>`, `\u003Chover>`), **or** with familiar\nlegacy colour codes (`&a`, `&l`, `&#ff8800`) — both are accepted and legacy\ncodes are converted to MiniMessage automatically, so you can mix styles or paste\nexisting coloured strings:\n\n```java\nlogger.info(\"\u003Cgreen>New\u003C\u002Fgreen> and \u003Cgold>old\u003C\u002Fgold> styles\");\nlogger.info(\"&aNew&r and &6old&r styles\");   \u002F\u002F same result\n```\n\nOne string renders correctly on every platform, in chat and in the console, and\nthe same call can localise, resolve placeholders, and honour per-logger prefixes.\n\n**Before** (raw Bukkit, colour codes, console vs player split):\n\n```java\nString msg = ChatColor.translateAlternateColorCodes('&', \"&aReady&r, &e\" + count + \"&r loaded\");\nBukkit.getConsoleSender().sendMessage(msg);\nplayer.sendMessage(msg);\n```\n\n**After** (MagicUtils, one call, MiniMessage, any platform):\n\n```java\nlogger.info()\n        .toAll()\n        .args(count)\n        .send(\"\u003Cgreen>Ready\u003C\u002Fgreen>, \u003Cyellow>{0}\u003C\u002Fyellow> loaded\");\n```\n\n## Setup\n\nThe recommended path is to obtain the logger from a bootstrap result or\n`MagicRuntime`.\n\n### Bukkit\u002FPaper\n\n```java\nBukkitBootstrap.RuntimeResult magic = BukkitBootstrap.forPlugin(plugin)\n        .buildRuntime();\n\nLogger logger = magic.logger();\n```\n\n### Fabric\n\n```java\nFabricBootstrap.RuntimeResult magic = FabricBootstrap.forMod(\"mymod\", () -> server)\n        .buildRuntime();\n\nLogger logger = magic.logger();\n```\n\n### Velocity\n\nVelocity bootstrap returns `LoggerCore` directly:\n\n```java\nVelocityBootstrap.RuntimeResult magic = VelocityBootstrap.forPlugin(proxy, plugin, \"MyPlugin\", dataDirectory)\n        .buildRuntime();\n\nLoggerCore logger = magic.logger();\n```\n\n### NeoForge \u002F Custom Platforms\n\nNeoForge and custom platforms typically wire `LoggerCore` manually:\n\n```java\nPlatform platform = new NeoForgePlatformProvider();\nConfigManager configManager = new ConfigManager(platform);\nLoggerCore logger = new LoggerCore(platform, configManager, this, \"MyMod\");\n```\n\n## Basic Usage\n\n```java\nlogger.info(\"\u003Cgreen>Ready.\u003C\u002Fgreen>\");\nlogger.warn(\"Slow query detected\");\nlogger.error(\"Database unavailable\");\nlogger.success(\"Migration complete\");\nlogger.debug(\"Cache miss for {key}\");\n```\n\nEach level also has form-string overloads (`info(format, args...)`) and variants\nthat target the console (`infoConsole(...)`) or every audience (`infoAll(...)`).\nThe logger accepts MiniMessage markup and can target console, chat, or both.\n\nSend a plain broadcast to every online player and the console:\n\n```java\nlogger.broadcast(\"\u003Cgold>Server restarting in 60s\u003C\u002Fgold>\");\n```\n\n## Log Builder\n\nStart a builder with `log()`, `noPrefix()`, or any level (`info()`, `success()`,\n...), chain the targeting\u002Fformatting calls, then `send(...)`:\n\n```java\nlogger.info()\n        .toConsole()\n        .noPrefix()\n        .send(\"\u003Cyellow>Reloaded\u003C\u002Fyellow>\");\n\nlogger.log()\n        .to(playerAudience)\n        .args(playerName, count)\n        .send(\"\u003Cgreen>{0} claimed {1} rewards\u003C\u002Fgreen>\");\n```\n\nBuilder methods:\n\n- `target(LogTarget.CHAT | CONSOLE | BOTH)`, `toConsole()`, `toAll()`\n- `to(audience)`, `toAudiences(collection)`, `recipient(audience)`\n- `noPrefix()`, `prefixMode(PrefixMode.FULL | SHORT | CUSTOM | NONE)`\n- `args(Object...)` for `{0}`, `{1}`, ... substitution\n- `placeholders(Map)` for named `{key}` tokens\n- `withResolvers(TagResolver...)` for custom MiniMessage tags\n- `send(message, placeholders...)` to render and dispatch\n\n## Prefixed Loggers\n\n```java\nPrefixedLogger db = logger.withPrefix(\"database\", \"[DB]\");\ndb.info(\"Connected\");\n```\n\nEach prefixed logger gets its own entry under `sub-loggers` in `logger.{ext}`\nfor enable or disable toggles.\n\n## Prefix Modes\n\nPrefix rendering is controlled by `PrefixMode`:\n\n- `FULL` -> full plugin\u002Fmod name\n- `SHORT` -> short name from config\n- `CUSTOM` -> `setCustomPrefix(...)`\n- `NONE` -> no prefix\n\n`Logger` delegates these controls to the underlying `LoggerCore`.\n\n## Runtime Integration\n\nWhen you already have `MagicRuntime`, the logger is a shared typed component:\n\n```java\nMagicRuntime runtime = magic.runtime();\nLoggerCore loggerCore = runtime.requireComponent(LoggerCore.class);\n```\n\nThat makes it easy to pass the logger into reloadable services or register\nnamed runtime resources that log through the same config and placeholder setup.\n\n## Logger Configuration\n\n`LoggerConfig` is stored as `logger.{ext}`.\n\n- Bukkit: plugin config directory\n- Fabric: `config\u002F\u003Cmodid>\u002F` by default\n- Velocity \u002F custom platforms: resolved through the active `Platform`\n\nSee [Logger Config](logger-config.md) for a full key reference.\n\nKey sections:\n\n- `prefix`\n- `defaults`\n- `chat` \u002F `console`\n- `help`\n- `sub-loggers`\n\n## Localisation\n\nAttach a `LanguageManager` to enable `@key` lookups:\n\n```java\nlogger.setLanguageManager(languageManager);\nlogger.info(\"@myplugin.ready\");\n```\n\nThe logger resolves the key through the attached `LanguageManager` and then\nrenders the result as MiniMessage.\n\nBootstrap helpers bind the language manager automatically when language support\nis enabled.\n\n## Internal And External Placeholders\n\nLogger messages pass through both:\n\n1. `MagicPlaceholders` for `{key}` and `{namespace:key}` tokens.\n2. Platform-specific external placeholder engines.\n\nExamples:\n\n```java\nlogger.info(\"Balance: {economy:balance}\");\nlogger.info(\"Hello {player}\");\n```\n\nPlatform integrations:\n\n- Bukkit logger installs the PlaceholderAPI bridge and a Bukkit external\n  placeholder engine.\n- Fabric logger installs Text Placeholder API \u002F MiniPlaceholders \u002F PB4 support\n  when those mods are present.\n- `LoggerCore` also supports a custom `ExternalPlaceholderEngine` for custom\n  platforms.\n",{"title":5,"description":587},"modules\u002Flogger","KBGk6z97c0R5rfpzTEHjHHRQ7UjZeVCbEEM1daDm5cw",1783944487661]