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

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

Предтеча программистких логов — бортовой журнал.

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

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

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

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

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

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

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

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

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

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

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

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

 {

…

"dependencies": {

…	

	"@vsirotin/log4ts": "^2.0.2",

…

При следующей компиляции и построении вашего проекта библиотека будет скачана в ваш проект.

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

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

logger = LoggerFactory.getLogger('MyClass');

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

DOMEN.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);

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

Например,  приведенный ниже пример позволяет отключить логирование для всех логгеров с '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

+

-

+

+

-

+

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

LoggerFactory.setLogLevelsByAllLoggers(1);

или перезадать уровень по умолчанию (2) с помощью

LoggerFactory.recetDefaults();

В некоторых особых случаях, таких как отладка проекта, где используется несколько подходов к логированию, вы можете захотеть уничтожить все логгеры из 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/

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

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


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

© Habrahabr.ru