📝 Логирование и ошибки

A1sLog, обработка исключений, безопасные возвраты

Средне
🐱 Кот Айван
Логи — это чёрный ящик твоего кода. Когда что-то падает в 3 часа ночи, логи — единственное, что расскажет, что случилось. Не экономь на логировании, но и не спамь.

Уровни логов

Уровень Метод Когда использовать
ERROR A1sLog.Error() Критические ошибки, операция не выполнена
WARN A1sLog.Warn() Подозрительное поведение, но работаем дальше
INFO A1sLog.Info() Важные события: старт, финиш, ключевые операции
DEBUG A1sLog.Debug() Детали для отладки (не в продакшене)

A1sLog API

// Простое сообщение
A1sLog.Info("Загрузка завершена");

// С контекстом (структура)
A1sLog.Info("Обработано записей", A1sDS.Of(
    "Всего", 100,
    "Успешно", 95,
    "Ошибок", 5
));

// Ошибка с информацией об исключении
Попытка
    // ...
Исключение
    A1sLog.Error("Ошибка загрузки", ИнформацияОбОшибке());
КонецПопытки;

// С указанием модуля (для фильтрации)
A1sLog.Info("Синхронизация", , "МодульСинхронизации");

Когда логировать

✅ Логируй

  • Начало и конец длительных операций
  • Все ошибки и исключения
  • Входящие данные из внешних систем
  • Результаты пакетных операций
  • Действия пользователей (аудит)
  • Изменение критичных настроек

❌ Не логируй

  • Каждую итерацию цикла
  • Промежуточные значения (для отладки — Debug)
  • Персональные данные (ПДн)
  • Пароли и токены
  • Очевидные события

Обработка исключений

Правила

  1. Не глуши ошибки молча — как минимум логируй
  2. Лови конкретные ошибки, не все подряд
  3. Не используй исключения для логики — они для ошибок
  4. Библиотека не должна "падать" — возвращай признак ошибки

❌ Плохо

Попытка
    Результат = ВыполнитьОперацию();
Исключение
    // Молча проглотили ошибку
КонецПопытки;

✅ Хорошо

Попытка //⚙
    Результат = ВыполнитьОперацию(); //▶️
Исключение //⚙
    A1sLog.Error("Ошибка операции", ИнформацияОбОшибке()); //▶️
    Возврат Неопределено; //↩
КонецПопытки;

Безопасные возвраты

Библиотечные функции не должны бросать исключения наверх без явной причины.

Паттерн: Возврат Неопределено

// Функция поиска — возвращает Неопределено если не найдено
Функция НайтиТовар(Код)
    
    ib = "Безопасный поиск товара по коду";
    
    Попытка //⚙
        Товар = Справочники.Товары.НайтиПоКоду(Код); //⚡
        
        Если Товар.Пустая() Тогда
            Возврат Неопределено; //↩
        КонецЕсли;
        
        Возврат Товар; //↩
        
    Исключение //⚙
        A1sLog.Warn("Ошибка поиска товара: " + Код); //▶️
        Возврат Неопределено; //↩
    КонецПопытки;
    
КонецФункции

Паттерн: Возврат структуры результата

// Для сложных операций — возвращаем структуру с флагом успеха
Функция ЗагрузитьДанные(URL)
    
    ib = "Загрузка с детальным результатом";
    
    Результат = A1sDS.Of(
        "Успех", Ложь,
        "Данные", Неопределено,
        "Ошибка", ""
    ); //✏
    
    Попытка //⚙
        
        Ответ = A1sWeb.Get(URL); //▶️ //⚡
        
        Если Ответ.Код = 200 Тогда
            Результат.Успех = Истина; //✏
            Результат.Данные = A1sJ.Parse(Ответ.Тело); //✏
        Иначе
            Результат.Ошибка = "HTTP " + Ответ.Код; //✏
        КонецЕсли;
        
    Исключение //⚙
        Результат.Ошибка = ОписаниеОшибки(); //✏
        A1sLog.Error("Ошибка загрузки", ИнформацияОбОшибке()); //▶️
    КонецПопытки;
    
    Возврат Результат; //↩
    
КонецФункции

// Использование:
Загрузка = ЗагрузитьДанные("https://api.example.com");
Если Загрузка.Успех Тогда
    // Работаем с Загрузка.Данные
Иначе
    Сообщить("Ошибка: " + Загрузка.Ошибка);
КонецЕсли;

Паттерны логирования

Начало/Конец операции

Процедура ЗагрузитьВсеТовары()
    
    A1sLog.Info("▶ Загрузка товаров — СТАРТ"); //▶️
    
    СтартВремя = ТекущаяУниверсальнаяДатаВМиллисекундах(); //✏
    
    // ... логика ...
    
    Длительность = ТекущаяУниверсальнаяДатаВМиллисекундах() - СтартВремя; //✏
    
    A1sLog.Info("✓ Загрузка товаров — ФИНИШ", A1sDS.Of(
        "Загружено", Счётчик,
        "МС", Длительность
    )); //▶️
    
КонецПроцедуры

Пакетная обработка

Функция ОбработатьПакет(Данные)
    
    Успешно = 0; //✏
    Ошибок = 0; //✏
    
    Для Каждого Элемент Из Данные Цикл //⟳
        Попытка //⚙
            ОбработатьЭлемент(Элемент); //▶️
            Успешно = Успешно + 1; //✏
        Исключение //⚙
            Ошибок = Ошибок + 1; //✏
            A1sLog.Warn("Ошибка элемента", A1sDS.Of(
                "ID", Элемент.ID,
                "Причина", ОписаниеОшибки()
            )); //▶️
        КонецПопытки;
    КонецЦикла;
    
    A1sLog.Info("Пакет обработан", A1sDS.Of(
        "Всего", Данные.Количество(),
        "Успешно", Успешно,
        "Ошибок", Ошибок
    )); //▶️
    
    Возврат Ошибок = 0; //↩
    
КонецФункции

Шпаргалка

A1sLog.Error() — Критическая ошибка
A1sLog.Warn() — Предупреждение
A1sLog.Info() — Информация
A1sLog.Debug() — Отладка

Контекст: A1sLog.Info("Msg", A1sDS.Of("key", val))
Исключение: A1sLog.Error("Msg", ИнформацияОбОшибке())