Логирование

Описание TracerLogDestination

Конструктор структуры Configuration содержит поле logDestinations: any Sequence<TracerLogDestination>. В это поле можно передать набор выводов, куда будут логироваться сообщения. Настройка этого параметра позволяет гибко управлять тем, куда и как будут записываться логи, используя различные способы вывода.

Пример создания конфигурации логирования:

import OKTracer let logDestinations: [TracerLogDestination] = [ .console(format: "$LEVEL $D[yyyy-MM-dd'T'HH:mm:ssZZZZZ] $M[255] $FILE:$LINE $FUNC $C", minLevel: .debug), .file(format: "$LEVEL $D[yyyy-MM-dd'T'HH:mm:ssZZZZZ] $M[255] $FILE:$LINE $FUNC $C", minLevel: .warning), .oslog(format: "$LEVEL $D[yyyy-MM-dd'T'HH:mm:ssZZZZZ] $M[255] $FILE:$LINE $FUNC $C", minLevel: .error) ] let configuration = Configuration( // ваши опции ... logDestinations: logDestinations )

Форма логирования

TracerLogDestination представляет собой перечисление, включающее различные методы вывода логов. Каждый метод вывода (или дестинация) имеет свой формат и минимальный уровень логирования, которые могут быть настроены:

ФормаОписание
console(format: String, minLevel: TracerLogLevel)Вывод в консоль Xcode.
file(format: String, minLevel: TracerLogLevel)Вывод в файл. Максимальный размер файла составляет 123KB.
oslog(format: String, minLevel: TracerLogLevel)Вывод в Консоль (отдельное приложение на macOS). При использовании oslog логи дублируются в консоль Xcode, поэтому при одновременном использовании console и oslog будет активен только oslog
buildin(format: String, minLevel: TracerLogLevel)Внутреннее логирование Трейсера в Консоль, начиная с "OKTracer: ".

Форматирование логов

Форматирование логов осуществляется с помощью строки формата, которая может включать следующие псевдоинструкции:

ФорматОписание
$LEVELТекстовое представление уровня логирования
$D[yyyy-MM-dd'T'HH:mm:ssZZZZZ]Форматирование даты, аналогичное используемому в классе DateFormatter
$M[255]Сам лог с опцией ограничения его длины. Ограничение сработает, если в квадратных скобках указать число больше 0. Если ограничение не требуется, можно оставить просто $M
$FILEИмя файла
$LINEНомер строки
$FUNCИмя метода
$CКонтекст, передаваемый последним параметром в методы логирования, выводится его текстовое представление

Комбинация по умолчанию: $LEVEL $D[yyyy-MM-dd'T'HH:mm:ssZZZZZ] $M[255] $FILE:$LINE $FUNC $C.

Уровни логирования

TracerLogLevel определяет уровни логирования (свойство minLevel в TracerLogDestination), отсортированные по приоритету – он задает минимальный уровень логов, который будет записываться в соответствующий вывод (например, в файл или консоль). Это позволяет гибко настраивать, какие сообщения следует сохранять и отображать в зависимости от их важности.

УровеньОписание
criticalСамый высокий уровень логирования, используется для сообщений о критических ошибках, которые могут привести к серьезным последствиям для работы системы.
errorИспользуется для отслеживания ошибок, которые не критические, но требуют внимания разработчиков.
warningПредупреждения указывают на потенциальные проблемы, которые могут повлиять на работу приложения
infoИнформационные сообщения, которые дают контекст о текущем состоянии системы.
debugИспользуется для вывода отладочной информации, которая помогает разработчикам отслеживать ход выполнения программы в процессе разработки и тестирования.

Процесс логирования

В основе логирования лежит сущность logger, которая предоставляется протоколом TracerServiceProtocol. SDK предоставляет несколько методов для синхронного и асинхронного логирования. Эти методы позволяют логировать сообщения с различными уровнями детализации и контекстом.

Синхронные методы логирования

  • func log<T>(level: TracerLogLevel, message: @autoclosure () -> T) – cинхронно отправляет лог-сообщение в указанные в конфигурации выводы (кроме buildin).
logger.log(level: .info, message: "Приложение запущено")
  • func log<T>(level: TracerLogLevel, message: @autoclosure () -> T, file: String?, function: String?, line: Int?, context: Any?) – аналогично первому методу, но с возможностью указать кастомное имя файла, имя метода, номер строки и контекст.
logger.log(level: .error, message: "Ошибка при загрузке данных", file: #file, function: #function, line: #line, context: nil)

Асинхронные методы логирования

  • logAsync<T>(level: TracerLogLevel, message: @autoclosure () -> T) – отправляет лог-сообщение асинхронно, что позволяет не блокировать основной поток выполнения программы.
logger.logAsync(level: .warning, message: "Низкий уровень памяти")
  • logAsync<T>(level: TracerLogLevel, message: @autoclosure () -> T, file: String?, function: String?, line: Int?, context: Any?) – аналогично предыдущему методу, но с возможностью указать кастомное имя файла, имя метода, номер строки и контекст.
logger.logAsync(level: .debug, message: "Значение переменной x = 10", file: #file, function: #function, line: #line, context: nil)

Обертки над log предустановленными уровнями

  • debug<T>(message: @autoclosure () -> T, file: String = #file, function: String = #function, line: Int = #line, context: Any? = nil)
logger.debug(message: "Отладочное сообщение")
  • error<T>(message: @autoclosure () -> T, file: String = #file, function: String = #function, line: Int = #line, context: Any? = nil)
logger.error(message: "Ошибка загрузки данных")
  • info<T>(message: @autoclosure () -> T, file: String = #file, function: String = #function, line: Int = #line, context: Any? = nil)
logger.info(message: "Начало синхронизации данных")
  • warning<T>(message: @autoclosure () -> T, file: String = #file, function: String = #function, line: Int = #line, context: Any? = nil)
logger.warning(message: "Низкий уровень батареи")
  • critical<T>(message: @autoclosure () -> T, file: String = #file, function: String = #function, line: Int = #line, context: Any? = nil)
logger.critical(message: "Критическая ошибка в работе системы")

Процесс переноса логов из файла

Для логирования из внешнего файла необходимо реализовать протокол TracerLogProviderProtocol и передать имплементацию в поле logProvider: TracerLogProviderProtocol? = nil в Configuration.

ВАЖНО! При передаче logProvider логирование в сам Tracer не имеет смысла, так как при отправке событий всегда будут браться данные из logProvider.

class CustomLogProvider: TracerLogProviderProtocol { func getData() -> Data? { // Реализация чтения логов из внешнего источника } } let logProvider = CustomLogProvider() let configuration = Configuration( // ваши опции ... logProvider: logProvider, logDestinations: [.file(), .console()] )