Разработчик подключил сбор ошибок, обрадовался первому графику и через неделю перестал открывать панель. Уведомлений приходило по двести в день, среди них были те же самые сбои, известные проблемы сторонних библиотек и сообщения от старых версий, которые уже никого не волновали. Инструмент работал, а пользы не приносил. Проблема не в нём, а в том, что между сбором данных и решением стоит работа, которую никто не сделал.
Наблюдаемость описывает способность понять состояние системы
Разговоры о мониторинге упираются в путаницу терминов. Сбор данных и понимание происходящего это разные вещи.
Наблюдаемость в теории управления означает, насколько хорошо состояние системы определяется по её выходам. В программной инженерии смысл похож: это способность понять, что происходит внутри, по данным, которые система производит.
Практическое различие формулируется просто. Мониторинг отвечает на заранее известные вопросы: работает ли служба, сколько запросов в секунду, не превышена ли задержка. Наблюдаемость позволяет отвечать на вопросы, которых заранее не было: почему у части пользователей из одного региона выросло время ответа именно в эти часы.
Из этого следует важный вывод. Панель с десятком графиков это мониторинг. Наблюдаемость появляется тогда, когда к цифрам можно задать произвольный вопрос и получить ответ без правки кода.
Четыре вида данных образуют основу. Метрики это числовые показатели во времени. Журналы это записи о событиях. Трассировки связывают операции в цепочку. Профили показывают, где тратится время внутри процесса.
Сбор ошибок начинается с правильной группировки
Первое, что превращает поток сообщений в полезный инструмент, это объединение одинаковых сбоев.
Без группировки одинаковые ошибки, вызванные одним дефектом, приходят тысячами записей. С группировкой они превращаются в одну проблему с указанием числа случаев.
Основа группировки это отпечаток. Он строится из типа ошибки, места возникновения и так называемого стабильного фрагмента стека, то есть части вызовов без номеров строк и случайных значений.
import hashlib
import re
def fingerprint(error):
frames = []
for frame in error.get("stack", [])[:5]:
module = re.sub(r"\d+", "N", frame.get("module", ""))
function = frame.get("function", "")
frames.append(module + ":" + function)
raw = "|".join([error.get("type", "Error"), *frames])
return hashlib.sha1(raw.encode("utf-8")).hexdigest()[:16]
Второй приём это определение причины. Если сбой вызван известной проблемой во внешней библиотеке, такую группу стоит помечать отдельно и исключать из оповещений.
Третий приём это привязка к версии. Ошибка, которая перестала появляться в новой версии, не требует внимания. Привязка к релизу позволяет отсеять устаревшие проблемы автоматически.
Четвёртый приём это учёт окружения. Сбои на локальных машинах разработчиков и на рабочем контуре смешивать нельзя, иначе статистика теряет смысл.
Приоритеты расставляются по частоте, охвату и влиянию
Второй шаг это понимание, что исправлять первым. Здесь помогает простая оценка по трём величинам.
Первая величина это частота. Сколько раз сбой произошёл за период. Здесь важна не общая цифра, а темп: растёт, падает, держится на месте.
Вторая величина это число затронутых пользователей. Один человек, столкнувшийся с ошибкой сто раз, это не то же самое, что сто человек, столкнувшихся по разу.
Третья величина это влияние на главный сценарий. Ошибка при оформлении заказа важнее ошибки при открытии страницы с редко используемой настройкой.
def priority(issue):
frequency = min(issue["events"] / 100, 1.0)
reach = min(issue["users"] / 50, 1.0)
critical = 1.0 if issue["affects_checkout"] else 0.4
score = frequency * 0.3 + reach * 0.3 + critical * 0.4
return round(score * 100, 1)
queue = [
{"events": 400, "users": 30, "affects_checkout": False},
{"events": 40, "users": 40, "affects_checkout": True},
]
print([priority(issue) for issue in queue])
На этом примере видно, как редкая ошибка обгоняет частую. Сорок случаев у сорока разных людей в главном сценарии важнее четырёхсот случаев у тридцати человек в настройках.
Второй приём это пороги. Разные сценарии имеют разные допустимые уровни. Ошибка оплаты недопустима ни в каком количестве, ошибка загрузки аватара может подождать неделю.
Третий приём это отслеживание регрессий. Если проблема, закрытая месяц назад, снова появилась, это отдельный сигнал. Автоматическая проверка по отпечатку ловит такие случаи.
Оповещения настраиваются только на то, что требует действия
Третий шаг самый важный для того, чтобы инструмент не забросили. Оповещение должно означать, что кто-то обязан встать и что-то сделать.
Первое правило это оповещать о новом, а не о каждом. Первое появление проблемы заслуживает внимания. Дальнейшие повторы это уже статистика.
Второе правило это ограничивать частоту. Уведомление о проблеме приходит один раз, а не каждые пять минут. Повтор допустим, если ситуация ухудшилась.
Третье правило это настраивать пороги по критичности. Ошибка в оформлении заказа будит ночью. Рост числа предупреждений в журнале ждёт утра.
Четвёртое правило это разделять каналы. Срочное идёт в один канал, требующий немедленной реакции, остальное в другой, для планового разбора.
Пятое правило это проверять состав. Раз в месяц стоит просмотреть, какие оповещения срабатывали, и убрать те, на которые никто не реагировал.
const RULES = [
{ match: /checkout|payment/i, channel: "oncall", threshold: 1 },
{ match: /телефон/i, channel: "analytics", threshold: 1 },
{ match: /.*/, channel: "digest", threshold: 50 },
];
function route(issue) {
const hit = RULES.find((rule) => rule.match.test(issue.title));
return hit || RULES[RULES.length - 1];
}
Такая таблица заменяет десяток ручных настроек и делает поведение предсказуемым. Новый сотрудник смотрит на список и понимает правила.
Контекст в отчёте об ошибке определяет скорость разбора
Четвёртый шаг это сбор достаточного контекста. Отчёт без подробностей требует воспроизведения, а воспроизведение занимает часы.
Первое, что нужно приложить, это сведения о пользователе. Не имя и адрес, а идентификатор и признак авторизации. Персональные данные в отчётах об ошибках не нужны и создают риск.
Второе это сведения об окружении. Версия приложения, браузер, операционная система, тип устройства. Без этого невозможно понять, повторяется ли проблема у всех.
Третье это действия до сбоя. Цепочка шагов, приведшая к ошибке. Автоматический сбор последних действий удобнее ручных пометок.
Четвёртое это состояние данных. Какие параметры были в запросе, какой ответ пришёл, сколько времени заняла операция.
Пятое это скриншот или запись сессии. Для интерфейсных сбоев это часто единственный способ понять, что видел человек, не запрашивая у него подробности.
function buildContext(event) {
return {
release: event.release,
page: location.pathname,
viewport: window.innerWidth + "x" + window.innerHeight,
online: navigator.onLine,
lastActions: actionBuffer.slice(-5),
requestId: event.requestId,
};
}
Скриншот стоит делать с осторожностью. На нём может оказаться чужая личная информация. Маскирование полей ввода и удаление чувствительных блоков обязательны.
Приватность и объём данных требуют осознанных ограничений
Пятый шаг это ограничения. Инструмент легко превращается в хранилище лишних сведений.
Первое ограничение это персональные данные. Почта, телефон, адрес, номер карты не должны попадать в отчёты. Фильтрация выполняется до отправки.
Второе ограничение это срок хранения. Данные об ошибках нужны месяцами, а не годами. Старые записи удаляются автоматически.
Третье ограничение это объём. Сбор всех событий без исключения приводит к росту расходов и замедлению интерфейса. Часть событий отбрасывается на стороне клиента.
Четвёртое ограничение это доступ. Отчёты содержат сведения о внутреннем устройстве системы. Круг людей с доступом стоит ограничить.
Пятое ограничение это согласие. Требования к обработке данных различаются по странам, и это учитывается при настройке.
Замыкание цикла отличает рабочий процесс от красивой панели
Шестой шаг это связь между ошибкой и её исправлением. Именно здесь инструмент превращается в рабочий процесс.
Первое звено это создание задачи. Из отчёта формируется обращение в системе учёта с ссылкой на группу ошибок.
Второе звено это привязка к выпуску. Обращение связывается с версией, в которой исправление попадёт к людям.
Третье звено это проверка. После выпуска отслеживается, исчезли ли новые случаи. Автоматическое закрытие проблемы при отсутствии новых событий экономит время.
Четвёртое звено это анализ после разбора. Почему ошибка не была поймана тестами, что стоит изменить в проверках. Запись вывода предотвращает повторение.
Пятое звено это метрика. Доля проблем, разобранных за неделю, показывает, работает ли процесс.
def close_if_resolved(issue, releases):
if issue["status"] != "исправление выпущено":
return issue
last_seen = issue.get("last_seen_version")
if last_seen and releases.index(last_seen) < releases.index(issue["fixed_in"]):
issue["status"] = "закрыто"
issue["resolved_at"] = issue.get("checked_at")
return issue
Шестое звено это итог месяца. Число разобранных проблем, время до первого ответа, число повторных появлений. Эти цифры показывают состояние работы без иллюзий.
Сравнение двух подходов к разбору показывает разницу в скорости
Полезно сопоставить, как проходит разбор одной проблемы в двух командах.
Первая команда собирает всё. Панель пестрит событиями, оповещения приходят на каждый случай, задачи создаются вручную из самых громких. Разбор начинается с поиска: какая из сотни групп соответствует жалобе. На это уходит час, потом выясняется, что проблема известна и помечена как незначительная.
Вторая команда настроила группировку, пороги и маршрутизацию. Событие попадает в нужную группу автоматически, из группы создаётся задача, к ней приложены версия, окружение и цепочка действий. Разбор начинается сразу с причины. Время от жалобы до понимания проблемы сокращается в разы.
Разница не в инструменте. Обе команды пользуются одинаковыми возможностями. Разница в объёме работы, проделанной до того, как случился первый сбой.
Посчитаем трудозатраты. Настройка группировки, порогов и маршрутизации занимает два-три дня. Экономия на каждом разборе это час-два. При десяти проблемах в месяц настройка окупается в первый же месяц, а дальше начинает экономить время постоянно.
Ошибки внедрения обходятся дороже, чем отсутствие инструмента
Разберём частые провалы, чтобы не повторять их.
Первая ошибка это оповещение о каждой ошибке. Люди быстро перестают реагировать на поток, и настоящая проблема тонет среди известных.
Вторая ошибка это отсутствие версии в отчёте. Без неё невозможно понять, исправлено ли уже, и приходится проверять вручную.
Третья ошибка это сбор персональных данных. Через месяц выясняется, что в отчётах лежат адреса и телефоны клиентов, а это уже нарушение, а не небрежность.
Четвёртая ошибка это отсутствие владельца. Проблемы копятся, потому что непонятно, кто отвечает за разбор конкретной области.
Пятая ошибка это игнорирование ложных срабатываний. Если половина оповещений оказывается пустыми, доверие к инструменту падает и его перестают замечать.
Шестая ошибка это бесконечное хранение. Объём растёт, стоимость тоже, а старые данные всё равно никто не открывает.
Порядок внедрения занимает неделю и даёт результат сразу
Работу стоит вести по шагам, начиная с самого простого.
Первый шаг это сбор данных с минимальным набором полей: тип ошибки, стек, версия, идентификатор пользователя без личных сведений.
Второй шаг это группировка и проверка, что одинаковые сбои объединяются в одну группу.
Третий шаг это приоритеты. Настраивается оценка по частоте, охвату и влиянию на главные сценарии.
Четвёртый шаг это оповещения. Сначала только на критичное, остальное в ежедневную сводку.
Пятый шаг это контекст. Добавляются окружение, цепочка действий и сведения о запросе.
Шестой шаг это связь с задачами. Из группы ошибок создаётся обращение в системе учёта.
Седьмой шаг это проверка результата. Через месяц считаются разобранные проблемы и время до первого ответа.
Такой порядок занимает неделю и не требует сложных решений. Главное в нём то, что каждый шаг приносит пользу отдельно, и останавливаться можно на любом.
Мониторинг ошибок получился инструментом, который сам по себе не решает ничего. Он собирает данные и показывает картину. Польза появляется на следующих шагах: отсеять шум, расставить приоритеты, настроить осмысленные оповещения, собрать контекст и довести каждую проблему до исправления и проверки. Пропуск любого звена превращает панель в красивую картинку, которую через месяц перестают открывать.