Logger that optionally mirror to a on-page UI overlay shared by every page match-common userscript
Este script não deve ser instalado diretamente. É uma biblioteca destinada a ser incluída por outros scripts através da diretiva de metadados // @require https://update.greasyfork.org/scripts/588114/1893327/Logging%20Handler%20%20UI%20Overlay.js
One logging call, two sinks: the browser console and a translucent, click-through log panel pinned to the top-right of the page.
LoggingUI.create) for @requiren scripts on a page therefore produce one panel, not n stacked copies.console.debug/info/warn/errorToggle scoping:
data-logui-panel on documentElement rather than on the panel node: it is the one surface that exists before any logger does, so a controller with no logger of its own can drive it. Instances observe the attribute, follow it, and persist it as their own preference.logging-ui-controls.shim.user.js), which matches every site, stays inert until a logger announces itself via data-logui-consumers, and stamps the remembered choice at document-start so it wins over each script's default instead of racing it. Consumers should no longer call registerMenuCommands(); doing so just duplicates the entry.Persistence is best-effort. GM_getValue and GM_setValue are used when the calling script granted them; without the grants the toggles simply live for the lifetime of the page.
Compatibility: 1.1.0 still mirrors data-logui-visible onto the panel node, so a 1.0.x instance pinned by some other script on the same page keeps following flips. The reverse does not hold — a 1.0.x instance writes only the panel node, which nothing in 1.1.0 observes — so read a mixed-version page as "1.1.0 leads, 1.0.x follows".
// @require https://update.greasyfork.org/...
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
const logger = LoggingUI.create({
name: '$NAME', // console prefix
tag: 'gcr', // panel prefix
console: true, // default console mirror
panel: true, // default panel visibility
panelSink: !IS_PROFILE, // this instance may write
});
logger.info('feed seeded with %d comments', n);
logger.warn('poll failed:', err);
logger.consoleOnly.debug('response body', dump); // devtools, never the panel
LoggingUI.create(cfg):
| key | default | note |
|---|---|---|
| name | falls back to tag | console prefix, bracketed |
| tag | name, else 'log' | panel prefix, and the identity announced in data-logui-consumers |
| console | true | initial console mirror; a stored preference outranks it |
| panel | true | initial panel visibility; both the page-wide state and a stored preference outrank it |
| panelSink | true | false makes this instance console-only — it never builds or writes the panel, but still tracks panelEnabled for a settings UI |
| prefsKey | 'logui_prefs' | GM storage key; give each script its own to keep preferences separate |
| maxLines | 500 | panel scrollback, oldest lines dropped |
| minLevel | 'debug' | severity floor, dropped before either sink |
The floor here is the library's; a script wanting a user-facing verbosity control layers its own on top and gates its call sites (the mail helper's Advanced "Log level" slider is the worked example). Keep the two distinct: minLevel is how severe a line must be, consoleOnly is where it is allowed to go.
| export | note |
|---|---|
| LoggingUI.create | the factory |
| LoggingUI.LEVELS | ['debug','info','warn','error'], in ascending severity |
| LoggingUI.ATTRS | 1.1.0 — { state, consumers }, the documentElement attribute names, so a controller can reason about the page's loggers without owning one |
logging-ui-controls.shim.user.js is a standalone userscript, not part of the library. It owns the "Toggle log panel" menu command for the whole page.
@match *://*/*, @run-at document-start. Stamping data-logui-panel before any consumer constructs means the remembered choice wins over each script's panel default rather than racing it.@require the library. It runs on every page and must stay inert on the overwhelming majority that have no logger; pulling in the overlay CSS and instance machinery just to conclude "not here" is the wrong trade. Its contract is the two attributes, reimplemented in miniature.data-logui-consumers. Consumers announce as they construct, which can be well after document-start, so the shim watches the attribute rather than sampling once.logui_controls, separate from any consumer's prefsKey. Default is off.Consumer migration to 1.1.0:
registerMenuCommands() call; the shim provides the entry, and a second registration is a duplicate row that moves only that one script.logger.consoleOnly.* so they reach devtools without flooding the panel every other script shares.| method(s) | note |
|---|---|
| logger.debug | info |
| logger.log(...args) | alias of info |
| logger.consoleEnabled | getter/setter (boolean) |
| logger.panelEnabled | getter/setter (boolean, page-wide) |
| logger.consoleOnly.debug | info |
| logger.toggleConsole() / togglePanel() | flip and persist, returns new state |
| logger.registerMenuCommands(opts) | deprecated 1.1.0 — the shim owns the panel command |
| logger.clear() | empty the shared panel |
| logger.element | the panel node, or null |