Логи
Каждый запрос, дошедший до API гейта, попадает в журнал. Запись идёт пакетно и вне горячего пути: запрос не ждёт базы.
Что записывается¶
Кто и куда: ключ клиента (имя денормализовано — удаление ключа не должно стирать историю его расхода), провайдер, метка ключа провайдера, запрошенная и обслужившая модели, эндпоинт, формат, операция, признак потока.
Как прошло: код ответа, тип и текст ошибки, задержка, время до первого байта, число попыток, цепочка фолбэков, IP и User-Agent клиента.
Сколько: входные, выходные, суммарные токены, чтение и запись кэша, reasoning-токены, длительность аудио, себестоимость и списанное.
Тела: полный JSON запроса и ответа, если включено. Вызовы инструментов — отдельной таблицей, с направлением: «предложен клиентом» или «вызван моделью».
Две колонки стоимости¶
cost_base_usd — чего запрос стоил по цене модели. cost_usd — что списано с
ключа, то есть та же величина, умноженная на наценку владельца.
Одно число не смогло бы ответить на оба вопроса: обзор — про то, чего трафик стоит развёртыванию, и он не должен дёргаться, когда кому-то поднимают наценку; страница ключа — про то, что должен его владелец. Каждая страница читает ту колонку, которую имеет в виду.
Две колонки модели¶
requested_model — как адресовал клиент. resolved_model — что ушло
провайдеру. Подробно — Адресация моделей.
Цена считается по второму. Страница цен ищет неоплаченные модели тоже по второму. Разбивки по моделям — на обзоре, у ключа, на странице пользователя — по первому: там интересно, чем пользуются, а не как это разложилось внутри.
Разбор тела в диалог¶
Страница запроса показывает сохранённое тело диалогом: роли, текст, вызовы инструментов с разобранными аргументами, ответы инструментов, рассуждения модели под спойлером, вложения без инлайна base64.
Сохранённое тело — это wire-формат, о котором три провайдера не договорились: OpenAI кладёт содержимое строкой, Anthropic списком типизированных блоков, Responses API третьим способом. В сыром виде это экран JSON, в середине которого где-то лежит то, за чем пришли.
Понимаются chat completions, Anthropic Messages и Responses API. Тело, которое разобрать не удалось, даёт пустой результат — и страница показывает только сырой JSON, он остаётся на месте всегда. Это вид над строкой, а не её замена.
Аргументы инструментов OpenAI присылает строкой с JSON внутри; напечатанная как есть, она даёт строку экранированных кавычек — ровно то, ради избавления от чего этот вид и существует. Поэтому они разбираются и печатаются с отступами.
Скорость¶
Длительность запроса показывается в секундах, рядом — выходных токенов в секунду.
Скорость считается по всему запросу, а не по одной генерации: время до первого байта гейт записывает не для всех ответов, а величина, у которой знаменатель молча меняется между строками, хуже стабильно консервативной. То есть это то, что почувствовал вызывающий, а не decode rate, который назвал бы провайдер.
Длительность аудио¶
Для модели, тарифицируемой за минуту, плитка «Токены» заменяется на «Аудио»: секунды, минуты и токены рядом (запрос может иметь и то и другое). В списке секунды показываются в колонке токенов.
Ноль у аудио-запроса означает, что длительность измерить не удалось — см. Цены.
Что не записывается¶
- Тело потокового ответа. Буферизация сломала бы выдачу. Токены, стоимость и вызовы инструментов при этом считаются полностью — по служебным полям потока, который для этого прослушивается на проходе.
- Тела не-JSON. Multipart-загрузка — это байты аудио или картинки; хранить их значило бы раздуть таблицу без аналитической пользы.
- Тела больше предела.
max_logged_body_bytes, по умолчанию 256 КиБ. Тело сверх предела не сохраняется; всё остальное о запросе записывается. /healthzи/api/show. Ни один не несёт трафика, за который кто-то платит или отвечает: один проба живости, другой вопрос о возможностях, который некоторые клиенты задают перед каждым запросом. Их запись похоронила бы журнал под строками, которые никто не читает, и раздула бы все счётчики по ключам на тех страницах, которые читают.
Настройки¶
В панели, применяются гейтом без перезапуска:
| Настройка | Смысл |
|---|---|
| Писать тело запроса | |
| Писать тело ответа | |
| Предел размера тела | по умолчанию 256 КиБ |
| Срок хранения | по умолчанию 30 дней |
Строки старше срока удаляются гейтом. Размер таблицы виден на странице настроек — вместе с числом записей, чтобы решение о сроке принималось по цифрам.
Отбор¶
Журнал фильтруется по подстроке (искать можно и по запрошенной модели, и по обслужившей), провайдеру, ключу, коду ответа и окну времени. Фильтры применяются на сервере и не меняют URL — страница подгружает строки htmx-ом.