pino-logging
Модульная Pino-архитектура для Node.js / Fastify / Next.js: один root logger в infrastructure/logging, child loggers, redaction, requestId, event-поля, JSON в stdout. Use когда внедряешь, аудируешь ил
Files4
View on GitHubSKILL.mdskills/pino-logging/SKILL.md
GitHubНавык: Modular Pino Logging
Канон архитектуры — references/architecture.md. Этот файл — операционный контракт: как аудировать, покрывать и обновлять логирование.
Когда применять
- В проекте нет единого Pino logger или каждый модуль создаёт свой
pino(). - Нужно покрыть модуль/воркер/route handler структурными логами.
- Нужно привести существующие
console.log/ interpolated strings / дубли ошибок к стандарту. - Fastify, Next.js App Router, queues, cron, workers, Docker/Render/ECS/K8s.
Не использовать для try/catch-границ — это роль resilience и скилл error-handling.
Обязательные правила
- Один root Pino logger в
src/infrastructure/logging(илиsrc/shared/logging). Неmodules/logger/. - Pino — часть приложения. Collector/agent забирает stdout JSON. Не слать каждый лог HTTP в Loki/SigNoz.
- Модули не вызывают
pino(). ТолькоcreateModuleLogger(module, component)илиrequest.log.child(...). - Business log:
{ event, ...ids }, сообщение без интерполяции id. - HTTP:
requestIdна каждом запросе; дальшеrequest.log→RequestContext.logger. - Ошибку передавать как
{ err }, неerr.message. - Логировать один раз — на слое, который обрабатывает ошибку. Проброс без лога.
- Никогда не логировать secrets/PII/полный
req.body. Root logger обязан иметьredact. - Development:
pino-pretty. Production: JSON в stdout, без pretty transport. - Database query на
infoне писать; slow/retry/failure —warn/error+durationMs. - Next.js: только server-side +
import 'server-only'. Client Components и Edge — нельзя. - Audit trail ≠ application log. Критический audit пишется в БД, Pino его только дублирует.
Сканер
Перед правками и после них запусти zero-dependency scanner:
node <skill-root>/scripts/scan.mjs --root <project> --format json
Хук (один изменённый файл, fail-open):
node <skill-root>/scripts/scan.mjs --hook
Правила сканера (stable IDs):
| ID | Что ловит |
|---|---|
pino.local-instance |
pino() вне infrastructure/logging или shared/logging |
pino.console-log |
console.log/info/debug/warn/error в production-пути |
pino.interpolated-message |
log.info(`User ${id}`) вместо structured fields |
pino.error-as-message |
log.error(err.message) вместо { err } |
pino.secret-field |
password/token/authorization/apiKey/cookie/card в payload |
pino.request-body |
req.body / req.headers / полный user object в логе |
pino.missing-redact |
root pino({...}) без redact |
pino.pretty-unconditional |
pino-pretty без NODE_ENV === 'development' |
pino.direct-collector |
pino-loki / Loki push URL / SigNoz ingest из приложения |
pino.client-import |
import pino в 'use client' файле |
Каждый finding: file:line, rule ID, severity, evidence. Сканер — кандидаты; контекст читаешь сам.
Режимы работы
audit (read-only)
- Найди текущий logger:
pino(,createLogger,infrastructure/logging,shared/logging. - Запусти scanner.
- Прочитай root logger, Fastify/Next bootstrap, 2–3 модуля и один worker.
- Подтверди или сними каждый finding. Не чини код.
- Отчёт: gaps по правилам 1–12, где должен жить logger, какие модули покрыть первыми.
cover (новый модуль / зелёное поле)
- Если root logger нет — создай пакет
infrastructure/loggingпо architecture.md (§3–8, §27). - Подключи Fastify
loggerInstanceили Next server-only child logger. - В модуле:
createModuleLogger('debtors', 'DebtorService')илиrequest.log.child. - HTTP-операции — через
RequestContext; jobs — child от root сjobId/queue. - Не добавляй AsyncLocalStorage без доказанной боли от проброса
ctx.
update (легаси)
- Сначала audit. Не переписывай работающий logger ради красоты.
- Сведи все
pino()к одному root. Замениconsole.*в production-пути. - Вынеси redaction в root. Убери прямые Loki/HTTP sinks.
- Замени interpolated strings на
{ event, id }. - Сними дубли ошибок по слоям. Global handler логирует необработанное один раз.
- Поведение бизнеса не меняй: прогони затронутые тесты. Покажи образец JSON без секретов.
Целевые файлы пакета
src/infrastructure/logging/
logger.ts
logger.config.ts
logger.types.ts
logger.factory.ts
logger.redaction.ts
logger.serializers.ts
request-context.ts
index.ts
Один export на файл. Типы явные, без any. Имена полей — camelCase: requestId, traceId, durationMs, event.
Event naming
entity.action: debtor.updated, payment.failed, email.sent, automation.job.started, http.request.completed, http.request.failed.
Проверка готовности
- Scanner по затронутому дереву: либо 0 confirmed findings, либо явный список оставленных с причиной.
- Root logger:
redact+ JSON в production. - Модуль не импортирует
pinoнапрямую. - HTTP-путь сохраняет
requestId. - Тесты зелёные;
LOG_LEVEL=silentдопустим в unit tests. - Не добавлен unit test вида
expect(logger.info).toHaveBeenCalled()без security/fatal повода.
Связанные роли
logging— владелец архитектуры и правок логов.resilience— try/catch, typed errors, retries. Точечные логи на границе ошибки может править, Pino-пакет — нет.security— secrets/PII audit; не чинит logger.devops— collector/Fluent Bit/OTel agent, не код приложения.