Логи SMS-отправок: что хранить для поддержки и диагностики

Логи SMS-отправок должны отвечать на простой вопрос поддержки: что произошло с конкретным уведомлением от момента бизнес-события до финального статуса. Для этого недостаточно строки «API вернул 200». Нужна связанная история запроса, очереди, ответа провайдера, повторов и DLR — но без OTP, API-ключей и лишних персональных данных.
Хороший журнал помогает найти системную проблему и разобрать единичное обращение клиента. Плохой либо ничего не объясняет, либо сам становится утечкой: в нём лежат полные номера, тексты, коды входа и секреты интеграции.
Какие идентификаторы связывают цепочку
У одного сообщения обычно несколько идентификаторов. Каждый отвечает за свой уровень:
event_id— бизнес-событие, например изменение статуса заказа;idempotency_key— одна логическая операция отправки;attempt_id— конкретная техническая попытка вызова API;message_id— идентификатор, который вернул SMS-провайдер;delivery_id— конкретное событие webhook;correlation_idилиtrace_id— сквозной поиск по сервисам.
Не пытайтесь заменить их одним случайным UUID. Поддержке важно видеть, что три HTTP-попытки относятся к одному сообщению, а пять webhook-событий — к его жизненному циклу. Правила повторов и ключей разобраны в статьях про идемпотентность и webhook статусов.
Минимальная запись отправки
Для каждого этапа фиксируйте время, имя сервиса, тип события, результат и идентификаторы. У исходной отправки полезны:
- сценарий и версия шаблона;
- тип трафика и приоритет;
- маскированный получатель или внутренний customer ID;
- Sender ID и маршрут;
- число сегментов;
- idempotency key;
- код ответа API и message ID;
- длительность запроса;
- номер попытки и причина повтора.
Для DLR добавляют исходный код провайдера, нормализованный статус, время события у провайдера, время приёма и задержку. Если код неизвестен, это должно быть отдельным значением, а не молчаливым успехом.
Что нельзя писать в лог
Не сохраняйте API-ключи, токены авторизации, пароли, секреты подписи webhook и OTP. Полный текст сообщения тоже редко нужен для технической диагностики. Вместо него храните ID и версию шаблона, длину, кодировку и контрольную сумму, если необходимо доказать совпадение.
Номер телефона — персональные данные. Для обычного поиска достаточно маски вроде +7<strong><em></strong></em>1234, внутреннего ID клиента либо стойкого псевдонима. Если бизнесу действительно нужен поиск по полному номеру, доступ к такому индексу отделяют от общего журнала, ограничивают ролями и аудируют.
OWASP рекомендует удалять, маскировать, хешировать или шифровать access tokens, секреты и чувствительные персональные данные, а также защищать журнал от подмены и несанкционированного доступа (Logging Cheat Sheet).
Структурированный формат
Строка свободного текста удобна при разработке, но плохо подходит для поиска и метрик. Лучше писать структурированное событие с постоянными полями:
{
"event": "sms.api.response",
"correlation_id": "c-...",
"idempotency_key": "order-...",
"attempt": 2,
"provider": "route-a",
"http_status": 202,
"message_id": "m-...",
"duration_ms": 438,
"recipient_masked": "+7******1234"
}Названия полей и значений должны быть едиными во всех сервисах. Если один компонент пишет success, второй ok, а третий DELIVRD, общая аналитика быстро превращается в ручную работу.
Уровни логирования
Обычный успешный этап можно писать как info. Временная ошибка, которая будет повторена, — warning. Исчерпание попыток, нарушение подписи webhook или невозможность сохранить статус — error. Уровень не должен зависеть только от HTTP-кода: 404 при поиске необязательного ресурса и 404 исходного сообщения для DLR имеют разный смысл.
Не используйте debug как постоянный способ получить нужную бизнес-информацию. Базовый production-уровень должен позволять расследовать инцидент без включения полного тела запросов. Временный расширенный режим ограничивают по времени, компоненту и доступу.
Срок хранения и доступ
Срок журнала определяется задачами поддержки, договорами и правилами обработки данных. «Хранить всё навсегда» — плохая политика. Для разных слоёв могут действовать разные сроки: агрегированные метрики живут дольше, чем события с техническими идентификаторами, а временные debug-логи — меньше всего.
Зафиксируйте владельца данных, роли чтения, порядок выгрузки и удаления. Доступ сотрудников к журналам тоже логируйте. Резервные копии должны учитывать тот же жизненный цикл, иначе удалённые из основной системы данные останутся в архиве без понятного срока.
NIST определяет log management как процесс создания, передачи, хранения, доступа и удаления лог-данных и рекомендует планировать роли и политику на уровне организации (проект NIST Log Management).
Метрики поверх логов
Логи нужны для единичных расследований, метрики — для раннего обнаружения системной проблемы. Из событий SMS удобно строить:
- долю запросов, принятых с первой попытки;
- частоту таймаутов, 429 и 5xx;
- задержку API и полную задержку доставки;
- долю доставленных и финальных ошибок по маршрутам;
- возраст очереди и количество просроченных задач;
- неизвестные коды DLR;
- конфликты ключей и предотвращённые дубли;
- расходы по сценарию и число сегментов.
Не подставляйте в метрики номер телефона или message ID как label: высокая кардинальность перегрузит систему мониторинга. Такие значения остаются в журнале и открываются по ссылке из агрегированного графика.
Как работает поддержка
У сотрудника должен быть безопасный поисковый вход: ID заказа, внутренний ID клиента, маскированный номер плюс интервал времени или message ID. Результат показывает временную шкалу человеческим языком: событие создано, задача принята, запрос повторён после таймаута, провайдер вернул ID, получен финальный статус.
Текст ошибки провайдера дополняют внутренней категорией и подсказкой. «UNDELIV 34» мало помогает первой линии, а «номер недоступен, повтор не планируется; исходный код 34» уже позволяет ответить клиенту и передать технические детали второй линии.
Проверка журнала
Возьмите тестовое сообщение и попробуйте восстановить его путь, не обращаясь к базе вручную. Затем проверьте, что поиск не показывает полный OTP, ключ API и открытый номер сотруднику без соответствующей роли.
Смоделируйте повтор запроса и дублирующий DLR. В журнале должны появиться две технические попытки и один бизнес-результат. Удалите или измените запись в тестовой среде и убедитесь, что защита целостности либо аудит доступа позволяет это заметить.
Полезно регулярно проводить выборочную сверку: взять несколько записей из CRM, найти соответствующие события в очереди и журнале провайдера, затем сравнить время и итоговый статус. Такая проверка выявляет разрывы корреляции и ошибки нормализации, которые ещё не привели к заметному инциденту.
Итог
Полезные логи SMS — это сквозная, структурированная и безопасная история. Они связывают бизнес-событие, очередь, попытки API, message ID и статусы доставки, но не превращаются в склад секретов и персональных данных. Такой журнал сокращает время ответа клиенту, даёт основу метрикам и позволяет разбирать сбой по фактам, а не по догадкам.