Отладка 1С 8.3: точки останова, табло и стек вызовов

Дата: 21.09.2026 10:36:30
Отладка 1С
Программирование 1С
Ошибки 1С
Доработка 1С
Комментарий:
0
Платформа:
8.3
Конфигурация:
Любая
Формы:
Любые

Отладка 1С 8.3 — это умение остановить код в нужном месте и увидеть, где испортились данные. F9 и F5 знают все, а время экономят другие приёмы: условная точка на нужной строке, просмотр временных таблиц, стек вызовов, остановка на «проглоченной» ошибке, замер по этапам и журнал регистрации там, где отладчик не подключить. Ниже — эти приёмы и код для своей конфигурации или расширения.

Отладка 1С 8.3: как запустить и подключиться

Запуск отладки в файловой базе — F5 в конфигураторе («Отладка → Начать отладку»): точки останова срабатывают и в клиентском, и в серверном коде. Какой клиент стартует, задаётся в «Сервис → Параметры → Запуск 1С:Предприятия». Клиент, запущенный не из конфигуратора, подключают ключами командной строки:

1cv8c.exe /F"D:\Bases\Test" /DEBUG -http -attach /DEBUGGERURL "http://localhost:1550"

В клиент-серверной базе агент кластера должен работать с ключом -debug (для HTTP-отладки — -debug -http), иначе серверные точки молча пропускаются, а F11 на вызове сервера перешагивает строку. Протокол отладчика («Сервис → Параметры → Отладка») должен совпадать с серверным. При HTTP-отладке работает сервер отладки dbgs.exe, через него подключаются EDT, веб-клиент и удалённые предметы отладки. Настройка службы — в статье про отладку на сервере 1С.

Где выполняется кодЧто нужно для остановки
Клиент: формы, &НаКлиентеЗапуск по F5 или с ключом /DEBUG
Сервер, файловая базаТолько запуск по F5
Сервер, клиент-серверная базаКластер с -debug, предмет «Сервер» в «Отладка → Подключение»
Фоновые и регламентные заданияАвтоподключение фоновых заданий в «Отладка → Подключение»
HTTP- и веб-сервисыАвтоподключение сервисов; для файловой базы на веб-сервере — отладка, разрешённая в публикации

Точки останова: обычные, условные, остановка по ошибке

F9 ставит и снимает точку, Alt+F9 открывает список всех точек: там их отключают, не удаляя, и правят условия. Точка срабатывает до выполнения строки, поэтому её результат виден только после F10.

Условная точка («Отладка → Точка останова с условием», Alt+Shift+F9) останавливает выполнение, только когда условие истинно. Условие — выражение встроенного языка в контексте строки: доступны локальные переменные, реквизиты объекта и функции общих модулей.

ЗадачаУсловие
Одна строка из тысячиСтрокаТЧ.НомерСтроки = 152
Пустая ценаНе ЗначениеЗаполнено(СтрокаТЧ.Цена)
Конкретный документНомер = "ТД00-000123"
Только свой сеанс в общей базеИмяПользователя() = "Иванов"
Нужный запросСтрНайти(Запрос.Текст, "ВТ_Остатки") > 0
Записать значение без остановкиОтладкаСервер.Трасса("Цена", СтрокаТЧ.Цена)

Последняя строка — «точка трассировки»: функция пишет значение в журнал и возвращает Ложь, выполнение не прерывается. В длинных циклах быстрее «ловушка» в коде — проверку делает сам код:

// Общий модуль ОтладкаСервер. Флажки: «Сервер», «Вызов сервера».
// «Вызов сервера» нужен, чтобы функции работали и в условиях точек
// останова в клиентском коде.

// «Точка трассировки»: пишет значение в журнал регистрации и возвращает Ложь,
// поэтому условная точка останова с этой функцией не прерывает выполнение.
Функция Трасса(Метка, Значение = Неопределено) Экспорт
	ЗаписьЖурналаРегистрации("Отладка.Трасса", УровеньЖурналаРегистрации.Информация, , ,
		Строка(Метка) + ": " + ЗначениеВТекст(Значение));
	Возврат Ложь;
КонецФункции

// Текстовое представление значения: коллекции разворачиваются в XML целиком.
Функция ЗначениеВТекст(Значение) Экспорт
	ТипЗначения = ТипЗнч(Значение);
	Если ТипЗначения = Тип("Структура") Или ТипЗначения = Тип("Массив")
		Или ТипЗначения = Тип("Соответствие") Или ТипЗначения = Тип("ТаблицаЗначений") Тогда
		Попытка
			Запись = Новый ЗаписьXML;
			Запись.УстановитьСтроку();
			СериализаторXDTO.ЗаписатьXML(Запись, Значение, НазначениеТипаXML.Явное);
			Возврат Запись.Закрыть();
		Исключение
			// Внутри есть несериализуемое значение: оставляем тип и размер
			Возврат СтрШаблон("%1, элементов: %2", ТипЗначения, Значение.Количество());
		КонецПопытки;
	КонецЕсли;
	Возврат СтрШаблон("%1 (%2)", Значение, ТипЗначения);
КонецФункции

// «Ловушка» в модуле объекта документа (временно, удалить после отладки).
// F9 ставится на строку с вызовом Трасса: отладчик остановится только
// на проблемной строке, а без отладчика данные останутся в журнале.
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
	Для Каждого СтрокаТЧ Из Товары Цикл
		Если СтрокаТЧ.Количество > 0 И СтрокаТЧ.Цена = 0 Тогда
			ОтладкаСервер.Трасса("Нулевая цена", Новый Структура("НомерСтроки, Номенклатура",
				СтрокаТЧ.НомерСтроки, СтрокаТЧ.Номенклатура));
		КонецЕсли;
	КонецЦикла;
КонецПроцедуры
  • Возврат Ложь — суть приёма: условие никогда не выполняется, а след в журнале остаётся.
  • СериализаторXDTO.ЗаписатьXML разворачивает коллекцию целиком, ссылкам и примитивам хватает представления с типом.

Остановка по ошибке («Отладка → Остановка по ошибке») ставит выполнение на паузу там, где возникло исключение, в том числе внутри Попытка…Исключение, которая его потом «глотает». Так находят причину пустых результатов и сообщения «В данной транзакции уже происходили ошибки!». Чтобы не останавливаться на каждом исключении типовой, задайте подстроку текста, например «Деление на 0».

Шаги, табло, «Вычислить выражение» и стек вызовов

ДействиеКлавиши
Начать отладку / продолжить до следующей точкиF5
Завершить отладкуShift+F5
Шагнуть через процедуруF10
Шагнуть в процедуру / выйти из неёF11 / Shift+F11
Идти до курсораShift+F10
Вычислить выражениеShift+F9
Стек вызововCtrl+Alt+C

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

Стек вызовов показывает цепочку процедур до текущей строки. Двойной щелчок по уровню открывает место вызова, а выражения вычисляются в контексте этого уровня: видно, с какими параметрами пришли в процедуру.

Временные таблицы удобно выгрузить одной функцией. Без менеджера временных таблиц подойдёт Запрос.ВыполнитьПакетСПромежуточнымиДанными(): он вернёт результаты всех запросов пакета, включая ПОМЕСТИТЬ, но выполнит пакет повторно.

// Общий модуль ОтладкаСервер (продолжение).
// Содержимое временных таблиц для просмотра в отладчике. В «Вычислить выражение»:
// ОтладкаСервер.ВременныеТаблицы(Запрос.МенеджерВременныхТаблиц, "ВТ_Остатки, ВТ_Цены")
Функция ВременныеТаблицы(МенеджерВТ, Знач ИменаТаблиц = "") Экспорт
	Результат = Новый Соответствие;
	Если ТипЗнч(МенеджерВТ) <> Тип("МенеджерВременныхТаблиц") Тогда
		Возврат Результат;
	КонецЕсли;
	Отбор = СтрРазделить(ВРег(СтрЗаменить(ИменаТаблиц, " ", "")), ",", Ложь);
	Для Каждого Таблица Из МенеджерВТ.Таблицы Цикл
		Если Отбор.Количество() > 0 И Отбор.Найти(ВРег(Таблица.ПолноеИмя)) = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		Результат.Вставить(Таблица.ПолноеИмя, Таблица.ПолучитьДанные().Выгрузить());
	КонецЦикла;
	Возврат Результат;
КонецФункции

ПолучитьДанные() читает уже созданную таблицу без повторного выполнения пакета, поэтому функцию можно вызывать на любом шаге. Запрос.Выполнить() в окне выражения, наоборот, повторит ПОМЕСТИТЬ и может упасть на уже существующей таблице.

Серверный код и клиент-серверные вызовы

На строке с вызовом &НаСервере-процедуры F11 переносит отладчик в серверный код; если строка просто перешагивается, сервер не подключён к отладке. Что путает на стыке контекстов:

  • в &НаСервере реквизиты формы — копия, приехавшая с вызовом: на клиенте изменения появятся только после возврата;
  • в &НаСервереБезКонтекста формы нет, и выражение Объект.Товары даёт «Переменная не определена (Объект)»;
  • пока отладчик стоит на серверной строке внутри транзакции, держатся блокировки, и другие сеансы ждут до таймаута.

Фоновые и регламентные задания

Фоновое задание выполняется в отдельном сеансе, и точка в нём срабатывает только при автоподключении — см. статью о фоновых заданиях. Метод регламентного задания часто проще вызвать в текущем сеансе с теми же параметрами: работают обычные точки и остановка по ошибке, запуск можно повторять. Форма внешней обработки для этого:

// Внешняя обработка, модуль формы. Реквизит формы ИмяЗадания (Строка) -
// имя регламентного задания в метаданных, команда ЗапуститьМетод.
// Метод выполняется в текущем сеансе: точки останова срабатывают
// без автоподключения фоновых заданий.

&НаКлиенте
Процедура ЗапуститьМетод(Команда)
	ВыполнитьМетодЗадания(ИмяЗадания);
	ПоказатьОповещениеПользователя("Метод регламентного задания выполнен");
КонецПроцедуры

&НаСервереБезКонтекста
Процедура ВыполнитьМетодЗадания(Имя)
	МетаданныеЗадания = Метаданные.РегламентныеЗадания.Найти(Имя);
	Если МетаданныеЗадания = Неопределено Тогда
		ВызватьИсключение СтрШаблон("Регламентное задание ""%1"" не найдено", Имя);
	КонецЕсли;
	// Параметры берём у самого задания. Непредопределённых заданий
	// одного вида может быть несколько - тогда берётся первое.
	Задания = РегламентныеЗадания.ПолучитьРегламентныеЗадания(
		Новый Структура("Метаданные", МетаданныеЗадания));
	ПараметрыЗадания = Новый Массив;
	Если Задания.Количество() > 0 Тогда
		ПараметрыЗадания = Задания[0].Параметры;
	КонецЕсли;
	Аргументы = Новый Массив;
	Для Индекс = 0 По ПараметрыЗадания.ВГраница() Цикл
		Аргументы.Добавить(СтрШаблон("ПараметрыЗадания[%1]", Формат(Индекс, "ЧН=0; ЧГ=0")));
	КонецЦикла;
	// ИмяМетода имеет вид "ИмяОбщегоМодуля.ИмяПроцедуры"
	Выполнить(МетаданныеЗадания.ИмяМетода + "(" + СтрСоединить(Аргументы, ", ") + ");");
КонецПроцедуры
  • Параметры берутся у самого задания, поэтому вызов совпадает с вызовом планировщика.
  • Выполнить видит локальные переменные, поэтому в строку подставляются обращения ПараметрыЗадания[0], а не сами значения.
  • Метод работает от текущего пользователя и не в фоне: код с проверкой ПолучитьТекущийСеансИнформационнойБазы().ПолучитьФоновоеЗадание() поведёт себя иначе. Создание заданий из кода — в статье о регламентных заданиях.

Внешние обработки

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

Замер производительности и секундомер в коде

Когда вопрос «где тормозит», включите «Отладка → Замер производительности», выполните операцию и остановите замер: конфигуратор покажет строки модулей с числом выполнений и долей времени. Строка с тысячами выполнений внутри цикла — первый кандидат. Остальные инструменты — в статье «1С тормозит и зависает».

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

// Общий модуль ОтладкаСервер (продолжение): секундомер по этапам.

Функция НачатьЗамер(Операция) Экспорт
	Сейчас = ТекущаяУниверсальнаяДатаВМиллисекундах();
	Возврат Новый Структура("Операция, Начало, Отсечка, Этапы", Операция, Сейчас, Сейчас, Новый Массив);
КонецФункции

Процедура Этап(Замер, ИмяЭтапа) Экспорт
	Сейчас = ТекущаяУниверсальнаяДатаВМиллисекундах();
	Замер.Этапы.Добавить(СтрШаблон("%1: %2 мс", ИмяЭтапа, Формат(Сейчас - Замер.Отсечка, "ЧН=0; ЧГ=0")));
	Замер.Отсечка = Сейчас;
КонецПроцедуры

// Пишет в журнал, только если операция шла дольше порога.
Процедура ЗавершитьЗамер(Замер, ПорогМс = 0) Экспорт
	Всего = ТекущаяУниверсальнаяДатаВМиллисекундах() - Замер.Начало;
	Если Всего < ПорогМс Тогда
		Возврат;
	КонецЕсли;
	ЗаписьЖурналаРегистрации("Отладка.Замер", УровеньЖурналаРегистрации.Предупреждение, , ,
		СтрШаблон("%1: всего %2 мс%3%4", Замер.Операция, Формат(Всего, "ЧН=0; ЧГ=0"),
			Символы.ПС, СтрСоединить(Замер.Этапы, Символы.ПС)));
КонецПроцедуры

// Использование в модуле объекта документа. ЗаполнитьДвижения и ПроверитьОстатки -
// процедуры самого документа, время которых нужно разделить.
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
	Замер = ОтладкаСервер.НачатьЗамер("Проведение " + Строка(Ссылка));
	ЗаполнитьДвижения();
	ОтладкаСервер.Этап(Замер, "Движения");
	ПроверитьОстатки(Отказ);
	ОтладкаСервер.Этап(Замер, "Контроль остатков");
	ОтладкаСервер.ЗавершитьЗамер(Замер, 1000); // в журнал - только дольше секунды
КонецПроцедуры
  • ТекущаяУниверсальнаяДатаВМиллисекундах() даёт миллисекунды и не зависит от часового пояса.
  • Порог отсекает быстрые вызовы, а в записи о медленном сразу видно, какой этап съел время.
  • Уровень «Предупреждение» отделяет замеры от обычных записей при отборе по важности.

Журнал регистрации вместо отладчика

Отладчик не подключить к рабочему серверу без перезапуска службы, к HTTP-сервису, который вызывает внешняя система с таймаутом, к сеансу пользователя в другом городе. Там отладочные записи пишут через ЗаписьЖурналаРегистрации. Чтобы не засорять журнал, подробный режим включается для одного пользователя через хранилище общих настроек — без новых объектов метаданных и перезапуска:

// Общий модуль ОтладкаСервер (продолжение): подробный лог по требованию.

// Включён ли подробный лог для текущего пользователя.
Функция ПодробныйЛог() Экспорт
	Возврат ХранилищеОбщихНастроек.Загрузить("Отладка", "ПодробныйЛог") = Истина;
КонецФункции

// Функция, а не процедура: её можно вызвать и из «Вычислить выражение».
// Чтобы включить лог другому пользователю, нужны административные права.
Функция УстановитьПодробныйЛог(ИмяПользователяИБ, Включить = Истина) Экспорт
	ХранилищеОбщихНастроек.Сохранить("Отладка", "ПодробныйЛог", Включить, , ИмяПользователяИБ);
	Возврат Включить;
КонецФункции

// Шаг операции. ИдОперации связывает все записи одного вызова.
Процедура Шаг(ИдОперации, Текст, Ссылка = Неопределено) Экспорт
	ЗаписьЖурналаРегистрации("Отладка.Шаг", УровеньЖурналаРегистрации.Информация,
		Метаданные.НайтиПоТипу(ТипЗнч(Ссылка)), Ссылка, СтрШаблон("[%1] %2", ИдОперации, Текст));
КонецПроцедуры

Обработчик HTTP-сервиса с этим модулем: ошибка пишется всегда, шаги — только в подробном режиме, а код операции уходит в ответ.

// Модуль HTTP-сервиса Заказы, обработчик метода POST.
Функция ЗаказыPOST(Запрос)
	ИдОперации = Строка(Новый УникальныйИдентификатор);
	Подробно = ОтладкаСервер.ПодробныйЛог();
	Тело = Запрос.ПолучитьТелоКакСтроку();
	Если Подробно Тогда
		ОтладкаСервер.Шаг(ИдОперации, "Получено: " + Лев(Тело, 5000));
	КонецЕсли;
	Попытка
		Заказ = ЗаказыСервер.ЗаписатьЗаказ(Тело); // прикладная логика сервиса
		Если Подробно Тогда
			ОтладкаСервер.Шаг(ИдОперации, "Заказ записан", Заказ);
		КонецЕсли;
		Ответ = Новый HTTPСервисОтвет(200);
	Исключение
		ЗаписьЖурналаРегистрации("Отладка.Ошибка", УровеньЖурналаРегистрации.Ошибка, , ,
			СтрШаблон("[%1] %2", ИдОперации, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())));
		Ответ = Новый HTTPСервисОтвет(500);
		Ответ.УстановитьТелоИзСтроки("Ошибка обработки, код операции " + ИдОперации);
	КонецПопытки;
	Ответ.Заголовки.Вставить("X-Operation-Id", ИдОперации);
	Возврат Ответ;
КонецФункции
  • Режим читается один раз в начале вызова, а не перед каждой записью.
  • Интегратор присылает код из заголовка X-Operation-Id, а вы отбираете события «Отладка.Шаг» и «Отладка.Ошибка» и ищете код в комментарии.
  • Лев(Тело, 5000) ограничивает размер записи; пароли, токены и персональные данные в журнал не пишите.
  • Режим включают вызовом ОтладкаСервер.УстановитьПодробныйЛог("Интеграция") из внешней обработки администратора, выключают — тем же вызовом с Ложь.

Типичные ошибки

  • Точка в серверной процедуре не срабатывает. Кластер запущен без -debug, протоколы сервера и отладчика разные или в «Отладка → Подключение» не подключён «Сервер».
  • Точка стоит, а выполняется другой код. Метод перехвачен расширением через &Вместо — ставьте точку в модуле расширения. Или при F5 отказались обновлять конфигурацию базы данных, и отладка идёт по старому коду.
  • «В данной транзакции уже происходили ошибки!» Исходное исключение перехвачено раньше в той же транзакции. Включите остановку по ошибке — отладчик встанет на первой. Правильный шаблон — в статье о транзакциях.
  • «Переменная не определена (ОтладкаСервер)» в условии точки. Условие вычисляется на клиенте, а у модуля нет флажка «Вызов сервера».
  • Каждый шаг идёт секунды. На табло тяжёлое выражение вроде Запрос.Выполнить().Выгрузить(), и оно выполняется после каждого F10.
  • Остановили чужой сеанс. В общей тестовой базе серверная точка в общем модуле может сработать у коллеги — добавьте условие ИмяПользователя() = "Иванов".

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

Как включить режим отладки, если 1С запущена не из конфигуратора?

Перезапустите клиент с ключом /DEBUG, для HTTP-отладки — с -http -attach /DEBUGGERURL и адресом сервера отладки, как в примере выше. Сеанс появится в «Отладка → Подключение».

Как отладить код расширения?

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

Можно ли отлаживать рабочую базу?

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

Чем отладка в EDT отличается от конфигуратора?

EDT работает только через HTTP-отладку, а клавиши там как в Eclipse: F5 — шаг внутрь, F6 — шаг через, F7 — выход из процедуры, F8 — продолжить. Условные точки, остановка по исключениям и изменение значений переменных есть и там.

Когда проще заказать

Если ошибка воспроизводится только на рабочей базе, «плавает» между сеансами или прячется в обмене и фоновых заданиях, поиск причины легко растягивается на дни. Разместите задание с текстом ошибки и шагами воспроизведения — исполнитель найдёт причину на копии базы и предложит исправление.

По теме

Не хотите разбираться сами?

Адаптируем это решение под вашу базу. Оценка бесплатно.

Оставить задачу

Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.


1С, 1С:Предприятие — товарные знаки ООО «1С». Сайт не является официальным представительством фирмы «1С» и не аффилирован с ней.