113 lines
4.5 KiB
Markdown
113 lines
4.5 KiB
Markdown
# Logging standard
|
|
|
|
Lumi uses the structured logger in `src/services/logger.js` for operational
|
|
events. It stores searchable entries for the admin UI, attaches request context,
|
|
redacts common credential fields, and publishes live admin updates.
|
|
|
|
## Operational logging
|
|
|
|
Core services create a named logger:
|
|
|
|
```js
|
|
const { createLogger } = require("./logger");
|
|
const logger = createLogger("core:updater", { category: "updates" });
|
|
|
|
logger.info("Update check completed", { version }, {
|
|
event: "update_check_completed"
|
|
});
|
|
```
|
|
|
|
Plugins receive a plugin-scoped `logger` in their `init()` dependencies. Use
|
|
that injected logger when practical. A plugin module that must log outside
|
|
`init()` may create a logger named `plugin:<plugin-id>`.
|
|
|
|
Use these source prefixes consistently:
|
|
|
|
- `core:<component>` for Lumi core and WebUI services.
|
|
- `platform:<provider>` for Discord, Twitch, YouTube, and similar integrations.
|
|
- `plugin:<plugin-id>` for bundled and locally installed plugins.
|
|
- `companion:<component>` for the desktop Companion host.
|
|
|
|
Give each logger a stable default category such as `lifecycle`, `http`,
|
|
`integration`, `command`, `automation`, `security`, `updates`, or `plugin`.
|
|
Every operational call must provide a stable, lowercase `snake_case` event ID.
|
|
Messages are for people and may improve over time; event IDs are for filtering
|
|
and automation and should remain stable.
|
|
|
|
Use:
|
|
|
|
- `debug` for detailed, low-value troubleshooting information.
|
|
- `info` for meaningful lifecycle and administrative actions.
|
|
- `warn` for degraded behavior that Lumi can continue through.
|
|
- `error` for a failed operation that may require attention.
|
|
|
|
Pass an `Error` as the details argument when one is available. The logger
|
|
preserves its stack trace while applying credential redaction:
|
|
|
|
```js
|
|
logger.error("Plugin refresh failed", error, {
|
|
event: "plugin_refresh_failed"
|
|
});
|
|
```
|
|
|
|
The metadata argument only accepts `source`, `category`, `event`, and
|
|
`requestId`. Operational fields such as `plugin_id`, `user_id`, `status`, or
|
|
`duration_ms` belong in the details argument:
|
|
|
|
```js
|
|
logger.warn("Plugin health check degraded", {
|
|
plugin_id: plugin.id,
|
|
status: health.status
|
|
}, {
|
|
event: "plugin_health_degraded"
|
|
});
|
|
```
|
|
|
|
Do not include passwords, tokens, cookies, pairing secrets, authorization
|
|
headers, signature fragments, full request bodies, or full third-party payloads
|
|
in messages or details. Record a bounded summary with IDs, status, counts, and
|
|
safe error text instead. Redaction is a safety net, not a reason to collect
|
|
secrets.
|
|
|
|
## Metrics and high-frequency events
|
|
|
|
Do not write high-frequency counters or per-frame events to the operational log.
|
|
There is no global metrics API.
|
|
|
|
A feature may retain its own bounded metrics only when it also owns the storage,
|
|
retention, and inspection UI. Lumi AI is one example:
|
|
`plugins/lumi_ai/backend/metrics.js` aggregates AI timings and retains bounded
|
|
work history. Operational failures in such a feature still belong in the core
|
|
logger.
|
|
|
|
Feature-owned diagnostic logs follow the same credential and payload rules.
|
|
They must have explicit size/age retention, sanitize recursively before writing,
|
|
and remain admin-only. Transcription worker diagnostics are kept separately
|
|
because they are high-volume troubleshooting data; they are not a substitute
|
|
for operational warnings and errors in the core logger.
|
|
|
|
The desktop Companion cannot write directly to the server database. Its local
|
|
JSON Lines logs therefore carry the same `level`, `source`, `category`, `event`,
|
|
and human-readable `message` shape, use the shared
|
|
`CompanionLogSanitizer`, and enforce local retention.
|
|
|
|
The native OBS Bridge must use OBS's `blog()` facility so its messages remain in
|
|
the operator's OBS log. Prefix each message with `[Lumi Companion]` and a stable
|
|
`event=<snake_case>` field, and never include IPC payloads or credentials.
|
|
|
|
## Console output
|
|
|
|
Direct `console.*` calls are captured after `hookConsole()` starts, but they lose
|
|
the useful source and event metadata of a named logger. Prefer a named logger in
|
|
runtime code, including startup and shutdown paths. Console output remains
|
|
reasonable in standalone verification and build scripts where the terminal is
|
|
the intended consumer. Browser-side console diagnostics and isolated worker
|
|
sandboxes are outside the server operational-log boundary.
|
|
|
|
## Retention and context
|
|
|
|
Operational logs default to 30 days and at most 100,000 entries. Request
|
|
correlation is inherited through `withLogContext()` and logger `run()` scopes.
|
|
The logger redacts common sensitive keys and credential-looking text before an
|
|
entry is stored or published.
|