ФиксИнтернет-магазин на 1С-Битрикс под ключ за 30 дней по фиксированной цене

Логирование, отладка и мониторинг ошибок на 1С-Битрикс

Логирование, отладка и мониторинг ошибок на 1С-Битрикс: журнал событий, свои логи, режим отладки, exception_handling, мониторинг и алерты

Магазин на 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, чтобы логи не забили диск и сами не уронили сайт.

Зачем магазину логирование и мониторинг

Есть соблазн относиться к логам как к чему-то «для галочки»: работает же сайт, зачем что-то писать в файлы. Но у логирования и мониторинга сугубо денежная функция — сокращать время между сбоем и его починкой. Каждая минута, что оформление заказа отдаёт ошибку, а вы об этом не знаете, — это потерянные заказы и подорванное доверие. Логи и алерты превращают «невидимый» сбой в видимый и адресный.

Практически хорошо выстроенное логирование решает три задачи:

Обратная сторона — цена отсутствия. Проект без логов диагностируется методом «включим отладку на проде и посмотрим» — а это и утечка данных, и лишняя нагрузка, и потерянные часы. Проект с логами, но без мониторинга, знает о своих ошибках, но узнаёт о них слишком поздно. Цель этой статьи — собрать обе половины: аккуратную запись того, что происходит, и своевременное уведомление, когда что-то идёт не так.

Ключевая мысль: логирование и мониторинг — это не «дополнительная фича», а часть эксплуатационной надёжности магазина, наравне с бэкапами. Их закладывают заранее, а не в момент аварии, когда «посмотреть некуда».

Как ошибка проходит путь от сбоя до разработчика

Прежде чем нырять в конкретные механизмы, полезно увидеть общий маршрут. Любая проблема в магазине проходит один и тот же путь: где-то происходит сбой (исключение, фатальная ошибка PHP, ошибка обмена), он фиксируется в логе (журнал событий, файл, внешний сервис), по определённым условиям срабатывает алерт, и уведомление доходит до человека, который может починить. Цель инженера — сделать каждое звено этой цепочки надёжным и быстрым.

Если хоть одно звено выпадает, система «слепнет». Сбой без логирования — вы не узнаете, что случилось. Лог без алерта — узнаете, но случайно и поздно. Алерт без адресата — уведомление уходит «в никуда». Поэтому логирование проектируют как сквозной поток, а не как отдельные не связанные друг с другом файлы.

Путь ошибки: сбой → лог → алерт → разработчик Сбой исключение, 500, падение обмена Лог журнал событий, файл, сервис Алерт условие → триггер, мессенджер, почта Разработчик диагностика и починка обратная связь: исправление устраняет причину сбоя
Схема: сбой фиксируется в логе, по условию срабатывает алерт, уведомление доходит до разработчика, а исправление замыкает цикл, устраняя причину. Слабое звено рвёт всю цепочку — «слепой» участок остаётся невидимым.

Журнал событий Битрикса: что это и как включить

Журнал событий — встроенный механизм платформы для фиксации значимых событий системы. Открывается он в административной части: Настройки → Инструменты → Журнал событий (в части сборок пункт лежит прямо как Настройки → Журнал событий). Это первое, куда стоит смотреть при любом «что-то отвалилось», потому что сюда ядро и модули пишут ошибки обмена, почты, прав доступа и многого другого без всякого участия разработчика.

Чтобы журнал реально писался, аудит событий должен быть включён. Настройка живёт в параметрах модуля main (Настройки → Настройки продукта → Настройки модулей → Главный модуль), где включают ведение журнала и отмечают, какие типы событий фиксировать: ошибки, аудит безопасности, действия пользователей и так далее. Отдельно задаётся срок хранения записей — чтобы таблица журнала не разрасталась бесконечно.

Важно понимать, что журнал событий хранится в базе данных (таблица журнала), а не в файле. Это удобно для просмотра через админку с фильтрами, но означает, что при очень большом потоке событий журнал добавляет нагрузку на базу. Поэтому в него пишут значимые события, а не отладочный «шум» с каждого запроса — для потокового детального лога лучше подходят файлы, о которых ниже.

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

Что писать в журнал событий и как его читать

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

Типовые события, которые платформа пишет сама:

Свои события в журнал добавляют штатной функцией 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-3: если оформить логгер по интерфейсу 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, фильтрация по уровням перестаёт работать.

Уровни логирования: от шума к тревоге DEBUG детальная отладка — только dev INFO штатные события — «всё по плану» WARNING подозрительно, но работаем дальше ERROR операция не выполнена — идти чинить CRITICAL / ALERT немедленное вмешательство — алерт сейчас серьёзность
Схема: уровни логирования выстроены по возрастанию серьёзности. На проде обычно пишут от INFO и выше, DEBUG оставляют для среды разработки, а на CRITICAL/ALERT настраивают немедленное уведомление.

Режим отладки и 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 — писать ли ошибки в файл и в какой. От их сочетания зависит, увидите вы проблему или она уйдёт в тишину.

Типичные значения по средам:

; 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)OnOn — единственная видимость
error_reportingE_ALL — всёБез notice/deprecated
debug (.settings.php)truefalse
exception_handling.debugtrue — трассировка виднаfalse — детали в лог
Уровень своих логовDEBUGINFO / WARNING
Показ ошибки пользователюПолный стек на экранеАккуратная страница «Ошибка»
Внешний мониторинг ошибокОпциональноОбязателен для магазина

Чтобы переключение между средами не делалось руками (и не забывалось), настройки завязывают на переменную окружения или отдельный конфиг окружения. Тогда одна и та же кодовая база на dev-сервере ведёт себя «шумно», а на проде — «тихо», без ручной правки файлов при каждом деплое. Это тесно связано с процессом выкладки: как разводить конфигурацию по средам в конвейере, мы разбираем в статье про CI/CD и деплой на 1С-Битрикс.

Одна ошибка — два поведения: dev и prod DEV — показать Fatal error: Call to undefined method ... in /local/php/...:42 #0 stack trace ... display_errors = On debug = true видит разработчик, чинит сразу PROD — в лог Извините, произошла ошибка аккуратная страница для клиента display_errors = Off debug = false → лог + мониторинг детали ушли в файл, не пользователю
Схема: одна и та же ошибка на dev выводится разработчику с полной трассировкой, а на prod скрыта от клиента аккуратной страницей и записана в лог и внешний мониторинг. Показывать детали посетителям нельзя ни при каких условиях.

Фатальные ошибки и белый экран

«Белый экран смерти» — пустая или полупустая страница без внятного текста — классический симптом фатальной ошибки PHP при выключенном display_errors. Пользователь видит белизну, потому что скрипт прервался на фатальной ошибке до того, как успел что-то отрисовать, а показывать детали на проде (справедливо) запрещено. Задача — не «включить показ», а найти запись в логе.

Наиболее частые причины фатальных ошибок и белого экрана:

Куда смотреть при белом экране, по порядку: сначала лог ошибок 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). Ошибка на любом шаге останавливает всю цепочку.

Порядок отладки обмена, который работает:

  1. Журнал событий. Ошибки обмена ядро пишет в журнал с соответствующим типом. Первым делом отфильтруйте журнал и посмотрите тексты — часто причина видна сразу (нет прав, не хватило памяти, битый файл).
  2. Протоколирование обмена. Включите ведение протокола обмена в настройках торгового каталога. Тогда каждый шаг сессии пишется в файл, и видно, на какой именно фазе процесс останавливается.
  3. Лимиты PHP. Проверьте memory_limit и max_execution_time: большие каталоги падают по памяти или таймауту. Обмен часто идёт частями (пошагово), но один шаг всё равно может упереться в лимит.
  4. HTTP-статусы и ответы. Посмотрите, что возвращает сайт на каждый запрос 1С. 500-я на любом шаге рвёт сессию. Полезно логировать код ответа и первые байты тела.
  5. Свои логи на узле обмена. Временно поднимите детальность: логируйте входящие параметры (type, mode, имя файла), размер переданного файла, количество обработанных элементов. Это локализует место сбоя.

Ключевая мысль: обмен нельзя отлаживать «по экрану» — он идёт фоновым HTTP-диалогом, и белый экран или таймаут вы там не увидите глазами. Только логи (протокол обмена, журнал событий, лог php-fpm) показывают, что реально произошло на каждом шаге. Про построение самих интеграций и их надёжность у нас есть отдельный разбор — API, очереди и надёжность интеграций в 1С-Битрикс.

Отладка агентов и очередей

Агенты — отложенные задания Битрикса, которые выполняются по расписанию (на хите или по cron). Их коварство в том, что они работают без пользователя и без экрана: ошибка в агенте не всплывёт как «страница с ошибкой», она просто тихо не сделает свою работу. Поэтому агенты — территория, где логирование обязательно, а не опционально.

Что важно знать при отладке агентов:

<?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 с разумным порогом, собираете за день-два список медленных запросов, находите повторяющиеся и оптимизируете их — индексы, устранение 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 и подобные ему решения (обзорно, без привязки к конкретному вендору). Их задача — агрегировать исключения и делать их управляемыми.

Что даёт такой сервис поверх обычных логов:

Технически интеграция обычно сводится к подключению 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С 500-е в логах место на диске аптайм страниц Мониторинг условия и пороги группировка повторов Мессенджер дежурный канал Дежурный реагирует на инцидент алерт срабатывает по условию, а повторы группируются — чтобы не было шума
Схема: метрики обмена, 500-х, диска и аптайма собираются мониторингом, который по условиям-порогам генерирует алерты и адресно шлёт их в дежурный канал. Группировка повторов гасит шум, чтобы уведомления не игнорировали.

Ротация логов

Логи растут постоянно, и без ротации они превращаются из помощника в проблему. Файл журнала ошибок или лог php-fpm за недели способен вырасти до десятков гигабайт и заполнить диск — а переполненный диск сам по себе роняет сайт: перестают писаться сессии, кэш и загружаемые файлы. Ирония в том, что забота о видимости ошибок без ротации сама становится причиной аварии.

Ротацию организуют на двух уровнях:

Типовой конфиг 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 на проде и не показывайте ошибки посетителям. Вся диагностика идёт в лог, а не на экран.

Безопасные приёмы отладки на боевом сервере:

  1. Повышайте детальность точечно. Не включайте DEBUG глобально — добавьте подробные логи только на подозрительном участке кода. Меньше шума, меньше нагрузки, точнее диагностика.
  2. Ограничивайте отладку собой. Если нужен подробный вывод, включайте его по условию — по вашему IP или идентификатору сессии. Тогда детали видите только вы, а остальные пользователи — штатное поведение.
  3. Логируйте контекст, а не «дошёл сюда». Пишите входные данные, результат операции, идентификаторы — то, по чему потом восстановите картину. Записи вида «point 1», «point 2» бесполезны.
  4. Воспроизводите на стейджинге. Для тяжёлых кейсов снимите дамп запроса и повторите его на копии прода (стейджинге), где можно включать любую отладку без риска.
  5. Убирайте за собой. После диагностики удалите временные логи и верните штатные уровни. Забытый отладочный вывод — источник нагрузки, утечки данных и переполнения диска.

Пример условной отладки только для своего 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, склад, маркетплейсы — самое «мутное» место: сбой происходит на стыке двух систем, и без логов невозможно понять, чья сторона виновата. Поэтому в интеграциях логируют щедро, но с умом: достаточно, чтобы разобрать инцидент, но без утечки секретов.

Обязательный минимум для каждого внешнего вызова:

Хорошая практика — единый идентификатор операции (correlation id), который проходит через все логи одного бизнес-действия: и в вашем логе, и (по возможности) в запросе к внешней системе. Тогда при разборе вы фильтруете логи по одному id и видите всю цепочку от начала до конца, даже если она прошла через очередь и несколько повторов. Как выстраивать надёжные интеграции с очередями, повторами и идемпотентностью, подробно разобрано в статье про API, очереди и надёжность интеграций. А проверять устойчивость интеграций к сбоям помогает грамотное тестирование и QA магазина на Битриксе.

Частые ошибки

Логирование и мониторинг обрастают своим набором типовых граблей. Зная их заранее, вы избежите большинства «слепых зон» и опасных мисконфигураций.

Чек-лист логирования и мониторинга

Короткий список, по которому удобно свериться при настройке проекта и на код-ревью эксплуатационной готовности:

Вывод

Логирование, отладка и мониторинг — это эксплуатационный фундамент магазина на 1С-Битрикс, а не «дополнительная опция». Встроенный журнал событий (Настройки → Журнал событий) даёт первый взгляд на обмен, почту и безопасность; свои логи через AddMessage2Log и файловые логгеры с уровнями фиксируют технический поток; секция exception_handling в .settings.php управляет тем, куда девается каждая ошибка ядра. Настройки PHP (error_reporting, display_errors) и разведение dev/prod определяют, увидит проблему разработчик на экране или посетитель на «белом экране» — и правильный ответ всегда «в лог, не на экран».

Поверх логов строится наблюдаемость: монитор производительности и медленные запросы показывают, что тормозит; логи веб-сервера и php-fpm ловят сбои, не долетевшие до кода; внешний сервис мониторинга ошибок агрегирует исключения и присылает алерты; ротация не даёт логам уронить диск. Собранные вместе, эти механизмы превращают «узнали от клиента через двое суток» в «получили алерт через минуту после деплоя». Если нужно выстроить это под ваш проект — мы делаем логирование, мониторинг и разбор инцидентов в рамках технической поддержки и ускорения сайта на 1С-Битрикс. Смежные материалы по теме — CI/CD и деплой, тестирование и QA магазина, API и очереди для интеграций и вся рубрика «Разработка и архитектура».

Частые вопросы

Где находится журнал событий в 1С-Битрикс и что он показывает?

Журнал событий открывается в административной части по пути Настройки → Инструменты → Журнал событий (в некоторых сборках — Настройки → Журнал событий). Это встроенный механизм платформы, который фиксирует значимые события системы: ошибки при обмене с 1С, ошибки при отправке почты, изменения прав доступа, попытки входа и блокировки проактивной защитой, ошибки модулей и agent-заданий, а также ваши собственные записи. По каждому событию видно время, тип (уровень серьёзности), модуль-источник, пользователя и текст с подробностями. Чтобы журнал вообще писался, аудит событий должен быть включён в настройках модуля main — иначе многие типы событий просто не фиксируются. Журнал событий — первое место, куда стоит смотреть, когда «что-то отвалилось», особенно обмен и почта.

Как писать свои сообщения в лог Битрикса?

Самый простой встроенный способ — функция AddMessage2Log($text, $module), которая пишет строку в файл журнала ядра. Ей передают текст (строку или сериализованные данные) и код модуля-источника, чтобы потом было понятно, откуда запись. Чтобы эта функция реально писала в файл, в конфигурации .settings.php должен быть включён параметр exception_handling с ключом log и указан файл лога — иначе сообщения никуда не попадут. Для более гибкого сценария в проекте заводят собственный логгер: пишут в отдельный файл через file_put_contents с флагом FILE_APPEND и блокировкой, добавляют метку времени, уровень (DEBUG/INFO/WARNING/ERROR) и контекст. Такой логгер удобно обернуть в класс или PSR-совместимый интерфейс и подключить внешний пакет вроде monolog, если проект это позволяет.

Чем отличаются настройки отладки для dev и prod?

Принцип один: на среде разработки ошибки видно немедленно на экране, на проде — они пишутся в лог, но пользователю не показываются. На dev включают display_errors = On, error_reporting по максимуму (E_ALL), в .settings.php ставят debug = true и exception_handling с debug = true, чтобы видеть полную трассировку исключений. На проде наоборот: display_errors = Off (или строго в лог через log_errors = On и error_log в файл), debug = false, exception_handling в «боевом» режиме, когда пользователю показывается аккуратная страница ошибки, а детали уходят в файл лога. Показывать стек-трейс и пути к файлам живым посетителям — это и утечка информации для злоумышленника, и удар по доверию к магазину, поэтому на проде детали ошибок всегда прячут в логи.

Что такое exception_handling в .settings.php и зачем он нужен?

exception_handling — секция файла /bitrix/.settings.php, которая управляет тем, как ядро D7 обрабатывает исключения и записывает ошибки. В ней задают режим отладки (debug), уровни ошибок, которые перехватываются как исключения (handled_errors_types) и как фатальные (exception_errors_types), а также подсекцию log с указанием класса-логгера и файла, куда писать. Именно через exception_handling функция AddMessage2Log и внутренние ошибки ядра попадают в файл. По сути это центральный переключатель поведения при ошибках: на dev вы включаете debug и подробный вывод, на prod — оставляете тихую запись в лог без показа деталей пользователю. Понимание этой секции критично, потому что без включённого log ваши вызовы логирования будут молча теряться.

Как отлаживать обмен с 1С, если заказы не выгружаются?

Начните с журнала событий: ошибки обмена CommerceML модуль каталога и обмена пишет туда с типом, относящимся к обмену. Далее включите протоколирование обмена в настройках торгового каталога — тогда каждый шаг сессии обмена (авторизация, checkauth, init, file, import, query, success) фиксируется в файле протокола, и видно, на каком именно шаге всё останавливается. Проверьте лимиты PHP (memory_limit, max_execution_time) — большие каталоги часто падают по памяти или таймауту. Посмотрите ответы на стороне 1С и HTTP-статусы: обмен идёт по протоколу «запрос-ответ», и 500-я на любом шаге останавливает всю сессию. Полезно временно поднять уровень логирования на самом узле обмена: логировать входящие параметры, размер файлов, количество обработанных элементов. Так вы локализуете, где именно ломается — в авторизации, в передаче файла или в самом импорте.

Нужен ли внешний сервис мониторинга ошибок, если есть журнал событий?

Журнал событий и файловые логи отвечают на вопрос «что случилось», но плохо отвечают на вопросы «как часто», «у скольких пользователей» и «когда началось». Внешние сервисы мониторинга ошибок (Sentry и подобные) агрегируют исключения: группируют одинаковые ошибки, считают частоту, показывают затронутых пользователей, версию релиза, окружение и полный стек с контекстом, а также присылают алерт, как только появляется новая ошибка. Для магазина это разница между «узнали о падении оформления заказа из журнала через неделю» и «получили уведомление в мессенджер через минуту после деплоя». На небольшом сайте достаточно журнала и грамотных файловых логов; на нагруженном магазине с деньгами и интеграциями внешний мониторинг ошибок окупается очень быстро, потому что резко сокращает время обнаружения проблем.

Как безопасно отлаживать проблему прямо на продакшене?

Золотое правило — никогда не включать display_errors на проде и не показывать ошибки посетителям. Вместо этого пишите диагностику в лог: временно повышаете уровень логирования на подозрительном участке, добавляете подробные записи с контекстом (какие данные пришли, какой результат вернула операция) и смотрите файл лога, а не экран. Если нужна отладка под конкретным пользователем, используйте условие по IP или по идентификатору сессии, чтобы подробный вывод шёл только вам. Для тяжёлых кейсов снимают дамп запроса и воспроизводят его на стейджинге — точной копии прода. После диагностики обязательно уберите временные логи и верните штатные уровни: забытый отладочный вывод сам становится источником нагрузки и утечки данных. И всегда следите за размером логов — включённая подробная отладка способна за часы забить диск.

Как настроить ротацию логов, чтобы они не забили диск?

Логи растут постоянно, и без ротации файл журнала или лог php-fpm может за недели вырасти до десятков гигабайт и заполнить диск, что само по себе роняет сайт. На уровне сервера ротацию настраивают через logrotate: он режет большие файлы по расписанию или по размеру, сжимает старые копии и удаляет их через заданное число дней (например, хранить 14 дней). Для собственных файловых логов приложения ту же логику закладывают в код: писать в файлы с датой в имени (app-2026-07-02.log) и удалять файлы старше N дней по агенту или cron-задаче. Отдельно контролируйте место на диске алертом: свободное место ниже порога — уведомление, потому что переполненный диск на Битриксе проявляется как случайные ошибки записи сессий, кэша и загрузки файлов, которые трудно диагностировать, если не знать причину.

Поделиться:

Нужны логи, мониторинг и быстрая реакция на сбои?

Настроим журнал событий и свои логи, разведём отладку по средам, поднимем алерты об упавшем обмене, 500-х и нехватке места. Реагируем на инциденты раньше, чем о них узнают ваши покупатели.

Игорь Воскресенский

Команда студии B2Bsite. С 2014 года разрабатываем, ускоряем и поддерживаем проекты на 1С-Битрикс: настраиваем логирование и мониторинг, разбираем инциденты по журналу событий и логам, поднимаем алерты и держим обмен с 1С под наблюдением для среднего и крупного бизнеса.

← Все статьи блога