Магазин на 1С-Битрикс живёт своей жизнью: посетители оформляют заказы, ночью запускаются агенты, идёт обмен с 1С, отрабатывают интеграции с платёжными и складскими сервисами. Пока всё работает, о логах никто не вспоминает. А потом в понедельник утром выясняется, что заказы вторые сутки не выгружаются в учётную систему, часть покупателей видела «белый экран» на оплате, а менеджеры узнали об этом от разгневанных клиентов, а не от сайта. Разница между «узнали через минуту» и «узнали через двое суток» — это и есть отладка Битрикс, выстроенная как система: журнал событий, свои логи, режим отладки, мониторинг ошибок и алерты.
Эта статья — практическая карта того, как видеть, что происходит внутри магазина, и находить проблемы раньше пользователей. Разберём встроенный журнал событий Битрикса (Настройки → Журнал событий) и что туда писать; собственные логи через AddMessage2Log и файловые логгеры; уровни логирования; режим отладки и exception_handling в .settings.php; ошибки PHP — error_reporting и display_errors на dev против выключения на prod; фатальные ошибки и белый экран; отладку обмена с 1С и агентов; монитор производительности и медленные запросы БД; внешние сервисы мониторинга ошибок (Sentry-подобные, обзорно); алерты, логи веб-сервера и php-fpm, ротацию логов и безопасную отладку прямо на проде. Материал вырос из практики нашей технической поддержки 1С-Битрикс, где скорость обнаружения ошибки напрямую влияет на выручку клиента.
Коротко
- Журнал событий (Настройки → Журнал событий) — первое место диагностики: обмен, почта, права, вход, ошибки модулей. Аудит событий должен быть включён.
- Свои логи пишут через
AddMessage2Logи собственные файловые логгеры с уровнями DEBUG/INFO/WARNING/ERROR — но для записи нужен включённыйexception_handling.logв.settings.php. - Dev против prod: на разработке
display_errors = Onиdebug = true; на проде ошибки только в лог, пользователю — аккуратная страница, без стек-трейсов. - Мониторинг — это монитор производительности ядра, медленные запросы БД, логи php-fpm и веб-сервера плюс внешний сервис мониторинга ошибок для агрегации и алертов.
- Алерты и ротация: уведомления об упавшем обмене, всплеске 500-х и нехватке места на диске;
logrotate, чтобы логи не забили диск и сами не уронили сайт.
Зачем магазину логирование и мониторинг
Есть соблазн относиться к логам как к чему-то «для галочки»: работает же сайт, зачем что-то писать в файлы. Но у логирования и мониторинга сугубо денежная функция — сокращать время между сбоем и его починкой. Каждая минута, что оформление заказа отдаёт ошибку, а вы об этом не знаете, — это потерянные заказы и подорванное доверие. Логи и алерты превращают «невидимый» сбой в видимый и адресный.
Практически хорошо выстроенное логирование решает три задачи:
- Обнаружение. Узнать о проблеме раньше пользователя. Алерт об упавшем обмене или всплеске 500-х приходит вам, а не приходит жалоба от клиента.
- Диагностика. Когда проблема уже случилась, лог отвечает на вопрос «что именно и где сломалось»: какой запрос, какие данные, на каком шаге, у какого пользователя.
- Предотвращение. Тренды в логах — медленные запросы, участившиеся предупреждения, растущее число ошибок валидации — сигнализируют о проблеме до того, как она станет аварией.
Обратная сторона — цена отсутствия. Проект без логов диагностируется методом «включим отладку на проде и посмотрим» — а это и утечка данных, и лишняя нагрузка, и потерянные часы. Проект с логами, но без мониторинга, знает о своих ошибках, но узнаёт о них слишком поздно. Цель этой статьи — собрать обе половины: аккуратную запись того, что происходит, и своевременное уведомление, когда что-то идёт не так.
Как ошибка проходит путь от сбоя до разработчика
Прежде чем нырять в конкретные механизмы, полезно увидеть общий маршрут. Любая проблема в магазине проходит один и тот же путь: где-то происходит сбой (исключение, фатальная ошибка PHP, ошибка обмена), он фиксируется в логе (журнал событий, файл, внешний сервис), по определённым условиям срабатывает алерт, и уведомление доходит до человека, который может починить. Цель инженера — сделать каждое звено этой цепочки надёжным и быстрым.
Если хоть одно звено выпадает, система «слепнет». Сбой без логирования — вы не узнаете, что случилось. Лог без алерта — узнаете, но случайно и поздно. Алерт без адресата — уведомление уходит «в никуда». Поэтому логирование проектируют как сквозной поток, а не как отдельные не связанные друг с другом файлы.
Журнал событий Битрикса: что это и как включить
Журнал событий — встроенный механизм платформы для фиксации значимых событий системы. Открывается он в административной части: Настройки → Инструменты → Журнал событий (в части сборок пункт лежит прямо как Настройки → Журнал событий). Это первое, куда стоит смотреть при любом «что-то отвалилось», потому что сюда ядро и модули пишут ошибки обмена, почты, прав доступа и многого другого без всякого участия разработчика.
Чтобы журнал реально писался, аудит событий должен быть включён. Настройка живёт в параметрах модуля main (Настройки → Настройки продукта → Настройки модулей → Главный модуль), где включают ведение журнала и отмечают, какие типы событий фиксировать: ошибки, аудит безопасности, действия пользователей и так далее. Отдельно задаётся срок хранения записей — чтобы таблица журнала не разрасталась бесконечно.
Важно понимать, что журнал событий хранится в базе данных (таблица журнала), а не в файле. Это удобно для просмотра через админку с фильтрами, но означает, что при очень большом потоке событий журнал добавляет нагрузку на базу. Поэтому в него пишут значимые события, а не отладочный «шум» с каждого запроса — для потокового детального лога лучше подходят файлы, о которых ниже.
Что писать в журнал событий и как его читать
По каждому событию журнал показывает набор полей, по которым и ведут диагностику: время, тип события (он же уровень серьёзности и категория), модуль-источник, идентификатор пользователя, а также текст с деталями. Читать журнал — значит фильтровать: по типу события, по дате, по модулю. Когда вы знаете, что «отвалился обмен», вы фильтруете журнал по соответствующему типу и сразу видите цепочку ошибок с текстами.
Типовые события, которые платформа пишет сама:
- Ошибки обмена с 1С. Проблемы импорта каталога и выгрузки заказов по CommerceML — один из самых частых поводов заглянуть в журнал.
- Ошибки отправки почты. Не ушло письмо о заказе, не сработало событие почты — журнал зафиксирует ошибку почтовой подсистемы.
- Безопасность и доступ. Неудачные попытки входа, блокировки проактивной защитой, изменения прав доступа и групп.
- Ошибки модулей и агентов. Сбои в agent-заданиях и модулях, если те настроены писать в журнал.
Свои события в журнал добавляют штатной функцией CEventLog::Add(). Это правильный инструмент именно для значимых бизнес-событий, которые важно видеть в общей ленте админки: например, ручная отмена крупного заказа, срабатывание критичной ветки бизнес-логики или ошибка интеграции, о которой должен знать администратор.
<?php
// Запись собственного значимого события в журнал Битрикса
\CEventLog::Add([
'SEVERITY' => 'WARNING', // уровень: SECURITY / WARNING / INFO / ERROR / DEBUG
'AUDIT_TYPE' => 'SHOP_PAYMENT_FAILED', // свой код типа события — по нему потом фильтруют
'MODULE_ID' => 'sale', // модуль-источник
'ITEM_ID' => $orderId, // к чему относится (ID заказа)
'DESCRIPTION' => 'Платёж по заказу не подтверждён шлюзом: код '.$gatewayCode,
]);
Ключ здесь — осмысленный AUDIT_TYPE: по нему вы потом отфильтруете именно свои события среди сотен системных. Не сваливайте в журнал отладочный поток — для него есть файловые логи. В журнал событий пишите то, что администратор магазина должен увидеть в ленте: важные бизнес-инциденты и ошибки интеграций.
Свои логи: AddMessage2Log
Самый простой встроенный способ записать что-то в лог ядра — функция AddMessage2Log(). Она пишет строку в файл журнала ошибок, который настроен в .settings.php. В отличие от журнала событий, это именно файловый лог: он не грузит базу и подходит для более частых, технических записей.
<?php
// Простейшая запись в файловый лог ядра
AddMessage2Log('Не удалось получить остаток по товару '.$productId, 'shop.stock');
// Можно передать не только строку, но и данные — они будут сериализованы
AddMessage2Log([
'context' => 'checkout',
'order' => $orderId,
'error' => $errorMessage,
], 'shop.checkout');
Первый аргумент — текст или данные (массив/объект сериализуется в читаемый вид), второй — код модуля-источника, чтобы потом было понятно, откуда запись. Критично: чтобы AddMessage2Log реально писала в файл, в .settings.php должна быть включена секция exception_handling с подсекцией log и указан файл лога. Без этого вызовы функции молча теряются — это одна из самых частых причин «я пишу в лог, а там пусто».
Минимальная настройка секции лога в /bitrix/.settings.php выглядит так:
<?php
// фрагмент /bitrix/.settings.php
return [
// ...
'exception_handling' => [
'value' => [
'debug' => false, // на проде — false
'handled_errors_types' => E_ALL & ~E_STRICT & ~E_NOTICE,
'exception_errors_types' => E_ALL & ~E_STRICT & ~E_NOTICE,
'log' => [
'settings' => [
'file' => '/local/logs/error.log', // куда писать
'log_size' => 1000000, // байт до ротации
],
],
],
'readonly' => false,
],
// ...
];
Обратите внимание на log_size — это встроенная примитивная ротация: при превышении размера ядро переименовывает старый файл. Полноценную ротацию всё равно лучше делать средствами системы (о ней ниже), но log_size страхует от бесконечного роста одного файла.
Файловые логи и собственный логгер
AddMessage2Log хороша для быстрых записей, но у неё нет уровней, контекста и гибкости. На серьёзном проекте заводят собственный логгер — небольшой класс, который пишет структурированные строки в отдельный файл с меткой времени, уровнем и контекстом. Это даёт единый формат по всему проекту и возможность потом парсить логи автоматикой.
Минимальный файловый логгер на чистом PHP выглядит так:
<?php
namespace Vendor\Shop;
class FileLogger
{
private string $file;
private string $minLevel;
// порядок уровней по возрастанию серьёзности
private const LEVELS = ['DEBUG' => 10, 'INFO' => 20, 'WARNING' => 30, 'ERROR' => 40];
public function __construct(string $file, string $minLevel = 'INFO')
{
$this->file = $file;
$this->minLevel = $minLevel;
}
public function log(string $level, string $message, array $context = []): void
{
// не пишем то, что ниже минимального уровня — экономим диск на проде
if (self::LEVELS[$level] < self::LEVELS[$this->minLevel]) {
return;
}
$line = sprintf(
"[%s] %s: %s %s\n",
date('Y-m-d H:i:s'),
$level,
$message,
$context ? json_encode($context, JSON_UNESCAPED_UNICODE) : ''
);
// FILE_APPEND — дописываем; LOCK_EX — защита от гонки при параллельных запросах
file_put_contents($this->file, $line, FILE_APPEND | LOCK_EX);
}
public function error(string $m, array $c = []): void { $this->log('ERROR', $m, $c); }
public function warning(string $m, array $c = []): void { $this->log('WARNING', $m, $c); }
public function info(string $m, array $c = []): void { $this->log('INFO', $m, $c); }
public function debug(string $m, array $c = []): void { $this->log('DEBUG', $m, $c); }
}
Использование становится читаемым и однородным по всему коду:
<?php
$log = new \Vendor\Shop\FileLogger($_SERVER['DOCUMENT_ROOT'].'/local/logs/checkout.log', 'INFO');
$log->info('Начато оформление заказа', ['user' => $userId, 'sum' => $basketSum]);
if (!$paymentResult->isSuccess()) {
$log->error('Платёж отклонён', [
'order' => $orderId,
'errors' => $paymentResult->getErrorMessages(),
]);
}
Несколько важных практик. Логи держите вне публичной директории или закрывайте доступ к ним на уровне веб-сервера — файл лога, доступный по прямой ссылке, это утечка. Пишите с LOCK_EX, иначе при параллельных запросах строки будут «наезжать» друг на друга. И закладывайте minLevel: на проде обычно INFO или WARNING, на dev — DEBUG. Для крупных проектов вместо самописного класса берут PSR-совместимый логгер (например, monolog), если стек проекта это позволяет: он даёт готовые обработчики, форматтеры и отправку в разные приёмники сразу.
Psr\Log\LoggerInterface, вы сможете передавать его в любой код, который «умеет» PSR-логгер, и без переписывания менять приёмник — файл, syslog, внешний сервис мониторинга. Это делает логирование переносимым между проектами.
Уровни логирования и когда какой
Уровень логирования — это степень серьёзности записи. Без уровней лог превращается в неотличимую кашу, где важная ошибка тонет среди отладочного «шума». С уровнями вы фильтруете поток: на проде пишете только значимое, на dev — всё подряд, а при разборе инцидента смотрите сначала ERROR, потом WARNING.
Общепринятая шкала (близкая к стандарту PSR-3) выглядит так:
| Уровень | Что означает | Пример на магазине |
|---|---|---|
DEBUG | Подробная отладка, только для разработки | Полное тело запроса к платёжному шлюзу |
INFO | Штатное событие, «всё идёт по плану» | Заказ №N создан, обмен стартовал |
NOTICE | Заметное, но не проблемное событие | Использовано значение по умолчанию |
WARNING | Подозрительно, но работа продолжается | Медленный ответ шлюза, повтор запроса |
ERROR | Операция не выполнена, но сайт жив | Заказ не выгрузился в 1С |
CRITICAL | Критический сбой компонента | Недоступна база данных сессий |
ALERT / EMERGENCY | Требуется немедленное вмешательство | Сайт не отвечает, обмен встал полностью |
Практическое правило выбора уровня: спросите себя, что нужно сделать, увидев эту запись. Если ничего — это DEBUG/INFO. Если «посмотреть, но не срочно» — WARNING. Если «идти чинить» — ERROR и выше. И договоритесь в команде о единой шкале: если у одного разработчика «не отправилось письмо» это ERROR, а у другого INFO, фильтрация по уровням перестаёт работать.
Режим отладки и exception_handling в .settings.php
Центральный переключатель поведения ядра D7 при ошибках — файл /bitrix/.settings.php, а в нём две связанные вещи: параметр debug и секция exception_handling. Именно они определяют, как система реагирует на исключения и куда девает ошибки. Понимание этой части — база всей отладки на Битриксе.
Параметр верхнего уровня debug включает режим отладки платформы: в нём подробнее показываются ошибки, доступнее диагностическая информация, отключается часть агрессивного кэширования служебных данных. На проде он должен быть false, на dev — true.
<?php
// фрагмент /bitrix/.settings.php
return [
'debug' => [
'value' => true, // dev: true, prod: false
'readonly' => false,
],
// ...
];
Секция exception_handling тоньше. Её ключевые параметры:
| Параметр | Назначение |
|---|---|
debug | Показывать подробности исключения (трассировку) — dev: true, prod: false |
handled_errors_types | Какие уровни ошибок PHP перехватываются обработчиком как исключения |
exception_errors_types | Какие ошибки считаются фатальными и прерывают выполнение |
log → settings → file | Файл, куда пишутся ошибки и вызовы AddMessage2Log |
log → settings → log_size | Порог размера файла для встроенной примитивной ротации |
log → className | Класс-логгер (можно подставить свой, например пишущий во внешний сервис) |
Через className в секции log можно подключить свой класс-логгер, реализующий стандартный интерфейс диагностики ядра. Это удобный способ направить ошибки ядра не только в файл, но и во внешний сервис мониторинга: ядро само будет вызывать ваш логгер при каждом перехваченном исключении. Так вы не теряете ни одну системную ошибку и получаете её в общий поток мониторинга.
log с корректным путём к файлу ни AddMessage2Log, ни внутренние ошибки ядра никуда не пишутся. Если «логи пустые» — первым делом проверьте exception_handling.log в .settings.php и права на запись в указанный файл.
Ошибки PHP: error_reporting и display_errors
Ниже уровня Битрикса лежит сам PHP, и у него свои настройки поведения при ошибках. Две главные — error_reporting (какие типы ошибок вообще учитывать) и display_errors (показывать их в вывод или нет). Плюс log_errors и error_log — писать ли ошибки в файл и в какой. От их сочетания зависит, увидите вы проблему или она уйдёт в тишину.
error_reporting— битовая маска уровней. На dev обычноE_ALL(всё, включая notice и deprecated), на проде — чуть уже, чтобы не засорять лог мелочами: например,E_ALL & ~E_DEPRECATED & ~E_NOTICE.display_errors— выводить ли ошибки в HTML-ответ. На dev —On, на проде — строгоOff. Показ ошибок посетителям недопустим.log_errors— писать ли ошибки в файл. На проде —Onвсегда, это ваша единственная видимость.error_log— путь к файлу лога ошибок PHP. Задайте его явно, иначе ошибки могут уйти в общий лог сервера, где их труднее найти.
Типичные значения по средам:
; php.ini на РАЗРАБОТКЕ (видим всё сразу на экране)
error_reporting = E_ALL
display_errors = On
log_errors = On
error_log = /var/www/dev/local/logs/php-error.log
; php.ini на ПРОДЕ (пользователю ничего, всё в файл)
error_reporting = E_ALL & ~E_DEPRECATED & ~E_NOTICE
display_errors = Off
log_errors = On
error_log = /var/www/prod/local/logs/php-error.log
Важный нюанс: Битрикс частично управляет этими настройками сам через exception_handling, но базовый уровень задаётся в php.ini (или в конфиге php-fpm пула). Если вы видите ошибки на экране прода, а debug в .settings.php уже false — проверяйте display_errors в php.ini: скорее всего он On. Это одна из самых опасных мисконфигураций: полный стек-трейс с путями к файлам, видимый посетителю, — подарок для злоумышленника и сигнал непрофессионализма для клиента.
Dev против prod: где показывать, где логировать
Всё сказанное сводится к одному принципу, который стоит повесить на стену: на разработке ошибки видно сразу, на проде — только в логе. Разработчику нужна мгновенная обратная связь на экране; посетителю магазина нельзя показывать ни строчки технических деталей. Смешение этих режимов — источник и утечек, и потерянного времени.
Сведём настройки в таблицу — это удобная «карта переключения» при выкладке в разные среды:
| Настройка | Dev (разработка) | Prod (продакшен) |
|---|---|---|
display_errors (PHP) | On — видно на экране | Off — не показывать |
log_errors (PHP) | On | On — единственная видимость |
error_reporting | E_ALL — всё | Без notice/deprecated |
debug (.settings.php) | true | false |
exception_handling.debug | true — трассировка видна | false — детали в лог |
| Уровень своих логов | DEBUG | INFO / WARNING |
| Показ ошибки пользователю | Полный стек на экране | Аккуратная страница «Ошибка» |
| Внешний мониторинг ошибок | Опционально | Обязателен для магазина |
Чтобы переключение между средами не делалось руками (и не забывалось), настройки завязывают на переменную окружения или отдельный конфиг окружения. Тогда одна и та же кодовая база на dev-сервере ведёт себя «шумно», а на проде — «тихо», без ручной правки файлов при каждом деплое. Это тесно связано с процессом выкладки: как разводить конфигурацию по средам в конвейере, мы разбираем в статье про CI/CD и деплой на 1С-Битрикс.
Фатальные ошибки и белый экран
«Белый экран смерти» — пустая или полупустая страница без внятного текста — классический симптом фатальной ошибки PHP при выключенном display_errors. Пользователь видит белизну, потому что скрипт прервался на фатальной ошибке до того, как успел что-то отрисовать, а показывать детали на проде (справедливо) запрещено. Задача — не «включить показ», а найти запись в логе.
Наиболее частые причины фатальных ошибок и белого экрана:
- Нехватка памяти —
Allowed memory size exhausted. Тяжёлая выборка, обработка большого файла обмена, утечка в цикле. Смотритеmemory_limitи оптимизируйте выборку. - Превышение времени выполнения —
Maximum execution time exceeded. Долгий агент, тяжёлый импорт, зависший внешний запрос без таймаута. - Вызов несуществующего метода/класса — часто после неполного обновления или отключённого модуля, класс которого больше не автозагружается.
- Ошибка парсинга — синтаксическая ошибка в только что выложенном файле. Здесь спасает предварительная проверка
php -lперед деплоем.
Куда смотреть при белом экране, по порядку: сначала лог ошибок PHP (error_log), затем файл лога Битрикса из exception_handling, затем лог php-fpm и лог веб-сервера. Фатальная ошибка почти всегда оставляет след хотя бы в одном из них. Если след есть только в логе php-fpm, а в остальных пусто — значит скрипт умер до инициализации ядра, что тоже подсказка.
Для фатальных ошибок, которые обычный try/catch не ловит (память, таймаут), в PHP есть register_shutdown_function — функция, гарантированно вызываемая при завершении скрипта, даже аварийном. В ней можно поймать последнюю ошибку и записать её в лог:
<?php
register_shutdown_function(function () {
$err = error_get_last();
// ловим именно фатальные типы, которые не перехватываются try/catch
if ($err && in_array($err['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR], true)) {
AddMessage2Log(
sprintf('FATAL: %s in %s:%d', $err['message'], $err['file'], $err['line']),
'shop.fatal'
);
}
});
Обработка исключений: try/catch и ExceptionHandler
Исключения (exceptions) — штатный механизм PHP для «нештатных ситуаций». В коде D7 значительная часть ошибок бросается именно как исключения: не найден модуль, не прошла валидация, недоступен внешний сервис. Правильная обработка исключений — половина хорошего логирования: пойманное исключение нужно записать с контекстом, а не проглотить молча.
Базовый паттерн — оборачивать рискованную операцию в try/catch, логировать в catch и решать, пробрасывать дальше или обработать:
<?php
use Bitrix\Main\Loader;
try {
if (!Loader::includeModule('sale')) {
throw new \RuntimeException('Модуль sale не установлен');
}
$result = $paymentGateway->charge($orderId, $sum);
if (!$result->isSuccess()) {
throw new \RuntimeException('Шлюз вернул ошибку: '.implode('; ', $result->getErrorMessages()));
}
} catch (\Throwable $e) {
// Логируем с контекстом — не «проглатываем» исключение
AddMessage2Log(sprintf(
'[%s] %s (%s:%d)',
get_class($e), $e->getMessage(), $e->getFile(), $e->getLine()
), 'shop.payment');
// Пользователю — аккуратное сообщение, без технических деталей
ShowError('Не удалось провести оплату. Попробуйте ещё раз или свяжитесь с нами.');
}
Обратите внимание на \Throwable в catch — он ловит и исключения (Exception), и ошибки (Error, например вызов несуществующего метода), что надёжнее, чем ловить только Exception. Логируйте класс исключения, сообщение, файл и строку — по ним восстанавливается картина.
На уровне всего приложения ядро использует собственный ExceptionHandler, поведением которого управляет уже знакомая секция exception_handling. Именно он превращает неперехваченное исключение в запись лога и (на проде) в аккуратную страницу ошибки вместо стек-трейса. Ваша задача на уровне кода — не мешать ему: не глотать исключения пустым catch и логировать то, что обрабатываете сами.
try { ... } catch (\Throwable $e) {} — пустой catch, который молча проглатывает любую ошибку. Это создаёт «тихие» сбои, которые невозможно диагностировать: операция не сработала, а в логах пусто. Даже если вы решили не пробрасывать исключение, запишите его в лог.
Отладка обмена с 1С
Обмен с 1С по протоколу CommerceML — самый частый «пациент» на магазинах, и отлаживать его нужно по особой методике, потому что это многошаговый диалог «запрос-ответ» между сайтом и учётной системой. Сессия обмена проходит фазы: авторизация (checkauth), инициализация (init), передача файлов (file), импорт (import), выгрузка заказов (query), завершение (success). Ошибка на любом шаге останавливает всю цепочку.
Порядок отладки обмена, который работает:
- Журнал событий. Ошибки обмена ядро пишет в журнал с соответствующим типом. Первым делом отфильтруйте журнал и посмотрите тексты — часто причина видна сразу (нет прав, не хватило памяти, битый файл).
- Протоколирование обмена. Включите ведение протокола обмена в настройках торгового каталога. Тогда каждый шаг сессии пишется в файл, и видно, на какой именно фазе процесс останавливается.
- Лимиты PHP. Проверьте
memory_limitиmax_execution_time: большие каталоги падают по памяти или таймауту. Обмен часто идёт частями (пошагово), но один шаг всё равно может упереться в лимит. - HTTP-статусы и ответы. Посмотрите, что возвращает сайт на каждый запрос 1С. 500-я на любом шаге рвёт сессию. Полезно логировать код ответа и первые байты тела.
- Свои логи на узле обмена. Временно поднимите детальность: логируйте входящие параметры (
type,mode, имя файла), размер переданного файла, количество обработанных элементов. Это локализует место сбоя.
Ключевая мысль: обмен нельзя отлаживать «по экрану» — он идёт фоновым HTTP-диалогом, и белый экран или таймаут вы там не увидите глазами. Только логи (протокол обмена, журнал событий, лог php-fpm) показывают, что реально произошло на каждом шаге. Про построение самих интеграций и их надёжность у нас есть отдельный разбор — API, очереди и надёжность интеграций в 1С-Битрикс.
Отладка агентов и очередей
Агенты — отложенные задания Битрикса, которые выполняются по расписанию (на хите или по cron). Их коварство в том, что они работают без пользователя и без экрана: ошибка в агенте не всплывёт как «страница с ошибкой», она просто тихо не сделает свою работу. Поэтому агенты — территория, где логирование обязательно, а не опционально.
Что важно знать при отладке агентов:
- Способ запуска. Агенты на хите запускаются на посетителях (медленно и непредсказуемо), на cron — по расписанию. На проде правильный вариант — cron: тогда агенты не зависят от трафика и их выполнение предсказуемо. Проверьте, как настроен запуск.
- Возвращаемое значение. Агент должен вернуть строку своего повторного вызова, иначе он выполнится один раз и «умрёт». Если агент «пропал» — частая причина в неверном возвращаемом значении или брошенном исключении внутри.
- Изоляция ошибок. Оборачивайте тело агента в
try/catchи логируйте: неперехваченное исключение может остановить не только этот агент, но и цепочку следующих на том же хите. - Долгие агенты. Тяжёлые задания (пересчёт, массовая рассылка) упираются в
max_execution_time. Разбивайте их на порции и логируйте прогресс, чтобы видеть, где остановились.
<?php
// Тело агента с логированием и изоляцией ошибок
function shopNightlyRecalcAgent()
{
$log = new \Vendor\Shop\FileLogger($_SERVER['DOCUMENT_ROOT'].'/local/logs/agent.log', 'INFO');
$log->info('Агент пересчёта стартовал');
try {
$processed = \Vendor\Shop\Recalc::run(500); // порция в 500 элементов
$log->info('Агент отработал', ['processed' => $processed]);
} catch (\Throwable $e) {
$log->error('Агент упал', ['msg' => $e->getMessage(), 'line' => $e->getLine()]);
}
return 'shopNightlyRecalcAgent();'; // обязательно вернуть свой повторный вызов
}
Для очередей (собственных или на базе таблиц/highload-блоков) логика та же: логируйте постановку задачи, её выполнение, результат и ошибку. Очередь без логов — чёрный ящик: непонятно, задачи не ставятся, не берутся или падают при обработке. Про надёжные очереди для интеграций подробнее — в связанной статье об API и очередях.
Монитор производительности и медленные запросы
Логирование ошибок отвечает на «что сломалось», а мониторинг производительности — на «что тормозит». В 1С-Битрикс есть встроенный монитор производительности (Настройки → Производительность), который снимает метрики: время генерации страниц, число и время запросов к базе, попадания в кэш, конфигурацию сервера. Это отправная точка, чтобы понять, где узкое место.
Отдельная важная вещь — медленные запросы БД. Именно они чаще всего делают страницы тяжёлыми. Инструменты диагностики:
- Slow query log на стороне СУБД — включаемый лог, куда попадают запросы дольше заданного порога (
long_query_time). Это прямой список «виновников» без гадания. - Монитор производительности Битрикса — вкладка с медленными запросами и с разбивкой времени по компонентам страницы.
- Отладочная панель — в режиме отладки внизу страницы показывается сводка: время, число запросов, память. Удобно на dev, чтобы поймать N+1 и лишние выборки.
Практический подход: включаете slow query log с разумным порогом, собираете за день-два список медленных запросов, находите повторяющиеся и оптимизируете их — индексы, устранение N+1 через связи ORM, кэширование выборок. Мониторинг производительности — это цикл «измерил → нашёл узкое место → ускорил → снова измерил». Комплексно ускорением магазина мы занимаемся в рамках отдельной услуги.
Логи веб-сервера и php-fpm
Часть проблем не долетает до кода Битрикса и не попадает в его логи — они умирают на уровне веб-сервера или PHP-процесса. Поэтому в диагностике всегда есть ещё два источника: логи веб-сервера (nginx/Apache) и логи php-fpm. Игнорировать их — значит не видеть целый класс сбоев.
| Источник | Что там искать |
|---|---|
| access.log веб-сервера | Всплеск 500-х, 502/504 (шлюз/таймаут), подозрительные всплески запросов |
| error.log веб-сервера | Ошибки апстрима, таймауты связи с php-fpm, отказ в правах на файлы |
| Лог php-fpm | Аварийные завершения воркеров, превышение памяти, медленные скрипты |
| php-fpm slowlog | Трассировки «зависших» скриптов дольше порога — что именно тормозит |
Особенно полезен slowlog php-fpm: при включённом request_slowlog_timeout процесс-менеджер записывает стек «зависшего» скрипта — вы видите не просто «медленно», а в какой функции скрипт застрял (часто это внешний запрос без таймаута или тяжёлый цикл). Ошибка 502/504 в логе nginx при пустых логах приложения почти всегда означает, что php-fpm не ответил вовремя: воркер умер по памяти, упёрся в таймаут или закончились свободные процессы в пуле.
Связка «код магазина ↔ php-fpm ↔ веб-сервер» — единая цепочка, и диагностировать надо всю её. Как устроена инфраструктура вокруг Битрикса и где что логируется на уровне сервера, зависит от конкретной сборки окружения, но принцип один: при непонятном сбое проверяйте все звенья, а не только логи приложения.
Внешние сервисы мониторинга ошибок
Журнал событий и файловые логи хороши, но у них есть предел: они отвечают на «что случилось», но плохо — на «как часто», «у скольких пользователей» и «с какого момента». Эти вопросы закрывают внешние сервисы мониторинга ошибок — Sentry и подобные ему решения (обзорно, без привязки к конкретному вендору). Их задача — агрегировать исключения и делать их управляемыми.
Что даёт такой сервис поверх обычных логов:
- Группировка. Тысячи одинаковых ошибок сворачиваются в одну запись со счётчиком — вы видите «эта ошибка случилась 4000 раз», а не листаете 4000 строк.
- Контекст. Полный стек-трейс, версия релиза, окружение, URL, пользователь, параметры запроса — всё в одной карточке ошибки.
- Тренды и регрессии. Видно, когда ошибка появилась (часто — сразу после конкретного деплоя) и растёт ли её частота.
- Мгновенный алерт. Новая ошибка после релиза — и через минуту приходит уведомление в мессенджер или почту.
Технически интеграция обычно сводится к подключению SDK и глобального обработчика, который перехватывает неотловленные исключения и отправляет их в сервис. В Битриксе это удобно совместить с exception_handling: свой класс-логгер, указанный в секции log, дополнительно шлёт ошибку во внешний сервис. Тогда ни одна ошибка ядра не теряется.
<?php
// Упрощённая идея: свой логгер шлёт ошибку и в файл, и во внешний сервис мониторинга
class MonitoringLogger
{
public function write($message, $level = 'ERROR')
{
// 1) локальный файл — всегда, как надёжный резерв
AddMessage2Log($message, 'shop.monitoring');
// 2) внешний сервис — асинхронно, чтобы не тормозить ответ пользователю
// (SDK сервиса, очередь или неблокирующий HTTP-вызов)
\App\Monitoring\Client::capture([
'message' => $message,
'level' => $level,
'release' => getenv('APP_RELEASE'), // версия деплоя
'environment' => getenv('APP_ENV'), // prod / staging
]);
}
}
Нужен ли внешний мониторинг именно вам — зависит от масштаба. Небольшому сайту достаточно журнала и файловых логов. Нагруженному магазину с деньгами, интеграциями и регулярными релизами внешний сервис окупается очень быстро: он превращает «узнали о падении оформления заказа через неделю» в «получили алерт через минуту после деплоя». Важный нюанс — не отправляйте во внешний сервис персональные данные и секреты: настройте фильтрацию полей (пароли, токены, номера карт) до отправки.
Алерты: упал обмен, 500-е, место на диске
Лог, который никто не читает, бесполезен — поэтому важнейшая часть мониторинга это алерты: автоматические уведомления при выполнении условия. Хороший алерт приходит вовремя, адресно и с достаточным контекстом, чтобы понять серьёзность, не открывая ноутбук.
Минимальный набор алертов для магазина на Битриксе:
- Упал обмен с 1С. Нет успешной сессии обмена дольше N часов — алерт. Это прямой риск: заказы копятся, остатки устаревают. Контролируют по времени последней успешной сессии.
- Всплеск 500-х. Число ошибок 5xx в логе веб-сервера за интервал превысило порог — что-то массово сломалось (частая причина — неудачный деплой). Реагировать нужно немедленно.
- Место на диске. Свободное место ниже порога — уведомление. Переполненный диск роняет запись сессий, кэша, загрузку файлов, и симптомы выглядят хаотично, если не знать причины.
- Сайт недоступен. Внешний аптайм-мониторинг проверяет доступность ключевых страниц (главная, каталог, оформление) и алертит при 5xx или таймауте.
- Новая ошибка в мониторинге. Внешний сервис ошибок присылает уведомление о новой или резко участившейся ошибке.
Два правила, чтобы алерты работали, а не превращались в фон. Первое — адресность: алерт должен уходить туда, где его увидят (рабочий мессенджер, дежурный канал), а не в почтовый ящик, куда никто не заходит. Второе — борьба с шумом: слишком чувствительные алерты приучают их игнорировать. Настраивайте пороги так, чтобы уведомление означало реальную проблему, и группируйте повторы, чтобы один инцидент не породил сотню сообщений.
Ротация логов
Логи растут постоянно, и без ротации они превращаются из помощника в проблему. Файл журнала ошибок или лог php-fpm за недели способен вырасти до десятков гигабайт и заполнить диск — а переполненный диск сам по себе роняет сайт: перестают писаться сессии, кэш и загружаемые файлы. Ирония в том, что забота о видимости ошибок без ротации сама становится причиной аварии.
Ротацию организуют на двух уровнях:
- Системный (logrotate). Стандартный инструмент Linux режет большие файлы по расписанию или размеру, сжимает старые копии (
gzip) и удаляет их через заданное число дней. Так обслуживают логи веб-сервера, php-fpm и общий error_log PHP. - Уровень приложения. Для собственных логов ту же логику закладывают в код: пишут в файлы с датой в имени (
app-2026-07-02.log) и удаляют файлы старше N дней агентом или cron-задачей. Плюс встроенныйlog_sizeвexception_handlingкак страховка от роста одного файла.
Типовой конфиг logrotate для лога приложения — держать 14 дней, сжимать, не падать на отсутствующем файле:
# /etc/logrotate.d/shop
/var/www/prod/local/logs/*.log {
daily # ротация раз в сутки
rotate 14 # хранить 14 архивных копий
compress # сжимать старые логи
delaycompress # сжать со следующего цикла (вчерашний ещё читаем)
missingok # нет файла — не ошибка
notifempty # пустой файл не ротировать
copytruncate # обрезать файл на месте (процесс держит дескриптор)
}
Отдельно держите в голове баланс: слишком короткое хранение — и вы не сможете разобрать инцидент недельной давности; слишком длинное — логи съедают диск. Для магазина разумно хранить оперативные логи 2–4 недели, а важные бизнес-события (журнал событий) — по политике, которая устраивает и эксплуатацию, и требования к аудиту. И обязательно повесьте алерт на свободное место — как последнюю защиту от переполнения.
Безопасная отладка на проде
Иногда проблема воспроизводится только на проде — на реальных данных, реальном трафике, реальной конфигурации. Отлаживать её приходится «вживую», и делать это надо аккуратно, чтобы не навредить. Золотое правило: никогда не включайте display_errors на проде и не показывайте ошибки посетителям. Вся диагностика идёт в лог, а не на экран.
Безопасные приёмы отладки на боевом сервере:
- Повышайте детальность точечно. Не включайте DEBUG глобально — добавьте подробные логи только на подозрительном участке кода. Меньше шума, меньше нагрузки, точнее диагностика.
- Ограничивайте отладку собой. Если нужен подробный вывод, включайте его по условию — по вашему IP или идентификатору сессии. Тогда детали видите только вы, а остальные пользователи — штатное поведение.
- Логируйте контекст, а не «дошёл сюда». Пишите входные данные, результат операции, идентификаторы — то, по чему потом восстановите картину. Записи вида «point 1», «point 2» бесполезны.
- Воспроизводите на стейджинге. Для тяжёлых кейсов снимите дамп запроса и повторите его на копии прода (стейджинге), где можно включать любую отладку без риска.
- Убирайте за собой. После диагностики удалите временные логи и верните штатные уровни. Забытый отладочный вывод — источник нагрузки, утечки данных и переполнения диска.
Пример условной отладки только для своего IP — безопасный способ увидеть детали на проде, не показывая их никому другому:
<?php
// Подробная запись только для доверенного IP разработчика
$debugIps = ['203.0.113.10']; // ваш IP
$clientIp = $_SERVER['REMOTE_ADDR'] ?? '';
if (in_array($clientIp, $debugIps, true)) {
AddMessage2Log([
'url' => $_SERVER['REQUEST_URI'] ?? '',
'params' => $_REQUEST, // осторожно: не логируйте пароли/токены
'user' => $GLOBALS['USER']->GetID(),
], 'shop.debug');
}
Что логировать в интеграциях
Интеграции — платёжные шлюзы, службы доставки, CRM, склад, маркетплейсы — самое «мутное» место: сбой происходит на стыке двух систем, и без логов невозможно понять, чья сторона виновата. Поэтому в интеграциях логируют щедро, но с умом: достаточно, чтобы разобрать инцидент, но без утечки секретов.
Обязательный минимум для каждого внешнего вызова:
- Факт и направление вызова. Что вызвали, куда, когда. Метка времени и идентификатор операции (чтобы связать запрос и ответ).
- Ключевые параметры запроса. Достаточно для воспроизведения, но без секретов: токены, пароли, полные номера карт — маскируйте или не пишите.
- Ответ и статус. HTTP-код, тело ответа (или его начало), время ответа. Именно здесь видно «внешний сервис вернул 500» или «ответил за 40 секунд».
- Результат обработки. Что вы сделали с ответом: провели платёж, поставили в очередь на повтор, отклонили. Это связывает внешний ответ с вашим решением.
- Идемпотентность и повторы. Логируйте попытки повтора и их номер — иначе непонятно, был ли двойной платёж или это ретрай одной операции.
Хорошая практика — единый идентификатор операции (correlation id), который проходит через все логи одного бизнес-действия: и в вашем логе, и (по возможности) в запросе к внешней системе. Тогда при разборе вы фильтруете логи по одному id и видите всю цепочку от начала до конца, даже если она прошла через очередь и несколько повторов. Как выстраивать надёжные интеграции с очередями, повторами и идемпотентностью, подробно разобрано в статье про API, очереди и надёжность интеграций. А проверять устойчивость интеграций к сбоям помогает грамотное тестирование и QA магазина на Битриксе.
Частые ошибки
Логирование и мониторинг обрастают своим набором типовых граблей. Зная их заранее, вы избежите большинства «слепых зон» и опасных мисконфигураций.
- Логи пустые, потому что не включён
exception_handling.log.AddMessage2Logвызывается, а файла нет. Проверьте секциюlogв.settings.phpи права на запись. display_errors = Onна проде. Посетители видят стек-трейсы с путями к файлам — утечка и удар по доверию. На проде строгоOff, всё в лог.- Пустой
catch. Молчаливое проглатывание исключений создаёт «тихие» сбои без следов в логах. Даже не пробрасывая — логируйте. - Отладочный вывод забыт на проде.
var_dump,print_r, глобальный DEBUG — остались после отладки и грузят сайт, засоряют диск, светят данные. - Логи без ротации. Файл раздувается и заполняет диск, роняя сайт целиком. Настройте logrotate и алерт на место.
- Секреты в логах. Пароли, токены, номера карт в открытом виде — нарушение и риск. Маскируйте чувствительные поля перед записью.
- Всё валят в журнал событий. Отладочный поток в журнал (в базу) грузит СУБД. Для потоковых логов — файлы; в журнал — значимые бизнес-события.
- Нет уровней логирования. Всё пишется одинаково, важная ошибка тонет в шуме. Введите единую шкалу уровней и фильтруйте по ней.
- Логи есть, алертов нет. Сбой записан, но никто его не увидел вовремя. Логи без алертов = запоздалая реакция. Настройте уведомления на критичное.
- Агенты без логирования. Фоновые задания падают тихо, без экрана и пользователя. Оборачивайте тело агента в
try/catchи логируйте результат. - Смотрят только логи приложения. При 502/504 ответ умирает в php-fpm/веб-сервере — проверяйте и их логи, а не только логи Битрикса.
Чек-лист логирования и мониторинга
Короткий список, по которому удобно свериться при настройке проекта и на код-ревью эксплуатационной готовности:
- В настройках главного модуля включён аудит событий; журнал событий пишется и просматривается.
- В
.settings.phpнастроена секцияexception_handling.logс корректным путём и правами на запись. - Значения
debug(.settings.php) иdisplay_errors(php.ini) разведены по средам: dev — показывать, prod — в лог. - На проде
display_errors = Off,log_errors = On, заданerror_log; пользователю показывается аккуратная страница ошибки. - В проекте есть собственный логгер с уровнями (DEBUG/INFO/WARNING/ERROR) и единым форматом; логи лежат вне публичного доступа.
- Исключения не глотаются пустым
catch; всё пойманное логируется с классом, сообщением, файлом и строкой. - Фатальные ошибки перехватываются через
register_shutdown_functionи попадают в лог. - Обмен с 1С протоколируется; агенты и очереди пишут старт, результат и ошибку.
- Включён монитор производительности и slow query log; медленные запросы регулярно разбираются.
- Проверяются логи веб-сервера и php-fpm (включая slowlog) при непонятных 502/504.
- Настроены алерты: упавший обмен, всплеск 500-х, нехватка места на диске, недоступность сайта.
- Для нагруженного магазина подключён внешний сервис мониторинга ошибок с фильтрацией персональных данных.
- Настроена ротация логов (logrotate и/или уровень приложения); в логи не попадают секреты.
Вывод
Логирование, отладка и мониторинг — это эксплуатационный фундамент магазина на 1С-Битрикс, а не «дополнительная опция». Встроенный журнал событий (Настройки → Журнал событий) даёт первый взгляд на обмен, почту и безопасность; свои логи через AddMessage2Log и файловые логгеры с уровнями фиксируют технический поток; секция exception_handling в .settings.php управляет тем, куда девается каждая ошибка ядра. Настройки PHP (error_reporting, display_errors) и разведение dev/prod определяют, увидит проблему разработчик на экране или посетитель на «белом экране» — и правильный ответ всегда «в лог, не на экран».
Поверх логов строится наблюдаемость: монитор производительности и медленные запросы показывают, что тормозит; логи веб-сервера и php-fpm ловят сбои, не долетевшие до кода; внешний сервис мониторинга ошибок агрегирует исключения и присылает алерты; ротация не даёт логам уронить диск. Собранные вместе, эти механизмы превращают «узнали от клиента через двое суток» в «получили алерт через минуту после деплоя». Если нужно выстроить это под ваш проект — мы делаем логирование, мониторинг и разбор инцидентов в рамках технической поддержки и ускорения сайта на 1С-Битрикс. Смежные материалы по теме — CI/CD и деплой, тестирование и QA магазина, API и очереди для интеграций и вся рубрика «Разработка и архитектура».