Structured Logging — суть, форматы данных и принцип работы в приложениях

Автор: IT Sectr Опубликовано: 2026-05-28 Время чтения: 8 мин

Structured Logging — это подход к записи логов, где каждое сообщение представлено в машиночитаемом формате с парами ключ-значение, а не в виде неструктурированного текста. В отличие от плоских строк, структурированные логи содержат метаданные: timestamp, уровень, модуль, идентификатор запроса — и могут быть проиндексированы системами анализа. По данным O'Reilly Effective Logging, переход на структурированные форматы сокращает время поиска инцидента с часов до минут за счёт возможности фильтрации по полям. Это стандарт де-факто в современной мобильной и серверной разработке: JSON и logfmt позволяют обрабатывать логи программами, а не глазами.

Главное

  • Structured Logging — представление логов в формате ключ-значение вместо плоского текста, пригодное для автоматической обработки
  • JSON — самый распространённый формат структурированных логов, поддерживается всеми современными системами сбора и анализа
  • Logfmt — компактный формат от Heroku, удобный для чтения человеком и парсинга через grep
  • ELK Stack — Elasticsearch, Logstash, Kibana — стандартная инфраструктура для хранения и визуализации структурированных логов
  • Контекст — идентификатор запроса, сессия пользователя, версия приложения — обязательные поля каждого структурированного сообщения

Что такое Structured Logging

Structured Logging — это метод записи логов, при котором каждое сообщение содержит именованные поля с типизированными значениями. Вместо строки вида User 42 logged in from device ABC структурированный лог выглядит как набор полей: user_id=42, event=login, device_id=ABC, timestamp=2026-07-04T10:30:00Z.

Основное преимущество структурированных логов перед текстовыми — возможность программной обработки. Парсинг текстовых логов требует регулярных выражений и предположений о формате строки. Структурированные логи парсятся без потерь: каждое поле имеет известный тип и имя, что позволяет строить запросы уровня найти все ошибки авторизации за последний час для пользователя 42 без дополнительной обработки.

По данным Honeycomb.io (2023), команды, использующие structured logging в production, детектируют инциденты в среднем в 4 раза быстрее по сравнению с командами, полагающимися на текстовые логи и grep.

Форматы структурированных логов

Structured Logging поддерживает несколько форматов сериализации. Выбор формата зависит от инфраструктуры: JSON удобен для интеграции с Elasticsearch и облачными системами, logfmt — для консольного просмотра через tail и grep, Protocol Buffers — для высокопроизводительных систем с ограничением по пропускной способности.

ФорматПримерКогда использовать
JSON{"event":"login","user_id":42}ELK Stack, облачные сборщики, микросервисы
Logfmtevent=login user_id=42 duration_ms=150Консоль, tail, heroku logs
MessagePackБинарный эквивалент JSONВысоконагруженные системы, IoT

JSON — универсальный формат

JSON — самый распространённый формат для структурированных логов. Он нативно поддерживается всеми системами сбора: Logstash, Fluentd, Amazon CloudWatch, Google Cloud Logging. JSON-логи легко читаются человеком и парсятся любым языком программирования без дополнительных библиотек. Основной недостаток — избыточность: каждая пара ключ-значение требует кавычек и двоеточий, что увеличивает объём хранимых данных на 30–50% по сравнению с logfmt.

Logfmt — компактный формат

Logfmt был разработан в Heroku для консольной видимости. Он компактнее JSON, сохраняет читаемость для человека и легко обрезается через cut и awk. Пример: ts=2026-07-04T10:30:00Z level=error module=api status=500. Logfmt не требует экранирования большинства символов и хорошо подходит для stdout-логирования в контейнерах.

Зачем нужен Structured Logging в мобильной разработке

В мобильных приложениях Structured Logging решает три ключевые задачи: поиск причин падений без воспроизведения на устройстве, отслеживание пользовательских сессий и анализ производительности по версиям приложения.

Текстовые логи на мобильных устройствах почти бесполезны — разработчик не может grep-нуть логи на устройстве пользователя. Структурированные логи отправляются в облачные системы (Firebase, Sentry, Datadog) и там индексируются. Можно построить запрос: показать все crash с iOS 17.4, версия приложения 3.2, в модуле checkouts — и получить точную выборку за несколько секунд.

По данным Sentry (2024), приложения, использующие structured breadcrumbs, имеют на 60% больше контекста в каждом креш-репорте по сравнению с приложениями, логирующими только текст ошибки. Это напрямую влияет на скорость фикса бага.

Инструменты для сбора и анализа

ELK Stack — Elasticsearch, Logstash, Kibana — остаётся стандартной инфраструктурой для работы со структурированными логами. Logstash принимает логи в JSON, преобразует и отправляет в Elasticsearch для индексации, Kibana предоставляет визуальный интерфейс для запросов и дашбордов.

Для мобильных приложений популярны облачные решения: Firebase Crashlytics с кастомными логами, Sentry с breadcrumbs, Datadog с APM-трекингом. Они принимают структурированные логи напрямую из мобильного SDK и не требуют развёртывания собственного бэкенда. Firebase предоставляет бесплатный пакет для краш-репортов, Sentry добавляет distributed tracing, а Datadog интегрируется с APM для отслеживания производительности запросов на клиенте и сервере одновременно.

Grafana Loki — альтернатива Elasticsearch, оптимизированная для логов. Loki не индексирует содержимое сообщений по умолчанию, а использует метки (labels) для фильтрации. Это значительно дешевле в хранении и быстрее при запросах по фиксированному набору полей.

swift
// Structured logging через Swift Logger в JSON
struct StructuredLog {
    let event: String
    let attributes: [String: Any]
    let level: String

    func serialize() -> String {
        var base = "event=\(event) level=\(level)"
        for (key, value) in attributes {
            base += " \(key)=\(value)"
        }
        return base
    }
}

Лучшие практики Structured Logging

Первое правило структурированного логирования: каждое сообщение должно содержать идентификатор запроса или сессии. Без контекста отдельный лог бесполезен — невозможно понять, к какому пользователю или какому запросу он относится. Добавляйте correlation ID на старте сессии и передавайте его через все слои приложения.

Второе правило: типизация полей. Числовые поля (duration_ms, status_code, retry_count) должны передаваться как числа, а не как строки. Elasticsearch и аналогичные системы индексируют числа и строки по-разному: к числам можно применять агрегации (среднее, медиана, перцентиль), к строкам — полнотекстовый поиск. Ложная типизация лишает возможности строить аналитические дашборды.

Третье правило: избегайте вложенных объектов. JSON-логи с глубиной вложенности более 2 уровней сложно фильтровать и визуализировать. Вместо {"user": {"name": "Alice", "role": "admin"}} используйте плоские ключи: user_name=Alice user_role=admin.

kotlin
// Structured logging на Android через Timber + logfmt
class StructuredTree : Timber.Tree() {
    override fun log(priority: Int, tag: String?,
                  message: String?, t: Throwable?) {
        val level = priorityToLevel(priority)
        val logfmt = "level=$level tag=$tag message=$message"
        sendToRemote(logfmt)
    }
}

Какие поля обязательны

Минимальный набор полей для каждого структурированного сообщения: timestamp в ISO 8601, level (debug/info/warn/error/fatal), logger (имя модуля или класса), message (человекочитаемое описание события). Дополнительно: correlation_id, user_id (если известен), version (версия приложения), platform (iOS/Android), environment (dev/staging/prod).

Без correlation_id структурированные логи превращаются в набор разрозненных записей, которые невозможно связать в один пользовательский сценарий. Генерируйте UUID при каждом запуске приложения и добавляйте его во все логи сессии. На практике correlation_id должен передаваться через все слои: от UI-событий до сетевых запросов и фоновых задач — иначе часть логов останется без контекста и не будет участвовать в аналитике. При сквозном трекинге один UUID позволяет собрать полную картину пользовательского пути.

Примеры структурированного логирования в Swift и Kotlin

На iOS структурированное логирование можно реализовать через обёртку над os_log, которая сериализует поля в формат logfmt. На Android — через Timber с кастомным Tree, который преобразует сообщения в JSON или logfmt перед отправкой на сервер.

swift
import OSLog

struct StructuredLogger {
    let subsystem: String
    let category: String

    func log(level: OSLogType,
              event: String,
              context: [String: Any]) {
        let oslogger = Logger(
            subsystem: subsystem,
            category: category
        )
        let fields = context.map {
            "\($0.key)=\($0.value)"
        }.joined(separator: " ")
        oslogger.log(level: level,
                     "\(event) \(fields)")
    }
}

Structured vs Unstructured: сравнение подходов

Выбор между структурированными и текстовыми логами зависит от стадии проекта. На ранних этапах разработки текстовые логи проще и быстрее — разработчик пишет message напрямую без дополнительных обёрток. Но как только проект выходит за пределы одной команды или одного сервера, структурированные логи становятся обязательными.

КритерийТекстовые логиСтруктурированные логи
ЧитаемостьВысокая в консолиСредняя (требует pretty-print)
Поискgrep по подстрокеЗапросы по полям и значениям
АгрегацияНе поддерживаетсяСреднее, медиана, перцентили
ИнтеграцияТребует парсингаНативная в ELK/Loki/Datadog
Объём храненияМеньше (без метаданных)Больше (поля + значения)

Часто задаваемые вопросы

Какой формат лучше для мобильного логирования?

Для отправки на сервер используйте JSON — он нативно поддерживается Firebase Crashlytics, Sentry и Datadog. Для локального просмотра в логах Xcode или Android Studio используйте logfmt — он компактнее и читается без форматирования.

Нужно ли логировать в структурированном формате на клиенте?

Да, структурированные логи на клиенте позволяют добавить контекст к каждому креш-репорту: версия ОС, состояние сети, последние действия пользователя. Без структурированных breadcrumbs креш-репорт содержит только стек вызовов без пользовательского сценария.

Чем logfmt отличается от JSON?

Logfmt компактнее (на 30–50% меньше объём) и легче читается в терминале. JSON поддерживает вложенные объекты и массивы, но требует экранирования кавычек. Выбор зависит от инфраструктуры: для ELK — JSON, для консольного просмотра — logfmt.

Как добавить correlation ID во все логи?

Создайте один экземпляр UUID при запуске приложения, сохраните его в синглтоне или DI-контейнере и передавайте во все логгеры через конструктор. Альтернатива — использовать threading-локал или Continuation Local Storage в Kotlin корутинах.

Можно ли смешивать структурированные и текстовые логи?

Можно, но не рекомендуется — при смешивании теряется возможность автоматической индексации. Если часть логов текстовые, их приходится парсить регулярными выражениями, что снижает производительность и надёжность поиска. Лучше мигрировать все логи на структурированный формат.

Итоги

  • Structured Logging — формат логов с парами ключ-значение, пригодный для автоматической индексации и запросов, в отличие от текстовых строк
  • JSON и logfmt — основные форматы: JSON универсален для систем сбора, logfmt компактен для консольного просмотра и docker-логов
  • Correlation ID — обязательное поле каждого структурированного сообщения, без него логи невозможно связать в пользовательскую сессию
  • ELK Stack и Grafana Loki — стандартные инфраструктурные решения для хранения, индексации и визуализации структурированных логов
  • Производительность — команды со structured logging детектируют инциденты в 4 раза быстрее за счёт запросов по полям вместо grep по тексту
  • Типизация — числа должны передаваться как числа, а не строки, для возможности агрегаций (среднее, медиана, перцентили) в системах аналитики

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также