Логирование ошибок

Логирование ошибок в STOMP.js начинается с понимания того, что протокол STOMP работает поверх WebSocket и формально разделяет ошибки на несколько уровней: транспортный (WebSocket), протокольный (STOMP frame), прикладной (логика обработки сообщений и брокер), а также ошибки подтверждения доставки и подписок. Каждый уровень требует отдельной стратегии фиксации событий, поскольку единый механизм отладки в STOMP.js отсутствует.

В процессе работы STOMP.js ошибки возникают не только при разрыве соединения, но и на этапе установления сессии, подписки и обработки сообщений. Наиболее характерные источники:

WebSocket-уровень

  • невозможность установить соединение с сервером
  • обрыв соединения по сети
  • закрытие соединения сервером без STOMP-уведомления
  • ошибки TLS/SSL при wss-подключении

STOMP-уровень

  • некорректный CONNECT frame
  • отказ брокера в подключении (ERROR frame)
  • нарушение формата заголовков или тела сообщения
  • некорректные команды SEND, SUBSCRIBE, ACK, NACK

Прикладной уровень

  • ошибки обработки payload в callback подписки
  • исключения в сериализации/десериализации JSON
  • логические ошибки маршрутизации сообщений

Механизмы фиксации ошибок в STOMP.js

STOMP.js предоставляет несколько точек перехвата ошибок, которые формируют основу системы логирования.

WebSocket ошибки

На уровне транспорта используется стандартный обработчик WebSocket:

  • onWebSocketError
  • onWebSocketClose

Типовая задача этих обработчиков — фиксировать события разрыва и диагностировать причины нестабильности соединения.

Особенность заключается в том, что WebSocket не всегда передаёт текстовую причину ошибки. Поэтому логирование часто ограничивается кодами закрытия соединения и временными метками.

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

  • timestamp
  • readyState WebSocket
  • close code
  • reason (если доступен)
  • попытка переподключения

STOMP ERROR frame и обработка протокольных ошибок

При успешном подключении сервер может вернуть ERROR frame, который является ключевым источником диагностической информации.

В STOMP.js это обрабатывается через:

  • client.onStompError

Содержимое ERROR frame обычно включает:

  • headers (message, version, content-type)
  • body (описание ошибки от брокера)

Логирование на этом уровне должно сохранять:

  • заголовки полностью без фильтрации
  • raw body ответа
  • идентификатор сессии
  • destination, если он присутствует в контексте

Особое значение имеет сохранение исходного frame без преобразований, поскольку брокеры (ActiveMQ, RabbitMQ, Apollo) формируют разные форматы ошибок.

Ошибки подключения (CONNECT / DISCONNECT)

Процесс установления соединения также подвержен сбоям, особенно при использовании авторизации или прокси.

Типовые проблемы:

  • неверные credentials
  • отказ брокера по политике безопасности
  • превышение лимита подключений
  • несовместимость версии STOMP

В STOMP.js логирование строится вокруг callback:

  • onConnect
  • onStompError
  • onWebSocketClose

Ключевой аспект — различие между отказом соединения на уровне WebSocket и отказом на уровне STOMP. В первом случае отсутствует STOMP frame, во втором приходит ERROR frame с деталями.

Логирование подписок и доставки сообщений

Подписки создаются через client.subscribe, и ошибки здесь часто имеют скрытый характер.

Типовые ситуации:

  • подписка создана, но сообщений нет из-за неверного destination
  • сервер отклоняет подписку без явного error frame
  • потеря сообщений при нестабильном соединении

STOMP.js не предоставляет прямого error callback для subscribe, поэтому логирование строится косвенно:

  • фиксация факта подписки (destination, headers)
  • подтверждение получения первого сообщения
  • контроль таймаута ожидания сообщений
  • логирование heartbeat активности

Ошибки обработки сообщений

Callback обработки сообщений является наиболее частым источником runtime-ошибок.

Типовой обработчик:

  • message => { ... }

Основные риски:

  • JSON.parse падает на некорректном payload
  • неожиданный формат body (binary / text)
  • исключения бизнес-логики внутри handler

Практика логирования включает:

  • сохранение raw message body
  • логирование headers (destination, message-id, subscription)
  • фиксация stack trace исключений
  • изоляция ошибок в try/catch внутри callback

Особое значение имеет разделение:

  • ошибки транспорта (STOMP/WebSocket)
  • ошибки пользовательского обработчика

ACK / NACK и ошибки подтверждения доставки

При использовании клиентского подтверждения (ack: client) появляется дополнительный класс ошибок.

Сценарии:

  • сообщение не подтверждено (ACK не отправлен)
  • отправлен NACK по причине невозможности обработки
  • дублирование сообщений при повторной доставке

Логирование должно фиксировать:

  • message-id
  • subscription-id
  • тип подтверждения (ack/nack)
  • время обработки сообщения
  • результат обработки (success/failure)

Дополнительно важно фиксировать повторную доставку одного и того же message-id, так как это напрямую влияет на идемпотентность системы.

Heartbeat и скрытые ошибки соединения

Heartbeat в STOMP используется для обнаружения “тихих” обрывов соединения.

Ошибки:

  • отсутствие heartbeat от сервера
  • несинхронные интервалы heartbeat
  • блокировка event loop на клиенте

STOMP.js фиксирует heartbeat через таймеры, но логирование требует отдельной диагностики:

  • время последнего heartbeat
  • ожидаемый интервал
  • фактическое отклонение
  • состояние соединения в момент сбоя

Такие ошибки часто не приводят к явному disconnect, но вызывают деградацию доставки сообщений.

Централизованная стратегия логирования

Эффективная система логирования в STOMP.js строится как единый pipeline:

1. Уровень транспорта

  • WebSocket open/close/error

2. Уровень протокола

  • CONNECT
  • ERROR frame
  • heartbeat events

3. Уровень сообщений

  • subscribe events
  • incoming messages
  • ack/nack

4. Уровень приложения

  • обработка payload
  • бизнес-исключения

Каждое событие должно иметь единый формат:

  • timestamp
  • type (transport / stomp / message / app)
  • sessionId
  • destination
  • payload snapshot
  • error stack (если есть)

Практика агрегации логов

При высокой нагрузке логирование без агрегации приводит к потере диагностической ценности.

Используются подходы:

  • группировка по sessionId
  • корреляция message-id
  • дедупликация повторяющихся ошибок
  • буферизация логов перед отправкой в систему мониторинга

Дополнительно важна классификация:

  • transient errors (временные)
  • permanent errors (конфигурационные)
  • protocol errors (STOMP frame issues)

Особенности логирования в распределённых системах

При использовании брокеров сообщений (RabbitMQ, ActiveMQ, Apollo) логирование STOMP.js должно учитывать, что часть ошибок генерируется сервером, а часть — промежуточной инфраструктурой.

Поэтому важно сохранять:

  • raw frames без трансформации
  • correlation-id (если проксируется)
  • destination routing path
  • server-side error metadata

Это позволяет сопоставлять клиентские логи с серверными trace-логами.

Типовые ошибки и их интерпретация

Connection refused

  • проблема сети или брокера
  • логируется на WebSocket уровне

Broker authentication failed

  • ошибка CONNECT frame
  • фиксируется через onStompError

Message not delivered

  • проблема маршрутизации или подписки
  • требует корреляции subscribe + message logs

Unexpected disconnect

  • heartbeat failure или network drop
  • анализируется через heartbeat logs и close code

Handler exception

  • ошибка приложения
  • локализуется внутри message callback

Логирование в STOMP.js представляет собой не линейный процесс, а многослойную систему наблюдения за состоянием соединения, протокола и обработки данных. Эффективная диагностика возможна только при сохранении контекста всех уровней взаимодействия и строгой корреляции событий между транспортом и прикладной логикой.