Переход на JSON-логи обычно делают за день, а потом год живут с полями, которые невозможно запрашивать. Несколько правил, которые нам помогли.
Правило 1: стабильное имя, изменчивое значение
Плохо: {"user_42_action": "login"}. Хорошо:
{"event": "login", "user_id": 42}. Имя поля — часть схемы,
значение — данные. Если имя зависит от данных, индекс превращается в свалку.
Правило 2: одно событие — одна строка
Многострочные записи разваливаются при конкурентной записи в stdout.
Стек-трейс кладите в поле строкой с \n, а не отдельными строками.
logger.error({
event: 'order.create.failed',
order_id: order.id,
user_id: user.id,
reason: 'payment_declined',
provider_code: error.code,
stack: error.stack, // одной строкой, не построчно
});Правило 3: единицы измерения в имени
latency — это что, секунды или миллисекунды? Через полгода никто
не вспомнит. latency_ms вопрос снимает.
Правило 4: не логируйте то, что уже есть
Регион, ревизия, идентификатор инстанса, метод и путь добавляются платформой. Дублирование раздувает объём и расходится при рефакторинге.
Минимальная схема
{
"ts": "2026-07-18T09:14:22.108Z",
"level": "error",
"event": "order.create.failed",
"msg": "платёж отклонён провайдером",
"trace_id": "9f1c4b2ae8d34c1f",
"user_id": 8412,
"order_id": "ord_9a21",
"reason": "payment_declined",
"duration_ms": 842
}Что запрашивать потом
# все отказы платежей за сутки, сгруппированные по причине
vlone logs --since 24h \
--filter 'event == "order.create.failed"' \
--group-by reason --count
# конкретная трасса целиком, включая соседние сервисы
vlone logs --trace 9f1c4b2ae8d34c1fЧего не делать
- Не пишите персональные данные: логи хранятся дольше, чем вы думаете.
- Не логируйте тела запросов целиком — только размер и хеш.
- Не используйте
level: "info"для всего подряд: если всё важное, значит, ничего не важно.


