Проблема полевой заметки о 502 — не в нехватке терминов. Ошибка появляется, когда в неё заносят только внешний статус и сразу называют его причиной: «упал API». Цена такой записи практическая: следующий инженер ищет неисправность в приложении, хотя шлюз мог не установить соединение, или чинит upstream, хотя приложение уже вернуло понятный отказ. Без цепочки событий полевой разбор превращается в пересказ экрана.
Для одного запроса нужны как минимум две записи: access на границе и application в сервисе. Их соединяют request-id или traceparent, а не только время и путь. В каждой записи должны быть timestamp, route, status и длительность; в application log — операция и безопасное описание ошибки. Если второй записи нет, это не повод заполнить пропуск догадкой. Это отдельная ветка: отказ произошёл до приложения или запись потерялась.
Начинаем с внешней границы
RFC 9110 описывает 502 как ситуацию, в которой gateway или proxy получил недействительный ответ от upstream. Для полевой диагностики важен субъект статуса: где именно его увидел клиент. Access log gateway даёт внешний результат, но не раскрывает, был ли запрос принят приложением. Поэтому первой строкой карточки пишем узел и роль: edge.status=502, а не общее «сервер 502».
Затем ищем application event с тем же идентификатором в небольшом окне. Совпадение найдено — проверяем, что время и route согласуются, а статус приложения объясняет внешний ответ. Совпадения нет — проверяем timeout, фильтр коллектора, другой формат id и потерю записи. Такой разбор занимает меньше времени, чем просмотр всего журнала, потому что каждая проверка меняет одну гипотезу.
| Наблюдение | Следующая проверка | Рабочий вывод | Нельзя писать |
|---|---|---|---|
| 502 в edge, application не найден | timeout, collector, формат id | цепочка разорвана до подтверждения слоя | «приложение упало» |
| 502 в edge, app 500 с тем же id | статус и время app | ошибка дошла до приложения | что найден root cause |
| 502 в edge, app 200 | retry, cache, proxy mapping | границы преобразуют результат | что app ответил клиенту 200 |
| access не содержит id | конфигурация structured fields | ключ корреляции неполон | соединять по ближайшему времени |
Учебный сборщик цепочки
Функция ниже принимает два локальных массива и возвращает отдельную карточку на каждый request-id. Входы специально похожи на structured log, но не являются выгрузкой системы. Ожидаемый результат различает «gateway отказал до приложения», «ошибка приложения дошла до клиента» и обычное завершение. Это конкретная операционная техника: она показывает, какие поля нужны для первого прохода и как не потерять разрыв.
import { buildRequestTimeline } from './upgrade-2027-01.mjs';
const edge = [
{ requestId: 'r-1', at: '12:00:01.100', status: 502, message: 'upstream timeout' },
{ requestId: 'r-2', at: '12:00:02.100', status: 502, message: 'bad response' },
];
const app = [
{ requestId: 'r-2', at: '12:00:02.080', status: 500, message: 'db unavailable' },
];
console.log(buildRequestTimeline(edge, app).map(({ requestId, result }) => ({ requestId, result })));
// r-1: gateway-failed-before-app; r-2: app-error-reached-clientДля r-1 нет application event, поэтому функция не называет базу или приложение виновником. Для r-2 есть согласованная запись, но вывод всё ещё ограничен: ошибка приложения достигла внешнего ответа, а почему база недоступна — отдельный вопрос. В реальном коде добавьте проверку схемы, исключите секреты и сохраните raw-поля рядом с нормализованными.
Как читать время и повтор
Время в разных сервисах может иметь разную точность и сдвиг. Если access и application разделены десятками миллисекунд, это повод сверить clock sync и точку записи, а не автоматически отвергнуть связь. Повторный запрос тоже не обязан повторить тот же маршрут: gateway может выбрать другой upstream, а retry — создать новый идентификатор. В карточке держите request-id каждого повтора отдельно.
RFC 5424 полезен здесь не как готовая схема конкретного приложения, а как напоминание о структурированных полях и разделении источника, времени и сообщения. Поле message удобно читать человеку, но для соединения нужен отдельный ключ. Чем больше решений принимается по свободному тексту, тем выше стоимость следующего разбора.
Действия по порядку
- Скопировать из edge только одну попытку запроса: timestamp, route, method, status, duration и request-id.
- Найти application events по точному id и ограниченному временному окну; сохранить число найденных записей.
- Сопоставить status, route и длительность, затем отметить разрыв, retry или преобразование на proxy.
- Проверить зависимость только после подтверждения, что приложение действительно получило запрос.
- Сформулировать итог как наблюдение и следующий тест: например, «нет app записи; проверить timeout и collector», а не как окончательный root cause.
Ограничения и следующий шаг
Журнал может быть неполным из-за sampling, сбоя коллектора, буферизации или редактирования чувствительных полей. Один request-id может встретиться в retry, если система повторно использует контекст; это надо проверить по span-id и attempt. Нельзя публиковать токены, email, тело формы и сырые заголовки. Для юридически чувствительных систем храните безопасный fingerprint и ссылку на закрытый источник.
Следующий шаг — добавить в runbook три обязательных запроса: найти edge event, найти application event, проверить отсутствие/наличие dependency event. После одного реального разбора измерьте долю карточек, где цепочка собирается без ручного поиска по времени. Это покажет качество полей, а не только удобство инструмента.
Проверяемые источники
- RFC 9110: HTTP Semantics — версия и дата: Internet Standard, June 2022, DOI 10.17487/RFC9110. Применение: Семантика 502 и место, где gateway сообщает о недействительном ответе upstream. Граница: RFC не определяет топологию edge/application и не подтверждает конкретный отказ.
- RFC 5424: The Syslog Protocol — версия и дата: Standards Track, March 2009, DOI 10.17487/RFC5424. Применение: Разделение заголовка, structured data и message поддерживает выбор полей для безопасного журнала. Граница: Стандарт не гарантирует полноту, порядок доставки и наличие записей в конкретном collector.
- Trace Context — W3C Recommendation — версия и дата: Recommendation, 23 November 2021. Применение: Traceparent и request context используются как ключи соединения событий на HTTP-границах. Граница: Наличие идентификатора не доказывает, что цепочка полна или что найденная запись была причиной.