Logger
Библиотека логгирования
Подключение
Устанавливаем npm модуль
npm i --save @tinkoff/logger
или
yarn add @tinkoff/logger
Использование библиотеки
import logger from '@tinkoff/logger';
const log = logger('my-component');
log.trace('trace');
log.debug('debug');
log.info({ event: 'client-visited', message: 'client visited tinkoff.ru' });
log.warn('warn');
log.error({ event: 'form-send-error', error: new Error('form') });
log.fatal('fatal error');
Про уровни логгирования и что они обозначают можно почитать статью.
Как правильно логгировать
Для правильного логгирования на клиенте и на сервере, предпочтительно использовать следующий формат:
interface Log {
event?: string;
message?: string;
error?: Error;
[key]: any;
}
- Если надо просто залогировать некий текст, то склеиваем все сообщение в один аргумент и просто передаем в логгер. В json формате этот текст будет доступен в поле
message
logger.info('hello logger');
- Если необходимо залогировать некий объект или много аргументов, то собираем все в один объект и передаем в логер
logger.warn({
message: 'be warn',
event: 'my-warning',
...obj1,
...obj2,
a: 1,
b: 2,
});
- Если необходимо залогировать объект ошибки, то либо передаем саму ошибку под ключом
error
, либо явно передаем в логгер первым аргументом
logger.error({
error: new Error('message'),
});
logger.error(new Error('message'));
logger.error(new Error('typeError'), 'custom error message');
- Если в логгер было переданно несколько аргументов, то первый аргумент будет обработается по правилам выше, а остальные аргументы отдельно добавятся в поле args результат
logger.debug(
{
event: 'watch',
data: 'some data',
},
'arg2',
'arg3'
);
Данный формат прежде всего нужен для удобной работы с логами во внешних системах вроде kibana, splunk. Поэтому желательно его придерживаться, иначе возможны сложности с поиском и анализом логов.
Дочерние логгеры
С помощью метода инстанса логгера .child
можно создавать дочерние логгеры для данного инстанса, которые будут наследовать конфигурацию родительского логгера и могут эту конфигурацию переопределять.
const log = logger({ name: 'test' });
const childLog = log.child('child');
const childLogWithDefaults = log.child({
name: 'withDefaults',
defaults: {
child: true,
},
});
const childLogWithOverrides = log.child({
name: 'override',
reporters: [],
filters: [],
extensions: [],
});
Отображение логов
Библиотека дает возможность установить уровень логгирования, отображать или скрывать логи различных экземпляров логгера, и очищать все настройки.
По умолчанию, уровень логгирования выставлен как error
для всех логгеров.
Добавление отображения уникального логгера с уровнем выше error
, например logger.enable('info', 'my-logger')
, переопределяет уровень логгирования только для my-logger
.
Нельзя сделать уровень логгирования для определенного логгера ниже, чем общий уровень, например при установленном по умолчанию уровне error
запись logger.enable('fatal', 'my-logger')
ничего не изменит в отображаемых логах.
Каждое добавление уникальных настроек отображения для нового логгера не влияет на предыдущие, например отдельные вызовы методов logger.enable('info', 'my-logger')
и logger.enable('trace', 'yet-another-logger')
будут работать независимо друг от друга.
Отображение логов на сервере
Для настройки отображения логов на сервере используются переменные окружения LOG_LEVEL
и LOG_ENABLE
(параметры можно задавать вместе, тогда сначала проверяется LOG_LEVEL настройка, потом LOG_ENABLE):
- LOG_LEVEL = trace | debug | info | warn | error | fatal - включает отображение логов для заданного уровня и все уровней выше. Пример:
- если
LOG_LEVEL=info
, то будут отображаться все логи уровней info, warn, error, fatal
- LOG_ENABLE =
${name}
| ${level}:${name}
- позволяет включить отображение всех логов по определенному имени логгера или по определенному имени и уровню. Несколько вхождений передаются через запятую. Примеры:
- если
LOG_ENABLE=server
, то будут отображены логи всех уровней с именем server
- если
LOG_ENABLE=trace:server*
, то будут отображены только логи для server
с уровнем trace
- если
LOG_ENABLE=info:server,client,trace:shared
, то будут включены логи для заданных логгеров по правилам выше
Отображение логов в браузере
В браузере настройки сохраняются в localStorage, поэтому для отображения всех клиентских логов с новыми настройками, надо дополнительно перезагрузить страницу, либо очистить localStorage. Для удобной настройки параметров отображения в window
добавляется объект logger
через который можно настраивать отображение логов в браузере.
logger === window.logger;
logger.setLevel('warn');
logger.enable('info', 'test');
logger.enable('my-logger');
logger.enable('perf*');
logger.disable('my-logger');
logger.clear();
Конфигурация
Конфигурация локального логгера
import { logger } from '@tinkoff/logger';
const log = logger({ name: 'my-logger' });
const log = logger('my-logger');
const log = logger({
name: 'remote-logger',
defaults: {
remote: true,
},
});
Параметры:
name[='log']
- имя нового логгера
Расширение возможностей логгера
@tinkoff/logger
можно расширять различными действиями:
Фильтры
Фильтры позволяют отключать логгирование орпеделенных логов в зависимости от условий
import { logger } from '@tinkoff/logger';
interface Filter {
filter(logObj: LogObj): boolean;
}
logger.addFilter(filter as Filter);
logger.setFilters([filter1, filter2]);
Расширения данных
Расширения позволяют расширять или переопределять объект лога перед его логгированием
import { logger } from '@tinkoff/logger';
interface Extension {
extend(logObj: LogObj): LogObj;
}
logger.addExtension(extension as Extension);
logger.setExtensions([extension1, extension2]);
Репортеры
Репортеры позволяют настраивать вид отображения логов (json, красочные логи для браузера, отправка логов на апи).
По умолчанию подключены репортеры для отображения логов в консоли на основании настроек отображения .
Такие репортеры зависят от настроек уровня и включенных логгеров, т.е. такие репортеры не вызываются если уровень текущего лога ниже настроек или для данного имени логи не включены.
import { logger } from '@tinkoff/logger';
interface Reporter {
log(logObj: LogObj): void;
}
logger.addReporter(reporter as Reporter);
logger.setReporters([reporter1, reporter2]);
Безусловные репортеры
Тоже самое что и обычные репортеры, но вызываются безусловно для всех логов и до всей остальной логики с фильтрами и расширениями.
import { logger } from '@tinkoff/logger';
interface Reporter {
log(logObj: LogObj): void;
}
logger.addBeforeReporter(reporter as Reporter);
logger.setBeforeReporters([reporter1, reporter2]);
Готовые репортеры
BrowserReporter
Стандартный логгер для отображения логов в браузере.
NodeDevReporter
Стандартный логгер для отображения логов в консоли на сервере, цветной и с удобным форматированием.
Используется по умолчанию в дев режиме или если задана process.env.DEBUG_PLAIN
.
NodeBasicReporter
Репортер для отображения логов в консоли на сервере, минималистичный.
JSONReporter
Отображение логов в виде json.
RemoteReporter
Репортер для отправки логов на апи.
import { logger, RemoteReporter } from '@tinkoff/logger';
const remote = new RemoteReporter({
requestCount: 1,
emitLevels: { error: true, fatal: true },
async makeRequest(logObj) {
return await request();
},
});
logger.addReporter(remote);
const log = logger({ name: 'test-remote' });
log.error('error');
log.info('test');
const remoteLog = logger({ name: 'remote-for-all', remote: true });
remoteLog.info('test');
remoteLog.debug('test');
const traceLog = logger({ name: 'log-trace', emitLevels: { trace: true } });
traceLog.trace('test');
traceLog.error('test');
SageReporter
Репортер для поддержки формата логов sage. Расширяет функционал JSONReporter:
- добавляет поле
@timestamp
; - в поле
level
записывает строковое представление уровня логирования, числовое значение сохраняет в поле levelNumber
; - делает
message
массивом содержащим исходный message
и записывает в него все строковые и числовые значения из массива args
; - все массивы и объекты из
args
выносит в поля лога arrays
и objects
; Это решает основную массу проблем при индексации логов в sage.