Как определить и записать в лог ошибку, которая произошла в обработчике ПередЗаписью

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке механизмов обмена данными или автоматизированной загрузки объектов в 1С:Предприятие программисты часто сталкиваются с ситуацией, когда метод Записать() не срабатывает, но стандартные средства отлова ошибок не дают информации о причинах сбоя. В этой статье мы подробно разберем, почему конструкция Попытка...Исключение в связке с ОписаниеОшибки() может подвести, и как правильно извлечь текст ошибки, возникшей в обработчике ПередЗаписью или при проверке уникальности.

Проблема: Почему ОписаниеОшибки() возвращает пустую строку

Рассмотрим типичную ситуацию: вы выполняете запись объекта (например, справочника Номенклатура) в блоке исключения. Если запись прерывается, управление передается в блок Исключение, однако функция ОписаниеОшибки() не содержит привычного текста (например, сообщения о неуникальности номера или незаполненном реквизите).

Выясним причину такого поведения платформы. В 1С существует разделение между системными исключениями (критическими ошибками кода, падением сервера, нарушением прав доступа) и логическим отказом от записи. Когда в обработчике ПередЗаписью параметру Отказ присваивается значение Истина, или когда встроенные механизмы платформы (контроль уникальности, проверка заполнения) блокируют запись:

  1. Платформа инициирует прерывание транзакции.
  2. Происходит переход в блок Исключение.
  3. Текст ошибки при этом не регистрируется как системное исключение, а помещается в специальный буфер — сообщения пользователю.

Именно поэтому ОписаниеОшибки() оказывается пустым — с точки зрения системы критического сбоя не произошло, произошел штатный программный отказ.

Решение: Использование метода ПолучитьСообщенияПользователю

Для того чтобы «выловить» текст ошибки, который платформа или другой разработчик вывели через объект СообщениеПользователю, нам необходимо обратиться к очереди сообщений. Разберем по шагам, как модифицировать код записи для корректного логирования.

Проанализируем пример кода, который позволит собрать все сообщения, возникшие в процессе неудачной попытки записи:


Попытка
    ТекстОшибки = "";
    СпрОбъект.Записать();
Исключение
    // 1. Пытаемся получить системное описание (на случай ошибки кода)
    ТекстОшибки = ОписаниеОшибки();
    
    // 2. Извлекаем сообщения, накопленные платформой
    МассивСообщений = ПолучитьСообщенияПользователю(Истина);
    
    Для Каждого Сообщение Из МассивСообщений Цикл
        ТекстОшибки = ТекстОшибки + Символы.ПС + Сообщение.Текст;
    КонецЦикла;
    
    // 3. Записываем результат в лог (Журнал регистрации)
    Если ЗначениеЗаполнено(ТекстОшибки) Тогда
        ЗаписьЖурналаРегистрации("ЗагрузкаДанных.ОшибкаЗаписи",
            УровеньЖурналаРегистрации.Ошибка,
            СпрОбъект.Метаданные(),
            СпрОбъект.Ссылка,
            "Не удалось записать объект: " + ТекстОшибки);
    КонецЕсли;
КонецПопытки;

Разберем важные детали реализации

Посмотрим подробнее на параметры используемых функций. Метод ПолучитьСообщенияПользователю(Истина) принимает булево значение. Параметр Истина критически важен: он означает, что после получения сообщений они будут удалены из очереди. Если вы не очистите очередь, сообщения будут выведены пользователю стандартным окном сообщений 1С после завершения серверного вызова, что может привести к дублированию информации или путанице в интерфейсе.

Также стоит обратить внимание на объект СообщениеПользователю. Каждый элемент массива, возвращаемого функцией, содержит не только свойство Текст, но и данные о том, к какому полю или объекту относится ошибка. Если ваша цель — детальный лог, вы можете извлекать свойства ПутьКДанным и Поле.

Особенности платформенных проверок

Проанализируем ситуацию с контролем уникальности. Если у справочника в метаданных стоит галочка «Контроль уникальности», платформа сама проверяет код или другие реквизиты перед фиксацией транзакции. В случае нарушения уникальности:

  1. Вызов Записать() прерывается.
  2. Платформа автоматически генерирует сообщение (например: "Реквизит № по кат. не уникален!").
  3. Это сообщение попадает в тот же самый стек, который мы очищаем методом ПолучитьСообщенияПользователю().

Поэтому предложенное решение является универсальным как для ошибок, прописанных вручную в модуле объекта, так и для стандартных проверок платформы.

Рекомендации по логированию в современных версиях (8.3)

В актуальных версиях платформы 8.3 рекомендуется использовать функцию ИнформацияОбОшибке() вместо ОписаниеОшибки(). Она возвращает объект типа ИнформацияОбОшибке, который содержит структурированные данные о сбое.

Рассмотрим пример расширенного сбора данных:


Исключение
    Инфо = ИнформацияОбОшибке();
    ТекстЛога = "Краткое описание: " + Инфо.Описание + Символы.ПС;
    ТекстЛога = ТекстЛога + "Имя модуля: " + Инфо.ИмяМодуля + ", Строка: " + Инфо.НомерСтроки;
    
    // Добавляем сообщения из очереди
    Сообщения = ПолучитьСообщенияПользователю(Истина);
    Для Каждого Стр Из Сообщения Цикл
        ТекстЛога = ТекстЛога + Символы.ПС + "Сообщение: " + Стр.Текст;
    КонецЦикла;
    
    // Запись в Журнал Регистрации
    // ...
КонецПопытки;

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

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

← На главную