
В этой статье я хочу рассказать о моей библиотеке, которой не должно существовать.
Почему её не должно существовать? Потому что функциональность логирования, по моему глубокому убеждению, должна быть в числе первых включена в любой новый язык.
А разработчики старых языков тоже должны об этом подумать и включить логирование, если это ещё не сделано, в ближайший релиз.
Библиотека 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/
Кроме того, я пишу открытую электронную книгу “Мемуары кочевого программиста. Байки, были, думы”. Её текущий вариант можно найти здесь.
Я убеждён, что программирование - это материализаци я идей. Об этом я первый раз написал здесь. А вот уже несколько лет мы с группой единомышленников ведём группу в Телеграмме под названием “Материализация идей”. Если вам это интересно - подключайтесь.
Иллюстрация: Предтеча программистских логов - бортовой журнал. Совместное творение автора и ИИ.