Технологический журнал 1С: настройка logcfg.xml

Дата: 10.10.2026 09:23:44
Технологический журнал
Производительность
Администрирование 1С
Сервер 1С
Блокировки
Комментарий:
0
Платформа:
8.3
Конфигурация:
Любая
Формы:
Любые

Технологический журнал 1С 8.3 пишет на диск то, чего нет в журнале регистрации: запросы к СУБД с длительностью и строкой кода, исключения со стеком, ожидания управляемых блокировок, серверные вызовы. Его включают, когда база тормозит «иногда», ошибка у пользователя не оставляет следов или документы падают по таймауту блокировки. Вся настройка технологического журнала 1С — один файл logcfg.xml: ниже — куда его положить, готовые шаблоны, ротация и разбор логов. Общий порядок поиска тормозов — в статье «1С тормозит и зависает».

Где лежит logcfg.xml: сервер, клиент, файловая база

Технологический журнал сервера 1С и клиента настраивается одинаково: файл читает каждый процесс платформы — rphost, rmngr, ragent, клиентские приложения, модуль веб-сервера — в каталоге conf своей установки. Таких каталогов два:

Каталог confWindows, 64-разрядная платформаLinux
Общий для всех версийC:\Program Files\1cv8\conf/opt/1cv8/conf
Конкретной версииC:\Program Files\1cv8\8.3.27.xxxx\bin\conf/opt/1cv8/x86_64/8.3.27.xxxx/conf

В каталоге версии обычно лежит только conf.cfg: его параметр ConfLocation указывает на общий каталог. Кладите logcfg.xml туда — после обновления платформы журнал продолжит писаться. Если ConfLocation ведёт в другое место, кладите файл по этому пути. У 32-разрядной платформы корень — C:\Program Files (x86)\1cv8, а в старых Linux-установках из deb- и rpm-пакетов каталог /opt/1C/v8.3/x86_64/conf создают вручную.

Какой компьютер настраивать, зависит от того, где выполняется код:

Что расследуемКто пишет журналКуда положить logcfg.xml
Клиент-серверная база: запросы, блокировки, серверный кодrphost, rmngr, ragentна каждый рабочий сервер кластера
Клиентский код, ожидание ответа сервера1cv8c, 1cv8компьютер пользователя или терминальный сервер
Файловая базаклиентское приложение: в нём выполняется и серверный кодкомпьютер пользователя
Публикация на веб-серверепроцесс Apache или IIS с модулем 1Свеб-сервер

Каталог из location создайте заранее и дайте право записи учётной записи процесса: службе сервера 1С (по умолчанию USR1CV8 в Windows, usr1cv8 в Linux), пользователю — для клиентского журнала, службе Apache или пулу IIS — для веб-сервера. Перезапускать сервер 1С не нужно: процессы сами перечитывают logcfg.xml и в течение минуты начинают или прекращают запись. Признак, что журнал пишется, — подкаталоги вида rphost_4120 в каталоге журнала.

# Windows, PowerShell от администратора: каталог журнала с правом записи для службы 1С
New-Item -ItemType Directory -Force D:\techlog | Out-Null
icacls D:\techlog /grant "USR1CV8:(OI)(CI)M"
Copy-Item .\logcfg.xml "C:\Program Files\1cv8\conf\"
# Linux: то же для usr1cv8; в шаблонах location="/var/log/1c/techlog/sql" и т.п.
sudo mkdir -p /var/log/1c/techlog
sudo chown -R usr1cv8:grp1cv8 /var/log/1c/techlog
sudo cp logcfg.xml /opt/1cv8/conf/

Настройка технологического журнала 1С 8.3: шаблоны под задачи

Каждый шаблон — законченный logcfg.xml. Чтобы собирать несколько вещей сразу, перенесите элементы <log> в один <config>, у каждого — свой каталог. Вместо trade подставьте имя базы из консоли кластера.

Долгие запросы к СУБД: DBMSSQL и DBPOSTGRS

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://v8.1c.ru/v8/tech-log">
  <!-- Запросы к СУБД дольше 1 секунды в базе trade -->
  <log location="D:\techlog\sql" history="24">
    <event>
      <eq property="Name" value="DBMSSQL"/>
      <eq property="p:processName" value="trade"/>
      <ge property="Durationus" value="1000000"/>
    </event>
    <event>
      <eq property="Name" value="DBPOSTGRS"/>
      <eq property="p:processName" value="trade"/>
      <ge property="Durationus" value="1000000"/>
    </event>
    <property name="all"/>
  </log>
  <!-- Планы запросов: нагрузка на сервер, включайте на время разбора -->
  <plansql/>
</config>

Разбор ключевых строк:

  • xmlns="http://v8.1c.ru/v8/tech-log" — обязательное пространство имён; location — каталог, history — сколько часов хранить файлы.
  • Условия внутри одного <event> объединяются через «И», разные <event> — через «ИЛИ». Кроме eq и ge есть ne, gt, lt, le и like (шаблон, % — любые символы).
  • p:processName — имя базы в кластере, а не имя базы данных в СУБД.
  • Durationus — микросекунды: 1000000 — одна секунда. В старых примерах встречается Duration в десятитысячных долях секунды, не смешивайте их.
  • <property name="all"/> — все свойства события, включая Sql и Context.
  • <plansql/> пишет план запроса в planSQLText и нагружает сервер — включайте только на время разбора.

В файловой базе запросы пишет событие DBV8DBENG на компьютере пользователя.

Исключения: EXCP

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://v8.1c.ru/v8/tech-log">
  <!-- Исключения базы trade: класс, текст ошибки и стек кода -->
  <log location="D:\techlog\excp" history="72">
    <event>
      <eq property="Name" value="EXCP"/>
      <eq property="p:processName" value="trade"/>
    </event>
    <property name="all"/>
  </log>
</config>

В записи — класс ошибки (Exception), текст (Descr) и стек (Context). Попадают и ошибки, перехваченные в Попытка…Исключение, поэтому событий больше, чем жалоб. Шаблон для случая «у пользователя ошибка, а в журнале регистрации пусто»: запись находят по времени и Usr.

Управляемые блокировки: TLOCK, TTIMEOUT, TDEADLOCK

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://v8.1c.ru/v8/tech-log">
  <!-- Таймауты, взаимоблокировки и ожидания управляемых блокировок дольше 1 с -->
  <log location="D:\techlog\locks" history="48">
    <event>
      <eq property="Name" value="TTIMEOUT"/>
    </event>
    <event>
      <eq property="Name" value="TDEADLOCK"/>
    </event>
    <event>
      <eq property="Name" value="TLOCK"/>
      <eq property="p:processName" value="trade"/>
      <ge property="Durationus" value="1000000"/>
    </event>
    <property name="all"/>
  </log>
</config>

TTIMEOUT (истекло ожидание блокировки) и TDEADLOCK (взаимоблокировка) случаются редко, их можно не выключать. TLOCK пишется на каждую управляемую блокировку, поэтому шаблон берёт только ожидания дольше секунды: длительность TLOCK включает время ожидания. Как найти, кто держал данные, — в статье «Конфликт блокировок 1С».

Долгие серверные вызовы: CALL и SCALL

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://v8.1c.ru/v8/tech-log">
  <!-- Серверные вызовы дольше 5 секунд: что вызвали, память, процессор -->
  <log location="D:\techlog\calls" history="24">
    <event>
      <eq property="Name" value="CALL"/>
      <eq property="p:processName" value="trade"/>
      <ge property="Durationus" value="5000000"/>
    </event>
    <property name="all"/>
  </log>
</config>

CALL — входящий вызов на сервере, например серверной процедуры с клиента: в записи есть Context, память, процессорное время и объём переданных данных. SCALL — исходящий вызов: на компьютере пользователя он показывает, сколько клиент ждал сервер вместе с сетью.

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://v8.1c.ru/v8/tech-log">
  <!-- Компьютер пользователя: вызовы сервера дольше 1 с и ошибки клиента -->
  <log location="C:\techlog\client" history="24">
    <event>
      <eq property="Name" value="SCALL"/>
      <ge property="Durationus" value="1000000"/>
    </event>
    <event>
      <eq property="Name" value="EXCP"/>
    </event>
    <property name="all"/>
  </log>
</config>

Если клиентский SCALL намного длиннее серверного CALL того же сеанса, время уходит на сеть, а не на код.

logcfg.xml из кода

Чтобы настроить технологический журнал без ошибок в кодировке и единицах, шаблон удобно собирать кодом — например, во внешней обработке администратора. ЗаписьXML сама экранирует значения и пишет объявление с UTF-8.

// Модуль объекта внешней обработки «Разбор технологического журнала».
// Текст logcfg.xml: события одной базы не короче порога (ПорогМс = 0 - без порога).
// Пример: Текст = ТекстНастройкиЖурнала("D:\techlog\sql", "trade", 1000);
Функция ТекстНастройкиЖурнала(Каталог, ИмяБазы = "", ПорогМс = 0, ЧасовХранения = 24,
	События = "DBMSSQL,DBPOSTGRS") Экспорт

	Запись = Новый ЗаписьXML;
	Запись.УстановитьСтроку(Новый ПараметрыЗаписиXML("UTF-8", "1.0", Истина, Ложь, "  "));
	Запись.ЗаписатьОбъявлениеXML();
	Запись.ЗаписатьНачалоЭлемента("config");
	Запись.ЗаписатьСоответствиеПространстваИмен("", "http://v8.1c.ru/v8/tech-log");
	Запись.ЗаписатьНачалоЭлемента("log");
	Запись.ЗаписатьАтрибут("location", Каталог);
	Запись.ЗаписатьАтрибут("history", XMLСтрока(ЧасовХранения));

	Для Каждого ИмяСобытия Из СтрРазделить(События, ", ", Ложь) Цикл
		Запись.ЗаписатьНачалоЭлемента("event");
		ЗаписатьУсловие(Запись, "eq", "Name", ВРег(ИмяСобытия));
		Если Не ПустаяСтрока(ИмяБазы) Тогда
			ЗаписатьУсловие(Запись, "eq", "p:processName", ИмяБазы);
		КонецЕсли;
		Если ПорогМс > 0 Тогда // Durationus - микросекунды
			ЗаписатьУсловие(Запись, "ge", "Durationus", XMLСтрока(ПорогМс * 1000));
		КонецЕсли;
		Запись.ЗаписатьКонецЭлемента(); // event
	КонецЦикла;

	Запись.ЗаписатьНачалоЭлемента("property");
	Запись.ЗаписатьАтрибут("name", "all");
	Запись.ЗаписатьКонецЭлемента(); // property
	Запись.ЗаписатьКонецЭлемента(); // log
	Запись.ЗаписатьКонецЭлемента(); // config
	Возврат Запись.Закрыть();

КонецФункции

// Условие отбора вида <eq property="Name" value="DBMSSQL"/>.
Процедура ЗаписатьУсловие(Запись, Операция, ИмяСвойства, Значение)
	Запись.ЗаписатьНачалоЭлемента(Операция);
	Запись.ЗаписатьАтрибут("property", ИмяСвойства);
	Запись.ЗаписатьАтрибут("value", Значение);
	Запись.ЗаписатьКонецЭлемента();
КонецПроцедуры

Результат сохраните в logcfg.xml в кодировке UTF-8.

Ротация, history и объём логов

Каждый процесс пишет в свой подкаталог <процесс>_<PID> файлы по часам с именем ггммддчч.log: 26101014.log — 10 октября 2026 года, с 14:00 до 15:00. Файлы старше history часов платформа удаляет сама, так что на диске лежит примерно «объём за час × history».

  • Объём задают отборы: DBMSSQL без порога или TLOCK без условий на нагруженной базе могут давать гигабайты в час.
  • Пишите журнал не на системный диск и не на диск с файлами СУБД.
  • Берите history с запасом на разбор, а нужные часы копируйте в сторону.
  • В 8.3.25 добавили размещение файлов в одном каталоге, ротацию по периоду или размеру, сжатие и JSON; имена атрибутов — в документации своей версии.

Главный риск — забытый logcfg.xml с широким отбором, который съедает диск. Проверку размера повесьте на регламентное задание — оно проверит диск того сервера, где выполнилось.

// Серверный общий модуль ТехЖурналКонтроль: метод регламентного задания.
// Предупреждает в журнале регистрации, если каталог журнала разросся.
Процедура ПроверитьРазмерЖурнала(Каталог = "D:\techlog", ЛимитМБ = 20480) Экспорт
	Размер = РазмерЖурнала(Каталог);
	Если Размер.МБ > ЛимитМБ Тогда
		ЗаписьЖурналаРегистрации("ТехнологическийЖурнал.Размер", УровеньЖурналаРегистрации.Предупреждение, , ,
			СтрШаблон("Каталог %1: %2 МБ в %3 файлах, самый старый изменён %4. Проверьте logcfg.xml и history.",
				Каталог, Размер.МБ, Размер.Файлов, Размер.СамыйСтарый));
	КонецЕсли;
КонецПроцедуры

// Сколько места занимают файлы *.log в каталоге и подкаталогах процессов.
Функция РазмерЖурнала(Каталог) Экспорт
	Результат = Новый Структура("Файлов, МБ, СамыйСтарый", 0, 0, Неопределено);
	Байт = 0;
	Для Каждого Файл Из НайтиФайлы(Каталог, "*.log", Истина) Цикл
		Попытка
			Байт = Байт + Файл.Размер();
			Изменен = Файл.ПолучитьВремяИзменения();
		Исключение
			Продолжить; // файл удалён по history во время обхода
		КонецПопытки;
		Если Результат.СамыйСтарый = Неопределено Или Изменен < Результат.СамыйСтарый Тогда
			Результат.СамыйСтарый = Изменен;
		КонецЕсли;
		Результат.Файлов = Результат.Файлов + 1;
	КонецЦикла;
	Результат.МБ = Окр(Байт / 1048576, 1);
	Возврат Результат;
КонецФункции

Как читать файл технологического журнала

Файл текстовый, в UTF-8. Каждое событие начинается с новой строки со времени, а значения в кавычках — текст запроса, стек — могут занимать несколько строк. Пример записи (сокращён, имена условные):

46:02.123004-1520345,DBMSSQL,5,process=rphost,p:processName=trade,OSThread=5120,t:clientID=27,t:applicationName=1CV8C,t:computerName=pc-12,t:connectID=311,SessionID=48,Usr=Кладовщик,Trans=1,dbpid=73,Sql='SELECT T1._IDRRef, T1._Date_Time FROM dbo._Document123 T1 WHERE T1._Date_Time >= @P1',Rows=1840,Context='ОбщийМодуль.ОбменССайтомСервер.Модуль : 120 : ЗагрузитьЗаказы(Пакет);
	ОбщийМодуль.ОбменССайтомСервер.Модуль : 214 : Выборка = Запрос.Выполнить().Выбрать();'
ФрагментЧто значит
46:02.123004минуты, секунды и микросекунды; дата и час — в имени файла
-1520345длительность в микросекундах, здесь 1,52 с
DBMSSQL,5имя события и уровень
p:processName, Usr, SessionIDбаза в кластере, пользователь, номер сеанса
t:computerName, t:applicationNameкомпьютер и тип приложения: 1CV8C — тонкий клиент, BackgroundJob — фоновое задание
Sql, Rowsтекст запроса к СУБД и число строк результата
Contextстек кода 1С; последняя строка — место, откуда выполнен запрос

Свойства по событиям:

СобытиеЧто этоНа что смотреть
DBMSSQL, DBPOSTGRS, DBV8DBENGзапрос к MS SQL, PostgreSQL, файловой базеSql, Rows, RowsAffected, planSQLText
EXCPисключениеException — класс, Descr — текст ошибки
TLOCKустановка управляемой блокировкиRegions — пространства блокировок, WaitConnections — чьё соединение ждали
TTIMEOUTистекло время ожидания блокировкиWaitConnections
TDEADLOCKвзаимоблокировкаDeadlockConnectionIntersections
CALLвходящий вызов на сервереMemory, MemoryPeak, CpuTime, InBytes, OutBytes
SCALLисходящий вызовIName, MName — интерфейс и метод

PowerShell и grep

Для первого взгляда хватает строк-заголовков: в них есть длительность и имя события. На Windows-сервере:

# 20 самых долгих запросов к СУБД: секунды, файл и номер строки
$dir = 'D:\techlog\sql'
Get-ChildItem $dir -Recurse -Filter *.log |
  Select-String -Encoding UTF8 -Pattern '^\d\d:\d\d\.\d+-(\d+),(DBMSSQL|DBPOSTGRS|DBV8DBENG),' |
  ForEach-Object {
    [pscustomobject]@{
      Sec  = [math]::Round([long]$_.Matches[0].Groups[1].Value / 1e6, 2)
      File = $_.Path
      Line = $_.LineNumber
    }
  } | Sort-Object Sec -Descending | Select-Object -First 20 | Format-Table -AutoSize

# Запись целиком: 40 строк, начиная с найденной (здесь Line = 1235)
Get-Content 'D:\techlog\sql\rphost_4120\26101014.log' -Encoding UTF8 |
  Select-Object -Skip 1234 -First 40

# Какие исключения чаще всего: EXCP по классу ошибки
Get-ChildItem 'D:\techlog\excp' -Recurse -Filter *.log |
  Select-String -Encoding UTF8 -Pattern ',EXCP,.*?Exception=([^,]+)' |
  Group-Object { $_.Matches[0].Groups[1].Value } -NoElement |
  Sort-Object Count -Descending | Select-Object -First 15

На Linux многострочные записи сначала склеивают, потом сортируют по длительности:

# Linux: склеить многострочные записи и вывести 20 самых долгих запросов к СУБД
cd /var/log/1c/techlog/sql
LC_ALL=C awk -v ev='DBMSSQL|DBPOSTGRS' '
  function flush() { if (keep) print rec; keep = 0 }
  FNR == 1 { sub(/^\357\273\277/, "") }               # BOM в начале файла
  /^[0-9]+:[0-9]+\.[0-9]+-[0-9]+,/ {                  # начало новой записи
    flush()
    split($0, f, ",")                                 # f[1] = время-длительность, f[2] = событие
    keep = (f[2] ~ ("^(" ev ")$"))
    d = f[1]; sub(/.*-/, "", d)
    rec = d "\t" FILENAME "\t" $0; next
  }
  { rec = rec " " $0 }                                # продолжение текста запроса или стека
  END { flush() }' */*.log |
  sort -t "$(printf '\t')" -k1,1nr | head -20 | cut -c1-400

# Взаимоблокировки и таймауты блокировок по файлам
grep -rcE ',(TDEADLOCK|TTIMEOUT),' --include='*.log' /var/log/1c/techlog/locks | grep -v ':0$'

Разбор журнала кодом 1С

Нет доступа к серверу по RDP или SSH, но есть права администратора в базе — читайте журнал из 1С: серверный код видит диск сервера. Ниже — модуль объекта внешней обработки. Открывайте её через «Файл → Открыть»: в безопасном режиме чтение файлов запрещено.

// Модуль объекта обработки (продолжение). Код работает там, где создан объект:
// при вызове из серверной процедуры формы - на сервере 1С, поэтому Каталог -
// путь на сервере, тот же, что в location. Подкаталоги процессов обходятся сами.
// ИменаСобытий - "DBMSSQL,EXCP" и т.п., пустая строка - все события.
Функция ПрочитатьЖурнал(Каталог, ИменаСобытий = "", МинимумМс = 0) Экспорт

	Если Не ПравоДоступа("Администрирование", Метаданные) Тогда
		ВызватьИсключение "Читать технологический журнал может только администратор";
	КонецЕсли;

	Таблица = Новый ТаблицаЗначений;
	Для Каждого Колонка Из СтрРазделить("Момент,Событие,ДлительностьМс,База,Пользователь,Контекст,Свойства,Файл", ",") Цикл
		Таблица.Колонки.Добавить(Колонка);
	КонецЦикла;

	Отбор = Новый Соответствие;
	Для Каждого Имя Из СтрРазделить(ВРег(ИменаСобытий), ", ", Ложь) Цикл
		Отбор.Вставить(Имя, Истина);
	КонецЦикла;

	Для Каждого Файл Из НайтиФайлы(Каталог, "*.log", Истина) Цикл
		Попытка
			// Ложь - разделяемый режим: в файл текущего часа ещё пишет процесс сервера
			Чтение = Новый ЧтениеТекста(Файл.ПолноеИмя, КодировкаТекста.UTF8, , , Ложь);
		Исключение
			Продолжить; // файл удалён по history, пока шёл обход
		КонецПопытки;
		ТекстЗаписи = "";
		СтрокаФайла = Чтение.ПрочитатьСтроку();
		Пока СтрокаФайла <> Неопределено Цикл
			Если Лев(СтрокаФайла, 1) = Символ(65279) Тогда // BOM в начале файла
				СтрокаФайла = Сред(СтрокаФайла, 2);
			КонецЕсли;
			Если ЭтоНачалоЗаписи(СтрокаФайла) Тогда
				ДобавитьСобытие(Таблица, ТекстЗаписи, Файл, Отбор, МинимумМс);
				ТекстЗаписи = СтрокаФайла;
			Иначе // продолжение многострочного значения: текст запроса, стек
				ТекстЗаписи = ТекстЗаписи + Символы.ПС + СтрокаФайла;
			КонецЕсли;
			СтрокаФайла = Чтение.ПрочитатьСтроку();
		КонецЦикла;
		Чтение.Закрыть();
		ДобавитьСобытие(Таблица, ТекстЗаписи, Файл, Отбор, МинимумМс);
	КонецЦикла;

	Возврат Таблица;

КонецФункции

// Запись начинается со времени "мм:сс.мкс-длительность," (дата и час - в имени
// файла ггммддчч.log) или с полной датой "гггг-мм-ддTчч:мм:сс.мкс-длительность,".
Функция ЭтоНачалоЗаписи(СтрокаФайла)
	Если Сред(СтрокаФайла, 3, 1) = ":" И Сред(СтрокаФайла, 6, 1) = "." Тогда
		Возврат ТолькоЦифры(Лев(СтрокаФайла, 2) + Сред(СтрокаФайла, 4, 2));
	ИначеЕсли Сред(СтрокаФайла, 5, 1) = "-" И Сред(СтрокаФайла, 11, 1) = "T" Тогда
		Возврат ТолькоЦифры(Лев(СтрокаФайла, 4));
	КонецЕсли;
	Возврат Ложь;
КонецФункции

Процедура ДобавитьСобытие(Таблица, ТекстЗаписи, Файл, Отбор, МинимумМс)

	Если ПустаяСтрока(ТекстЗаписи) Тогда
		Возврат;
	КонецЕсли;
	// Шапка без кавычек: время-длительность,СОБЫТИЕ,уровень, дальше свойства
	Запятая1 = СтрНайти(ТекстЗаписи, ",");
	Запятая2 = НайтиДалее(ТекстЗаписи, ",", Запятая1 + 1);
	Если Запятая1 < 2 Или Запятая2 = 0 Тогда
		Возврат; // оборванная запись
	КонецЕсли;
	Событие = ВРег(Сред(ТекстЗаписи, Запятая1 + 1, Запятая2 - Запятая1 - 1));
	Если Отбор.Количество() > 0 И Отбор[Событие] = Неопределено Тогда
		Возврат;
	КонецЕсли;

	// Длительность - после последнего дефиса: в полном формате дефисы есть и в дате
	Шапка = Лев(ТекстЗаписи, Запятая1 - 1);
	Дефис = СтрНайти(Шапка, "-", НаправлениеПоиска.СКонца);
	Микросекунд = Сред(Шапка, Дефис + 1);
	Если Дефис = 0 Или Не ТолькоЦифры(Микросекунд) Тогда
		Возврат;
	КонецЕсли;
	ДлительностьМс = Число(Микросекунд) / 1000;
	Если ДлительностьМс < МинимумМс Тогда
		Возврат;
	КонецЕсли;

	Запятая3 = НайтиДалее(ТекстЗаписи, ",", Запятая2 + 1);
	Свойства = СвойстваЗаписи(ТекстЗаписи, ?(Запятая3 = 0, СтрДлина(ТекстЗаписи) + 1, Запятая3 + 1));

	НоваяСтрока = Таблица.Добавить();
	НоваяСтрока.Момент = МоментСобытия(Файл.ИмяБезРасширения, Лев(Шапка, Дефис - 1));
	НоваяСтрока.Событие = Событие;
	НоваяСтрока.ДлительностьМс = ДлительностьМс;
	НоваяСтрока.База = Свойство(Свойства, "p:processName");
	НоваяСтрока.Пользователь = Свойство(Свойства, "Usr");
	НоваяСтрока.Контекст = Свойство(Свойства, "Context");
	НоваяСтрока.Свойства = Свойства;
	НоваяСтрока.Файл = Файл.ПолноеИмя;

КонецПроцедуры

// Свойства "Имя=Значение" через запятую. Значение в одинарных или двойных
// кавычках может содержать запятые и переводы строк, кавычка внутри удваивается.
Функция СвойстваЗаписи(ТекстЗаписи, Начало)

	Свойства = Новый Соответствие;
	Длина = СтрДлина(ТекстЗаписи);
	Позиция = Начало;
	Пока Позиция <= Длина Цикл
		Равно = НайтиДалее(ТекстЗаписи, "=", Позиция);
		Если Равно = 0 Тогда
			Прервать;
		КонецЕсли;
		Имя = Сред(ТекстЗаписи, Позиция, Равно - Позиция);
		Позиция = Равно + 1;
		Кавычка = Сред(ТекстЗаписи, Позиция, 1);
		Если Кавычка = "'" Или Кавычка = """" Тогда
			Значение = "";
			Позиция = Позиция + 1;
			Пока Позиция <= Длина Цикл
				Граница = НайтиДалее(ТекстЗаписи, Кавычка, Позиция);
				Если Граница = 0 Тогда
					Граница = Длина + 1; // кавычка не закрыта: берём до конца записи
				КонецЕсли;
				Значение = Значение + Сред(ТекстЗаписи, Позиция, Граница - Позиция);
				Позиция = Граница + 1;
				Если Сред(ТекстЗаписи, Позиция, 1) = Кавычка Тогда
					Значение = Значение + Кавычка; // удвоенная кавычка - символ внутри значения
					Позиция = Позиция + 1;
				Иначе
					Позиция = Позиция + 1; // пропускаем запятую после значения
					Прервать;
				КонецЕсли;
			КонецЦикла;
		Иначе
			Граница = НайтиДалее(ТекстЗаписи, ",", Позиция);
			Если Граница = 0 Тогда
				Граница = Длина + 1;
			КонецЕсли;
			Значение = Сред(ТекстЗаписи, Позиция, Граница - Позиция);
			Позиция = Граница + 1;
		КонецЕсли;
		Свойства.Вставить(Имя, Значение);
	КонецЦикла;
	Возврат Свойства;

КонецФункции

// Дата события с точностью до секунды: в коротком формате час - из имени файла.
Функция МоментСобытия(ИмяФайла, Время)
	Если СтрДлина(Время) >= 19 И Сред(Время, 11, 1) = "T" Тогда
		ДатаСтрокой = СтрЗаменить(СтрЗаменить(СтрЗаменить(Лев(Время, 19), "-", ""), "T", ""), ":", "");
	ИначеЕсли СтрДлина(ИмяФайла) = 8 И ТолькоЦифры(ИмяФайла) Тогда
		ДатаСтрокой = "20" + ИмяФайла + Лев(Время, 2) + Сред(Время, 4, 2);
	Иначе
		Возврат Неопределено;
	КонецЕсли;
	Попытка
		Возврат Дата(ДатаСтрокой);
	Исключение
		Возврат Неопределено;
	КонецПопытки;
КонецФункции

// СтрНайти с проверкой: начальная позиция за концом строки - ошибка платформы.
Функция НайтиДалее(Текст, Подстрока, Позиция)
	Если Позиция > СтрДлина(Текст) Тогда
		Возврат 0;
	КонецЕсли;
	Возврат СтрНайти(Текст, Подстрока, , Позиция);
КонецФункции

Функция ТолькоЦифры(Текст)
	Для Номер = 1 По СтрДлина(Текст) Цикл
		Если СтрНайти("0123456789", Сред(Текст, Номер, 1)) = 0 Тогда
			Возврат Ложь;
		КонецЕсли;
	КонецЦикла;
	Возврат СтрДлина(Текст) > 0;
КонецФункции

Функция Свойство(Свойства, Имя)
	Значение = Свойства[Имя];
	Возврат ?(Значение = Неопределено, "", Значение);
КонецФункции

Сводка «где в коде больше всего времени уходит на запросы» — в тот же модуль:

// Где в коде больше всего времени уходит на запросы к СУБД. Группировка по
// последней строке Context - строке модуля, которая выполнила запрос.
Функция ТопКонтекстов(Каталог, Количество = 20, МинимумМс = 0) Экспорт

	Итог = Новый ТаблицаЗначений;
	Итог.Колонки.Добавить("МестоВКоде", Новый ОписаниеТипов("Строка"));
	Итог.Колонки.Добавить("Запросов", Новый ОписаниеТипов("Число"));
	Итог.Колонки.Добавить("ВсегоСек", Новый ОписаниеТипов("Число"));
	Итог.Колонки.Добавить("МаксимумМс", Новый ОписаниеТипов("Число"));
	Итог.Колонки.Добавить("ТекстЗапроса", Новый ОписаниеТипов("Строка"));

	ПоМесту = Новый Соответствие;
	События = ПрочитатьЖурнал(Каталог, "DBMSSQL,DBPOSTGRS,DBV8DBENG", МинимумМс);
	Для Каждого Событие Из События Цикл
		СтрокиСтека = СтрРазделить(Событие.Контекст, Символы.ПС, Ложь);
		Место = ?(СтрокиСтека.Количество() = 0, "<без контекста>",
			СокрЛП(СтрокиСтека[СтрокиСтека.ВГраница()]));
		СтрокаИтога = ПоМесту[Место];
		Если СтрокаИтога = Неопределено Тогда
			СтрокаИтога = Итог.Добавить();
			СтрокаИтога.МестоВКоде = Место;
			ПоМесту.Вставить(Место, СтрокаИтога);
		КонецЕсли;
		СтрокаИтога.Запросов = СтрокаИтога.Запросов + 1;
		СтрокаИтога.ВсегоСек = СтрокаИтога.ВсегоСек + Событие.ДлительностьМс / 1000;
		Если Событие.ДлительностьМс > СтрокаИтога.МаксимумМс Тогда
			СтрокаИтога.МаксимумМс = Событие.ДлительностьМс; // запоминаем самый долгий
			СтрокаИтога.ТекстЗапроса = Лев(Свойство(Событие.Свойства, "Sql"), 3000);
		КонецЕсли;
	КонецЦикла;

	Итог.Сортировать("ВсегоСек Убыв");
	Пока Итог.Количество() > Количество Цикл
		Итог.Удалить(Итог.Количество() - 1);
	КонецЦикла;
	Возврат Итог;

КонецФункции

Форма вызывает обе функции на сервере — с клиента файлы сервера недоступны:

// Модуль формы обработки. Реквизиты обработки: Каталог, ИмяБазы, ТекстНастройки
// (Строка); реквизит формы ТопЗапросов (ТаблицаЗначений) с колонками
// МестоВКоде, Запросов, ВсегоСек, МаксимумМс, ТекстЗапроса.
&НаКлиенте
Процедура СобратьНастройку(Команда)
	СобратьНастройкуНаСервере();
КонецПроцедуры

&НаКлиенте
Процедура РазобратьЖурнал(Команда)
	Если ПустаяСтрока(Объект.Каталог) Тогда
		ПоказатьПредупреждение(, "Укажите каталог журнала на сервере 1С");
		Возврат;
	КонецЕсли;
	РазобратьЖурналНаСервере();
КонецПроцедуры

&НаСервере
Процедура СобратьНастройкуНаСервере()
	Обработка = РеквизитФормыВЗначение("Объект");
	Объект.ТекстНастройки = Обработка.ТекстНастройкиЖурнала(Объект.Каталог, Объект.ИмяБазы, 1000);
КонецПроцедуры

&НаСервере
Процедура РазобратьЖурналНаСервере()
	// Файлы читает рабочий процесс сервера: с клиента диск сервера не виден
	Обработка = РеквизитФормыВЗначение("Объект");
	ЗначениеВРеквизитФормы(Обработка.ТопКонтекстов(Объект.Каталог, 20), "ТопЗапросов");
КонецПроцедуры

Разбор ключевых строк:

  • ЧтениеТекста(..., Ложь) — разделяемый режим: в файл текущего часа ещё пишет сервер, а по умолчанию файл открывается монопольно.
  • ЭтоНачалоЗаписи режет записи по времени в начале строки, в том числе в полном формате даты из 8.3.25.
  • СвойстваЗаписи читает значение в кавычках до парной кавычки, удвоенная кавычка — символ внутри.
  • НайтиДалее страхует от ошибки «Неверное значение параметра»: СтрНайти не принимает позицию за концом строки.
  • ТопКонтекстов группирует по последней строке Context — строке, которая выполнила запрос, — и хранит SQL самого долгого. Запрос 1С из этой строки удобно повторить в консоли запросов.

Все события держатся в памяти: для каталога в сотни мегабайт сначала сузьте отбор в logcfg.xml.

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

  • Журнал не появился и через минуту. Файл лежит не в том conf (другая версия, 32-разрядная платформа, компьютер разработчика вместо сервера) или у службы нет права записи в каталог location.
  • Файл сохранён в ANSI. В объявлении указана UTF-8, а комментарий или имя базы написаны по-русски: XML не разбирается, журнал не пишется.
  • Перепутаны единицы. Durationus со значением 1000 — это миллисекунда, а не секунда, и журнал разрастается за минуты.
  • Файл правильный, а журнал пустой. В p:processName указано имя базы данных в СУБД, а не в кластере, или файл лежит только на одном из рабочих серверов.
  • Код 1С не читает файлы. Обработка подключена как дополнительная и работает в безопасном режиме, или файл текущего часа открыт монопольно.

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

Как выключить технологический журнал без перезапуска сервера?

Удалите или переименуйте logcfg.xml: процессы перечитывают настройку сами, и через минуту запись прекратится. Собранные файлы удалите вручную — чистить их по history уже некому.

Можно ли собрать журнал по одному пользователю?

Да: добавьте в <event> условие <eq property="Usr" value="Кладовщик"/> с именем пользователя базы. Так же отбирают по компьютеру (t:computerName) и номеру сеанса (SessionID).

Можно ли держать журнал включённым постоянно?

Да, с узкими отборами: EXCP, TTIMEOUT, TDEADLOCK и запросы дольше нескольких секунд, history на двое-трое суток. TLOCK без порога и <plansql/> включайте только на время расследования.

Чем технологический журнал отличается от журнала регистрации?

Журнал регистрации хранит прикладные события — кто записал документ, какая ошибка у пользователя — и открывается из 1С. Технологический журнал пишет в файлы события платформы: запросы к СУБД, блокировки, вызовы. О первом — в статье «Где в 1С журнал регистрации».

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

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

По теме

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

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

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

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


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