Pull to refresh

Log4ts — библиотека, которой не должно быть

Level of difficultyMedium
Reading time7 min
Views8.2K
Предтеча программистких логов - бортовой журнал.
Предтеча программистких логов - бортовой журнал.

В этой статье я хочу рассказать о моей библиотеке, которой не должно существовать.
Почему её не должно существовать? Потому что функциональность логирования, по моему глубокому убеждению, должна быть в числе первых включена в любой новый язык. 

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

Библиотека Log4ts вдохновлена идеями Log4J и обеспечивает логирование в программах, написанных на  TypeScript.
Далее в этой статье я расскажу о том, как её установить, использовать и конфигурировать.

А в конце я опишу коротенько другие мои библиотеки и функции, которые тоже не должны были бы существовать.

А нужна ли она вообще?

Современные IDE позволяют производить отладку (debug)  JavaScript- и TypeScript-приложений напрямую. Кроме того, в JavaScript и TypeScript доступен console с функциями error, warn, log, debug и т.д. Разве этого недостаточно? - возможно спросит читатель. 

Иногда - нет. Отладка очень искажает логику асинхронных приложений, каковыми и являются большинство приложений на  JavaScript и TypeScript. А использование console может быть достаточно при наличии большого статического контекста или в относительно простых приложениях. Но в приложениях со сложной логикой, а тем более в корпоративных приложениях, работающих как в браузере, так и на сервере, этого оказывается недостаточно.

Почему? - Наивное использование функций console в таких приложениях ставит разработчика перед дилеммой. Если разработчик использовал их широко в своем коде, он в конечном итоге получит столько строк в своей консоли, что будет чрезвычайно трудно с ними разобраться. Если использование функций консоли минимизировано, их может оказаться недостаточно для нахождения некоторых проблем. Особенно, если речь идёт об удалённой поддержке пользователей.

Решение этой проблемы давно найдено в других языках программирования, например, в Java, где есть Log4J. И решение очевидно: вы должны иметь возможность управлять выводом функций логирования во время исполнения программы (runtime).
Не найдя среди открытых библиотек такой, которая удовлетворяла бы этому требованию так, как я этого хотел, я и решил разработать свою.  

Обратите внимание!

Важно отметить: библиотека предназначена прежде всего для работы в браузере. В серверных приложениях, в тяжеловесных приложениях на Node.JS, лучше использовать другие библиотеки логирования.

Библиотека может быть полезна как разработчикам, так и работникам отдела поддержки.

Типичный Use Case при разработке. Разработчик ищет ошибку и у него “под подозрением” находится какой-либо класс или пакет. Он настраивает логирование так, чтобы выводились сообщения только из этих источников.  

Типичный Use Case в production: Пользователь сообщает о проблеме с приложением. Сотрудник отдела поддержки решает, что проблема в клиентской части (которая работает в браузере). Он просит пользователя включить логирование, открыть вкладку консоли в браузере и повторить операцию, при которой происходит ошибка, скопировать вывод из консоли и послать в поддержку. И опять - инструктируя пользователя о настройках логирования, он может посоветовать ему включить логирование только “подозрительного” класса или пакета, сделав тем самым выдачу логирования обозримой. 

Как это может работать, можно посмотреть в нашем демо-приложении. Откройте в браузере окно консоли, а в приложении зайдите настройки и в разделе “Выдача журнала” выберите режим логирования. Потом поработайте с поиском чисел.

Важно отметить ещё одно обстоятельство. Хотя библиотека и вдохновлена идеями Log4J, она не повторяет её гигантские возможности, а является очень легковесной надстройкой над консолью браузера, позволяющей на лету управлять выводимой информацией.

Как её установить?

Если вы не новичок в веб-программировании, вы конечно знаете, что NPM (Node Package Manager) — это менеджер пакетов для JavaScript, который используется для установки, обновления и управления пакетами и библиотеками, а package.json — это файл конфигурации в веб- и простых Node.js проектах. Этот файл используется для управления зависимостями и автоматизации задач в проекте.

Поэтому для того, чтобы начать использовать Log4ts в вашем проекте, вам просто необходимо в ваш package.json добавить одну строчку:

 {

…

"dependencies": {

…	

	"@vsirotin/log4ts": “^3.0.0",

…

Если ваш NPM-проект правильно сконфигурирован, при следующей компиляции и построении вашего проекта библиотека будет скачана в ваш проект.

Как её использовать?

Конечно, логгер нужно перед использованием создать. В нашем случае мы должны сделать это, используя интерфейс ILogger:

logger = LoggerFactory.getLogger('MyClass');

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

DOMEIN.PROJECT.CLASS(COMPONENT).

например:

logger = LoggerFactory.getLogger(‘com.example.my-project.MyClass');

Как настроить в процессе разработки проекта?

В отличие от аналогичных вызовов консоли, после создания наш логгер по умолчанию будет выводить только вызовы из error и warn, игнорируя остальные, например, log или debug.

Это решение кажется мне более прагматичным, если в вашем проекте много классов с встроенным логированием.

Но иногда, особенно на этапе разработки, вам нужно логировать не только информацию об ошибках и предупреждениях, но и другую информацию. Какую другую информацию? - Log4ts предоставляет следующие уровни логирования в зависимости от их серьезности:

0 или отрицательное число - выводится вся информация (ошибка, предупреждение, лог и отладка),

1 - только ошибка, предупреждение и лог,

2 - только ошибка и предупреждение (этот режим включен по умолчанию),

3 - только ошибка,

4 и более - все вызовы игнорируются.

Чтобы изменить уровень логирования на лету, нужно вызвать функцию класса setLogLevel(...). Например, чтобы включить вывод всех вызовов логирования:

 logger.setLogLevel(0);

Однако вам не обязательно помнить, какое значение параметра чему соответствует.
Для этого существуют удобные функции:

  • setErrorLevel - выводит только ошибки.

  • setDefaultLevel - выводит ошибки и предупреждения.

  • setAllLevels - выводит все сообщения.

  • setNoLogging - отключает все сообщения.

Эти функции управляют поведением отдельного логгера.
Статические функции фабрики LoggerFactory с похожими названиями (setErrorLevelByAllLoggers, setDefaultLevelByAllLoggers, setAllLevelsByAllLoggers, setNoLoggingByAllLoggers)  выполняют те же настройки, но сразу для всех созданных к этому моменту логгеров.

Далее, используя текстовые фильтры, вы можете динамически переключать уровень логирования в своих классах.

Например, приведенный ниже пример позволяет отключить логирование для всех логгеров с 'com.example.my-project.M' в ID:

LoggerFactory.setLogLevel('com.example.my-project.M', 4);

Звездочки в строке поиска могут быть в начале или в конце шаблона поиска.

Таблица ниже показывает различные виды искомых под-путей (перечисленных в первой строке таблицы) для трех идентификаторов, перечисленных в левой колонке таблицы.

sub-path

*b/c

a*

*b*

e/b/c

x/y/z

*

a/b/c

+

+

+

-

-

+

a/d/c

-

+

-

-

-

+

e/b/c

+

-

+

+

-

+

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

LoggerFactory.clearAllLoggers();

Как настроить во время применения (runtime, production)?

Чтобы управлять логгерами во время исполнения (например, для целей поддержки конечных пользователей), вам нужно иметь возможность вызывать функции LoggerFactory из какого-то вашего UI компонентов.

Вот демо-приложение, которое показывает пример такого UI компонента.

Практические советы

При создании библиотек и общих компонентов, учитывая, что логирование может выполняться из многих компонентов одновременно, я рекомендую для лучшей читаемости и понятности логов использовать классические соглашения об именах при создании логгеров:

DOMAIN.PROJECT.CLASS(COMPONENT).

В текущей реализации отображение адреса точки логирования неинформативно, так как вывод в конечном итоге выполняется путем вызова функций console. 

Поэтому я рекомендую явно локализировать точку логирования, указывая имя логируемой функции.

Если ваша функция содержит несколько вызовов логгера с одинаковым уровнем, рекомендуется различать эти вызовы либо вводными текстами, либо с помощью некоторых номеров.

Вот пример того, как создать логгер, учитывая соглашение об именах, указывая логируемую функцию и различая логгеры в пределах одной функции:

export class FileProcessor {

  private logger: ILogger = LoggerFactory.getLogger('eu.sirotin.lfp.FileProcessor');

  constructor(listPath?: string) {

    this.logger.log('constructor: FileProcessor created. List path:', listPath);

  }

    public processFile(filePath: string, outputDir: string): void {
    if (!this.analyzeLanguageFileSyntax(filePath)) {
      this.logger.error('In processFile. ERROR 100: Syntax analysis failed.');
      return;
    }
    ...

    if (this.listPath && !this.compareLanguageCodes()) {
      this.logger.error('In processFile. ERROR 200: Language code comparison failed.');
      return;
    }
...
  }

}

Так что, пользуйтесь на здоровье!

А я пока выполню своё обещание, данное в начале статьи.

Другие мои библиотеки и функции, которых не должно быть

Ошибки в работе с физическими единицами (когда метры складывают с футами или секунды с килограммами) приводили к, наверное, самым дорогим ошибкам в истории программирования. Тем более удивительно, что в составе популярных языках программирования нет средств работы с единицами системы СИ. 

Поскольку мне это однажды самому понадобилось, я разработал мультиплатформенную библиотеку  KotUniL.    

Как её использовать в Kotlin я описал тут:     1, 2, 3.

Её также (правда, без элегантности, присущей Kotlin) на Java и на JavaScript.

Я так и не смог убедить котлинцев включить эту библиотеку в стандарт языка или разработать что-то своё (ещё лучше).

В Java 8 в своё время добавили много хороших возможностей, но среди них не было класса Optional, который мне пришлось реализовать самому.

Точно также в Java 8 не хватало мульти-арных  функций размерности больше двух. Так что пришлось реализовывать их самому.

В Java мне с самого начала не хватало возможности красиво выводить на печать матрицы. В результате я написал класс MatrixFormatter

И уж совсем приватно

Мой сайт - https://www.sirotin.eu/

Кроме того, я пишу открытую электронную книгу “Мемуары кочевого программиста. Байки, были, думы”. Её текущий вариант можно найти здесь.

Я убеждён, что программирование - это материализаци я идей. Об этом я первый раз написал здесь. А вот уже несколько лет мы с группой единомышленников ведём группу в Телеграмме под названием “Материализация идей”. Если вам это интересно - подключайтесь.


Иллюстрация: Предтеча программистских логов - бортовой журнал. Совместное творение автора и ИИ.

Tags:
Hubs:
Total votes 5: ↑2 and ↓3+2
Comments30

Articles