# 8. Ведение журнала

> Уровни, форматы и профили журналов, временные показатели, захват данных, состояния и примеры

---

Индекс LLMS: [llms.txt](/ru/llms.txt)

---

<!-- Generated by scripts/generate-haproxy-docs.py from pinned upstream text. -->

Одна из сильных сторон HAProxy — точность его журналов. Вероятно, они предоставляют наиболее подробную информацию среди продуктов такого рода, что очень важно для устранения неполадок в сложных средах. Стандартные сведения в журналах включают порты клиентов, временные показатели состояний TCP/HTTP, точное состояние потока и причину его завершения, информацию о решениях по направлению трафика на сервер и, конечно, возможность захвата произвольных заголовков.

Чтобы администраторы могли быстрее реагировать, HAProxy подробно сообщает о возникающих внутренних и внешних проблемах и позволяет одновременно отправлять журналы нескольким получателям с разными фильтрами уровней:

- глобальные журналы уровня процесса (системные ошибки, запуск/остановка и т. д.)
- системные и внутренние ошибки отдельных экземпляров (нехватка ресурсов, ошибки в программе и т. д.)
- внешние проблемы отдельных экземпляров (переходы серверов в доступное/недоступное состояние, максимальное число соединений)
- активность отдельных экземпляров (клиентские соединения), при установлении или завершении соединения.
- управление уровнем ведения журнала для отдельных запросов, например http-request set-log-level silent if sensitive_request

Возможность распределять журналы разных уровней между разными серверами журналирования позволяет нескольким эксплуатационным командам взаимодействовать и как можно быстрее решать свои проблемы. Например, системные администраторы могут отслеживать общесистемные ошибки, команда приложений — доступность своих серверов в реальном времени, а команда безопасности — анализировать журналы активности с задержкой в один час.

## 8.1. Уровни ведения журнала {#section-8-1}

Для соединений TCP и HTTP в журнал можно записывать дату, время, адрес IP источника и адрес назначения, длительность соединения, время ответа, запрос HTTP, код ответа HTTP, число переданных байтов, условия завершения потока и даже значения переданных cookie. Это позволяет, например, отслеживать проблемы конкретного пользователя. Все сообщения могут отправляться не более чем на два сервера syslog. Дополнительные сведения о средствах ведения журнала см. в описании ключевого слова "log" в [разделе 4.2](/ru/docs/haproxy/proxies/#section-4-2).

## 8.2. Форматы журналов {#section-8-2}

HAProxy поддерживает 5 форматов журналов. Несколько полей являются общими для этих форматов и будут подробно описаны в следующих разделах. Некоторые из них могут немного различаться в зависимости от конфигурации из-за индикаторов, относящихся к определённым опциям. Поддерживаются следующие форматы:

- формат по умолчанию — очень простой и крайне редко используемый. Он предоставляет лишь основные
  сведения о входящем соединении в момент его принятия: IP:port источника,
  IP:port назначения и frontend-name. Со временем этот режим исчезнет, поэтому
  подробно он не рассматривается.

- формат TCP — более развитый. Он включается, если во фронтенде задана "option tcplog".
  В этом случае HAProxy обычно ожидает завершения соединения перед записью в журнал.
  Формат предоставляет значительно больше сведений: временные показатели, число соединений,
  размер очереди и т. д. Он рекомендуется для прокси, работающих только с TCP.

- формат HTTP — наиболее развитый для проксирования HTTP. Он включается, если во фронтенде задана
  "option httplog". Он предоставляет те же сведения, что и формат TCP, с дополнительными
  HTTP-полями: запросом, кодом состояния, захваченными заголовками и cookie.
  Этот формат рекомендуется для прокси HTTP.

- формат CLF HTTP — эквивалент формата HTTP, но с полями в порядке формата CLF.
  В этом режиме все временные показатели, захваты, флаги и т. д. располагаются по одному
  в поле после общих полей, в том же порядке, что и в стандартном формате HTTP.

- пользовательский формат журнала позволяет задать собственную строку журнала.

В следующих разделах каждый из этих форматов рассматривается подробнее. Формат описывается по полям. Если не указано иное, поле — это фрагмент текста, отделённый произвольным числом пробелов. Поскольку серверы syslog могут вставлять поля в начало строки, первым всегда считается поле с именем и идентификатором процесса.

Примечание: строки журнала могут быть довольно длинными, поэтому примеры в следующих разделах иногда разбиты на несколько строк. Строки примеров начинаются с 3 закрывающих угловых скобок ('\>\>\>'). При переносе каждая строка, кроме последней, заканчивается обратной косой чертой ('&#92;'), а следующая начинается с отступом в два символа.

### 8.2.1. Формат журнала по умолчанию {#section-8-2-1}

Этот формат используется, если не задана специальная опция. Запись журнала выдаётся сразу после принятия соединения. Следует учитывать, что сейчас это единственный формат, в котором записываются IP и порты назначения запроса.

Пример:

```shell
    listen www
        mode http
        log global
        server srv1 127.0.0.1:8000

>>> Feb  6 12:12:09 localhost \
      haproxy[14385]: Connect from 10.0.1.2:33312 to 10.0.3.31:8012 \
      (www/HTTP)
```

Поле Формат Фрагмент приведённого выше примера

```text
    1   process_name '[' pid ']:'                            haproxy[14385]:
    2   'Connect from'                                          Connect from
    3   source_ip ':' source_port                             10.0.1.2:33312
    4   'to'                                                              to
    5   destination_ip ':' destination_port                   10.0.3.31:8012
    6   '(' frontend_name '/' mode ')'                            (www/HTTP)
```


Подробное описание полей:

- "source_ip" — адрес IP клиента, инициировавшего соединение.
- "source_port" — порт TCP клиента, инициировавшего соединение.
- "destination_ip" — адрес IP, к которому подключился клиент.
- "destination_port" — порт TCP, к которому подключился клиент.
- "frontend_name" — имя фронтенда (или слушателя), который принял и обработал
  соединение.
- "mode" — режим работы фронтенда (TCP или HTTP).

Для сокета UNIX адреса источника и назначения помечаются как "unix:", а порты отражают внутренний ID сокета, принявшего соединение (тот же ID, что и в статистике).

Рекомендуется не использовать этот устаревший формат в новых установках, поскольку со временем он исчезнет.

### 8.2.2. Формат журнала TCP {#section-8-2-2}

Формат TCP используется, когда во фронтенде задана "option tcplog", и рекомендуется для прокси, работающих только с TCP. Он предоставляет много полезной информации для устранения неполадок. Поскольку этот формат содержит временные показатели и счётчики байтов, запись журнала обычно выдаётся в конце сеанса. Её можно выдать раньше, указав "option logasap", что имеет смысл в большинстве сред с длительными сеансами, например для удалённых терминалов. Сеансы, соответствующие правилам "monitor", никогда не записываются в журнал. Кроме того, можно отключить записи для сеансов, в которых клиент и сервер не обменялись данными, задав во фронтенде "option dontlognull". Успешные соединения не записываются в журнал, если во фронтенде задана "option dontlog-normal".

Внутри HAProxy формат журнала TCP объявлен как пользовательский формат на основе следующей точной строки. При необходимости её можно использовать как основу для расширения формата. Вместо неё также можно использовать переменную HAPROXY_TCP_LOG_FMT. Порядок использования описан в [разделе 8.2.6](/ru/docs/haproxy/configuration-logging/#section-8-2-6) «Пользовательский формат журнала»:

```shell
# strict equivalent of "option tcplog"
log-format "%ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts \
            %ac/%fc/%bc/%sc/%rc %sq/%bq"
# or using the HAPROXY_TCP_LOG_FMT variable
log-format "${HAPROXY_TCP_LOG_FMT}"
```

Формат журнала CLF также объявлен внутри HAProxy как пользовательский формат на основе следующей точной строки:

```shell
# strict equivalent of "option tcplog clf"
log-format "%{Q}o %{-Q}ci - - [%T] \"TCP \" 000 %B \"\" \"\" %cp \
            %ms %ft %b %s %Th %Tw %Tc %Tt %U %ts-- %ac %fc %bc \
            %sc %rc %sq %bq \"\" \"\" "
```

Значения некоторых полей могут немного различаться в зависимости от параметров конфигурации. Такие поля отмечены ниже звёздочкой ('\*') после имени.

Пример:

```shell
    frontend fnt
        mode tcp
        option tcplog
        log global
        default_backend bck

    backend bck
        server srv1 127.0.0.1:8000

>>> Feb  6 12:12:56 localhost \
      haproxy[14387]: 10.0.1.2:33313 [06/Feb/2009:12:12:51.443] fnt \
      bck/srv1 0/0/5007 212 -- 0/0/0/0/3 0/0
```

Поле Формат Фрагмент приведённого выше примера

```text
    1   process_name '[' pid ']:'                            haproxy[14387]:
    2   client_ip ':' client_port                             10.0.1.2:33313
    3   '[' accept_date ']'                       [06/Feb/2009:12:12:51.443]
    4   frontend_name                                                    fnt
    5   backend_name '/' server_name                                bck/srv1
    6   Tw '/' Tc '/' Tt*                                           0/0/5007
    7   bytes_read*                                                      212
    8   termination_state                                                 --
    9   actconn '/' feconn '/' beconn '/' srv_conn '/' retries*    0/0/0/0/3
   10   srv_queue '/' backend_queue                                      0/0
```


Подробное описание полей:

- "client_ip" — адрес IP клиента, инициировавшего соединение TCP с HAProxy. Если соединение принято через сокет UNIX, вместо адреса IP указывается слово "unix". Если соединение принято через сокет с настройкой "accept-proxy" и протокол PROXY используется корректно либо через сокет с настройкой "accept-netscaler-cip" и корректным использованием протокола передачи IP клиента NetScaler, в журнале отражаются сведения о переданном соединении.

- "client_port" — порт TCP клиента, инициировавшего соединение. Если соединение принято через сокет UNIX, вместо порта указывается ID принимающего сокета, который также отображается в интерфейсе статистики.

- "accept_date" — точные дата и время получения соединения HAProxy. Они могут совсем немного отличаться от времени, наблюдаемого в сети, если соединение ожидало в системной очереди входящих соединений. Обычно это то же время, которое может появляться в журнале межсетевого экрана перед HAProxy. В режиме HTTP значение accept_date устанавливается заново в первый момент готовности соединения к приёму нового запроса: после завершения предыдущего ответа для HTTP/1 или сразу после предыдущего запроса для HTTP/2.

- "frontend_name" — имя фронтенда (или слушателя), который принял и обработал соединение.

- "backend_name" — имя бэкенда (или слушателя), выбранного для управления соединением с сервером. Оно будет таким же, как и у фронтенда, если не применялись правила переключения, что типично для приложений TCP.

- "server_name" — имя последнего сервера, на который направлялось соединение. Этот сервер может отличаться от первоначального, если из-за ошибок соединения произошло перенаправление. Сервер принадлежит бэкенду, обработавшему запрос. Если соединение прервалось, не достигнув сервера, вместо имени сервера указывается "`<NOSRV>`".

- "Tw" — общее время в миллисекундах, потраченное на ожидание в различных очередях. Может быть "-1", если соединение было прервано до попадания в очередь. Подробности см. в разделе «Таймеры» ниже.

- "Tc" — общее время в миллисекундах, потраченное на установление соединения с конечным сервером, включая повторные попытки. Может быть "-1", если соединение было прервано до установления соединения. Подробности см. в разделе «Таймеры» ниже.

- "Tt" — общее время в миллисекундах, прошедшее между принятием и последним закрытием соединения. Охватывает все возможные этапы обработки. Исключение — если указано "option logasap", то подсчёт времени останавливается в момент выдачи записи журнала. В этом случае перед значением добавляется знак '+', указывающий, что окончательное значение будет больше. Подробности см. в разделе «Таймеры» ниже.

- "bytes_read" — общее количество байт, переданных с сервера клиенту в момент выдачи записи журнала. Если указано "option logasap", это значение будет предваряться знаком '+', указывающим, что окончательное значение может быть больше. Обратите внимание, что это 64-битный счётчик, поэтому инструменты анализа журналов должны быть способны обрабатывать его без переполнения.

- "termination_state" — состояние сеанса в момент её завершения. Указывает состояние сеанса, сторону, вызвавшую завершение, и причину (тайм-аут, ошибка и т.д.). Обычные флаги — "--", что означает, что сеанс была закрыта одной из сторон без остатка данных в буферах. Подробности см. в разделе «Состояние потока при отключении» ниже.

- "actconn" — общее число одновременных соединений процесса на момент записи сеанса в журнал. Оно помогает определить, достигнуты ли системные ограничения для отдельного процесса. Например, если при многочисленных ошибках соединения actconn близко к 512, весьма вероятно, что система ограничивает процесс 1024 файловыми дескрипторами и все они заняты. Порядок настройки системы описан в [разделе 3](/ru/docs/haproxy/global/) «Глобальная секция».

- "feconn" — общее количество одновременных соединений на фронтенде в момент записи сеанса в журнал. Полезно для оценки объёма ресурсов, необходимых для поддержки высокой нагрузки, и для выявления достижения лимита "maxconn" фронтенда. Часто резкий рост этого значения указывает на перегрузку серверов бэкенда, но иногда может быть вызван атакой типа «отказ в обслуживании».

- "beconn" — общее количество одновременных соединений, обрабатываемых бэкендом в момент записи сеанса в журнал. Включает общее количество одновременных соединений на серверах, а также количество соединений, ожидающих в очередях. Полезно для оценки количества дополнительных серверов, необходимых для поддержки высокой нагрузки для данного приложения. Часто резкий рост этого значения указывает на перегрузку серверов бэкенда, но иногда может быть вызван атакой типа «отказ в обслуживании».

- "srv_conn" — общее число одновременных соединений, которые ещё активны на сервере на момент записи сеанса в журнал. Оно никогда не может превышать настроенный для сервера параметр "maxconn". Если значение очень часто близко к "maxconn" сервера или равно ему, это означает, что часто задействуется регулирование трафика: либо значение maxconn сервера слишком мало, либо серверов недостаточно, чтобы обрабатывать нагрузку с оптимальным временем ответа. Если высокое значение "srv_conn" наблюдается только у одного сервера, обычно у него есть проблема, из-за которой обработка соединений занимает больше времени, чем на остальных серверах.

- "retries" — число повторных попыток установить соединение с сервером в этом сеансе. Обычно оно должно быть равно нулю, кроме случая, когда сервер останавливается одновременно с попыткой подключения. Частые повторы обычно указывают либо на сетевую проблему между HAProxy и сервером, либо на неверную настройку системной очереди входящих соединений на сервере, из-за которой новые соединения не могут попасть в очередь. Поле может начинаться со знака '+': это означает, что после достижения максимального числа повторных попыток на первоначальном сервере сеанс был перенаправлен. Тогда в журнале указывается имя сервера, на который перенаправлено соединение, а не первоначального; однако иногда, например при хешировании, они могут совпадать. Поэтому, как правило, при наличии '+' перед числом повторных попыток это число не следует относить к серверу, указанному в журнале.

- "srv_queue" — общее число запросов, обработанных перед данным запросом в очереди сервера. Оно равно нулю, если запрос не проходил через очередь сервера. Разделив время ожидания в очереди на число запросов в ней, можно приблизительно оценить время ответа сервера. Если сеанс перенаправляется и проходит через очереди двух серверов, позиции в них суммируются. Запрос не должен проходить и через очередь сервера, и через очередь бэкенда, кроме случая перенаправления.

- "backend_queue" — общее число запросов, обработанных перед данным запросом в общей очереди бэкенда. Оно равно нулю, если запрос не проходил через общую очередь. Поле позволяет оценить среднюю длину очереди; разделив её на параметр "maxconn" сервера, легко получить число недостающих серверов. При перенаправлении сеанс может дважды пройти через очередь бэкенда, и тогда обе позиции суммируются. Запрос не должен проходить и через очередь сервера, и через очередь бэкенда, кроме случая перенаправления.

### 8.2.3. Формат журнала HTTP {#section-8-2-3}

Формат HTTP — наиболее полный и лучше всего подходит для прокси HTTP. Он включается, если во фронтенде задана "option httplog". Он предоставляет те же сведения, что и формат TCP, с дополнительными возможностями, относящимися к протоколу HTTP. Как и в формате TCP, запись журнала обычно выдаётся в конце потока, если не задана "option logasap"; эта опция обычно имеет смысл только для сайтов скачивания файлов. Поток, соответствующий правилам "monitor", никогда не записывается в журнал. Также можно отключить записи для потоков, в которых клиент не отправил никаких данных, задав во фронтенде "option dontlognull". Успешные соединения не записываются в журнал, если во фронтенде задана "option dontlog-normal".

Внутри HAProxy формат журнала HTTP объявлен как пользовательский формат на основе следующей точной строки. При необходимости её можно использовать как основу для расширения формата. Вместо неё также можно использовать переменную HAPROXY_HTTP_LOG_FMT. Порядок использования описан в [разделе 8.2.6](/ru/docs/haproxy/configuration-logging/#section-8-2-6) «Пользовательский формат журнала»:

```shell
# strict equivalent of "option httplog"
log-format "%ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC \
            %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
# or using the HAPROXY_HTTP_LOG_FMT variable
log-format "${HAPROXY_HTTP_LOG_FMT}"
```

Формат журнала CLF также объявлен внутри HAProxy как пользовательский формат на основе следующей точной строки:

```shell
# strict equivalent of "option httplog clf"
log-format "%{+Q}o %{-Q}ci - - [%trg] %r %ST %B \"\" \"\" %cp \
            %ms %ft %b %s %TR %Tw %Tc %Tr %Ta %tsc %ac %fc \
            %bc %sc %rc %sq %bq %CC %CS %hrl %hsl"
```

Большинство полей совпадают с форматом TCP, некоторые различаются. Некоторые поля могут незначительно отличаться в зависимости от опций конфигурации. Такие поля помечены звёздочкой ('\*') после названия поля ниже.

Пример:

```shell
    frontend http-in
        mode http
        option httplog
        log global
        default_backend bck

    backend static
        server srv1 127.0.0.1:8000

>>> Feb  6 12:14:14 localhost \
      haproxy[14389]: 10.0.1.2:33317 [06/Feb/2009:12:14:14.655] http-in \
      static/srv1 10/0/30/69/109 200 2750 - - ---- 1/1/1/1/0 0/0 {1wt.eu} \
      {} "GET /index.html HTTP/1.1"
```

Поле Формат Фрагмент приведённого выше примера

```text
    1   process_name '[' pid ']:'                            haproxy[14389]:
    2   client_ip ':' client_port                             10.0.1.2:33317
    3   '[' request_date ']'                      [06/Feb/2009:12:14:14.655]
    4   frontend_name                                                http-in
    5   backend_name '/' server_name                             static/srv1
    6   TR '/' Tw '/' Tc '/' Tr '/' Ta*                       10/0/30/69/109
    7   status_code                                                      200
    8   bytes_read*                                                     2750
    9   captured_request_cookie                                            -
   10   captured_response_cookie                                           -
   11   termination_state                                               ----
   12   actconn '/' feconn '/' beconn '/' srv_conn '/' retries*    1/1/1/1/0
   13   srv_queue '/' backend_queue                                      0/0
   14   '{' captured_request_headers* '}'                   {haproxy.1wt.eu}
   15   '{' captured_response_headers* '}'                                {}
   16   '"' http_request '"'                      "GET /index.html HTTP/1.1"
```


Подробное описание полей:

- "client_ip" — адрес IP клиента, инициировавшего соединение TCP с HAProxy. Если соединение принято через сокет UNIX, вместо адреса IP указывается слово "unix". Если соединение принято через сокет с настройкой "accept-proxy" и протокол PROXY используется корректно либо через сокет с настройкой "accept-netscaler-cip" и корректным использованием протокола передачи IP клиента NetScaler, в журнале отражаются сведения о переданном соединении.

- "client_port" — порт TCP клиента, инициировавшего соединение. Если соединение принято через сокет UNIX, вместо порта указывается ID принимающего сокета, который также отображается в интерфейсе статистики.

- "request_date" — точные дата и время получения HAProxy первого байта запроса HTTP (поле журнала %tr).

- "frontend_name" — имя фронтенда (или слушателя), который принял и обработал соединение.

- "backend_name" — имя бэкенда (или слушателя), выбранного для управления соединением с сервером. Будет совпадать с именем фронтенда, если не применялись правила переключения.

- "server_name" — имя последнего сервера, на который направлялось соединение. Этот сервер может отличаться от первоначального, если из-за ошибок соединения произошло перенаправление. Сервер принадлежит бэкенду, обработавшему запрос. Если запрос прервался, не достигнув сервера, вместо имени сервера указывается "`<NOSRV>`". Если запрос перехватила подсистема статистики, вместо него указывается "`<STATS>`".

- "TR" — общее время в миллисекундах, затраченное на ожидание полного запроса HTTP от клиента (без тела) после получения первого байта. Оно может быть равно "-1", если соединение прервалось до получения полного запроса или был получен некорректный запрос. Это время всегда должно быть очень малым, поскольку запрос обычно помещается в один пакет. Большие значения обычно указывают на сетевые проблемы между клиентом и HAProxy или на ввод запросов вручную. Подробнее см. [раздел 8.4](/ru/docs/haproxy/configuration-logging/#section-8-4) «Временные показатели событий».

- "Tw" — общее время в миллисекундах, затраченное на ожидание в различных очередях. Может быть равным "-1", если соединение было прервано до достижения очереди. Подробнее см. [раздел 8.4](/ru/docs/haproxy/configuration-logging/#section-8-4) «Временные показатели событий».

- "Tc" — общее время в миллисекундах, затраченное на установление соединения с конечным сервером, включая повторные попытки. Может быть равным "-1", если запрос был прерван до установления соединения. Подробнее см. [раздел 8.4](/ru/docs/haproxy/configuration-logging/#section-8-4) «Временные показатели событий».

- "Tr" — общее время в миллисекундах, затраченное на ожидание полного ответа HTTP от сервера, без учёта данных. Может быть равным "-1", если запрос был прерван до получения полного ответа. Обычно соответствует времени обработки запроса сервером, хотя может изменяться в зависимости от объёма данных, отправленных клиентом серверу. Большое время в случае запросов "GET" обычно указывает на перегруженность сервера. Подробнее см. [раздел 8.4](/ru/docs/haproxy/configuration-logging/#section-8-4) «Временные показатели событий».

- "Ta" — время активности запроса в HAProxy, то есть общее время в миллисекундах от получения первого байта запроса до отправки последнего байта ответа. Оно охватывает всю обработку, кроме согласования соединения (см. Th) и времени простоя (см. Ti). Есть одно исключение: если задана "option logasap", отсчёт останавливается в момент выдачи записи журнала. Тогда перед значением ставится знак '+', указывающий, что окончательное значение будет больше. Подробнее см. [раздел 8.4](/ru/docs/haproxy/configuration-logging/#section-8-4) «Временные показатели событий».

- "status_code" — код состояния HTTP, возвращённый клиенту. Этот код обычно устанавливается сервером, но может быть установлен и HAProxy, если сервер недоступен или если ответ был заблокирован HAProxy.

- "bytes_read" — общее число байтов, переданных клиенту на момент выдачи записи журнала, включая заголовки HTTP. Если задана "option logasap", перед значением ставится знак '+', указывающий, что окончательное значение может быть больше. Это 64-битный счётчик, поэтому инструменты анализа журналов должны обрабатывать его без переполнения.

- "captured_request_cookie" — необязательная запись "name=value", указывающая, что клиент передал этот cookie в запросе. Имя cookie и его максимальная длина задаются директивой "capture cookie" в конфигурации фронтенда. Если опция не задана, поле содержит один дефис ('-'). Захватить можно только один cookie; обычно он используется для отслеживания обмена ID сеансов между клиентом и сервером, чтобы выявлять смешение сеансов разных клиентов из-за ошибок приложения. Подробнее см. раздел «Захват заголовков HTTP и cookie» ниже.

- "captured_response_cookie" — необязательная запись "name=value", указывающая, что сервер вернул cookie в ответе. Имя cookie и его максимальная длина задаются директивой "capture cookie" в конфигурации фронтенда. Если опция не задана, поле содержит один дефис ('-'). Захватить можно только один cookie; обычно он используется для отслеживания обмена ID сеансов между клиентом и сервером, чтобы выявлять смешение сеансов разных клиентов из-за ошибок приложения. Подробнее см. раздел «Захват заголовков HTTP и cookie» ниже.

- "termination_state" — состояние потока в момент его завершения. Как и в журналах TCP, оно указывает состояние потока, сторону, вызвавшую завершение, и причину (тайм-аут, ошибка и т. д.), а последние два символа содержат информацию об операциях привязки с помощью cookie. Нормальные флаги должны начинаться с "--": это означает, что поток закрыла одна из сторон, а в буферах не осталось данных. Подробнее см. раздел «Состояние потока при разрыве соединения» ниже.

- "actconn" — общее число одновременных соединений процесса на момент записи потока в журнал. Оно помогает определить, достигнуты ли системные ограничения для отдельного процесса. Например, если при многочисленных ошибках соединения actconn близко к 512 или 1024, весьма вероятно, что система ограничивает процесс 1024 файловыми дескрипторами и все они заняты. Порядок настройки системы описан в [разделе 3](/ru/docs/haproxy/global/) «Глобальная секция».

- "feconn" — общее количество одновременных соединений на фронтенде на момент записи потока в журнал. Полезно для оценки объёма ресурсов, необходимых для поддержки высокой нагрузки, и для выявления достижения лимита "maxconn" фронтенда. Часто резкий рост этого значения указывает на перегрузку серверов бэкенда, хотя иногда может быть вызван атакой типа "отказ в обслуживании".

- "beconn" — общее количество одновременных соединений, обрабатываемых бэкендом на момент записи потока в журнал. Включает общее количество одновременных соединений на серверах, а также количество соединений, ожидающих в очередях. Полезно для оценки количества дополнительных серверов, необходимых для поддержки высокой нагрузки приложения. Часто резкий рост этого значения указывает на перегрузку серверов бэкенда, хотя иногда может быть вызван атакой типа "отказ в обслуживании".

- "srv_conn" — общее число одновременных соединений, которые ещё активны на сервере на момент записи потока в журнал. Оно никогда не может превышать настроенный для сервера параметр "maxconn". Если значение очень часто близко к "maxconn" сервера или равно ему, это означает, что часто задействуется регулирование трафика: либо значение maxconn сервера слишком мало, либо серверов недостаточно, чтобы обрабатывать нагрузку с оптимальным временем ответа. Если высокое значение "srv_conn" наблюдается только у одного сервера, обычно у него есть проблема, из-за которой обработка запросов занимает больше времени, чем на остальных серверах.

- "retries" — число повторных попыток установить соединение с сервером для этого потока. Обычно оно должно быть равно нулю, кроме случая, когда сервер останавливается одновременно с попыткой подключения. Частые повторы обычно указывают либо на сетевую проблему между HAProxy и сервером, либо на неверную настройку системной очереди входящих соединений на сервере, из-за которой новые соединения не могут попасть в очередь. Поле может начинаться со знака '+': это означает, что после достижения максимального числа повторных попыток на первоначальном сервере поток был перенаправлен. Тогда в журнале указывается имя сервера, на который перенаправлено соединение, а не первоначального; однако иногда, например при хешировании, они могут совпадать. Поэтому, как правило, при наличии '+' перед числом повторных попыток это число не следует относить к серверу, указанному в журнале.

- "srv_queue" — общее число запросов, обработанных перед данным запросом в очереди сервера. Оно равно нулю, если запрос не проходил через очередь сервера. Разделив время ожидания в очереди на число запросов в ней, можно приблизительно оценить время ответа сервера. Если поток перенаправляется и проходит через очереди двух серверов, позиции в них суммируются. Запрос не должен проходить и через очередь сервера, и через очередь бэкенда, кроме случая перенаправления.

- "backend_queue" — общее число запросов, обработанных перед данным запросом в общей очереди бэкенда. Оно равно нулю, если запрос не проходил через общую очередь. Поле позволяет оценить среднюю длину очереди; разделив её на параметр "maxconn" сервера, легко получить число недостающих серверов. При перенаправлении поток может дважды пройти через очередь бэкенда, и тогда обе позиции суммируются. Запрос не должен проходить и через очередь сервера, и через очередь бэкенда, кроме случая перенаправления.

- "captured_request_headers" — список заголовков, захваченных из запроса благодаря директиве "capture request header" во фронтенде. Можно захватывать несколько заголовков; они разделяются вертикальной чертой ('\|'). Если захват не включён, фигурные скобки не выводятся и оставшиеся поля сдвигаются. Поле может содержать пробелы, поэтому при его использовании нужен более сложный анализатор журналов. Подробнее см. раздел «Захват заголовков HTTP и cookie» ниже.

- "captured_response_headers" — список заголовков, захваченных из ответа благодаря директиве "capture response header" во фронтенде. Можно захватывать несколько заголовков; они разделяются вертикальной чертой ('\|'). Если захват не включён, фигурные скобки не выводятся и оставшиеся поля сдвигаются. Поле может содержать пробелы, поэтому при его использовании нужен более сложный анализатор журналов. Подробнее см. раздел «Захват заголовков HTTP и cookie» ниже.

- "http_request" — полная строка запроса HTTP, включая метод, сам запрос и строку версии HTTP. Непечатаемые символы кодируются (см. раздел «Непечатаемые символы» ниже). Это поле всегда последнее, всегда заключено в кавычки и только оно может содержать кавычки. Новые поля формата журнала добавляются перед ним. Поле может быть обрезано, если запрос настолько велик, что не помещается в стандартный буфер syslog (1024 символа). Именно поэтому оно всегда должно оставаться последним.

### 8.2.4. Формат журнала HTTPS {#section-8-2-4}

Формат HTTPS лучше всего подходит для соединений HTTP через SSL. Он расширяет формат HTTP (см. [раздел 8.2.3](/ru/docs/haproxy/configuration-logging/#section-8-2-3)) сведениями, связанными с SSL. Он включается, если во фронтенде задана "option
httpslog". Как и в форматах TCP и HTTP, запись журнала обычно выдаётся в конце потока, если не задана "option logasap". Поток, соответствующий правилам "monitor", никогда не записывается в журнал. Также можно отключить записи для потоков, в которых клиент не отправил никаких данных, задав во фронтенде "option dontlognull". Успешные соединения не записываются в журнал, если во фронтенде задана "option dontlog-normal".

Внутри HAProxy формат журнала HTTPS объявлен как пользовательский формат на основе следующей точной строки. При необходимости её можно использовать как основу для расширения формата. Вместо неё также можно использовать переменную HAPROXY_HTTPS_LOG_FMT. Порядок использования описан в [разделе 8.2.6](/ru/docs/haproxy/configuration-logging/#section-8-2-6) «Пользовательский формат журнала»:

```shell
# strict equivalent of "option httpslog"
log-format "%ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC \
           %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r \
           %[fc_err]/%[ssl_fc_err,hex]/%[ssl_c_err]/\
           %[ssl_c_ca_err]/%[ssl_fc_is_resumed] %[ssl_fc_sni]/%sslv/%sslc"
# or using the HAPROXY_HTTPS_LOG_FMT variable
log-format "${HAPROXY_HTTPS_LOG_FMT}"
```

По сути, это формат HTTP (см. [раздел 8.2.3](/ru/docs/haproxy/configuration-logging/#section-8-2-3)) с добавленными полями. Здесь подробно описываются новые поля (строки 17 и 18). Описание полей HTTP см. в разделе о формате HTTP.

Пример:

```shell
    frontend https-in
        mode http
        option httpslog
        log global
        bind *:443 ssl crt mycerts/srv.pem ...
        default_backend bck

    backend static
        server srv1 127.0.0.1:8000 ssl crt mycerts/clt.pem ...

>>> Feb  6 12:14:14 localhost \
      haproxy[14389]: 10.0.1.2:33317 [06/Feb/2009:12:14:14.655] https-in \
      static/srv1 10/0/30/69/109 200 2750 - - ---- 1/1/1/1/0 0/0 {1wt.eu} \
      {} "GET /index.html HTTP/1.1" 0/0/0/0/0 \
      1wt.eu/TLSv1.3/TLS_AES_256_GCM_SHA384
```

Поле Формат Фрагмент приведённого выше примера

```text
    1   process_name '[' pid ']:'                              haproxy[14389]:
    2   client_ip ':' client_port                               10.0.1.2:33317
    3   '[' request_date ']'                        [06/Feb/2009:12:14:14.655]
    4   frontend_name                                                 https-in
    5   backend_name '/' server_name                               static/srv1
    6   TR '/' Tw '/' Tc '/' Tr '/' Ta*                         10/0/30/69/109
    7   status_code                                                        200
    8   bytes_read*                                                       2750
    9   captured_request_cookie                                              -
   10   captured_response_cookie                                             -
   11   termination_state                                                 ----
   12   actconn '/' feconn '/' beconn '/' srv_conn '/' retries*      1/1/1/1/0
   13   srv_queue '/' backend_queue                                        0/0
   14   '{' captured_request_headers* '}'                     {haproxy.1wt.eu}
   15   '{' captured_response_headers* '}'                                  {}
   16   '"' http_request '"'                        "GET /index.html HTTP/1.1"
   17   fc_err '/' ssl_fc_err '/' ssl_c_err
        '/' ssl_c_ca_err '/' ssl_fc_is_resumed                       0/0/0/0/0
   18   ssl_fc_sni '/' ssl_version
        '/' ssl_ciphers                  1wt.eu/TLSv1.3/TLS_AES_256_GCM_SHA384
```


Подробное описание полей:

- "fc_err" — состояние соединения со стороны фронтенда. Соответствует извлечению образца "fc_err". См. функции извлечения образца "fc_err" и "fc_err_str" для получения дополнительной информации.

- "ssl_fc_err" — последняя ошибка в первом стеке ошибок SSL, возникшем на соединении со стороны фронтенда. Например, это поле позволяет выявлять ошибки согласования SSL. Если всё прошло успешно, значение равно 0. Подробнее см. описание функции извлечения образца "ssl_fc_err".

- "ssl_c_err" — состояние проверки сертификата клиента. Согласование может завершиться успешно даже при ненулевом коде ошибки проверки, если эта ошибка игнорируется. См. функцию извлечения образца "ssl_c_err" и опцию "crt-ignore-err".

- "ssl_c_ca_err" — состояние проверки цепочки сертификатов клиента. Согласование может завершиться успешно даже при ненулевом коде ошибки проверки, если эта ошибка игнорируется. См. функцию извлечения образца "ssl_c_ca_err" и опцию "ca-ignore-err".

- "ssl_fc_is_resumed" истинно, если входящий сеанс TLS возобновлён с помощью кэша состояния или билета без сохранения состояния. Помните, что один сеанс TLS может использоваться несколькими запросами.

- "ssl_fc_sni" — SNI (Server Name Indication), переданный клиентом для выбора сертификата. Обычно он совпадает с именем узла первого запроса в соединении. Отсутствие поля может означать, что клиент не передал SNI; тогда haproxy использует сертификат по умолчанию либо отклоняет соединение при strict-sni.

- "ssl_version" — версия SSL фронтенда.

- "ssl_ciphers" — шифр SSL, используемый в соединении.

### 8.2.5. Формат журнала ошибок {#section-8-2-5}

Если входящее соединение завершается ошибкой из-за согласования SSL или некорректного заголовка протокола PROXY, HAProxy записывает событие в сокращённом фиксированном формате, если строкой "error-log-format" не задан специальный формат журнала ошибок. По умолчанию записи выдаются с уровнем LOG_INFO, но при включённой в бэкенде опции "log-separate-errors" используется LOG_ERR. Соединения без обмена данными, например пробы, не записываются, если задана опция "dontlognull".

Формат по умолчанию выглядит так:

```text
  >>> Dec  3 18:27:14 localhost \
        haproxy[6103]: 127.0.0.1:56059 [03/Dec/2012:17:35:10.380] frt/f1: \
        Connection error during SSL handshake

Поле    Формат                                Фрагмент приведённого примера
```

```text
    1   process_name '[' pid ']:'                             haproxy[6103]:
    2   client_ip ':' client_port                            127.0.0.1:56059
    3   '[' accept_date ']'                       [03/Dec/2012:17:35:10.380]
    4   frontend_name "/" bind_name ":"                              frt/f1:
    5   message                        Connection error during SSL handshake
```

Эти поля дают лишь минимальные сведения для отладки ошибок соединения.

При использовании директивы "error-log-format" описанный выше устаревший формат больше не применяется: все записи ошибок следуют заданному формату.

Ниже приведён пример достаточно полного error-log-format. Он сообщает адрес и порт источника, дату и время принятия соединения вызовом accept(), имя фронтенда, число активных соединений процесса и этого фронтенда, внутренний ID ошибки haproxy на входящем соединении, шестнадцатеричный номер ошибки OpenSSL (его можно скопировать в "openssl errstr" для полной расшифровки), статус извлечения сертификата клиента (0 означает отсутствие ошибки), статус проверки сертификата клиента с использованием CA (0 означает отсутствие ошибки), логический признак нового или возобновлённого соединения, необязательный SNI, переданный клиентом, имя версии SSL и шифры SSL соединения, если они есть. Ошибки соединений с бэкендом здесь никогда не отражаются: чтобы попытка соединения с бэкендом состоялась и могла завершиться ошибкой, поток уже должен был пройти успешную обработку. Поэтому такой случай доступен в обычном журнале трафика (см. option httplog или option
httpslog).

```haproxy
# detailed frontend connection error log
error-log-format "%ci:%cp [%tr] %ft %ac/%fc %[fc_err]/\
      %[ssl_fc_err,hex]/%[ssl_c_err]/%[ssl_c_ca_err]/%[ssl_fc_is_resumed] \
      %[ssl_fc_sni]/%sslv/%sslc"
```

### 8.2.6. Пользовательский формат журнала {#section-8-2-6}

Исторически пользовательские форматы применялись только для журналов. Однако удобство построения строки из нескольких сложных выражений привело к их использованию во многих директивах, которые раньше принимали только строковый аргумент, а теперь также принимают описание пользовательского формата журнала. Такие аргументы, обычно обозначаемые в этом документе как "`<fmt>`", задаются точно так же, как описанный здесь аргумент директивы "log-format".

Если стандартных форматов журнала недостаточно, можно определить новые с очень подробной настройкой. Создать log-format с нуля не всегда просто, поэтому настоятельно рекомендуется сначала изучить существующие форматы ("option tcplog", "option
httplog", "option httpslog"), выбрать наиболее близкий к нужному, скопировать соответствующую строку "log-format" и изменить её.

С точки зрения конфигурации описание пользовательского формата журнала — один аргумент. Поэтому оно не может содержать пробелы или табуляцию, если они не экранированы обратной косой чертой ('&#92;') либо всё описание не заключено в кавычки, что является рекомендуемым способом. Использовать строки формата без кавычек больше не рекомендуется: опыт показал, что они часто приводят к ошибкам, поскольку один пропущенный обратный слеш может вызвать незаметное усечение формата. Такие конфигурации всё ещё распространены из-за массового внедрения форматов журналов после версии 1.5-dev9, за 3 года до появления поддержки кавычек. Теперь рекомендуется преобразовать их в строки в кавычках и убрать обратные слеши.

Описание формата журнала состоит из произвольного числа элементов, разделённых текстом и пробелами. Элемент начинается с '%'. Чтобы вывести сам символ '%', перед ним нужно поставить ещё один '%', получив '%%'.

Элементы logformat могут быть алиасами или выражениями образцов:

Если имя элемента заключено в квадратные скобки ('[' .. ']'), оно используется как правило выражения образца (см. [раздел 7.3](/ru/docs/haproxy/acls-and-samples/#section-7-3)). Это позволяет добавлять менее распространённые сведения, например DN сертификата SSL клиента, или записывать ключ, который использовался бы для хранения записи в таблице привязок. Этот способ также часто применяется в действиях, не связанных с журналом: работе с заголовками, переменными и т. д.

Если же элемент задан буквенно-цифровым именем, это алиас. Список доступных алиасов приведён в таблице ниже.

Элементы могут принимать аргументы в фигурных скобках ('{}'); несколько аргументов разделяются запятыми внутри скобок. Флаги можно добавлять и удалять с помощью префиксов '+' и '-' (список доступных флагов см. ниже).

Специальный алиас "%o" распространяет свои флаги на все остальные элементы logformat в той же строке формата. Это особенно удобно для строковых форматов с кавычками ("Q") и экранированием ("E").

Специальный алиас "%OG" позволяет получить источник записи — когда и где она была создана — в понятном человеку виде. Это особенно полезно с "option logasap": некоторые переменные журнала или функции извлечения образца могут возвращать неполные значения либо вести себя по-разному в зависимости от момента и места вычисления выражения logformat. Возможные значения:

- "sess_error": запись создана при обработке ошибки сеанса
- "sess_killed": запись создана при прерывании сеанса (уничтожен ещё не полностью созданный сеанс)
- "txn_accept": запись создана сразу после принятия соединения фронтендом
- "txn_request": запись создана после получения запроса клиента
- "txn_connect": запись создана после установления соединения с бэкендом
- "txn_response": запись создана при обработке ответа сервера
- "txn_close": запись создана на заключительном этапе txn перед закрытием
- "unspec": источник неизвестен или не указан. "%OG" имеет смысл только в контексте ведения журнала.

Элементам можно задавать имена с помощью ('()'). Имя должно идти сразу после '%' перед аргументами. При включении флага кодирования, например "json" или "cbor", оно автоматически используется как имя ключа. Если флаг кодирования не задан (по умолчанию), имя элемента игнорируется. Также можно принудительно задать тип выводимого значения, добавив ':type' после имени: %(itemname:itemtype)aliasname или %(itemname:itemtype)[expr], где itemtype может быть 'str', 'sint' или 'bool'. Указание типа имеет смысл только при использовании кодирования. Поддерживается и пустое имя, позволяющее задать тип вывода для безымянного элемента: %(:itemtype), то есть когда кодирование не включено глобально. Подробнее см. описание флагов ниже.

Поскольку пользовательские форматы изначально предназначались только для журналов, непечатаемые и небезопасные символы (за пределами кодов ASCII от 32 до 126 и некоторые другие) обрабатываются особо в зависимости от места использования. В [разделе 8.6](/ru/docs/haproxy/configuration-logging/#section-8-6) подробно описана обработка в журналах, предотвращающая вывод небезопасных кодов, которые ухудшают читаемость в терминале. При формировании полей заголовков, проверок работоспособности или содержимого ответов правила менее строгие: только символы, запрещённые в полях заголовков HTTP, заменяются шестнадцатеричным кодом с префиксом '%'. Обычно это не создаёт проблем, но может повлиять на вывод, если символ должен был воспроизводиться буквально, например при построении страницы ошибки или полного тела ответа, где переводы строк могут выглядеть как "%0A".

Примечание: в директивах конфигурации "log-format", "log-format-sd" и "unique-id-format" пробелы считаются разделителями и объединяются.

Примечание: в формате сообщений syslog RFC5424 символы '"', '&#92;' и ']' внутри PARAM-VALUE следует экранировать префиксом '&#92;' (подробнее см. <https://tools.ietf.org/html/rfc5424#section-6.3.3>). В таких случаях стоит рассмотреть флаг "E".

Поддерживаются следующие флаги элементов; их можно включать и выключать в аргументах элемента:

- Q: заключает строку в кавычки
- X: шестнадцатеричное представление (адреса IP, порты, %Ts, %rt, %pid)
- E: экранирует символы '"', '&#92;' и ']' в строке префиксом
  '&#92;' (предназначен для форматов журналов structured-data RFC5424)
- bin: пытается сохранить двоичные данные. Это полезно для выражений образцов,
  возвращающих двоичные данные, чтобы сохранить исходное содержимое. Однако
  возможны непечатаемые символы, включая NULL-байт, которых большинство
  получателей syslog не ожидает. Поэтому флаг предназначен главным образом
  для set-var-fmt, кольцевых буферов и получателей журналов с поддержкой двоичных данных.
  Его можно задать только глобально (через %o); в опциях отдельного элемента он игнорируется.
- json: автоматически кодирует значение в JSON; при глобальном включении учитываются только именованные элементы формата журнала. Неполные числовые значения, например '%B' при использовании logasap, которые без кодирования обычно получают префикс '+', кодируются без изменений. Параметр '+E' также игнорируется. Как описано в [разделе 8.6](/ru/docs/haproxy/configuration-logging/#section-8-6), символы вне диапазона 32..126 экранируются побайтно последовательностями JSON, чтобы при любых входных данных вывод оставался печатным ASCII. Это касается и корректных последовательностей UTF-8: после декодирования текст вне ASCII будет представлен отдельными байтами. Например, U+00E9, закодированный как 0xC3 0xA9, записывается как "&#92;u00C3&#92;u00A9". Для сохранения такого текста см. "utf8" ниже.
- utf8: в сочетании с "json" пропускает корректные многобайтовые последовательности UTF-8 без экранирования. Управляющие символы C1 (от U+0080 до U+009F) по-прежнему экранируются и представляются своей кодовой точкой. Некорректные последовательности экранируются побайтно, чтобы вывод всегда оставался корректным UTF-8. Поскольку корректный UTF-8 выводится без изменений, клиент может специальными символами изменить отображение строки журнала в терминале или просмотрщике, например переключением направления письма, символами нулевой ширины либо разделителями строк и абзацев. Поэтому рекомендуется использовать флаг только для данных из доверенных источников либо когда журналы не предназначены для отображения в терминале. Без "json" он не действует.
- cbor: автоматически кодирует значение в CBOR; при глобальном включении
  учитываются только именованные элементы logformat. По умолчанию данные cbor
  представляются в HEX, чтобы их можно было печатать в stdout и использовать
  с обычными получателями syslog. Как и при кодировании json, неполные числовые
  значения кодируются как есть, а опция '+E' игнорируется. В сочетании с '+bin'
  сразу создаётся необработанная двоичная полезная нагрузка CBOR. При этом
  возникают непечатаемые символы, поэтому такой режим предназначен главным
  образом для set-var-fmt, кольцевых буферов и получателей журналов с поддержкой
  двоичных данных.

Пример:

```text
log-format %T\ %t\ Some\ Text
log-format %{+Q}o\ %t\ %s\ %{-Q}r

log-format-sd %{+Q,+E}o\ [exampleSDID@1234\ header=%[capture.req.hdr(0)]]

log-format "%{+json}o %(request)r %(custom_expr)[str(custom)]"
log-format "%{+json,+utf8}o %(request)r %(custom_expr)[str(custom)]"
log-format "%{+cbor}o %(request)r %(custom_expr)[str(custom)]"
```

Ниже перечислены доступные алиасы:

```text
  +---+------+------------------------------------------------------+---------+
  | R | алиас| имя поля (описание в 8.2.2 и 8.2.3)                  | тип     |
  |   |      | эквивалентное выражение извлечения образца           |         |
  +===+======+======================================================+=========+
  |   | %o   | особый: флаги применяются ко всем следующим элементам|         |
  +---+------+------------------------------------------------------+---------+
  |                          форматы даты                                     |
  +---+------+------------------------------------------------------+---------+
  |   | %T   | Время приёма соединения в UTC + часовой пояс         |         |
  |   |      | %[accept_date,utime("%d/%b/%Y:%H:%M:%S %z")]         | дата    |
  +---+------+------------------------------------------------------+---------+
  |   | %Tl  | Местное время приёма соединения + часовой пояс       |         |
  |   |      | %[accept_date,ltime("%d/%b/%Y:%H:%M:%S %z")]         | дата    |
  +---+------+------------------------------------------------------+---------+
  |   | %Ts  | Время приёма соединения как временная метка UNIX     | число   |
  |   |      | %[accept_date]                                       |         |
  +---+------+------------------------------------------------------+---------+
  |   | %t   | Местное время приёма (точность до миллисекунд)       |         |
  |   |      | %[accept_date(ms),ms_ltime("%d/%b/%Y:%H:%M:%S.%3N")] | дата    |
  +---+------+------------------------------------------------------+---------+
  |   | %ms  | Миллисекунды времени приёма соединения               |         |
  |   |      | %[accept_date(ms),ms_utime("%3N")]                   | число   |
  +---+------+------------------------------------------------------+---------+
  | H | %tr  | Местное время запроса (точность до миллисекунд)      |         |
  |   |      | %[request_date(ms),ms_ltime("%d/%b/%Y:%H:%M:%S.%3N")]| дата    |
  +---+------+------------------------------------------------------+---------+
  | H | %trg | Время запроса в UTC + часовой пояс                   |         |
  |   |      | %[request_date,utime("%d/%b/%Y:%H:%M:%S %z")]        | дата    |
  +---+------+------------------------------------------------------+---------+
  | H | %trl | Местное время запроса + часовой пояс                 |         |
  |   |      | %[request_date,ltime("%d/%b/%Y:%H:%M:%S %z")]        | дата    |
  +---+------+------------------------------------------------------+---------+
  |                          Временные показатели событий                     |
  +---+------+------------------------------------------------------+---------+
  | H | %Ta  | Время активной обработки запроса (от TR до конца)    |         |
  |   |      | %[txn.timer.total]                                   | число   |
  +---+------+------------------------------------------------------+---------+
  |   | %Tc  | Tc                                                   |         |
  |   |      | %[bc.timer.connect]                                  | число   |
  +---+------+------------------------------------------------------+---------+
  |   | %Td  | Td = Tt - (Tq + Tw + Tc + Tr)                        |         |
  |   |      | %[res.timer.data]                                    | число   |
  +---+------+------------------------------------------------------+---------+
  |   | %Th  | Время согласования соединения (SSL, протокол PROXY)  |         |
  |   |      | %[fc.timer.handshake]                                | число   |
  +---+------+------------------------------------------------------+---------+
  | H | %Ti  | Время простоя перед запросом HTTP                    |         |
  |   |      | %[req.timer.idle]                                    | число   |
  +---+------+------------------------------------------------------+---------+
  | H | %Tq  | Th + Ti + TR                                         |         |
  |   |      | %[req.timer.tq]                                      | число   |
  +---+------+------------------------------------------------------+---------+
  | H | %TR  | Время приёма полного запроса с 1-го байта            |         |
  |   |      | %[req.timer.hdr]                                     | число   |
  +---+------+------------------------------------------------------+---------+
  | H | %Tr  | Tr (время ответа)                                    |         |
  |   |      | %[res.timer.hdr]                                     | число   |
  +---+------+------------------------------------------------------+---------+
  |   | %Tt  | Tt                                                   |         |
  |   |      | %[fc.timer.total]                                    | число   |
  +---+------+------------------------------------------------------+---------+
  |   | %Tu  | Tu                                                   |         |
  |   |      | %[txn.timer.user]                                    | число   |
  +---+------+------------------------------------------------------+---------+
  |   | %Tw  | Tw                                                   |         |
  |   |      | %[req.timer.queue]                                   | число   |
  +---+------+------------------------------------------------------+---------+
  |                          Прочее                                           |
  +---+------+------------------------------------------------------+---------+
  |   | %B   | bytes_read           (от сервера к клиенту)          | число   |
  |   |      | %[res.bytes_in]                                      |         |
  +---+------+------------------------------------------------------+---------+
  | H | %CC  | captured_request_cookie                              | строка  |
  +---+------+------------------------------------------------------+---------+
  | H | %CS  | captured_response_cookie                             | строка  |
  +---+------+------------------------------------------------------+---------+
  |   | %H   | hostname                                             | строка  |
  |   |      | %[hostname]                                          |         |
  +---+------+------------------------------------------------------+---------+
  | H | %HM  | Метод HTTP (например, POST)                          | строка  |
  |   |      | %[method]
  +---+------+------------------------------------------------------+---------+
  | H | %HP  | URI запроса HTTP без строки параметров               | строка  |
  +---+------+------------------------------------------------------+---------+
  | H | %HPO | Только путь HTTP (без узла и строки параметров)      | строка  |
  +---+------+------------------------------------------------------+---------+
  | H | %HQ  | Строка параметров URI HTTP (например, ?bar=baz)      | строка  |
  |   |      | ?%[query]                                            |         |
  +---+------+------------------------------------------------------+---------+
  | H | %HU  | URI запроса HTTP (например, /foo?bar=baz)            | строка  |
  +---+------+------------------------------------------------------+---------+
  | H | %HV  | Версия HTTP (например, HTTP/1.0)                     | строка  |
  |   |      | HTTP/%[req.ver]                                      |         |
  +---+------+------------------------------------------------------+---------+
  |   | %ID  | unique-id                                            | строка  |
  |   |      | %[unique-id]                                         |         |
  +---+------+------------------------------------------------------+---------+
  |   | %ST  | status_code                                          | число   |
  |   |      | %[txn.status]                                        |         |
  +---+------+------------------------------------------------------+---------+
  |   | %U   | bytes_uploaded       (от клиента к серверу)          | число   |
  |   |      | %[req.bytes_in]                                      |         |
  +---+------+------------------------------------------------------+---------+
  |   | %ac  | actconn                                              |         |
  |   |      | %[act_conn]                                          | число   |
  +---+------+------------------------------------------------------+---------+
  |   | %b   | backend_name                                         |         |
  |   |      | %[be_name]                                           | строка  |
  +---+------+------------------------------------------------------+---------+
  |   | %bc  | beconn      (одновременные соединения бэкенда)       | число   |
  |   |      | %[be_conn]                                           |         |
  +---+------+------------------------------------------------------+---------+
  |   | %bi  | backend_source_ip       (адрес исходящего соединения)|         |
  |   |      | %[bc_src]                                            | IP      |
  +---+------+------------------------------------------------------+---------+
  |   | %bp  | backend_source_port     (адрес исходящего соединения)|         |
  |   |      | %[bc_src_port]                                       | число   |
  +---+------+------------------------------------------------------+---------+
  |   | %bq  | backend_queue                                        | число   |
  |   |      | %[bc_be_queue]                                       |         |
  +---+------+------------------------------------------------------+---------+
  |   | %ci  | client_ip                (адрес принятого соединения)|         |
  |   |      | %[src]                                               | IP      |
  +---+------+------------------------------------------------------+---------+
  |   | %cp  | client_port              (адрес принятого соединения)|         |
  |   |      | %[src_port]                                          | число   |
  +---+------+------------------------------------------------------+---------+
  |   | %f   | frontend_name                                        | строка  |
  |   |      | %[fe_name]                                           |         |
  +---+------+------------------------------------------------------+---------+
  |   | %fc  | feconn     (одновременные соединения фронтенда)      | число   |
  |   |      | %[fe_conn]                                           |         |
  +---+------+------------------------------------------------------+---------+
  |   | %fi  | frontend_ip              (адрес приёма соединений)   |         |
  |   |      | %[dst]                                               | IP      |
  +---+------+------------------------------------------------------+---------+
  |   | %fp  | frontend_port            (адрес приёма соединений)   |         |
  |   |      | %[dst_port]                                          | число   |
  +---+------+------------------------------------------------------+---------+
  |   | %ft  | frontend_name_transport (суффикс '~' для SSL)        | строка  |
  +---+------+------------------------------------------------------+---------+
  |   | %lc  | frontend_log_counter                                 | число   |
  +---+------+------------------------------------------------------+---------+
  |   | %hr  | captured_request_headers в стиле по умолчанию        | строка  |
  +---+------+------------------------------------------------------+---------+
  |   | %hrl | captured_request_headers в стиле CLF                 | строка  |
  |   |      |                                                      | список  |
  +---+------+------------------------------------------------------+---------+
  |   | %hs  | captured_response_headers в стиле по умолчанию       | строка  |
  +---+------+------------------------------------------------------+---------+
  |   | %hsl | captured_response_headers в стиле CLF                | строка  |
  |   |      |                                                      | список  |
  +---+------+------------------------------------------------------+---------+
  | L | %OG  | Источник записи журнала в понятном человеку виде     | строка  |
  +---+------+------------------------------------------------------+---------+
  |   | %pid | PID                                                  |         |
  |   |      | %[pid]                                               | число   |
  +---+------+------------------------------------------------------+---------+
  | H | %r   | http_request                                         | строка  |
  +---+------+------------------------------------------------------+---------+
  |   | %rc  | retries                                              | число   |
  |   |      | %[txn.redispatched,iif(+,)]%[txn.conn_retries]       |         |
  +---+------+------------------------------------------------------+---------+
  |   | %rt  | request_counter (запрос HTTP или сеанс TCP)          | число   |
  |   |      | %[txn.id32]                                          |         |
  +---+------+------------------------------------------------------+---------+
  |   | %s   | server_name                                          | строка  |
  |   |      | %[srv_name]                                          |         |
  +---+------+------------------------------------------------------+---------+
  |   | %sc  | srv_conn     (одновременные соединения сервера)      | число   |
  +---+------+------------------------------------------------------+---------+
  |   | %si  | server_IP                   (адрес назначения)       |         |
  |   |      | %[bc_dst]                                            | IP      |
  +---+------+------------------------------------------------------+---------+
  |   | %sp  | server_port                 (адрес назначения)       |         |
  |   |      | %[bc_dst_port]                                       | число   |
  +---+------+------------------------------------------------------+---------+
  |   | %sq  | srv_queue                                            | число   |
  |   |      | %[bc_srv_queue]                                      |         |
  +---+------+------------------------------------------------------+---------+
  | S | %sslc| ssl_ciphers (например, AES-SHA)                      |         |
  |   |      | %[ssl_fc_cipher]                                     | строка  |
  +---+------+------------------------------------------------------+---------+
  | S | %sslv| ssl_version (например, TLSv1)                        |         |
  |   |      | %[ssl_fc_protocol]                                   | строка  |
  +---+------+------------------------------------------------------+---------+
  |   | %ts  | termination_state                                    | строка  |
  |   |      | %[txn.sess_term_state]                               |         |
  +---+------+------------------------------------------------------+---------+
  | H | %tsc | termination_state со статусом cookie                 | строка  |
  +---+------+------------------------------------------------------+---------+
```

    R = Ограничения: H = только режим http; S = только SSL; L = только журнал

## 8.3. Расширенные параметры ведения журнала {#section-8-3}

Некоторые расширенные параметры журналирования нужны часто, но их нелегко найти простым просмотром опций. Здесь собрано несколько опций, позволяющих улучшить ведение журнала. Подробнее об их использовании см. справочник ключевых слов.

### 8.3.1. Отключение записи внешних проверок {#section-8-3-1}

Инструменты мониторинга часто проверяют работоспособность HAProxy. Это может быть балансировщик уровня 3, например LVS или коммерческий балансировщик, либо более полноценная система мониторинга, например Nagios. При очень частых проверках пользователи часто спрашивают, как отключить их запись в журнал. Есть три возможности:

- Если соединения приходят из разных источников и представляют собой лишь пробы TCP, обычно удобно отключить запись соединений без обмена данными, задав "option dontlognull" во фронтенде. Это также отключает запись сканирования портов, что может быть как желательным, так и нежелательным.

- Можно использовать действие "http-request set-log-level silent" с различными условиями: исходными сетями, путями, пользовательскими агентами и т. д.

- Если проверки обращаются к известному URI, с помощью "monitor-uri" можно выделить этот URI для мониторинга. Любой узел, отправивший такой запрос, получит только результат проверки работоспособности, а сам запрос не будет записан в журнал.

### 8.3.2. Запись журнала до завершения потока {#section-8-3-2}

При записи журнала в конце соединения невозможно узнать, что происходит во время очень долгих потоков, например сеансов удалённого терминала или скачивания больших файлов. Это можно обойти, задав во фронтенде "option logasap". Тогда HAProxy выдаёт запись как можно раньше, непосредственно перед началом передачи данных. Для TCP в журнал по-прежнему попадёт состояние соединения с сервером, а для HTTP запись выдаётся сразу после обработки заголовков сервера. В этом случае указанное число байтов — это число байтов заголовков, отправленных клиенту. Чтобы отличать такие записи от обычных, перед полями полного времени и числа байтов ставится '+': реальные значения заведомо больше.

### 8.3.3. Повышение уровня журнала при ошибках {#section-8-3-3}

Иногда удобнее отделять журналы ошибок от обычного трафика, например для упрощения контроля ошибок по файлам журналов. При использовании "log-separate-errors" для соединений с ошибками, тайм-аутами, повторными попытками, перенаправлениями или кодами состояния HTTP 5xx уровень syslog повышается с "info" до "err". Это позволяет демону syslog сохранять записи в отдельный файл. Очень важно также оставлять ошибки в файле обычного трафика, чтобы порядок записей не нарушался. Следует быть осторожным, если демон syslog уже настроен сохранять все записи выше "notice" в файл "admin": уровень "err" выше "notice".

### 8.3.4. Отключение записи успешных соединений {#section-8-3-4}

Хотя поначалу это может показаться странным, некоторые крупные сайты обрабатывают по несколько тысяч записей журнала в секунду и испытывают трудности с их длительным сохранением в полном объёме или поиском ошибок среди них. Если во фронтенде задана "dontlog-normal", все нормальные соединения исключаются из журнала. Нормальным здесь считается соединение без ошибок, тайм-аутов, повторных попыток и перенаправлений. В HTTP также проверяется код состояния: ответ 5xx не считается нормальным и тоже записывается. Однако этот способ настоятельно не рекомендуется, поскольку убирает из журналов большую часть полезной информации. Применяйте его только при отсутствии альтернатив.

### 8.3.5. Профили журналов {#section-8-3-5}

Директивы "log-format", "log-format-sd", "error-log-format" и "log-tag" позволяют задавать форматирование журналов глобально или на уровне прокси. Однако иногда полезно задавать эти параметры как можно ближе к получателям журналов, то есть для каждой директивы "log".

Для этого служит секция "log-profile": "log-profile" можно определить в любом месте конфигурации. Она принимает набор ключевых слов, описывающих построение записей для определённой директивы `log`.

В директиве "log" можно выбрать конкретный log-profile по имени. Один профиль может использоваться несколькими директивами "log".

log-profile `<name>` Создаёт новый профиль журнала с именем `<name>`

log-tag `<string>` Переопределяет тег syslog, заданный глобально или для прокси директивой "log-tag".

on `<step>` [drop] [format `<fmt>`] [sd `<sd_fmt>`] Переопределяет строку log-format, обычно используемую для построения записи на этапе `<step>`. `<fmt>` заменяет строку "log-format" или "error-log-format" в зависимости от `<step>`, а `<sd_fmt>` заменяет строку "log-format-sd"; оба параметра можно сочетать.

Специальное ключевое слово "drop" указывает, что на данном этапе `<step>` запись не должна выдаваться. Оно имеет приоритет над ранее заданными "format" и "sd".

Возможные значения `<step>`:

- "accept" : переопределяет log-format, если запись создаётся сразу после принятия соединения фронтендом
- "request" : переопределяет log-format, если запись создаётся после получения запроса клиента
- "connect" : переопределяет log-format, если запись создаётся после установления соединения с бэкендом
- "response": переопределяет log-format, если запись создаётся при обработке ответа сервера
- "close" : переопределяет log-format, если запись создаётся на заключительном этапе транзакции (txn)
- "error" : переопределяет error-log-format, если запись создаётся из-за ошибки транзакции
- "any" : переопределяет log-format и error-log-format для всех этапов, если не задано
  переопределение для более конкретного этапа.

Дополнительные применимые значения `<step>` см. в описании действия "do-log".

Эта настройка имеет смысл только для директив "log" в контекстах, где применима директива "log-format", например для прокси http и tcp. В остальных случаях она просто игнорируется.

Пример:

```text
log-profile myprof

  log-tag "custom-tag"

  on error format "%ci: error"
  on connect drop
  on any sd "custom-sd"

listen myproxy
  mode http
  option httplog
  log-tag "normal"

  log stdout format rfc5424 local0
  # success:
  # <134>1 2024-06-12T10:09:11.823400+02:00 - normal 224482 - - 127.0.0.1:53594 [12/Jun/2024:10:09:11.814] myproxy myproxy/<NOSRV> 0/-1/-1/-1/0 200 49 - - LR-- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
  #
  # error:
  # <134>1 2024-06-12T10:09:44.810929+02:00 - normal 224482 - - 127.0.0.1:59258 [12/Jun/2024:10:09:44.426] myproxy myproxy/<NOSRV> -1/-1/-1/-1/384 400 0 - - CR-- 1/1/0/0/0 0/0 "<BADREQ>"

  log 127.0.0.1:514 format rfc5424 profile myprof local0
  # success:
  # <134>1 2024-06-12T10:09:11.823428+02:00 - custom-tag 224482 - custom-sd 127.0.0.1:53594 [12/Jun/2024:10:09:11.814] myproxy myproxy/<NOSRV> 0/-1/-1/-1/0 200 49 - - LR-- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
  #
  # error:
  # <134>1 2024-06-12T10:09:51.566524+02:00 - custom-tag 224482 - - 127.0.0.1: error
```

## 8.4. Временные показатели событий {#section-8-4}

Таймеры существенно помогают при поиске сетевых проблем. Все значения указаны в миллисекундах (ms). Их следует использовать вместе с флагами завершения потока. В режиме TCP с "option tcplog" во фронтенде выводятся 3 контрольные точки в виде "Tw/Tc/Tt", а в режиме HTTP — 5 в виде "TR/Tw/Tc/Tr/Ta". Дополнительно доступны ещё три показателя: "Th", "Ti" и "Tq".

Временные показатели событий в режиме HTTP:

```text
                 первый запрос               2-й запрос
      |<-------------------------------->|<-------------- ...
      t         tr                       t    tr ...
   ---|----|----|----|----|----|----|----|----|--
     : Th   Ti   TR   Tw   Tc   Tr   Td: Ti   ...
     :<---- Tq ---->:                  :
     :<-------------- Tt -------------->:
     :<--        -----Tu--------------->:
               :<--------- Ta --------->:
```

Временные показатели событий в режиме TCP:

```text
           Сеанс TCP
      |<----------------->|
      t                   t
   ---|----|----|----|----|---
      | Th   Tw   Tc   Td |
      |<------ Tt ------->|
```

- Th: полное время принятия соединения tcp и согласования низкоуровневых протоколов. Сейчас это proxy-protocol и SSL. Такое согласование возможно только один раз за всё время жизни соединения. Большое значение может означать, что клиент заранее установил соединение, но не передаёт данные, что сетевые проблемы мешают ему завершить согласование за разумное время (например, проблемы MTU) либо что согласование SSL потребовало больших вычислительных затрат. Это время указывается только перед первым запросом, поэтому его можно усреднять по всем запросам, распределяя затраты между ними. Для второго и последующих запросов здесь всегда указывается ноль.

  Этот таймер доступен как алиас log-format %Th и функция извлечения образца fc.timer.handshake.

- Ti: время простоя перед запросом HTTP (только режим HTTP). Таймер отсчитывает время от окончания согласования до первого байта запроса HTTP. Для второго запроса в режиме keep-alive отсчёт начинается после окончания передачи предыдущего ответа. Для мультиплексированного протокола, например HTTP/2, — сразу после предыдущего запроса. Некоторые браузеры заранее устанавливают соединения с сервером, чтобы уменьшить задержку будущего запроса, и оставляют их в ожидании до необходимости. Эта задержка отражается как время простоя. Значение -1 означает, что по соединению ничего не было получено.

  Этот таймер доступен как алиас log-format %Ti и функция извлечения образца req.timer.idle.

- TR: полное время получения запроса клиента (только режим HTTP). Это время от получения первых байтов до получения прокси пустой строки, отмечающей конец заголовков HTTP. Значение "-1" означает, что конец заголовков так и не был получен: клиент преждевременно закрыл соединение или истёк тайм-аут. Обычно время очень мало, поскольку большинство запросов помещается в один пакет. Большое значение может указывать на ручной ввод запроса во время тестирования.

  Этот таймер доступен как алиас log-format %TR и функция извлечения образца req.timer.hdr.

- Tq: полное время получения запроса клиента с момента принятия соединения либо отправки последнего байта предыдущего ответа (только режим HTTP). Оно в точности равно Th + Ti + TR, кроме случая, когда хотя бы одно из этих значений равно -1: тогда результат тоже -1. Этот таймер был очень полезен до появления HTTP keep-alive и упреждающих подключений браузеров. Сейчас рекомендуется заменить его на TR, поскольку время простоя вносит много шума в отчёты.

  Этот таймер доступен как алиас log-format %Tq и функция извлечения образца req.timer.tq.

- Tw: общее время ожидания свободного места для соединения в очередях. Учитываются очередь бэкенда и очереди серверов; время зависит от размера очереди и времени, нужного серверу для завершения предыдущих запросов. Значение "-1" означает, что запрос прерван до попадания в очередь, что обычно происходит с некорректными или запрещёнными запросами.

  Этот таймер доступен как алиас log-format %Tw и функция извлечения образца req.timer.queue.

- Tc: полное время установления соединения TCP с сервером. Это время между отправкой прокси запроса на соединение и его подтверждением сервером, то есть между пакетом TCP SYN и соответствующим ответным SYN/ACK. Значение "-1" означает, что соединение так и не было установлено.

  Этот таймер доступен как алиас log-format %Tc и функция извлечения образца bc.timer.connect.

- Tr: время ответа сервера (только режим HTTP). Это время от установления соединения TCP с сервером до отправки сервером всех заголовков ответа. Оно отражает только время обработки запроса, без сетевых издержек передачи данных. Однако если клиенту нужно отправить данные серверу, например при запросе POST, отсчёт уже идёт, и это может исказить видимое время ответа. Поэтому обычно не стоит слишком полагаться на это поле для запросов POST от клиентов из ненадёжной сети. Значение "-1" означает, что последний заголовок ответа (пустая строка) так и не был получен, скорее всего из-за истечения тайм-аута сервера до завершения обработки запроса либо некорректного ответа сервера.

  Этот таймер доступен как алиас log-format %Tr и функция извлечения образца res.timer.hdr.

- Td: полное время передачи полезной нагрузки ответа до отправки клиенту последнего байта. В HTTP отсчёт начинается после последнего заголовка ответа (после Tr).

  Получение отправленных данных клиентом не гарантируется: они могут задержаться в ядре или сети.

  Этот таймер доступен как алиас log-format %Td и функция извлечения образца res.timer.data.

- Ta: полное время активности запроса HTTP от получения прокси первого байта заголовка запроса до отправки последнего байта тела ответа. Исключение — заданная опция "logasap": тогда оно равно только (TR+Tw+Tc+Tr) и начинается со знака '+'. Из этого поля можно вычислить "Td", время передачи данных, вычтя остальные таймеры с допустимыми значениями:

```text
Td = Ta - (TR + Tw + Tc + Tr)
```

    Таймеры со значением "-1" необходимо исключить из этого уравнения.
    "Ta" никогда не может быть отрицательным.

    Этот таймер доступен как алиас log-format %Ta и функция извлечения
    образца txn.timer.total.

- Tt: полная длительность потока от принятия его прокси до закрытия обеих сторон. Исключение — заданная опция "logasap": тогда значение равно только (Th+Ti+TR+Tw+Tc+Tr) и начинается со знака '+'. Из этого поля можно вычислить "Td", время передачи данных, вычтя остальные таймеры с допустимыми значениями:

```text
Td = Tt - (Th + Ti + TR + Tw + Tc + Tr)
```

    Таймеры со значением "-1" необходимо исключить из этого уравнения.
    В режиме TCP также необходимо исключить "Ti", "Tq" и "Tr".
    "Tt" никогда не может быть отрицательным, а для HTTP Tt просто
    равно (Th+Ti+Ta).

    Этот таймер доступен как алиас log-format %Tt и функция извлечения
    образца fc.timer.total.

- Tu: оценка полного времени с точки зрения клиента от принятия соединения прокси до закрытия обеих сторон, без времени простоя. Она помогает приблизительно измерить сквозное время так, как его видит пользователь, без влияния простоя keep-alive между запросами. Это лишь оценка пользовательского времени, поскольку предполагается одинаковая сетевая задержка в обоих направлениях. Исключение — заданная опция "logasap": тогда значение равно только (Th+TR+Tw+Tc+Tr) и начинается со знака '+'.

  Этот таймер доступен как алиас log-format %Tu и функция извлечения образца txn.timer.user.

Эти таймеры дают ценные подсказки о причинах проблем. Поскольку протокол TCP задаёт задержки повторной передачи 3, 6, 12... секунд, значения, близкие к кратным 3s, почти всегда связаны с потерей пакетов из-за сетевых проблем: кабелей, согласования или перегрузки. Кроме того, если "Ta" или "Tt" близко к тайм-ауту из конфигурации, это часто означает, что поток прерван по тайм-ауту.

Наиболее частые случаи:

- Если "Th" или "Ti" близки к 3000, вероятно, между клиентом и прокси был потерян пакет. В локальных сетях это очень редко, но возможно для клиентов в далёких удалённых сетях, отправляющих большие запросы. Повышенные значения могут появляться и без сетевой причины. Иногда во время атаки или сразу после устранения нехватки ресурсов HAProxy принимает тысячи соединений за несколько миллисекунд. Время на их принятие неизбежно немного задерживает обработку других соединений, поэтому после одновременного принятия нескольких тысяч новых соединений время запроса может составлять несколько десятков миллисекунд. В режимах keep-alive время простоя может быть больше, поскольку "Ti" измеряет ожидание дополнительных запросов.

- Если "Tc" близко к 3000, при установлении соединения с сервером, вероятно, был потерян пакет между сервером и прокси. Это значение всегда должно быть очень малым: например, 1 ms в локальной сети и менее нескольких десятков ms в удалённых сетях.

- Если "Tr" почти всегда ниже 3000, за исключением редких значений, похожих на среднее плюс 3000, вероятно, между прокси и сервером теряются пакеты.

- Если "Ta" велико даже при малом числе байтов, обычно причина в том, что ни клиент, ни сервер не закрывают соединение: HAProxy работает в туннельном режиме, а обе стороны согласовали keep-alive. Для решения потребуется задать во фронтенде или бэкенде одну из опций HTTP, управляющих keep-alive или закрытием соединения. При регулировании соединений через серверную опцию "maxconn" важно свести 'Ta' или 'Tt' к минимуму: новое соединение не направляется на сервер, пока не освободится другое.

Другие примечательные случаи в журнале HTTP ('xx' означает любое значение, которое можно игнорировать):

```text
TR/Tw/Tc/Tr/+Ta  Во фронтенде задано "option logasap", и запись журнала
                 выдана до фазы передачи данных. Все таймеры достоверны,
                 кроме "Ta", значение которого меньше действительного.

-1/xx/xx/xx/Ta   Клиент не успел отправить полный запрос или слишком рано
                 прервал соединение. Проверьте флаги завершения потока,
                 затем настройки "timeout http-request" и "timeout client".

TR/-1/xx/xx/Ta   Обработать запрос не удалось: возможно, серверы не работали,
                 запрос был некорректен или запрещён правилами ACL.
                 Проверьте флаги завершения потока.

TR/Tw/-1/xx/Ta   Установить соединение с сервером не удалось: он либо явно
                 отказал в соединении, либо истёк тайм-аут через Ta-(TR+Tw) ms.
                 Проверьте флаги завершения потока, затем настройку
                 "timeout connect". Действие tarpit может давать похожие
                 последовательности, где "Tw" равно времени, в течение
                 которого соединение с клиентом оставалось открытым.

TR/Tw/Tc/-1/Ta   Сервер принял соединение, но не успел вернуть полный ответ
                 или неожиданно закрыл соединение через Ta-(TR+Tw+Tc) ms.
                 Проверьте флаги завершения потока, затем настройку
                 "timeout server".
```

## 8.5. Состояние потока при разрыве соединения {#section-8-5}

В журналах TCP и HTTP поле "termination_state" непосредственно перед числом активных соединений содержит индикатор завершения потока. В режиме TCP он состоит из 2 символов, а в режиме HTTP — из 4. У каждого символа своё значение:

- Первый символ — код первого события, вызвавшего завершение потока:

```text
C: клиент неожиданно прервал сеанс TCP.

S: сервер неожиданно прервал сеанс TCP или явно отказал в соединении.

P: прокси преждевременно прервал поток или сеанс из-за ограничения числа
    соединений, совпадения с фильтром DENY либо проверки безопасности,
    которая обнаружила и заблокировала опасную ошибку в ответе сервера,
    способную вызвать утечку информации (например, кэшируемый cookie).

L: поток обработан локально HAProxy.

R: на прокси исчерпан ресурс (память, сокеты, исходные порты и т. д.).
    Обычно это происходит на этапе соединения; системные журналы должны
    содержать копию точного сообщения об ошибке. Такое событие должно
    рассматриваться как очень серьёзная аномалия, которую следует устранить
    как можно скорее любыми средствами.

I: при самопроверке прокси обнаружил внутреннюю ошибку. Этого НИКОГДА
    не должно происходить; рекомендуется сообщать о любой записи журнала
    с этим флагом, поскольку почти наверняка это программная ошибка.
    После такого события разумно также в качестве предосторожности
    перезапустить процесс на случай, если причина — повреждение памяти.

D: HAProxy завершил поток, поскольку сервер признан недоступным и настроен
    на завершение всех соединений при переходе в недоступное состояние.

U: HAProxy завершил поток на этом резервном сервере, поскольку активный
    сервер признан доступным и настроен на завершение всех соединений
    с резервными серверами при переходе в доступное состояние.

K: администратор принудительно завершил поток средствами HAProxy.

c: истёк тайм-аут на стороне клиента при ожидании отправки или получения
    данных клиентом.

s: истёк тайм-аут на стороне сервера при ожидании отправки или получения
    данных сервером.

-: нормальное завершение потока; клиент и сервер закрыли соединение,
    в буферах не осталось данных.
```

- Второй символ — состояние потока TCP или HTTP в момент закрытия:

```text
R: прокси ожидал полный корректный ЗАПРОС от клиента (только в режиме HTTP).
    Ни одному серверу ничего не было отправлено.

Q: прокси ожидал в ОЧЕРЕДИ свободное место для соединения. Это возможно
    только при заданном у серверов параметре 'maxconn'. Также это возможно
    в общей очереди после повторного распределения вслед за неудачной
    попыткой соединиться с отказывающим сервером. Если повторное
    распределение не отмечено, попыток соединения с серверами не было.

C: прокси ожидал установления СОЕДИНЕНИЯ с сервером. Сервер мог заметить
    максимум попытку соединения.

H: прокси ожидал полные корректные ЗАГОЛОВКИ ответа сервера
    (только HTTP).

D: поток находился в фазе передачи ДАННЫХ.

L: прокси ещё передавал ПОСЛЕДНИЕ данные клиенту, а сервер уже завершил
    работу. Это очень редкий случай: он возможен только при отказе клиента
    во время получения последних пакетов.

T: запрос попал в ловушку соединений (tarpit). Соединение с клиентом
    оставалось открытым в течение всего "timeout tarpit" или до закрытия
    клиентом; в обоих случаях длительность отражается в таймере "Tw".

-: нормальное завершение потока после окончания передачи данных.
```

- Третий символ указывает, передал ли клиент cookie привязки (только в режиме HTTP):

```text
N: клиент НЕ передал cookie. Это обычно бывает у новых посетителей,
    поэтому подсчёт этого флага в журналах обычно достоверно отражает
    динамику посещаемости сайта.

I: клиент передал НЕДЕЙСТВИТЕЛЬНЫЙ cookie, не соответствующий ни одному
    известному серверу. Возможные причины: недавнее изменение конфигурации,
    смешение cookie сайтов HTTP/HTTPS, условное игнорирование привязки
    сеанса или атака.

D: клиент передал cookie, указывающий на НЕДОСТУПНЫЙ сервер. Если задано
    "option persist", клиент был направлен на этот сервер; если эта опция
    не задана, клиент был перенаправлен на другой сервер.

V: клиент передал ДЕЙСТВИТЕЛЬНЫЙ cookie и был направлен на связанный
    с ним сервер.

E: клиент передал действительный cookie, но последняя дата в нём старше,
    чем допускает параметр cookie "maxidle", поэтому cookie считается
    ПРОСРОЧЕННЫМ и игнорируется. Запрос будет распределён заново,
    как если бы cookie отсутствовал.

O: клиент передал действительный cookie, но первая дата в нём старше,
    чем допускает параметр cookie "maxlife", поэтому cookie считается
    слишком СТАРЫМ и игнорируется. Запрос будет распределён заново,
    как если бы cookie отсутствовал.

U: cookie присутствовал, но не использовался для выбора сервера,
    поскольку применялся другой механизм выбора (обычно правило
    "use-server").

-: неприменимо (cookie не задан в конфигурации).
```

- Последний символ сообщает, какие операции выполнены с cookie привязки, возвращённым сервером (только в режиме HTTP):

```text
N: сервер НЕ передал cookie, и прокси также не вставил его.

I: сервер не передал cookie, и прокси ВСТАВИЛ его. В режиме "cookie insert",
    если сервер передаёт cookie, тот всё равно перезаписывается
    и здесь отмечается как "I".

U: прокси ОБНОВИЛ последнюю дату в cookie, переданном клиентом. Это возможно
    только в режиме insert с "maxidle" и происходит при активности
    с датой, отличающейся от указанной в cookie. При любом другом изменении,
    например повторном распределении, cookie вместо этого отмечается
    как вставленный.

P: сервер ПЕРЕДАЛ cookie, который был отправлен без изменений.

R: прокси ПЕРЕПИСАЛ cookie сервера; это происходит в режимах
    "cookie rewrite" или "cookie prefix".

D: прокси УДАЛИЛ cookie, переданный сервером.

-: неприменимо (cookie не задан в конфигурации).
```

Сочетание первых двух флагов даёт много сведений о том, что происходило при завершении потока или сеанса и почему он завершился. Это помогает обнаруживать перегрузку серверов, сетевые проблемы, нехватку локальных системных ресурсов, атаки и т. д.

Ниже приведены наиболее частые сочетания флагов завершения. Они отсортированы по алфавиту, причём строчные буквы идут сразу после соответствующих прописных для удобства поиска и понимания.

Флаги Причина

     --   Нормальное завершение.

     CC   Клиент прервал соединение до его установления с сервером.
          Это возможно, когда HAProxy пытается подключиться к недавно
          отказавшему или непроверенному серверу, а клиент прерывает
          соединение, пока HAProxy ждёт ответа сервера или истечения
          "timeout connect".

     CD   Клиент неожиданно прервал соединение при передаче данных.
          Причиной может быть сбой браузера, принудительный разрыв
          соединения оборудованием между клиентом и HAProxy, проблемы
          сетевой маршрутизации между клиентом и HAProxy либо поток
          keep-alive между сервером и клиентом, который первым завершил
          клиент.

     cD   Клиент не отправлял и не подтверждал данные в течение
          "timeout client". Частые причины — сетевые сбои на стороне
          клиента или его отключение от сети без корректного завершения.

     CH   Клиент прервал соединение в ожидании начала ответа сервера.
          Возможно, сервер отвечал слишком долго или клиент слишком
          быстро нажал кнопку 'Stop'.

     cH   "timeout client" истёк при ожидании данных клиента во время
          запроса POST. Иногда причина в слишком больших значениях TCP MSS
          для сетей PPPoE, которые не могут передавать полноразмерные пакеты.
          Это также возможно, если тайм-аут клиента меньше серверного,
          а сервер отвечает слишком долго.

     CQ   Клиент прервал соединение, пока его поток стоял в очереди
          в ожидании сервера с достаточным числом свободных мест.
          Возможно, все серверы были перегружены либо назначенный сервер
          отвечал слишком долго.

     CR   Клиент прервал соединение, не отправив полный запрос HTTP.
          Вероятнее всего, запрос вводился вручную через клиент telnet
          и был прерван слишком рано. Здесь вероятен код состояния HTTP 400.
          Иногда причиной бывает IDS, разрывающая соединение между HAProxy
          и клиентом. "option http-ignore-probes" позволяет игнорировать
          соединения без передачи данных.

     cR   "timeout http-request" истёк до отправки клиентом полного запроса
          HTTP. Иногда причина в слишком больших значениях TCP MSS у клиента
          для сетей PPPoE, которые не могут передавать полноразмерные пакеты,
          либо в слишком медленном ручном вводе запроса или пропуске пустой
          строки в его конце. Здесь вероятен код состояния HTTP 408.
          Примечание: недавно некоторые браузеры начали реализовывать
          "pre-connect" — упреждающее подключение к недавно посещённым сайтам
          на случай, если пользователь захочет открыть их снова. В результате
          устанавливается много соединений с сайтами. Они заканчиваются
          ошибкой 408
          Request Timeout, если первым истечёт тайм-аут, или
          400 Bad Request, если браузер первым решит их закрыть. Такие случаи
          засоряют журнал и увеличивают счётчики ошибок. Сообщалось даже,
          что некоторые версии некоторых браузеров показывают код ошибки.
          Чтобы обойти нежелательные последствия, можно добавить "option
          http-ignore-probes" во фронтенд: тогда соединения без передачи
          данных полностью игнорируются. Однако это также полностью скроет
          ошибки пользователей с проблемами подключения.

     CT   Клиент прервал соединение, пока его поток находился в tarpit.
          Важно проверить, происходит ли это с корректными запросами,
          чтобы убедиться в отсутствии ошибочных правил tarpit. Если таких
          случаев много, имеет смысл уменьшить "timeout tarpit" до значения,
          близкого к среднему значению таймера "Tw", чтобы не расходовать
          ресурсы лишь на нескольких атакующих.

     LC   Запрос перехвачен и обработан локально самим HAProxy.
          На сервер запрос не отправлялся. Это возможно только при
          перенаправлении из-за параметра "redir" в строке server.

     LR   Запрос перехвачен и обработан локально самим HAProxy.
          На сервер запрос не отправлялся. Обычно это означает возврат
          перенаправления, выполнение директивы HTTP return либо обработку
          запроса апплетом (stats, cache, экспортёр Prometheus, апплет lua...).

     LH   Ответ перехвачен и обработан локально самим HAProxy. Обычно это
          означает возврат перенаправления или выполнение директивы HTTP return.

     SC   Сервер или оборудование между ним и HAProxy явно отказали
          в соединении TCP: прокси получил в ответ TCP RST или сообщение ICMP.
          Иногда так сетевой стек сообщает прокси о недоступности сервера,
          например при отсутствии маршрута или ответа ARP в локальной сети.
          В режиме HTTP код состояния в этом случае, вероятно, будет 502
          или 503.

     sC   "timeout connect" истёк до установления соединения с сервером.
          В режиме HTTP код состояния в этом случае, вероятно, будет
          503 или 504.

     SD   Соединение с сервером завершилось с ошибкой во время передачи
          данных. Обычно это означает, что при обмене данными с сервером
          HAProxy получил от него RST или сообщение ICMP от промежуточного
          оборудования. Причиной может быть аварийное завершение сервера
          или сетевая проблема на промежуточном оборудовании.

     sD   На этапе передачи данных сервер не отправлял и не подтверждал
          данные в течение времени "timeout server". Частые причины —
          слишком короткие тайм-ауты на оборудовании L4 перед сервером
          (межсетевые экраны, балансировщики нагрузки и т. д.) либо сеансы
          keep-alive между клиентом и сервером, которые раньше всего
          истекают на HAProxy.

     SH   Сервер прервал соединение до отправки всех заголовков ответа HTTP
          либо аварийно завершился при обработке запроса. Прерывание сервером
          на этом этапе встречается очень редко, поэтому стоит проверить
          его журналы: не было ли сбоя и чем он вызван. Запрос в журнале
          может помочь выделить небольшой набор проблемных запросов,
          указывающих на ошибки приложения. Иногда причиной бывает IDS,
          разрывающая соединение между HAProxy и сервером.

     sH   "timeout server" истёк до того, как сервер вернул заголовки ответа.
          Это наиболее частая аномалия: транзакции длятся слишком долго,
          вероятно, из-за перегрузки сервера или базы данных. Временное
          решение — увеличить "timeout server", но следует помнить, что
          столь долгий ответ ухудшает работу пользователей. Единственное
          долговременное решение — исправить приложение.

     sQ   Поток провёл слишком много времени в очереди и завершился
          по тайм-ауту. Если это происходит слишком часто, см. параметры
          "timeout queue" и "timeout connect". Частые массовые случаи
          в короткие промежутки могут указывать на общие проблемы
          затронутых серверов из-за перегрузки ввода-вывода или базы данных
          либо на перегрузку из-за внешних атак.

     PC   Прокси отказался устанавливать соединение с сервером, поскольку
          при попытке подключения был достигнут лимит сокетов процесса.
          Чтобы это больше не повторялось, в конфигурации можно увеличить
          глобальный параметр "maxconn". Этот статус встречается очень редко
          и может возникать при ручном задании глобального "ulimit-n".

     PD   Прокси заблокировал сообщение с неверным форматом chunked-кодирования
          в запросе или ответе после того, как сервер отправил заголовки.
          В большинстве случаев это указывает на некорректное сообщение
          от сервера клиенту. HAProxy поддерживает размеры блоков до
          2GB - 1 (2147483647 байт). Любой больший размер считается ошибкой.

     PH   Прокси заблокировал ответ сервера, потому что он был некорректным,
          неполным, опасным с точки зрения управления кэшем или соответствовал
          фильтру безопасности. В любом случае клиенту отправляется ошибка
          HTTP 502. Возможная причина — неверный синтаксис имени заголовка HTTP
          с недопустимыми символами. Ещё возможно, хотя и редко, что прокси
          до ответа сервера заблокировал запрос клиента с chunked-кодированием
          из-за неверного синтаксиса. Тогда клиенту отправляется ошибка
          HTTP 400, которая также записывается в журнал. Наконец, причиной
          может быть ошибка перезаписи заголовка HTTP в ответе. В этом случае
          отправляется ошибка HTTP 500; подробнее см. "tune.maxrewrite"
          и "http-response strict-mode".

     PR   Прокси заблокировал запрос HTTP клиента либо из-за неверного
          синтаксиса HTTP, вернув клиенту ошибку HTTP 400, либо из-за
          совпадения с запрещающим фильтром, вернув ошибку HTTP 403.
          Причиной также может быть ошибка перезаписи заголовка HTTP
          в запросе. Тогда отправляется ошибка HTTP 500; подробнее см.
          "tune.maxrewrite" и "http-request strict-mode".

     PT   Прокси заблокировал запрос клиента и задержал его соединение
          в tarpit, прежде чем вернуть ошибку сервера 500. На сервер ничего
          не отправлялось. Соединение оставалось открытым в течение времени,
          указанного в поле таймера "Tw".

     RC   Локальный ресурс (память, сокеты, исходные порты) исчерпан,
          что не позволило установить соединение с сервером. Журналы ошибок
          точно укажут, чего не хватило. Это очень редкий случай, который
          устраняется только правильной настройкой системы.

Сочетание двух последних флагов даёт много сведений о том, как клиент, сервер и HAProxy обрабатывали привязку сеанса. Это очень важно при поиске причин разрывов соединений, когда пользователи жалуются на необходимость повторной аутентификации. Часто встречаются следующие флаги:

```text
--   Cookie привязки сеанса не включён.

NN   Клиент не передал cookie, и в ответ cookie не вставлен. Например,
     это возможно в режиме insert с "postonly" для запроса GET.

II   Клиент передал cookie, указывающий на недействительный сервер;
     в ответ вставлен действительный cookie. Обычно это происходит
     после удаления записи "server" из конфигурации: клиент может
     передать её значение cookie, неизвестное остальным серверам.

NI   Клиент не передал cookie, и в ответ вставлен cookie. Обычно это
     происходит при первом запросе каждого пользователя в режиме "insert",
     что позволяет легко подсчитывать реальных пользователей.

VN   Клиент передал cookie, и в ответ cookie не вставлен. Это происходит
     для большинства ответов клиентам, у которых cookie уже есть.

VU   Клиент передал cookie с не вполне актуальной датой последнего визита,
     поэтому в ответ отправлен обновлённый cookie. Это также возможно,
     если даты не было вообще либо дата была, но параметр "maxidle"
     не задан: тогда cookie может стать бессрочным.

EI   Клиент передал cookie с датой последнего визита, слишком старой
     для параметра "maxidle"; cookie проигнорирован, и в ответ вставлен
     новый cookie.

OI   Клиент передал cookie с датой первого визита, слишком старой
     для параметра "maxlife"; cookie проигнорирован, и в ответ вставлен
     новый cookie.

DI   Сервер, указанный в cookie, был недоступен; выбран новый сервер,
     и в ответ отправлен новый cookie.

VI   Сервер, указанный в cookie, не был отмечен как недоступный, но связаться
     с ним не удалось. При повторном распределении выбран другой сервер,
     который затем был указан в ответе.
```

## 8.6. Непечатаемые символы {#section-8-6}

Чтобы при просмотре журналов не возникало проблем с анализаторами или терминалами, непечатаемые символы не записываются в файлы журналов как есть. Вместо этого используется двухзначное шестнадцатеричное представление их кода ASCII с префиксом '#'. Без экранирования можно записывать только символы с кодами от 32 до 126 включительно. Сам символ экранирования '#' также кодируется во избежание неоднозначности ("#23"). То же относится к символу '"', который превращается в "#22", а при записи заголовков — к символам '{', '\|' и '}'.

Это не относится к кодированию cbor, которое уже использует безопасные шестнадцатеричные цифры либо корректно разделённые двоичные блоки. Такие блоки не отправляются в терминал, а обрабатываются парсером CBOR.

Кодирование json вместо этого использует escape-последовательности JSON, а опция +utf8 также пропускает корректные многобайтовые последовательности UTF-8 без изменений (см. флаг "utf8" в [разделе 8.2.6](/ru/docs/haproxy/configuration-logging/#section-8-2-6)).

Пробел (' ') в заголовках не кодируется. Это может создавать проблемы для инструментов, которые определяют расположение полей по числу пробелов. Типичный заголовок, содержащий пробелы, — "User-Agent".

Наконец, некоторые демоны syslog, например syslog-ng, экранируют кавычку ('"') обратной косой чертой ('&#92;'). Обратное преобразование безопасно, поскольку в других местах журнала кавычки появляться не могут.

## 8.7. Захват cookie HTTP {#section-8-7}

Захват cookie упрощает отслеживание всего пользовательского сеанса. Для этого во фронтенде используется директива "capture cookie". Подробнее см. [раздел 4.2](/ru/docs/haproxy/proxies/#section-4-2). Можно захватить только один cookie, причём один и тот же cookie одновременно проверяется в запросе (заголовок "Cookie:") и ответе (заголовок "Set-Cookie:"). Соответствующие значения записываются в поля "captured_request_cookie" и "captured_response_cookie" журнала HTTP (о формате журнала HTTP см. [раздел
8.2.3](/ru/docs/haproxy/configuration-logging/#section-8-2-3)). Если какой-либо из cookie не обнаружен, вместо его значения ставится дефис ('-'). Так легко заметить, например, переход пользователя к новому сеансу: сервер назначит ему новый cookie. Также можно выявить неожиданную отправку сервером неверного cookie клиенту, приводящую к смешению сеансов.

Примеры:

```shell
# capture the first cookie whose name starts with "ASPSESSION"
capture cookie ASPSESSION len 32

# capture the first cookie whose name is exactly "vgnvisitor"
capture cookie vgnvisitor= len 32
```

Более сложный захват можно выполнить с помощью правил "http-request" и "http-response", присваивая cookie переменным с областью видимости "txn". Значения cookie извлекаются из запроса или ответа функциями извлечения образца "req.cook" и "res.cook" (см. [раздел 7.3.6](/ru/docs/haproxy/acls-and-samples/#section-7-3-6)) и присваиваются переменной действиями "set-var" или "set-var-fmt" (см. [раздел 4.3](/ru/docs/haproxy/proxies/#section-4-3)). Пользовательский log-format позволяет вывести эти переменные в нужном месте (см. [раздел 8.2.6](/ru/docs/haproxy/configuration-logging/#section-8-2-6)).

## 8.8. Захват заголовков HTTP (устаревший способ) {#section-8-8}

Захват заголовков помогает отслеживать уникальные ID запросов, заданные вышестоящим прокси, имена виртуальных узлов, пользовательские агенты, длину содержимого POST, источники переходов и т. д. В ответе можно искать сведения о его длине, указания сервера для кэша или местоположение объекта при перенаправлении.

Заголовки можно захватывать двумя способами. Современный способ — задавать переменные из захватываемых заголовков или составных образцов, возвращаемых "req.hdr_names", "req.hdrs", "res.hdr_names", "res.hdrs" (все возможности см. в [разделе 7.3.6](/ru/docs/haproxy/acls-and-samples/#section-7-3-6)). Их можно присваивать переменным с областью видимости "txn" действиями "set-var" и "set-var-fmt" из наборов правил "http-request" и "http-response" (см. [раздел 4.3](/ru/docs/haproxy/proxies/#section-4-3)), а затем ссылаться на переменные в пользовательских форматах журналов (см. [раздел 8.2.6](/ru/docs/haproxy/configuration-logging/#section-8-2-6)). Это рекомендуемый способ захвата заголовков HTTP.

Есть и устаревший способ, появившийся раньше правил http-request и переменных. Он не требует изменения формата журнала и долгое время использовался как для ведения журнала, так и в качестве обходного способа передавать сведения о запросе на протяжении всей транзакции HTTP с помощью старых наборов правил "capture". Именно этот способ описан в данном разделе.

При устаревшем способе заголовки захватываются директивами "capture request header" и "capture response
header" во фронтенде. Подробнее см. их описание в [разделе 4.2](/ru/docs/haproxy/proxies/#section-4-2).

Можно одновременно включить заголовки запроса и ответа. Отсутствующие заголовки записываются как пустые строки; если заголовок встречается несколько раз, записывается только последнее вхождение. Заголовки запроса группируются между фигурными скобками '{' и '}' в порядке объявления и разделяются вертикальной чертой '\|' без пробелов. Заголовки ответа представляются так же, но выводятся после блока заголовков запроса через пробел. Эти блоки располагаются в журнале непосредственно перед запросом HTTP.

В качестве особого случая захват заголовков HTTP можно настроить во фронтенде TCP. Это позволяет записывать заголовки, которые будут разобраны бэкендом HTTP, если запрос затем направляется в этот бэкенд HTTP.

Пример:

```shell
# This instance chains to the outgoing proxy
listen proxy-out
    mode http
    option httplog
    option logasap
    log global
    server cache1 192.168.1.1:3128

    # log the name of the virtual server
    capture request  header Host len 20

    # log the amount of data uploaded during a POST
    capture request  header Content-Length len 10

    # log the beginning of the referrer
    capture request  header Referer len 20

    # server name (useful for outgoing proxies only)
    capture response header Server len 20

    # logging the content-length is useful with "option logasap"
    capture response header Content-Length len 10

    # log the expected cache behavior on the response
    capture response header Cache-Control len 8

    # the Via header will report the next proxy's name
    capture response header Via len 20

    # log the URL location during a redirection
    capture response header Location len 20
```

```text
    >>> Aug  9 20:26:09 localhost \
          haproxy[2022]: 127.0.0.1:34014 [09/Aug/2004:20:26:09] proxy-out \
          proxy-out/cache1 0/0/0/162/+162 200 +350 - - ---- 0/0/0/0/0 0/0 \
          {fr.adserver.yahoo.co||http://fr.f416.mail.} {|864|private||} \
          "GET http://fr.adserver.yahoo.com/"
```

```text
    >>> Aug  9 20:30:46 localhost \
          haproxy[2022]: 127.0.0.1:34020 [09/Aug/2004:20:30:46] proxy-out \
          proxy-out/cache1 0/0/0/182/+182 200 +279 - - ---- 0/0/0/0/0 0/0 \
          {w.ods.org||} {Formilux/0.1.8|3495|||} \
          "GET http://trafic.1wt.eu/ HTTP/1.1"
```

```text
    >>> Aug  9 20:30:46 localhost \
          haproxy[2022]: 127.0.0.1:34028 [09/Aug/2004:20:30:46] proxy-out \
          proxy-out/cache1 0/0/2/126/+128 301 +223 - - ---- 0/0/0/0/0 0/0 \
          {www.sytadin.equipement.gouv.fr||http://trafic.1wt.eu/} \
          {Apache|230|||http://www.sytadin.} \
          "GET http://www.sytadin.equipement.gouv.fr/ HTTP/1.1"
```

## 8.9. Примеры журналов {#section-8-9}

Ниже приведены практические примеры журналов с пояснениями. Некоторые из них составлены вручную. Для удобства чтения часть syslog удалена. Единственная цель примеров — объяснить, как их расшифровывать.

    >>> haproxy[674]: 127.0.0.1:33318 [15/Oct/2003:08:31:57.130] px-http &#92;
          px-http/srv1 6559/0/7/147/6723 200 243 - - ---- 5/3/3/1/0 0/0 &#92;
          "HEAD / HTTP/1.0"

    => длительный ввод запроса (6.5s) вручную через 'telnet'. Сервер ответил
       за 147 ms, сеанс завершился нормально ('----')

    >>> haproxy[674]: 127.0.0.1:33319 [15/Oct/2003:08:31:57.149] px-http &#92;
          px-http/srv1 6559/1230/7/147/6870 200 243 - - ---- 324/239/239/99/0 &#92;
          0/9 "HEAD / HTTP/1.0"

    => то же самое, но запрос попал в общую очередь после 9 других запросов
       и ожидал в ней 1230 ms.

```text
    >>> haproxy[674]: 127.0.0.1:33320 [15/Oct/2003:08:32:17.654] px-http \
          px-http/srv1 9/0/7/14/+30 200 +243 - - ---- 3/3/3/1/0 0/0 \
          "GET /image.iso HTTP/1.0"
```

    => запрос на длительную передачу данных. Задана опция "logasap", поэтому
       запись журнала выдана непосредственно перед передачей данных. Сервер
       ответил за 14 ms, клиенту отправлено 243 байта заголовков, а общее время
       от принятия соединения до первого байта данных составило 30 ms.

    >>> haproxy[674]: 127.0.0.1:33320 [15/Oct/2003:08:32:17.925] px-http &#92;
          px-http/srv1 9/0/7/14/30 502 243 - - PH-- 3/2/2/0/0 0/0 &#92;
          "GET /cgi-bin/bug.cgi? HTTP/1.0"

    => прокси заблокировал ответ сервера из-за правила "http-response
       deny", неверного формата ответа, не соответствующего HTTP,
       либо наличия конфиденциальных данных, которые могли попасть
       в кэш. В этом случае ответ заменяется на "502 bad
       gateway". Флаги ("PH--") показывают, что вернуть 502 решил
       HAProxy, а не сервер.

    >>> haproxy[18113]: 127.0.0.1:34548 [15/Oct/2003:15:18:55.798] px-http &#92;
          px-http/`<NOSRV>` -1/-1/-1/-1/8490 -1 0 - - CR-- 2/2/2/0/0 0/0 ""

    => клиент так и не завершил запрос и сам прервал его ("C---") через
       8.5s, пока прокси ожидал заголовки запроса ("-R--").
       Ни на один сервер ничего не отправлялось.

    >>> haproxy[18113]: 127.0.0.1:34549 [15/Oct/2003:15:19:06.103] px-http &#92;
         px-http/`<NOSRV>` -1/-1/-1/-1/50001 408 0 - - cR-- 2/2/2/0/0 0/0 ""

    => клиент так и не завершил запрос; он был прерван по тайм-ауту
       ("c---") через 50s, пока прокси ожидал заголовки запроса
       ("-R--"). Ни на один сервер ничего не отправлялось, но прокси
       смог отправить клиенту код ответа 408.

    >>> haproxy[18989]: 127.0.0.1:34550 [15/Oct/2003:15:24:28.312] px-tcp &#92;
          px-tcp/srv1 0/0/5007 0 cD 0/0/0/0/0 0/0

    => эта запись журнала создана с "option tcplog". Тайм-аут клиента
       истёк через 5 секунд ("c----").

    >>> haproxy[18989]: 10.0.0.1:34552 [15/Oct/2003:15:26:31.462] px-http &#92;
          px-http/srv1 3183/-1/-1/-1/11215 503 0 - - SC-- 205/202/202/115/3 &#92;
          0/0 "HEAD / HTTP/1.0"

    => приём запроса занял 3s (вероятно, из-за сетевой проблемы), а
       соединение с сервером не удалось установить ('SC--') после 4 попыток
       по 2 секунды (в конфигурации задано 'retries 3'). Перенаправления
       не было, иначе мы увидели бы "/+3". Клиенту вернулся код состояния 503.
       На этом сервере было 115 соединений, на этом прокси — 202,
       а у процесса в целом — 205. Возможно, сервер отказал в соединении
       из-за слишком большого числа уже установленных соединений.

---

Обратные ссылки:

- [7. ACL и образцы](/ru/docs/haproxy/acls-and-samples/)
- [2. Основы конфигурации](/ru/docs/haproxy/configuration-basics/)
- [10. FastCGI](/ru/docs/haproxy/fastcgi/)
- [3. Секция global](/ru/docs/haproxy/global/)
- [4. Прокси](/ru/docs/haproxy/proxies/)
