Как в 1С программно определить имя процедуры или функции, вызвавшей текущий код

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

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

Метод получения стека вызовов через генерацию исключения

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

Разберем этот алгоритм по шагам. Мы создаем конструкцию Попытка — Исключение, внутри которой намеренно вызываем исключение. В блоке обработки мы извлекаем подробное описание этой ошибки, которое и будет содержать искомый стек вызовов.

Проанализируем пример кода, который реализует данную логику:


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

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

Парсинг строки стека и получение имени

Текст, возвращаемый платформой, обычно имеет формат: «ОбщийМодуль.ИмяМодуля.Модуль(НомерСтроки): ИмяПроцедуры». Чтобы выделить чистое имя, нам нужно использовать строковые функции для поиска двоеточия и скобок. Посмотрим на пример более продвинутого анализа:


// Пример упрощенного извлечения имени из строки стека
СтрокаСтека = СтрПолучитьСтроку(СтекТекст, 3); // Берем третью строку, так как первая - заголовок, вторая - эта функция
ПозицияДвоеточия = Найти(СтрокаСтека, ":");
Если ПозицияДвоеточия > 0 Тогда
    ИмяВызывающейПроцедуры = СокрЛП(Сред(СтрокаСтека, ПозицияДвоеточия + 1));
КонецЕсли;

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

Почему этот метод стоит использовать с осторожностью

Несмотря на то, что технически задача решаема, использование исключений для получения метаданных считается «антипаттерном» в среде 1С. Разберем основные причины, по которым за такое решение, как выразились участники обсуждения, «надо бить по пальцам».

  1. Проблема битых транзакций. Это самый критичный момент. Если ваш код выполняется внутри открытой транзакции (например, в обработчике ПередЗаписью или ПриЗаписи), любое возникшее исключение — даже если оно перехвачено блоком Попытка...Исключение — помечает транзакцию как невалидную. При попытке зафиксировать такую транзакцию система выдаст критическую ошибку: «В данной транзакции уже происходили ошибки». Поэтому в транзакционном коде данный метод использовать категорически нельзя.
  2. Падение производительности. Генерация исключения — крайне ресурсоемкая операция. Платформа выполняет так называемую «раскрутку стека» (stack unwinding), собирает информацию о контексте и строках кода. Если вы вызовете такую функцию внутри цикла на несколько тысяч итераций, время выполнения кода увеличится в десятки раз.
  3. Сложность отладки. Если у программиста в конфигураторе включена опция «Останавливаться по ошибке», отладчик будет постоянно прерывать выполнение на вашей «фейковой» ошибке, что крайне раздражает коллег и мешает нормальной работе.

Альтернативные подходы к решению задачи

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

1. Паттерн «Контекст вызова». Рассмотрим вариант передачи структуры параметров. Вместо того чтобы пытаться угадать вызывающего, мы явно передаем его имя. Это делает код прозрачным и легким для чтения.


Процедура МояПроцедура(ПараметрыКонтекста = Неопределено)
    Если ПараметрыКонтекста <> Неопределено Тогда
        Вызывающий = ПараметрыКонтекста.ИмяВызывающейПроцедуры;
    КонецЕсли;
КонецПроцедуры

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

3. Логирование через Технологический журнал. Если задача стоит не в оперативной логике программы, а в расследовании причин некорректных вызовов, лучше настроить logcfg.xml на сбор событий CALL. Это позволит увидеть полную цепочку вызовов в текстовых логах сервера без внесения изменений в код конфигурации.

Резюме

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

← На главную