Logger
Logging library
Installation
Install using package manager, e.g. for npm:
npm i --save @tinkoff/logger
for yarn:
yarn add @tinkoff/logger
Api
Child loggers
You can create child loggers using method .child
of the current logger instance.
Child logger will inherit parent logger settings and can override these settings.
:::info
Logger name always will be in lower case, e.g. myLogger
will be converted to mylogger
:::
const log = logger({ name: 'test' });
const childLog = log.child('child');
const childLogWithDefaults = log.child({
name: 'with-defaults',
defaults: {
child: true,
},
});
const childLogWithOverrides = log.child({
name: 'override',
reporters: [],
filters: [],
extensions: [],
});
Display logs
Library allows to specify used logging level, show/hide logs for specific instances of the logger, reset display settings.
By default, error
level is used for every logger.
Settings display level higher than error
for single logger, e.g. logger.enable('info', 'my-logger')
, overrides logging level only for my-logger
.
It is impossible to set logging level lower than common level, e.g. when using common logging level equal to error
calls to logger.enable('fatal', 'my-logger')
changes nothing.
All subsequent setup for log displaying are preserved, e.g. subsequent calls logger.enable('info', 'my-logger')
and logger.enable('trace', 'yet-another-logger')
will enable logs to both logger according to their settings.
Display logs on server
For control of displaying logs on server environment variables LOG_LEVEL
and LOG_ENABLE
are used:
- LOG_LEVEL = trace | debug | info | warn | error | fatal - enables displaying logs for specified level and higher. E.g.:
- if
LOG_LEVEL=info
then all logs of levels info, warn, error, fatal will be showed.
- LOG_ENABLE =
${name}
| ${level}:${name}
- let to enable displaying logs for a specific name and level. It can accept several entries that are passed as comma-separated. E.g.:
- if
LOG_ENABLE=server
then all logs for name server
will be displayed - if
LOG_ENABLE=trace:server*
then for logs with name server only trace
level will be showed - if
LOG_ENABLE=info:server,client,trace:shared
then displaying logs will be enabled for specified loggers using rules above
Display logs in browser
In browser display settings are stored in localStorage, so it will work even after page reloads. In order to reset settings you may clear localStorage. For convenient usage a special object logger
is added to window object in the browser.
logger === window.logger;
logger.setLevel('warn');
logger.enable('info', 'test');
logger.enable('my-logger');
logger.enable('perf*');
logger.disable('my-logger');
logger.clear();
Configuration
Local logger configuration
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,
},
});
Options:
name[='log']
- name of the new logger
Extend logger functionality
@tinkoff/logger
might be extended using next entities:
Filter
Filters can disable logging for specific logs base on inner conditions
import { logger } from '@tinkoff/logger';
interface Filter {
filter(logObj: LogObj): boolean;
}
logger.addFilter(filter as Filter);
logger.setFilters([filter1, filter2]);
Extension
Extensions can extend or override log object before making actual logging
import { logger } from '@tinkoff/logger';
interface Extension {
extend(logObj: LogObj): LogObj;
}
logger.addExtension(extension as Extension);
logger.setExtensions([extension1, extension2]);
Reporter
Reporters can change the way logs are showed (json, fancy logs in browser, send logs to remote api).
Be default, enabled only reporters for displaying logs in console based on display logs settings
Reporters are depends of logger level settings as reporters will not be called if level of the current log are lower than display logs setting
import { logger } from '@tinkoff/logger';
interface Reporter {
log(logObj: LogObj): void;
}
logger.addReporter(reporter as Reporter);
logger.setReporters([reporter1, reporter2]);
BeforeReporter
Same as usual Reporter
but BeforeReporter
are called unconditionally for every log and get called before any other extension.
import { logger } from '@tinkoff/logger';
interface Reporter {
log(logObj: LogObj): void;
}
logger.addBeforeReporter(reporter as Reporter);
logger.setBeforeReporters([reporter1, reporter2]);
Bundled Reporters
BrowserReporter
Standard reporter to show logs in browser
NodeDevReporter
Standard reporter to showing logs in the server console with handy formatting
Used by default in dev-mode or if environment variable process.env.DEBUG_PLAIN
is specified.
NodeBasicReporter
Minimal reporter to showing logs in the server console.
JSONReporter
Show logs in json format.
RemoteReporter
Sends logs on remote api.
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');
How to
Base usage
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');
More about logging level and what do they mean in the article.
How to log properly
To log properly it is suitable to use next format:
interface Log {
event?: string;
message?: string;
error?: Error;
[key]: any;
}
- In case of logging simple text just use string template to pass result string to logger. For json format this string will be available in the
message
props.
logger.info('hello logger');
- In order to log some object or many arguments, compile they together to single object:
logger.warn({
message: 'be warn',
event: 'my-warning',
...obj1,
...obj2,
a: 1,
b: 2,
});
- In order to log error object either pass the error with the props
error
or pass it to logger as only argument
logger.error({
error: new Error('message'),
});
logger.error(new Error('message'));
logger.error(new Error('typeError'), 'custom error message');
- In case of several arguments were passed to logger then only the first argument will be proceeded with the rules from above while all of the other arguments will be passed as an
args
props
logger.debug(
{
event: 'watch',
data: 'some data',
},
'arg2',
'arg3'
);
These formatting rules are handful to connect logging to external tools like kibana, splunk. So it is desirable to follow these rules, otherwise it may lead to troubles with searching and analyzing your logs.
Troubleshooting
I use logger in my Nest.js application, and it does not work
Be sure that you set all required environment variable (LOG_LEVEL
and LOG_ENABLE
) before app initialization. If you set all variable in .env
and parse them via Nest.js's ConfigModule, they will not be available in the logger initialization phase. ConfigModule
parses .env
-file later.
Also, check here that DEBUG_PLAIN
or NODE_ENV
variables are available.