Все подсистемы Galleon пишут один поток структурированных логов в stdout — формат JSON, одна запись на строку. Ротация и доставка в систему хранения логов — забота платформы развёртывания.

Настройка

Блок logging конфигурации:

КлючПо умолчаниюНазначение
levelinfoПорог логов Galleon: debug, info, warn, error
formatjsonjson или text
registry_levelwarnОтдельный порог для записей о работе с образами контейнеров

События аудита при работе с образами контейнеров (загрузка и удаление манифестов, блобов, тегов) пишутся всегда, независимо от registry_level.

Access-лог

Каждый запрос пишет одну запись msg="http request" с полями: source (подсистема), method, path, status, size, user, client_ip, duration, время и число запросов к базе и завершающим request_id. В user стоит аутентифицированная учётная запись; у запроса без успешной аутентификации там -.

Тот же идентификатор Galleon возвращает клиенту в заголовке X-Request-ID. По нему в логе находятся все записи одного запроса. client_ip за обратным прокси корректен только при настроенном доверии (Обратный прокси).

Ошибки самого HTTP-сервера пишутся с источником server.http на уровне warn. Когда Galleon отдаёт HTTPS сам, в этот источник попадают неудачные TLS-рукопожатия (TLS).

Поля, которые появляются только на проблемном трафике:

  • sqlstate — запрос столкнулся с ошибкой PostgreSQL;
  • served_stale=true — proxy-репозиторий отдал устаревшую копию, потому что внешний реестр не ответил;
  • deny_reason — отказ аутентификации или доступа; словарь значений ниже.

Поле attempted_user — логин, предъявленный клиентом: учётные данные отвергнуты или не проверялись, потому что запрос отклонён раньше. Значение ? — авторизация не Basic или пустой логин. Неудачные входы ищите по этому полю: в user у таких записей -. Поле появляется и на обычном трафике, например когда мониторинг опрашивает открытый эндпоинт с учётными данными.

Причины отказов

Поле deny_reason объясняет каждый отказ, не меняя ответ клиенту (коды ответов не раскрывают существование чужих репозиториев):

ЗначениеПричина
no_credentialsЗапрос без учётных данных там, где они обязательны
bad_credentialsУчётные данные предъявлены и отвергнуты
anonymous_disabledАнонимный доступ выключен
anonymous_forbiddenРоли anonymous не хватает привилегии
forbiddenПользователю не хватает привилегии на репозиторий
admin_requiredНе хватает административной привилегии
anon_no_adminАнонимный запрос к образам контейнеров, требующий административных прав
password_change_requiredЗаблокировано до принудительной смены пароля
repository_not_foundЦелевой репозиторий не найден; ставится и на ответ 404 до проверки учётных данных
repository_name_invalidИмя репозитория не разобрано, поиск не выполнялся
wrong_formatРепозиторий существует, но другого формата
monitoring_ip_deniedАдрес вне monitoring_allowlist
upstream_manually_blockedОбращения к внешнему реестру заморожены вручную
upstream_auto_blockedОбращения приостановлены автоблокировкой

Запись с 401/403 без deny_reason — признак инфраструктурного сбоя: смотрите поля err и sqlstate. Ответ 404 по репозиторию тоже несёт причину; без неё остаются ответы репозитория, выведенного из обслуживания, и отказы из-за неверной формы запроса.

События аудита

Административные и доменные события пишутся на уровне info:

  • публикации артефактов — записи msg="<FORMAT> artifact published" с координатами и репозиторием, по одной на артефакт;
  • операции с образами контейнеров — загрузка и удаление манифестов, блобов и тегов;
  • инвалидация кеша репозитория (source=audit.repository);
  • создание bootstrap-администратора, создание стартового набора репозиториев, итоги циклов сборки мусора, смены состояния соединений с внешними реестрами.

Секреты в лог не попадают ни на каком уровне: значения заголовков авторизации, пароли, токены и содержимое тел не логируются. Управляющие символы и некорректный UTF-8 в значениях, пришедших от клиента (путь, заголовки, имена файлов), заменяются в логе на ?.