awesome-everything EN
↑ Обратно к восхождению

Наблюдаемость

Схема продакшн-лога: поля, которые несёт каждая строка

Суть Что содержит продакшн-grade структурная log-строка в 2026 — поля OTel Logs Data Model, resource-атрибуты, и почему схема — это API, который ожидает on-call-тулинг.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на middle-высоте — в небе
◷ 12 min

Два сервиса одной команды называют одно поле “status_code” в одном и “http_status” в другом. Каждый дашборд, который их соединяет, ломается. Фикс — не regex, а общая схема, которую проверяют до того, как код уехал в прод.

Что несёт каждая продакшн-log-строка

Продакшн-grade структурная log-строка в 2026 содержит как минимум эти поля, примерно в таком приоритете:

  1. timestamp — ISO-8601 UTC с sub-second точностью: 2026-04-12T14:02:11.482Z. Основной sort-ключ любого backend’а.
  2. level — строковый enum: TRACE / DEBUG / INFO / WARN / ERROR / FATAL. Контролирует, что хранится и кого пейджат.
  3. service.name — OTel-каноничный ключ, идентифицирующий эмиттер. Join-ключ обратно к метрикам и трейсам.
  4. trace_id и span_id — когда лог эмитится внутри traced-запроса, это join-ключи к tracing-backend’у. Без них pivot log → trace не работает.
  5. message — короткое читаемое резюме. Единственное поле, которое скимят люди; остальное — для машин.
  6. Event-specific поля — плоское key-value-дерево по OTel Semantic Conventions: http.route, http.response.status_code, db.system, error.type и т. д.
  7. Resource-атрибуты — ставятся один раз на старте: host.name, cloud.region, service.version, deployment.environment. Описывают эмиттер, не событие.
Группа полейПримерыКто ставитЧастота
Ядроtimestamp, level, messageLogger SDKКаждая строка
Идентичность сервисаservice.name, service.versionLogger SDK + конфигКаждая строка
Trace-контекстtrace_id, span_id, trace_flagsMixin активного span’аВнутри traced-запросов
Event-specifichttp.route, http.response.status_code, error.typeКод приложенияЗависит от типа события
Resourcehost.name, cloud.region, deployment.environmentПлатформа / конфигОдин раз на старте

OTel Logs Data Model

OpenTelemetry Logs specification (стабильный API конец 2023, SDK конец 2024) формализует это разделение. Log-record содержит:

  • Timestamp — когда событие фактически произошло (ставится приложением).
  • ObservedTimestamp — когда collector увидел запись. При clock-skew или backpressure они расходятся; senior-команды алертят на расхождение как pipeline-health-метрику.
  • SeverityNumber — числовая лестница (TRACE=1-4, DEBUG=5-8, INFO=9-12, WARN=13-16, ERROR=17-20, FATAL=21-24), чтобы backend мог сравнивать severity через библиотеки с разными текстовыми label.
  • Body — человекочитаемое сообщение.
  • Attributes — flat key-value-карта event-specific-данных.
  • Resource — ставится один раз на эмиттер (service.name, host.name, cloud.region).
  • TraceId / SpanId / TraceFlags — W3C traceparent-контекст, наследуемый от активного span’а на emit-time.

Принять эту форму — даже на не-OTel-backend’е — даёт forward compatibility: можно менять backend без переписывания инструментации, и каждый дашборд и on-call-runbook может говорить одним словарём полей.

OTel Semantic Conventions: одно имя поля для всех сервисов

Semantic Conventions определяют канонические имена для общих полей: http.route (не route, не path, не url), http.response.status_code (не status, не http_status), db.system (не db_type), error.type. Это значит:

  • Дашборд, запрашивающий http.response.status_code, работает одинаково для Node- и Go-сервисов.
  • Alert-правило, ссылающееся на error.type:timeout, работает без per-service конфигурации.
  • Новый сервис, принявший схему, наследует все существующие запросы.

Цена несоблюдения conventions — в incident response: когда checkout называет поле status, а payment-gateway — http_status, join-запрос ломается, и кто-то должен знать маппинг под давлением в 03:00.

Почему это работает

Схема — не бюрократия, а несущая конструкция. Каждый запрос, каждый дашборд, каждое alert-правило, каждый шаг runbook’а, ссылающийся на имя поля, предполагает, что оно стабильно и консистентно между сервисами. Дрейф схемы ломает их молча: запрос возвращает меньше результатов, алерт срабатывает только на части сервисов, шаг runbook’а требует ручного перевода. Централизация схемы в per-org wrapper-logger (один модуль, импортируемый каждым сервисом) превращает дрейф в build-time-ошибку, а не открытие в 03:00.

Цифры log-схемы
Стабильность OTel Logs API (GA)
Конец 2023
Стабильность OTel Logs SDK (большинство langs)
Конец 2024
Типовой размер структурной log-строки
~0.5–2 KB
Диапазон SeverityNumber (TRACE–FATAL)
1–24
OTLP/Logs gRPC payload, compressed
~30–50% меньше JSON
Викторина

Log-строка несёт Timestamp = 14:00:00 и ObservedTimestamp = 14:05:00. Что означает этот разрыв?

Викторина

Зачем OTel Logs Data Model определяет числовой SeverityNumber (1-24) в дополнение к текстовому SeverityText?

Расставь шаги по порядку

Расставь поля OTel Logs Data Model от наиболее фундаментальных к наиболее event-specific:

  1. 1 Timestamp — когда событие произошло
  2. 2 SeverityNumber — числовая severity (1-24)
  3. 3 Resource — per-emitter атрибуты (service.name, host.name)
  4. 4 TraceId / SpanId — W3C trace-контекст
  5. 5 Body — человекочитаемое сообщение
  6. 6 Attributes — event-specific flat key-value (http.route, error.type, ...)
Вспомните перед уходом
  1. 01
    Что такое Timestamp и ObservedTimestamp в OTel Logs Data Model, и почему важны оба?
  2. 02
    Почему нужно использовать имена полей OTel Semantic Conventions (http.route, http.response.status_code) вместо своих?
  3. 03
    Какие поля ставятся один раз при старте, а какие — на каждой log-строке?
Итог

Продакшн-схема лога в 2026 следует OTel Logs Data Model: Timestamp (время события), ObservedTimestamp (время collector’а), SeverityNumber (1-24) плюс SeverityText, Body, Resource (per-emitter: service.name, host.name, cloud.region), Attributes (event-specific: http.route, error.type) и TraceId/SpanId (W3C trace-контекст). Resource-атрибуты ставятся один раз при старте; trace-контекст тянется из активного span’а на emit-time; event-specific атрибуты пишутся в коде приложения. Использование имён полей OTel Semantic Conventions единообразно между сервисами — то, что делает кросс-сервисные запросы, дашборды и runbook’и рабочими без per-service перевода. Разрыв между Timestamp и ObservedTimestamp — сигнал здоровья pipeline’а: алертить на p99 больше 60 секунд.

Связанные уроки
встречается в268
Продолжить восхождение ↑Log levels и маршрутизация алертов
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.