From a14fb01631a6485c65b59f627572e12207f49563 Mon Sep 17 00:00:00 2001 From: SandObserver <260779319+SandObserver@users.noreply.github.com> Date: Mon, 10 Aug 2026 17:36:50 -0400 Subject: [PATCH] Docs: document the log format and correct the level descriptions The support doc said both Nginx and the API log to stdout. Nginx now sends request errors to stderr and keeps no access log, so the claim is restated. Adds the record shape, the five level abbreviations, the fact that audit records are never filtered, and one line for anyone shipping to Loki, since the format is logfmt and needs no custom parser. warn and error share a threshold and behave identically. The Compose comment and the environment table both listed four levels as though they were four behaviours. --- CHANGELOG.md | 19 +++++++++++++++++++ docker-compose.yml | 5 +++-- docs/architecture.md | 2 +- docs/support.md | 31 +++++++++++++++++++++++++++++-- 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24ed5524..88c964c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The Docker Hub repository description is published from `README.md` on each stable release. +- The support documentation describes the log format, the level abbreviations + and how to read the logs. + +### Changed + +- The container prints six lines when it starts, instead of twenty-three. + +- Nginx request errors now appear in `docker logs`, and Nginx no longer writes + an access log to a file inside the container that nothing rotated. + +- A misconfigured `TRUST_PROXY` produces one short warning instead of two long + ones. + ### Fixed - The Books, Now Playing and Backup widgets now show why they failed, such as a @@ -20,12 +33,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The last visible row in a Settings group no longer draws a separator under itself, which showed under Password Protection whenever protection was off. +- The startup banner no longer prints a Web UI address that pointed at the + internal API port and worked for nobody. + ### Security - A Connections tile that cannot reach a service now says so in plain words instead of printing the address it tried, which put an internal host and port on the dashboard. +- A failed connection test no longer writes the request path to the log, where + a service that carries its API key in the path would have left it. + ## [1.5.2] - 2026-08-09 ### Changed diff --git a/docker-compose.yml b/docker-compose.yml index eb28ee63..6fe48ac1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -53,8 +53,9 @@ services: # - PASSWORD_HASH_MEMORY=64mib # Set to true to allow widget URLs using private/LAN IP addresses # - ALLOW_PRIVATE_IPS=true - # Log verbosity: debug, info, warn or error. Settings, General sets this - # too, and that wins once the config has loaded. + # Log verbosity: debug, info, warn or error, where warn and error behave + # the same. Settings, General sets this too, and that wins once the config + # has loaded. # - LOG_LEVEL=info # Where the widget folders are read from. Only if you have moved them. # - WIDGETS_PATH=/usr/share/nginx/html/widgets diff --git a/docs/architecture.md b/docs/architecture.md index d2ae8619..38cb8489 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -36,7 +36,7 @@ Everything is optional; the defaults are what the container ships with. | `ICONS_PATH` | `/icons` | Where uploaded icons are written. | | `WIDGETS_PATH` | `/usr/share/nginx/html/widgets` | Where the widget folders are read from. Point it elsewhere only if you have moved them; a wrong path loads an empty registry, and every widget then reports as unknown. | | `PORT` | `3000` | The port the API listens on. nginx proxies to it, so changing it means changing `nginx/dashboard.conf` too. | -| `LOG_LEVEL` | `info` | `debug`, `info`, `warn` or `error`. Settings, General also sets this, and that setting wins from the moment the config loads; the variable is what applies during boot and if no setting is stored. | +| `LOG_LEVEL` | `info` | `debug`, `info`, `warn` or `error`, where `warn` and `error` behave the same: both show warnings and errors. Settings, General also sets this, and that setting wins from the moment the config loads; the variable is what applies during boot and if no setting is stored. | | `APP_VERSION` | the version in `package.json` | What the update check compares against. The release build stamps it, so leave it alone outside a build. | | `TRUST_PROXY` | unset | Believe `X-Forwarded-Proto`, so a request through a TLS-terminating proxy gets a `Secure` cookie. Only behind a proxy you control. See [security.md](./security.md#https-and-the-session-cookie). | | `TRUSTED_PROXY` | unset | Where a front proxy sits, so nginx can resolve the real client for rate limiting. See [security.md](./security.md#authentication). | diff --git a/docs/support.md b/docs/support.md index d867b911..f188d513 100644 --- a/docs/support.md +++ b/docs/support.md @@ -17,7 +17,8 @@ Redact secrets before pasting logs or config. ## Reading the logs -Both Nginx and the API log to the container's stdout: +The API logs to the container's stdout. Nginx logs request errors to stderr and +keeps no access log, so both reach the same place: ``` docker logs @@ -31,7 +32,33 @@ docker compose logs -f In Portainer, open the container and use the **Logs** view. -The API logs `key=value` pairs; errors carry an `error=` field. +### What a log line looks like + +Every API record is one line: + +``` + msg= key=value +``` + +`LVL` is one of `DBG`, `INF`, `WRN`, `ERR` or `AUD`. `AUD` marks a +security-relevant event and is never filtered by the level setting. + +A few things worth knowing when reading them: + +- Warnings are emitted at both `warn` and `error`, so choosing Errors in + Settings still shows them. +- The startup banner is not a record. It has no timestamp and no level, and it + always prints. +- Secrets are never logged. Values that could carry one, such as the address of + a service that failed a connection test, are reduced to the host. +- Lines from supervisord and Nginx have their own shapes and are not Stackyard + records. + +The format is logfmt, so anything shipping to Loki or Grafana parses it with +`| logfmt` and no custom rules. + +To change how much is logged, see the `LOG_LEVEL` row in +[architecture.md](architecture.md#environment). ## Common problems