> For the complete documentation index, see [llms.txt](https://docs.ipcheck.ing/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ipcheck.ing/developer/ru/configuration/logging.md).

# Логирование

Оба процесса Node — backend API и сервер статических файлов — пишут в один общий [pino](https://getpino.io/) логгер. Им управляют три переменные окружения. Все три необязательны.

| Переменная   | Значения                              | По умолчанию |
| ------------ | ------------------------------------- | ------------ |
| `LOG_LEVEL`  | `debug` / `info` / `warn` / `ошибкой` | `info`       |
| `LOG_FORMAT` | `json`, или что угодно еще            | pretty       |
| `LOG_HTTP`   | `"true"`                              | из           |

Всё идёт в stdout. Встроенного файла журнала нет — за него отвечает ваш менеджер процессов (pm2, systemd, Docker).

## `LOG_LEVEL`

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

* `debug` — всё, включая многословные сообщения об обновлении наборов данных. Полезно, когда загрузка MaxMind или CAIDA ведёт себя странно.
* `info` — по умолчанию. Строки запуска, загрузка наборов данных, планы запланированных задач.
* `warn` — только деградация: IP с ограничением по частоте, частичные сбои вышестоящих сервисов, тайм-ауты.
* `ошибкой` — только сбои обработчиков.

{% hint style="info" %}
`LOG_LEVEL` также управляет тем, что попадает в Sentry. Мост Sentry установлен внутри логгера, поэтому строка, подавленная уровнем, никогда не становится логом или issue в Sentry. См. [Мониторинг ошибок](/developer/ru/configuration/error-monitoring.md).
{% endhint %}

## `LOG_FORMAT`

### Красивый вывод (по умолчанию)

Оставьте `LOG_FORMAT` пустым, и вывод пойдёт через `pino-pretty`: с цветовой разметкой, по одной строке на событие, локальные для хоста временные метки со смещением UTC, `pid` и `имя хоста` опущен.

```
[2026-07-14 10:23:45.221 +0800] INFO: 🚀 Backend server ready on http://localhost:11966
```

Это то, что вам нужно для `pnpm dev` и для чтения `pm2 logs` или `docker logs` вручную.

### JSON

```bash
LOG_FORMAT="json"
```

Вывод становится одним необработанным JSON-объектом на строку — нативный формат pino — без цветов и ANSI-экранирований:

```json
{"level":30,"time":1752459825221,"msg":"🚀 Сервер backend готов на http://localhost:11966"}
{"level":40,"time":1752460013887,"ip":"203.0.113.45","msg":"IP ограничен по частоте"}
{"level":50,"time":1752460101044,"err":{"type":"Error","message":"Вышестоящий сервис ответил 429"},"ip":"1.1.1.1","msg":"обработчик ipinfo-io завершился с ошибкой"}
```

Примечания к полям:

* `level` — числовой: `20` debug, `30` info, `40` warn, `50` error.
* `time` — это миллисекунды Unix-времени.
* `msg` — это понятное человеку сообщение.
* Любые другие ключи — это структурированный контекст, который добавил вызывающий код — `ip`, `ASN`, `префикс`, `err`, и так далее.

Используйте JSON, когда логи читает кто-то кроме человека. ANSI-коды цвета в режиме pretty сбивают с толку большинство парсеров.

## `LOG_HTTP`

```bash
LOG_HTTP="true"
```

Включает логирование каждого запроса для `/api/*` только маршрутов. По умолчанию выключено, чтобы логи менеджера процессов оставались читаемыми.

```
INFO: GET /api/ipinfo?ip=1.1.1.1 → 200
WARN: GET /api/report/abc → 404
```

Детали, которые стоит знать:

* Каждый запрос логирует метод, URL, код ответа и время отклика.
* Уровень соответствует результату: `5xx` или выброшенная ошибка → `ошибкой`, `4xx` → `warn`, всё остальное → `info`.
* middleware подключён **до** перед ограничителем частоты запросов, поэтому `429` ответы тоже логируются. См. [Параметры безопасности](/developer/ru/configuration/security-options.md).
* Ошибки на уровне обработчика логируются независимо от этого флага — `LOG_HTTP` добавляет успешные запросы, а не ошибки.

{% hint style="warning" %}
URL запросов содержат параметры строки запроса, включая IP-адреса, которые ищут посетители. На публичном экземпляре это персональные данные. Включайте `LOG_HTTP` для отладки, а затем снова выключайте — или убедитесь, что это покрывается вашей политикой хранения.
{% endhint %}

## Чтение успешного запуска

Строки запуска начинаются с эмодзи, чтобы можно было оценить загрузку с одного взгляда.

| Строка                                                                            | Значение                                                                               |
| --------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| `📝 Логирование HTTP-запросов включено (LOG_HTTP=true)`                           | `LOG_HTTP` включено                                                                    |
| `🛡️ Ограничитель частоты включён — N запросов в …`                               | `SECURITY_RATE_LIMIT` задано                                                           |
| `🐢 Ограничитель скорости включён — замедление после N запросов`                  | `SECURITY_DELAY_AFTER` задано                                                          |
| `📥 Базы данных MaxMind отсутствуют; выполняется попытка первой загрузки …`       | Первый запуск, GeoLite2 загружается                                                    |
| `📦 Базы данных MaxMind загружены (…)`                                            | Геолокация готова                                                                      |
| `📦 CAIDA as2org загружена (…)` / `📦 CAIDA as-rel загружена (…)`                 | Имена организаций ASN и граф связности готовы                                          |
| `🗓️ … план автообновления: следующая проверка в …`                               | Запланированное обновление набора данных активировано                                  |
| `📦 Кэш статуса сервиса подготовлен`                                              | Страница статуса сервиса содержит данные                                               |
| `🛰️ Мониторинг backend в Sentry включён`                                         | `SENTRY_DSN_BACKEND` задано                                                            |
| `🚀 Бэкенд-сервер готов на http://localhost:11966`                                | API принимает трафик                                                                   |
| `🚀 Сервер статических файлов готов на http://localhost:18966`                    | SPA обслуживается                                                                      |
| `❌ API MaxMind будет возвращать 503, пока базы данных не будут успешно загружены` | **Проблема** — см. [Настройка MaxMind](/developer/ru/getting-started/maxmind-setup.md) |

Оба `🚀` строки говорят `localhost` потому что это адрес, к которому процесс привязывается внутри своего хоста или контейнера. Это не подсказка о вашем публичном URL.

## Отправка JSON-логов

Set `LOG_FORMAT="json"` и пусть ваша платформа собирает stdout. Больше ничего в приложении менять не нужно.

{% tabs %}
{% tab title="Docker" %}

```bash
docker run -d -p 18966:18966 \
  -e LOG_FORMAT="json" \\
  -e LOG_LEVEL="info" \
  --log-driver=json-file \\
  --name myip \
  jason5ng32/myip:latest
```

После этого любой драйвер логирования Docker или sidecar-сборщик (Vector, Fluent Bit, Promtail, агент Datadog) подхватывает строки. Каждая строка уже является валидным JSON, так что многострочный или regex-разбор не нужен.
{% endtab %}

{% tab title="pm2" %}
{% code title=".env" %}

```bash
LOG_FORMAT="json"
LOG_LEVEL="info"
```

{% endcode %}

pm2 записывает stdout в собственные файлы логов; укажите вашему сборщику эти пути (`pm2 info <name>` показывает их).

{% hint style="warning" %}
pm2 делает снимок переменных окружения при первом запуске процесса. `pm2 restart` воспроизводит старый снимок. После изменения `.env`, сделайте `pm2 delete <name> && pm2 start ecosystem.config.cjs && pm2 save`.
{% endhint %}
{% endtab %}

{% tab title="Разовое использование / jq" %}

```bash
# Только ошибки, самые свежие первыми
docker logs myip 2>&1 | jq -c 'select(.level >= 50)'

# Какие IP были ограничены по частоте
docker logs myip 2>&1 | jq -r 'select(.msg == "IP rate-limited") | .ip' | sort | uniq -c

# Снова отформатировать JSON-поток для чтения человеком
docker logs myip 2>&1 | npx pino-pretty
```

{% endtab %}
{% endtabs %}

Разумная базовая конфигурация для продакшена: `LOG_FORMAT="json"`, `LOG_LEVEL="info"`, `LOG_HTTP` выключено. Добавляйте `LOG_HTTP="true"` временно, когда нужна видимость по каждому запросу.

## Связанные страницы

* [Мониторинг ошибок](/developer/ru/configuration/error-monitoring.md) — как `warn` и `ошибкой` строки попадают в Sentry
* [Параметры безопасности](/developer/ru/configuration/security-options.md) — события, стоящие за `IP ограничен по частоте` предупреждениями
* [Переменные окружения](/developer/ru/reference/environment-variables.md) — полный список
* [Backend](/developer/ru/architecture/backend.md) — где логгер находится в пути запроса


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.ipcheck.ing/developer/ru/configuration/logging.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
