Текст ошибки из блока Исключение: показать пользователю, записать в журнал, передать дальше
Содержание
Чтобы вывести ошибку в исключении 1С, внутри блока Исключение получите информацию о ней функцией ИнформацияОбОшибке(), превратите её в текст через КраткоеПредставлениеОшибки() (для пользователя) или ПодробноеПредставлениеОшибки() (для журнала) и покажите через СообщениеПользователю или запишите ЗаписьЖурналаРегистрации(). Старый способ ОписаниеОшибки() тоже работает, но даёт только строку без модуля, номера строки и цепочки причин.
Частая ошибка новичка — пустой блок Исключение, после которого код идёт дальше, будто ничего не случилось. Ошибку при этом не видит ни пользователь, ни администратор. Правильный обработчик всегда делает одно из трёх: сообщает, записывает в журнал или пробрасывает исключение выше. Всё, что ниже, относится к платформе 8.3 и не зависит от конфигурации.
Попытка… Исключение: как устроен перехват ошибки
Конструкция перехвата в языке 1С одна:
Попытка
Результат = 100 / Делитель;
Исключение
// сюда попадаем при любой ошибке времени выполнения
ТекстОшибки = ОписаниеОшибки();
Сообщить(ТекстОшибки);
КонецПопытки;
Что происходит по шагам:
- Платформа выполняет операторы между
ПопыткаиИсключение. - На первой ошибке выполнение блока прерывается. Оставшиеся строки не выполняются.
- Управление переходит в блок
Исключение. Если ошибки не было, блок пропускается. - После
КонецПопыткикод продолжается как обычно.
Блока finally, как в других языках, нет. Код «выполнить в любом случае» пишут дважды: в конце блока Попытка и в блоке Исключение, либо выносят после КонецПопытки.
Конструкции можно вкладывать. Ошибка ловится ближайшим внешним блоком Попытка. Если обработчиков нет ни в одной процедуре стека вызовов, платформа показывает стандартное окно ошибки и прерывает выполнение.
Перехватывайте ошибку там, где знаете, что с ней делать. Если процедура не может исправить ситуацию, ей не нужна Попытка — пусть ошибку поймает вызывающий код.
Как получить подробности об ошибке в исключении 1С
ОписаниеОшибки() возвращает строку. Для разбора ошибки этого мало. Функция ИнформацияОбОшибке() возвращает объект с полями:
| Свойство | Что содержит |
|---|---|
Описание | текст ошибки без служебной обёртки |
ИмяМодуля | модуль, где произошла ошибка |
НомерСтроки | номер строки в модуле |
ИсходнаяСтрока | текст строки кода, на которой упало |
Причина | вложенная ИнформацияОбОшибке — исходная ошибка, если исключение было переброшено |
Цепочку причин удобно обойти циклом. Так видно, с чего всё началось:
Исключение
Инфо = ИнформацияОбОшибке();
Уровень = 0;
Пока Инфо <> Неопределено Цикл
Сообщить(СтрШаблон("[%1] %2 (%3, строка %4)",
Уровень, Инфо.Описание, Инфо.ИмяМодуля,
Формат(Инфо.НомерСтроки, "ЧГ=0")));
Инфо = Инфо.Причина;
Уровень = Уровень + 1;
КонецЦикла;
КонецПопытки;
Краткое и подробное представление
Платформа умеет собрать текст сама:
- 🟢
КраткоеПредставлениеОшибки(ИнформацияОбОшибке())— только суть, без модулей и строк кода. Это показывают пользователю. - 🔵
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())— полный текст со стеком и причинами. Это пишут в журнал регистрации.
В новых редакциях Библиотеки стандартных подсистем есть одноимённые функции в общем модуле ОбработкаОшибок. Они дополнительно чистят текст от служебной информации. Если модуль есть в вашей конфигурации, пользуйтесь им — так принято в типовых решениях.
Вызывайте ИнформацияОбОшибке() и ОписаниеОшибки() первой строкой блока Исключение. Если до этого выполнить другой код, который сам перехватит свою ошибку, вы получите описание чужой ошибки.
Вывод ошибки пользователю: сообщение, предупреждение, поле формы
Выбор способа зависит от того, где выполняется код и насколько срочно человек должен увидеть ошибку.
| Способ | Где работает | Когда использовать |
|---|---|---|
СообщениеПользователю | клиент и сервер | ошибка в данных, проверка заполнения |
ПоказатьПредупреждение() | только клиент | ошибка, которую нельзя пропустить |
Сообщить() | клиент и сервер | быстрая отладка, простые обработки |
ВызватьИсключение | везде | операцию надо прервать полностью |
Сообщение с привязкой к полю
СообщениеПользователю выводит текст в окно сообщений формы и может подсветить реквизит, в котором ошибка. Это удобнее, чем просто строка внизу:
Исключение
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не удалось рассчитать сумму: "
+ КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
Сообщение.Поле = "Объект.Сумма";
Сообщение.Сообщить();
КонецПопытки;
В конфигурациях на БСП то же самое делает ОбщегоНазначения.СообщитьПользователю() на сервере и ОбщегоНазначенияКлиент.СообщитьПользователю() на клиенте.
Модальное предупреждение
В интерфейсе «Такси» модальные окна по умолчанию запрещены, поэтому используйте асинхронный вариант:
&НаКлиенте
Процедура Выполнить(Команда)
Попытка
ВыполнитьНаСервере();
Исключение
ПоказатьПредупреждение(, КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецПроцедуры
Исключение, возникшее в серверной процедуре, долетает до клиента. Его можно поймать на клиенте той же конструкцией, текст сохраняется.
Когда сообщение не дойдёт
Сообщения из фонового задания пользователь сам не увидит. Их забирают из формы методом ПолучитьСообщенияПользователю() фонового задания. Ошибку, на которой задание упало, читают из его свойства ИнформацияОбОшибке.
Ошибка в HTTP-сервисе
У HTTP-сервиса нет пользователя с окном сообщений. Если исключение не перехватить, клиент получит ответ с кодом 500 и служебным текстом платформы. Лучше вернуть понятный ответ самому:
Функция ЗаказыPOST(Запрос)
Попытка
Результат = ОбработатьЗаказ(Запрос.ПолучитьТелоКакСтроку());
Ответ = Новый HTTPСервисОтвет(200);
Ответ.УстановитьТелоИзСтроки(Результат);
Исключение
Инфо = ИнформацияОбОшибке();
ЗаписьЖурналаРегистрации("HTTPСервис.Заказы",
УровеньЖурналаРегистрации.Ошибка, , ,
ПодробноеПредставлениеОшибки(Инфо));
Ответ = Новый HTTPСервисОтвет(500);
Ответ.УстановитьТелоИзСтроки(КраткоеПредставлениеОшибки(Инфо));
КонецПопытки;
Возврат Ответ;
КонецФункции
Вызывающая система получает код и короткий текст, а подробности остаются в журнале. Стек модулей наружу не уходит.
Как записать ошибку из исключения в журнал регистрации
Пользователь может закрыть сообщение и забыть. Администратору нужен след в журнале. Минимальный обработчик для серверного кода:
Исключение
ЗаписьЖурналаРегистрации("Загрузка прайса",
УровеньЖурналаРегистрации.Ошибка,
Метаданные.Справочники.Номенклатура,
,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение;
КонецПопытки;
Параметры по порядку: имя события, уровень, объект метаданных, данные (ссылка на документ или элемент), комментарий.
Советы по журналу:
- 📌 Имя события делайте иерархическим:
"Обмен.Загрузка","Обмен.Выгрузка". По нему потом фильтруют журнал. - 📌 В параметр «Данные» передавайте ссылку на объект. Тогда из журнала можно сразу открыть документ, на котором упало.
- 📌 Пишите подробное представление: по стеку и номеру строки место сбоя находится сразу, без воспроизведения.
Смотреть записи: Администрирование → Обслуживание → Журнал регистрации в типовых конфигурациях, в Конфигураторе — Администрирование → Журнал регистрации. Отбор ставьте по уровню «Ошибка» и имени события.
Запись в журнал внутри транзакции по умолчанию делается независимо от неё: если транзакция откатится, запись останется. Это поведение задаёт последний параметр РежимТранзакцииЗаписиЖурналаРегистрации.
Где обработчик ломает данные: ошибки в работе с исключениями
Правильный шаблон транзакции
Самая дорогая ошибка — перехват внутри транзакции без отката. Рабочая схема:
НачатьТранзакцию();
Попытка
// блокировки и запись данных
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ЗаписьЖурналаРегистрации("Проведение",
УровеньЖурналаРегистрации.Ошибка, , ,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение;
КонецПопытки;
НачатьТранзакцию() стоит до Попытка. Если упадёт сам вызов начала транзакции, блок Исключение не будет отменять транзакцию, которой нет. ОтменитьТранзакцию() — первым делом в обработчике, до любых других действий с базой.
Собственные ошибки: ВызватьИсключение, коды и категории
Классов исключений, как в Java или C#, в 1С нет. Свою ошибку вызывают оператором ВызватьИсключение.
Три формы, которые нужно знать:
// 1. Своя ошибка с текстом
ВызватьИсключение "Не заполнен склад в строке " + Формат(НомерСтроки, "ЧГ=0");
// 2. Проброс текущей ошибки без изменений (только внутри блока Исключение)
ВызватьИсключение;
// 3. Расширенная форма (платформа 8.3.21 и выше)
// второй параметр (категория) здесь опущен
ВызватьИсключение("Сервис недоступен", , "SRV-503", ,
ИнформацияОбОшибке());
Форма без параметров сохраняет исходный модуль и номер строки. Если вместо неё написать ВызватьИсключение ОписаниеОшибки(), место ошибки потеряется: в журнале будет строка, где стоит повторный вызов.
Расширенная форма в 8.3.21+
В платформе с номером не ниже 8.3.21 у ВызватьИсключение появились параметры: текст, категория, код ошибки, дополнительная информация и причина. Те же значения затем читаются из ИнформацияОбОшибке(). Через параметр «Причина» строится цепочка: верхний уровень говорит «не удалось загрузить прайс», а в причине лежит исходный сбой.
Если конфигурация должна работать в режиме совместимости ниже 8.3.21, расширенная форма недоступна. Проверьте значение «Режим совместимости» в свойствах корня конфигурации.
Как обойтись без классов на старых версиях
Распространённый приём — префикс-код в тексте ошибки:
ВызватьИсключение "[ERR_STOCK] Недостаточно остатка по товару " + Строка(Товар);
Обработчик выше по стеку проверяет префикс через СтрНачинаетсяС(Инфо.Описание, "[ERR_STOCK]") и решает: показать пользователю или упасть. Коды держите в одном общем модуле, чтобы не разъезжались по конфигурации.
Подключение мониторинга и технологического журнала
Журнал регистрации видит только то, что вы туда записали. Для полной картины подключают ещё два источника.
Технологический журнал
Технологический журнал пишет все исключения платформы, включая те, что вы перехватили. Настраивается файлом logcfg.xml в каталоге conf платформы. Минимальная настройка на исключения:
<config xmlns="http://v8.1c.ru/v8/tech-log">
<log location="C:\v8logs" history="24">
<event>
<eq property="name" value="EXCP"/>
</event>
<property name="all"/>
</log>
</config>
history="24" — хранить логи 24 часа. Не оставляйте сбор всех событий на рабочем сервере надолго: логи быстро занимают диск. Включили, воспроизвели ошибку, выключили.
Внешние системы
Для внешнего мониторинга есть два пути:
- Отправлять ошибки из обработчика через
HTTPСоединениев свою систему сбора логов. Делайте это в отдельной процедуре со своейПопытка, чтобы сбой сети не перекрывал исходную ошибку. - Читать журнал регистрации снаружи. Он хранится либо в текстовом формате (файлы
.lgfи.lgp), либо в формате SQLite (файл.lgd); формат видно по файлам в каталоге журнала базы. Оба варианта выгружают в стороннюю систему специальными утилитами.
В последних версиях платформы есть механизм отчётов об ошибках: пользователь прямо из окна ошибки формирует отчёт со стеком и сведениями о системе. Это полезно, когда ошибки ловят не программисты: не нужно просить скриншоты.
Отладка исключений в Конфигураторе
Когда ошибка перехвачена, отладчик на ней по умолчанию не остановится. Это мешает найти место сбоя.
Что помогает:
- 🔍
Отладка → Остановка по ошибкев Конфигураторе. Включите флажок, и отладчик встанет на строке, где возникло исключение, даже внутриПопытка. Можно указать фрагмент текста ошибки, чтобы останавливаться только на нужной. - 🔍 Временно закомментируйте
ПопыткаиИсключение … КонецПопытки. Ошибка всплывёт со стандартным окном и стеком. - 🔍 В обработчике поставьте точку останова и посмотрите в «Табло» значение
ИнформацияОбОшибке(): там видны и описание, и причина. - 🔍 Для серверного кода включите отладку на сервере (ключ
-debugу службы сервера 1С) или запустите базу в файловом варианте, если ошибка там воспроизводится.
Изменение параметров службы сервера 1С требует её перезапуска. Все сеансы пользователей оборвутся — делайте это вне рабочего времени.