Зачем
Бывают ситуации, когда нет возможности отладить код. Зачастую вообще нет доступа до базы, в которой требуется отладка. Соответственно, понять, в чем же проблема, и тем более ее устранить получается не всегда.
В сообществе уже существуют решения для логирования (см. ссылки в конце статьи). Во многом, данная разработка основана на них, но есть несколько существенных отличий.
Во-первых, хотелось отказаться от передачи переменной или обработки во все участки кода, где требуется запись лога. Вместо этого один раз проинициализировать логирование и затем обращаться к нему из любого метода и контекста. Например, для записи информации об ошибке достаточно написать лЛог.От_("Мое сообщение"). Причем, если сделать небольшую адаптацию под конкретную базу, можно вызывать логирование без предварительной инициализации.
Во-вторых, хотелось иметь возможность, чтобы пользователь самостоятельно мог подключить логирование и, повторив ошибку, прислать файл с логами.
В-третьих, заложить в решение возможность адаптации под конкретные условия. Например, добавление своего способа логирования (отправка на сторонний сервис, мессенджер и т.п.).
Совместимость
Для поставки в виде расширения режим совместимости конфигурации должен быть 8.3.12 и выше.
Для поставки в виде конфигурации должно работать и с более ранними режимами совместимости. Но это не проверялось
Ограничений по операционной системе не нашел.
Тестировалось на платформах 8.3.14.2095, 8.3.17.1851
Общий концепт
В системе задается несколько настроек логов. Вся работа с логами идет в разрезе настроек логов.
Для каждой настройки логов задается уровень срабатывания записи и способы записи логов(способы логирования), шаблон сообщения и другие настройки. У каждой настройки логирования одновременно могут быть несколько способов логирования.
Имя настройки лога можно не указывать в методах. В этом случае используется имя по умолчанию "logFor1C"
При выводе сообщения происходит поиск настройки логов. Далее проверяется необходимость срабатывания по уровню логирования. После происходит вывод сообщения последовательно всеми способами, указанными в настройке.
Инициализация
- Инициализация с настройками по умолчанию
лЛог.НовыйЛог();
- Инициализация по наименованию настройки
лЛог.НовыйЛог(Наименование);
Далее все логирование должно идти с указанием имени лога
Особенности изменения настроек лога на сервере
Ввиду технологических ограничений (отсутствия единого хранилища для клиента и сервера), пришлось реализовать отдельные хранилища для клиента и сервера. При создании/настройке лога на клиенте, настройки автоматически обновляются на сервере.
При инициализации лога или изменении его настроек на сервере, после завершения серверного вызова нужно на клиенте вызвать метод
лЛог.ОбновитьЛогиНаКлиентеПоДаннымСервера();
Уровни логирования и основные методы
В подсистеме используется следующие (по возрастанию приоритета):
- НЕТ - Логирование не происходит
- ОТЛАДКА
- ИНФОРМАЦИЯ
- ПРЕДУПРЕЖДЕНИЕ
- ОШИБКА
- КРИТИЧЕСКАЯОШИБКА
По умолчанию используется уровень логирования ИНФОРМАЦИЯ. При установке какого-либо уровня, в лог будут выводиться только сообщения этого уровня и уровней с большим приоритетом. Уровень логирования задается для каждого инициализированного лога отдельно.
Например, если установлен уровень ПРЕДУПРЕЖДЕНИЕ то будут выводиться сообщения следующих уровней: ПРЕДУПРЕЖДЕНИЕ, ОШИБКА, КРИТИЧЕСКАЯОШИБКА.
Уровень логирования можно изменить с помощью метода УстановитьУровеньЛогирования():
лЛог.УстановитьУровеньЛогирования("Ошибка");
лЛог.УстановитьУровеньЛогирования("Ошибка", "НеОсновнойЛог");
Вывод сообщений в лог
Каждому уровню логирования соответствует свой метод вывода информации:
лЛог.Отл_("Отладочное сообщение", ИмяЛога = Неопределено);
лЛог.Пред_("Отладочное сообщение", ИмяЛога = Неопределено);
лЛог.Инф_("Отладочное сообщение", ИмяЛога = Неопределено);
лЛог.Ош_("Отладочное сообщение", ИмяЛога = Неопределено);
лЛог.Крит_("Отладочное сообщение", ИмяЛога = Неопределено);
Так же есть длинные варианты тех же методов
лЛог.Отладка_("Отладочное сообщение", ИмяЛога = Неопределено);
лЛог.Информация_("Отладочное сообщение", ИмяЛога = Неопределено);
лЛог.Предупреждение_("Отладочное сообщение", ИмяЛога = Неопределено);
лЛог.Ошибка_("Отладочное сообщение", ИмяЛога = Неопределено);
лЛог.КритическаяОшибка_("Отладочное сообщение", ИмяЛога = Неопределено);
Если лог с указанным именем не был инициализирован, то логирование не выполнится
Шаблон сообщения
Для лога можно задать свой шаблон сообщения. В шаблонах поддерживаются следующие псевдонимы:
- %УРОВЕНЬ% - уровень лога которым было сформировано сообщение (например: ИНФОРМАЦИЯ).
- %СОБЫТИЕ% - указанное событие логирования (имя лога).
- %СООБЩЕНИЕ% - текст выводимого сообщения.
- %ДАТА% - дата и время в формате yyyy.MM.dd HH:mm:ss (например: 2020.09.16 23:52:49).
- %ДАТАМС% - количество миллисекунд текущей даты.
- %УНИВЕРСАЛЬНАЯДАТАМС% - универсальная дата полученная с помощью функции ТекущаяУниверсальнаяДатаВМиллисекундах().
По-умолчанию используется шаблон %ДАТА% - %УРОВЕНЬ% - %СООБЩЕНИЕ%
ВАЖНО: псевдонимы регистрозависмые и допускается их указание только в верхнем регистре.
Пример шаблона:
лЛог.УстановитьШаблонСообщения("%ДАТА%.%ДАТАМС%/ %УНИВЕРСАЛЬНАЯДАТАМС% /%СООБЩЕНИЕ% | %СОБЫТИЕ% | %УРОВЕНЬ% |");
лЛог.Пред_("Привет. Это первый лог в базе");
Вывод:
2021.11.01 18:35:32.830/ 63771377732830 /Привет. Это первый лог в базе | Логирование | ПРЕДУПРЕЖДЕНИЕ |
Способы логирования
Поддерживаются следующие способы:
- Консоль - вывод в стандартные сообщения
- ЖурналРегистрации
- Память - работает только в контексте клиента
- База - запись в специальный регистр сведений.
- Файл - Логирование производится в указанный файл. Каталог файла должен быть ранее создан. У одной настройки логов может быть несколько
- КаталогФайлов - для логирования указывается каталог и шаблон имени файла. Файлы в данном случае генерятся автоматически. Каталог должен быть ранее создан. У одной настройки логов может быть несколько
При использовании логирования в файлы предполагается, что каталоги файлов уже созданы и доступны с текущего контекста. При использовании логирования в ВебКлиенте расширение работы с файлами должно быть предварительно подключено.
Общий формат добавления способа логирования к логу
лЛог.ДобавитьСпособЛогирования(Способ, Параметры, ЛогИлиИмяЛога = Неопределено, Контекст = "");
У способа логирования могут быть параметры, которые необходимо указать при добавлении.
Параметры способа логирования можно получить методом:
лЛог.ПараметрыСпособаЛогирования(Способ);
Для типовых способов логирования предусмотрены специфичные методы добавления в лог
лЛог.ДобавитьСпособЛогированияКонсоль(ЛогИлиИмяЛога = Неопределено, Контекст = "");
лЛог.ДобавитьСпособЛогированияБаза(ЛогИлиИмяЛога = Неопределено, Контекст = "");
лЛог.ДобавитьСпособЛогированияЖурналРегистрации(ЛогИлиИмяЛога = Неопределено, Контекст = "");
лЛог.ДобавитьСпособЛогированияПамять(ЛогИлиИмяЛога = Неопределено, Контекст = "");
лЛог.ДобавитьСпособЛогированияФайл(ИмяФайла, ЛогИлиИмяЛога = Неопределено, Контекст = "");
лЛог.ДобавитьСпособЛогированияКаталогФайлов(Каталог, ШаблонИмениФайла = "", ЛогИлиИмяЛога = Неопределено, Контекст = "");
Контекст для способа логирования
Для каждого способа логирования можно указать контекст, в котором данный способ будет срабатывать. Сейчас доступно:
- Клиент - Логирование для способа происходит только на клиенте
- Сервер - Логирование для способа происходит только на сервере
- КлиентСервер или пустой контекст - фильтр по контексту не применяется
Например,
лЛог.ДобавитьСпособЛогированияКонсоль(, "Клиент"); //ЛОгирование для лога по умолчанию в консоль будет выполняться только на клиенте
лЛог.ДобавитьСпособЛогированияБаза(, "Сервер"); //Логирование для лога по умолчанию в базу будет тол
Шаблон наименования файла для логирования в каталог
По умолчанию равен [ИМЯЛОГА].txt.
Поддерживаются следующие параметры:
- [ИМЯЛОГА] - Имя текущего лога
- [ДАТА] - Текущая дата в формате dd.MM.yyyy
- [ДЕНЬ] - номер текущего дня месяца
- [ДЕНЬНЕДЕЛИ] - Номер текущего дня недели
- [МЕСЯЦ] - Номер текущего месяца
- [ГОД] - Текущий год
- [НОМЕРСЕАНСА] - Номер текущего сеанса пользователя
- [ПОЛЬЗОВАТЕЛЬ] - Имя текущего пользователя системы
Добавление своих способов логирования
Есть возможность определять свои способы логирования. Для этого предоставляются два варианта. Использование добавленных способов идет по общей схеме.
ПараметрыСпособа = лЛог.ПараметрыСпособаЛогирования("Мой");
ПараметрыСпособа.Суффикс = "Привет";
лЛог.ДобавитьСпособЛогирования("Мой", ПараметрыСпособа);
Добавление способа логирования через переопределяемый модуль
Нужно в общем модуле лЛогПереопределяемый доработать методы
- ПриОпределенииСпособовЛогирования - для добавления вашего способа в список Например,
МойСпособ = лЛогСлужебный.НовыйСпособЛогирования("Мой");
Способы.Вставить(МойСпособ.Имя, МойСпособ);
- ПриОпределенииПараметровСпособаЛогирования - для определения параметров, необходимых вашему способу(Необязательно) Например,
Если ИмяСпособа = "Мой" Тогда
ПараметрыСпособа = Новый Структура;
ПараметрыСпособа.Вставить("Суффикс", "");
КонецЕсли;
- ПриВыводеСообщенияВЛогПоСпособу - здесь нужно добавить алгоритм записи лога по вашему способу
Например,
Если ИмяСпособа = "Мой" Тогда
Сообщить(Сообщение+Параметры.Суффикс);
КонецЕсли;
Добавление способа логирования через новый общий модуль
Нужно добавить новый общий модуль в конфигурацию/расширение/новое расширение с префиксом лЛогСпособЛогирования. Пример добавления способа логирования через общий модуль приведен тут
Префикс можно переопределить в процедуре ПриОпределенииПрефиксаОбщихМодулейОпределяющихСпособыЛогирования общего модуля лЛогПереопределяемый
Имя нового способа логирования получается из имени модуля путем отсечения префикса.
Например, модуль с именем лЛогСпособЛогированияОповещениеПользователя добавляет способ логирования с именем "ОповещениеПользователя". Также имя можно задать непосредственно в модуле определив функцию Имя()
В модуле должны быть определены следующие методы
//необязательна. Показывает необхоодимость серверного контекста для выполнения записи. По умолчанию Ложь
Функция ЗаписьТолькоНаСервере() Экспорт
Возврат Ложь;
КонецФункции
//Необязательна. Указывает на невозможность добавления способа два раза в один лог. По умолчанию Истина
Функция ЗапретДублейУЛога() Экспорт
Возврат Истина;
КонецФункции
//Необязательна. Позволяет переопределить имя, получаемое из имени модуля
Функция Имя() Экспорт
Возврат "МоеИмя";
КонецФункции
//Необязательна. Определяет параметры, необходимые для способа логировнаия. По умолчанию Неопределено
Функция НовыйПараметрыСпособаЛогирования() Экспорт
ПараметрыСпособа = Новый Структура;
ПараметрыСпособа.Вставить("Префикс","");
Возврат ПараметрыСпособа;
КонецФункции
//Обязательна. Выполняет запись лога по вашему алгоритму
Процедура ЗаписатьСообщениеВЛог(Сообщение, Лог, УровеньЛогирования, Параметры) Экспорт
СообщениеДляЗаписи = Параметры.Префикс + Сообщение;
лЛогСлужебныйСервер.ЗаписатьСообщениеЛогаВБазу(Лог, СообщениеДляЗаписи, УровеньЛогирования);
КонецПроцедуры
Управление логированием
- Отключение логирования для лога. В этом случае логирование по данному логу прекращается, но все настройки сохраняются
лЛог.Отключить(ЛогИлиИмяЛога = Неопределено);
- Включение логирования для лога после отключения.
лЛог.Включить(ЛогИлиИмяЛога = Неопределено);
Это может быть удобным, если требуется отключить логи на определенном участке кода.
- Завершение логирования для лога. Удаление настройки лога из актуальных
лЛог.ЗавершитьЛогирование(ЛогИлиИмяЛога = Неопределено);
- Получения текущих настроек логов
лЛог.АктивныеЛоги();
- Удаление всех настроек логов. Остановка всего логирования
лЛог.ОчиститьСписокЛогов();
- Получение данных лога для способа логирования Память
лЛог.ДанныеЛога(ЛогИлиИмяЛога = Неопределено);
Интеграция в стороннее решение
Есть возможность простой интеграции в стороннее решение с переименованием модулей и объектов подсистемы. Для этого нужно:
- Перенести объекты подсистемы в ваше решение
- Переименовать объекты подсистемы на ваши имена
- В модулях найти область с именем ПереопределениеМодулейПодсистемы и во вложенных процедурах указать новые имена модулей и объектов
- В модулях приложения, внешнего соединения и сеанса изменить вызов общих модулей на ваши.
- Можно пользоваться
Другие решения
- Обработка для логирования из одного объекта (обработки): https://github.com/codenull/log1c
- Модуль logos из OneScript: https://github.com/oscript-library/logos
- Подсистема логирования на базе модуля logos: https://github.com/1823244/logos-1c
- 1C_logger. Подсистема логирования -//infostart.ru/public/671835/ https://gitlab.com/shmalevoz/1C_logger
Обновления
- Понижен режим совместимости расширения до 8.3.12
- Хранение параметров логов на сервере переведено на использование модуля повторного использования. Удалено использование параметров сеанса