Логи, метрики и трейсы: три столпа observability

Три типа телеметрии решают разные задачи — важно не путать их и понимать, где логи незаменимы.

Observability (наблюдаемость) — способность по внешним сигналам системы понять, что происходит у неё внутри. Её три классических столпа: метрики, логи и трейсы.

Зачем различать

У нас на сайте уже есть отдельный учебник про мониторинг на Prometheus и Grafana (метрики) — и это не случайно. Логи, метрики и трейсы — разные инструменты, и попытка решать одной задачу другой приводит либо к дикому перерасходу денег, либо к тому, что нужного ответа в данных просто нет. Этот урок проводит границу, чтобы дальше мы сфокусировались именно на логах и не дублировали материал по метрикам.

Метрики: числа во времени

Метрика — это числовое значение, измеряемое регулярно: загрузка CPU, число запросов в секунду, задержка 95-го перцентиля, длина очереди. Метрики дешёвые: одно число раз в 15 секунд занимает байты. Их легко агрегировать и рисовать графиками, по ним удобно ставить алерты («CPU > 90% пять минут»).

Но метрика отвечает только на вопрос «сколько». Она скажет, что число ошибок 500 выросло в десять раз. Она не скажет, какие именно это были запросы, от каких пользователей, с каким стектрейсом. Метрика — это агрегат, в котором детали по построению потеряны.

Логи: события с деталями

Лог — это запись о конкретном событии с максимумом контекста: время, уровень, сообщение, идентификаторы, стектрейс. Если метрика говорит «ошибок стало больше», то лог говорит «вот эта конкретная ошибка: NullPointerException в OrderService.calculate(), запрос /api/checkout, пользователь 8842, в 14:32:07».

{"@timestamp":"2026-06-24T14:32:07Z","level":"ERROR","service":"billing","msg":"payment failed","order_id":8842,"reason":"gateway timeout"}

Логи дороже метрик: каждое событие — это сотни байт текста, а событий могут быть миллионы в минуту. Зато только в логах есть детали, по которым реально разбирать инцидент. ELK — это в первую очередь система для логов.

Трейсы: путь одного запроса

Трейс показывает путь одного запроса сквозь все сервисы: запрос вошёл в gateway (2 мс), сходил в auth (15 мс), затем в billing (320 мс — вот оно, узкое место), который ждал ответа от платёжного шлюза. Трейс отвечает на вопрос «где именно потратилось время и где сломалось в цепочке вызовов». Технологии тут — OpenTelemetry, Jaeger, Zipkin; Elastic тоже умеет APM-трейсы, но это отдельная большая тема.

Как работает под капотом: связь через идентификаторы

В зрелой системе три столпа не существуют отдельно, а связаны общими идентификаторами. У каждого запроса есть trace_id, который прокидывается через все сервисы и попадает и в трейс, и в каждую строку лога. Тогда сценарий расследования выглядит так:

  1. Метрика-алерт: latency checkout вырос  --> ЧТО случилось
  2. Трейс: время теряется в billing       --> ГДЕ в цепочке
  3. Логи billing по этому trace_id        --> ПОЧЕМУ (детали, стектрейс)

Метрика ловит проблему, трейс локализует её в сервисе, лог объясняет причину. Поэтому общий trace_id в логах — это не роскошь, а то, что превращает разрозненные строки в связную историю.

Стоимость каждого столпа

Различие между тремя столпами хорошо видно через их стоимость и объём данных. Метрики — самые дешёвые: одно число, снимаемое раз в несколько секунд, занимает байты, и даже тысячи метрик на сервис — это мегабайты в день. Поэтому метрики можно хранить долго и с высокой частотой. Логи на порядки дороже: каждое событие — это сотни байт текста, а нагруженный сервис порождает тысячи событий в секунду, что складывается в гигабайты и терабайты. Именно дороговизна логов заставляет нас позже так серьёзно заниматься их жизненным циклом, фильтрацией шума и сжатием. Трейсы занимают промежуточное положение, но их обычно семплируют — сохраняют не все запросы, а долю, потому что хранить трейс каждого запроса нагруженной системы тоже непомерно дорого.

Из этой экономики вытекает практическое правило проектирования наблюдаемости: дешёвыми метриками покрывают всё (каждый сервис, каждый эндпоинт) и держат их долго; дорогими логами покрывают то, где нужны детали, и агрессивно управляют их сроком жизни; трейсы включают точечно и семплируют. Команда, которая путает назначение столпов — например, пытается считать бизнес-показатели по логам или хранить детали в метках метрик, — либо разоряется на хранении, либо обнаруживает, что нужного ответа в данных нет.

Частые ошибки

  • Считать логи по событиям как метрики. Строить график «число запросов» из логов можно, но это дорого и медленно: для счётчиков есть метрики. Логи — для деталей, а не для дешёвых числовых трендов.
  • Хранить детали в метках метрик. Засунуть user_id или order_id в label метрики — классический способ устроить «взрыв кардинальности» и положить Prometheus. Высококардинальные детали — это работа логов.
  • Думать, что одного столпа достаточно. Только метрики — слепота к деталям; только логи — дорого и без быстрых трендов. Зрелая observability использует все три по назначению.

Итоги

  • Метрики отвечают «сколько» (дёшево, агрегаты, алерты), логи — «что именно и почему» (детали, стектрейсы), трейсы — «где в цепочке вызовов».
  • ELK — система для логов; метрики живут в Prometheus/Grafana (отдельный учебник), не дублируйте их в логах.
  • Общий trace_id связывает три столпа в одну историю расследования.
  • Высококардинальные детали (id пользователей, заказов) — это логи, а не метки метрик.
Проверьте себя
1. На какой вопрос отвечает лог, в отличие от метрики?
AСколько ресурсов потребляет система в среднем
BЧто именно за событие произошло и почему, с деталями и контекстом
CКакова общая загрузка CPU за сутки
DСколько запросов в секунду обрабатывает сервис
2. Что связывает логи, метрики и трейсы в единую историю расследования?
AОбщий часовой пояс
BОбщий идентификатор запроса (trace_id), прокидываемый через все сервисы
CОдинаковый формат файлов
DЕдиный сервер хранения
3. Почему не стоит хранить user_id или order_id в метках (labels) метрик Prometheus?
AЭто запрещено лицензией Prometheus
BВысокая кардинальность таких меток приводит к взрыву числа временных рядов и падению системы
CМетрики не поддерживают строковые значения
DЭто замедляет работу Grafana