fluent-logging — unified logging standard
Invariant: every project ships logs to Graylog via xakki/fluent-log.
Containers write structured JSON to stdout/stderr (or an NDJSON file) →
Docker fluentd driver → fluent-bit (GELF) → Graylog. fluent-bit metrics → Prometheus.
- Lib: https://github.com/Xakki/FluentLog (
xakki/fluent-log).
- Log rules themselves (levels / fields / what not to log) — rules.md
(digest of LaraLog
docs/LoggingRules.ru.md, language-agnostic).
Happy-path (any stack)
- Lib. PHP/composer:
composer require xakki/fluent-log. Otherwise — git submodule
docker/vendor/fluent-log (as a whole dir).
- Overlay
docker/fluent-logging.yml: include: the lib's docker-fluent.yml +
COPY the x-logging anchor (anchors don't cross include) + <<: *_logging +
labels:{tier,log_format} + depends_on: fluent-bit on your services.
.env: activate via COMPOSE_FILE; set COMPOSE_PROJECT_NAME
(required — otherwise a name with a leading dash!), EXT_FLUENT_*, GRAYLOG_*,
HOST_NAME/IP, TZ.
- Makefile:
HOST_IP from hostname -I, log-test target (see new-project-docker).
- Verify end-to-end → find in Graylog by
docker_project:<name> (source =
host IP, shared; distinguish by docker_project/docker_service).
Steps 2–5 in full (overlay snippet, env table, fluent-bit ports, search, verification
order, log_format→parsers routing) — integration.md.
Per-stack
- Laravel:
composer require xakki/laralog (structured Monolog) + log_format:"php".
- Python: one JSON line per record to stdout (
json_default fluent-bit unpacks it;
log_format can be left unset → gl.auto). Formatter + redaction filter —
python.md. Reference: <project>/app/logging_setup.py.
- Node/other: same principle — structured JSON to stdout, secrets redacted.
CRITICAL safety
- NEVER log secrets/PII (tokens, passwords, keys, sessions, full
request/response body, email in plaintext). Redact before emit (ban-list
filter). Common leak — httpx/SDK log a URL with the token in the path.
- Logging never fails the request — best-effort (
fluentd-async: true): Graylog/socket
unavailable → request completes normally.
- Log once, at the boundary; values go in
context fields (snake_case,
typed), NOT interpolated into message.
- Host paths for file-tail (
MYSQL_SLOWLOG_PATH/JSON_LOG_PATH) — ABSOLUTE only
(a relative one silently binds an empty/wrong dir; details — integration.md).
COMPOSE_FILE in .env changes ALL docker compose commands (auto-merges the overlay).
- Switching a service to the fluentd driver = container recreation (DB — during a
maintenance window; the app pool must survive, Python
pool_pre_ping=True).
Details on demand: integration.md, rules.md, python.md.
1---2name: fluent-logging3description: Cross-project logging standard using xakki/fluent-log, Fluent Bit, and Graylog GELF; containers emit structured JSON to stdout or stderr. Use for logging setup, Docker logging, Fluent Bit, Graylog, log location, level or format, secret redaction, Laravel, or Python JSON-to-stdout logging.4---56# fluent-logging — unified logging standard78**Invariant: every project ships logs to Graylog via `xakki/fluent-log`.**9Containers write **structured JSON** to stdout/stderr (or an NDJSON file) →10Docker fluentd driver → `fluent-bit` (GELF) → Graylog. fluent-bit metrics → Prometheus.1112- Lib: <https://github.com/Xakki/FluentLog> (`xakki/fluent-log`).13- Log rules themselves (levels / fields / what not to log) — [rules.md](rules.md)14 (digest of LaraLog `docs/LoggingRules.ru.md`, language-agnostic).1516## Happy-path (any stack)171. **Lib.** PHP/composer: `composer require xakki/fluent-log`. Otherwise — git submodule18 `docker/vendor/fluent-log` (as a whole dir).192. **Overlay `docker/fluent-logging.yml`:** `include:` the lib's `docker-fluent.yml` +20 COPY the `x-logging` anchor (anchors don't cross `include`) + `<<: *_logging` +21 `labels:{tier,log_format}` + `depends_on: fluent-bit` on your services.223. **`.env`:** activate via `COMPOSE_FILE`; set `COMPOSE_PROJECT_NAME`23 (required — otherwise a name with a leading dash!), `EXT_FLUENT_*`, `GRAYLOG_*`,24 `HOST_NAME/IP`, `TZ`.254. **Makefile:** `HOST_IP` from `hostname -I`, `log-test` target (see `new-project-docker`).265. **Verify end-to-end** → find in Graylog by `docker_project:<name>` (`source` =27 host IP, shared; distinguish by `docker_project`/`docker_service`).2829Steps 2–5 in full (overlay snippet, env table, fluent-bit ports, search, verification30order, `log_format`→parsers routing) — [integration.md](integration.md).3132## Per-stack33- **Laravel:** `composer require xakki/laralog` (structured Monolog) + `log_format:"php"`.34- **Python:** one JSON line per record to stdout (`json_default` fluent-bit unpacks it;35 `log_format` can be left unset → `gl.auto`). Formatter + redaction filter —36 [python.md](python.md). Reference: `<project>/app/logging_setup.py`.37- **Node/other:** same principle — structured JSON to stdout, secrets redacted.3839## CRITICAL safety40- **NEVER log secrets/PII** (tokens, passwords, keys, sessions, full41 request/response body, email in plaintext). Redact **before** emit (ban-list42 filter). Common leak — httpx/SDK log a URL with the token in the path.43- **Logging never fails the request** — best-effort (`fluentd-async: true`): Graylog/socket44 unavailable → request completes normally.45- **Log once, at the boundary**; values go in `context` fields (snake_case,46 typed), NOT interpolated into `message`.47- **Host paths for file-tail (`MYSQL_SLOWLOG_PATH`/`JSON_LOG_PATH`) — ABSOLUTE only**48 (a relative one silently binds an empty/wrong dir; details — [integration.md](integration.md)).49- `COMPOSE_FILE` in `.env` changes ALL `docker compose` commands (auto-merges the overlay).50- Switching a service to the fluentd driver = container recreation (DB — during a51 maintenance window; the app pool must survive, Python `pool_pre_ping=True`).5253Details on demand: [integration.md](integration.md), [rules.md](rules.md), [python.md](python.md).