Как работает ведение журналов
Caddy обладает мощными и гибкими средствами ведения журналов, которые могут отличаться от привычных, особенно если вы перешли с устаревших служб совместного хостинга или других устаревших веб-серверов.
Обзор
В ведении журналов есть два основных аспекта: выдача и потребление.
Выдача означает создание сообщений. Она состоит из трех шагов:
- Сбор релевантной информации (контекст)
- Создание полезного представления (кодирование)
- Отправка этого представления на вывод (запись)
Эта функциональность интегрирована в ядро Caddy, что позволяет любой части кода Caddy или модулям (плагинам) выдавать журналы.
Потребление — это прием и обработка сообщений. Для того чтобы быть полезными, выданные журналы должны быть обработаны. Журналы, которые просто записываются, но никогда не читаются, не представляют никакой ценности. Потребление журналов может быть простым, например, чтение администратором вывода консоли, или сложным, например, подключение инструмента агрегации журналов или облачной службы для фильтрации, подсчета и индексации сообщений журнала.
Роль Caddy
Caddy является источником журналов. Он не потребляет журналы, за исключением минимальной обработки, необходимой для кодирования и записи журналов. Это важно, потому что это упрощает ядро Caddy, что приводит к меньшему количеству ошибок и исключительных случаев, а также снижает нагрузку на обслуживание. В конечном итоге, обработка журналов выходит за рамки ядра Caddy.
Однако всегда есть возможность создания модуля приложения Caddy, потребляющего журналы. (По нашим данным, такого модуля пока нет.)
Структурированные журналы
Как и в большинстве современных приложений, журналы Caddy являются структурированными. Это означает, что информация в сообщении не просто необработанная строка или срез байтов. Вместо этого данные остаются строго типизированными и имеют ключи отдельных названий полей до момента кодирования сообщения и записи его на вывод.
Сравните традиционные неструктурированные журналы, такие как устаревший общий формат журнала (CLF), обычно используемый с традиционными HTTP-серверами:
127.0.0.1 - - [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.1" 200 2326
Этот формат «имеет структуру», но не является «структурированным»: он может использоваться только для ведения журнала HTTP-запросов. Нет (эффективного) способа закодировать его по-другому, поскольку это необработанная строка байтов. Ему также недостаёт множества информации. Он даже не включает заголовок Host запроса! Этот формат журнала полезен только при размещении одного сайта и для получения самой базовой информации о запросах.
Теперь сравните эквивалентное сообщение структурированного журнала из Caddy, закодированное как JSON и отформатированное для отображения:
{
"level": "info",
"ts": 1646861401.5241024,
"logger": "http.log.access",
"msg": "handled request",
"request": {
"remote_ip": "127.0.0.1",
"remote_port": "41342",
"client_ip": "127.0.0.1",
"proto": "HTTP/2.0",
"method": "GET",
"host": "localhost",
"uri": "/",
"headers": {
"User-Agent": ["curl/7.82.0"],
"Accept": ["*/*"],
"Accept-Encoding": ["gzip, deflate, br"],
},
"tls": {
"resumed": false,
"version": 772,
"cipher_suite": 4865,
"proto": "h2",
"server_name": "example.com"
}
},
"bytes_read": 0,
"user_id": "",
"duration": 0.000929675,
"size": 10900,
"status": 200,
"resp_headers": {
"Server": ["Caddy"],
"Content-Encoding": ["gzip"],
"Content-Type": ["text/html; charset=utf-8"],
"Vary": ["Accept-Encoding"]
}
}
Вы можете увидеть, как структурированный журнал намного полезнее и содержит гораздо больше информации. Большое количество информации в этом сообщении журнала не только полезно, но и почти не влияет на производительность: журналы Caddy не требуют выделения памяти. Структурированные журналы не имеют ограничений на типы данных или контекст: они могут использоваться в любом пути кода и содержать любую информацию.
Поскольку журналы структурированы и строго типизированы, их можно закодировать в любой формат. Так что, если вы не хотите работать с JSON, журналы могут быть закодированы в любом другом представлении. Caddy поддерживает другие через модули кодировщиков журналов, и можно добавить ещё больше.
Самое важное в различии между структурированными журналами и устаревшими форматами заключается в том, что структурированный журнал может быть преобразован в устаревший общий формат журнала (Common Log Format) с некоторой потерей производительности, но не наоборот. Преобразование из CLF в структурированные форматы нетривиально (или, по крайней мере, неэффективно), а ввиду отсутствия информации — невозможно.
По сути, эффективное структурированное ведение журналов, как правило, основывается на этих принципах:
- Лучше иметь слишком много журналов, чем слишком мало
- Лучше фильтровать, чем выбрасывать
- Отложить кодирование для большей гибкости и межплатформенной совместимости
Выдача
В коде выдача журнала похожа на следующее:
logger.Debug("proxy roundtrip",
zap.String("upstream", di.Upstream.String()),
zap.Object("request", caddyhttp.LoggableHTTPRequest{Request: req}),
zap.Object("headers", caddyhttp.LoggableHTTPHeader(res.Header)),
zap.Duration("duration", duration),
zap.Int("status", res.StatusCode),
)
Вы видите, что этот один вызов функции содержит уровень журнала, сообщение и несколько данных полей. Все они строго типизированы, и Caddy использует библиотеку ведения журналов без выделения памяти, поэтому выдача журналов быстрая и эффективная с минимальной накладной стоимостью.
Переменная logger является zap.Logger, которая может содержать любое количество контекста, включая имя и данные полей. Это позволяет логгерам «унаследовать» родительские контексты, что позволяет осуществлять продвинутое отслеживание и метрики.
После этого сообщение отправляется через высокоэффективную обработку, где оно кодируется и записывается.
Поток ведения журналов
Как вы видели выше, сообщения выдаются логгерами. Затем сообщения отправляются в журналы для обработки.
Caddy позволяет настроить несколько журналов, которые могут обрабатывать сообщения. Журнал состоит из кодировщика, записывающего устройства, минимального уровня, коэффициента выборки и списка логгеров для включения или исключения. В Caddy всегда есть журнал по умолчанию, названный default. Вы можете настроить его, указав журнал с ключом "default" в этом объекте в конфигурации.
- Кодировщик: Формат журнала. Преобразует представление данных в памяти в срез байтов. Кодировщики имеют доступ ко всем полям сообщения журнала.
- Записывающее устройство: Вывод журнала. Может быть любым модулем записи журналов, например, в файл или сетевой сокет. Он просто записывает байты.
- Уровень: У журналов есть различные уровни, от DEBUG до FATAL. Сообщения, уровень которых ниже указанного, будут игнорироваться журналом.
- Выборка: Очень загруженные пути могут выдавать больше журналов, чем можно эффективно обработать; включение выборки — способ уменьшить нагрузку, сохраняя при этом репрезентативную выборку сообщений.
- Включить/исключить: Каждое сообщение выдается логгером, который имеет имя (обычно полученное из идентификатора модуля). Журналы могут включать или исключать сообщения из определённых логгеров.
Когда сообщение журнала выдаётся Caddy:
- Проверяется имя исходного логгера в списке включения/исключения каждого журнала; если он включён (или не исключён), он допускается в этот журнал.
- Если включена выборка, выполняется быстрый вычисление, определяющее, следует ли сохранить сообщение журнала.
- Сообщение кодируется с помощью настроенного кодировщика журнала.
- Закодированные байты записываются в настроенное записывающее устройство журнала.
По умолчанию все сообщения отправляются во все настроенные журналы. Это соответствует описанным выше принципам структурированного ведения журналов. Вы можете ограничить, какие сообщения поступают в какие журналы, установив списки включения/исключения, но это в основном для фильтрации сообщений из разных модулей; не предназначено для использования как служба агрегации журналов. Для поддержания потока ведения журналов Caddy эффективным, обработка сообщений журнала на более высоком уровне делегируется потребителям.
Потребление
После отправки сообщений на вывод потребитель прочитает их, проанализирует и обработает соответствующим образом.
Это очень отличается от области задачи выдачи журналов, и ядро Caddy не обрабатывает потребление (хотя модуль приложения Caddy, безусловно, может). Существует множество инструментов, которые можно использовать для обработки потоков сообщений JSON (или других форматов) и для просмотра, фильтрации, индексации и запросов журналов. Вы даже можете написать или реализовать свой собственный.
Например, если вы используете устаревшее программное обеспечение, которое требует разделения CLF на разные файлы на основе определённого поля (например, имени хоста), вы можете использовать или написать простой инструмент, который считывает JSON, вызывает sprintf() для создания строки CLF, а затем записывает её в файл на основе значения в поле request.host.
Средства ведения журналов Caddy также могут быть использованы для реализации метрик и отслеживания: метрики в основном подсчитывают сообщения с определёнными характеристиками, а отслеживание связывает несколько сообщений вместе на основе общих черт между ними.
Возможностей потребления журналов Caddy бесчисленное множество!
© 2015-2025 Matthew Holt and The Caddy Authors
Licensed under the Apache License 2.0.
Caddy is a registered trademark of Stack Holdings GmbH.
https://caddyserver.com/docs/logging