Basic Logging
Logger Class
Constructor
new Logger() // start with just the defaults
new Logger(options) // configuration options, see below
new Logger(name) // if you were to set only one thing...
new Logger(name, options) // you can split them out if you prefer
Options object properties:
name(string): Logger name (if not passed separately)context(object): Context data to include with all log recordslevel(string|number): Minimum Syslog-style severity level (e.g., 'INFO', 'DEBUG')format(string): Output format ('json' or 'text'); convenience setting that overwrites the outputs array if usedtransforms(array): Array of transform instances; leave unset to use defaultsoutputs(array): Array of output instances; leave unset to use defaultsparent(Logger): Parent logger instance for hierarchical logging (typically use "child" call instead)
Logging Methods
logger.log(...params) // Generic call used by all convenience methods below; defaults to INFO
logger.debug(...params) // DEBUG level, not interesting to anyone but the developers
logger.info(...params) // INFO level; default level
logger.notice(...params) // NOTICE level; consider this like INFO but for more "important stuff"
logger.warn(...params) // WARNING level; basic advisories and simple runtime errors that don't affect operation
logger.error(...params) // ERR level; typically actual errors that a developer may care about
logger.fatal(...params) // CRIT level; only emit this if something has gone horribly wrong
Severity Levels
The library uses standard syslog severity levels:
import { SyslogSeverity } from '@versionzero/logger';
// Available severity levels (from highest to lowest priority)
SyslogSeverity.EMERG // 0: System is unusable - (no convenience method; reserved for system)
SyslogSeverity.ALERT // 1: Action must be taken immediately - (no convenience method; reserved for system)
SyslogSeverity.CRIT // 2: Critical conditions
SyslogSeverity.ERR // 3: Error conditions
SyslogSeverity.WARNING // 4: Warning conditions
SyslogSeverity.NOTICE // 5: Normal but significant condition
SyslogSeverity.INFO // 6: Informational messages
SyslogSeverity.DEBUG // 7: Debug-level messages - (also used by default for traces)
You can filter log messages sent below a specified level by setting the logger's level. The default is INFO.
The level can also be set in the constructor options.
logger.level = 'WARN'; // filter out notice, info, and debug
logger.level = 'DEBUG'; // allow everything through
Log Parameter Collection
Each logging method accepts any number of parameters, from which it builds up a log record object.
Some property names in the log record are standardized for convenience:
msg(string): textual log message for humanserr(object): error objectreq(request): http requestres(response): http responsetrace(object): call telemetry
If you log simple primitives, they will get appended to the msg field. Other more complex types
may get assigned to appropriate standardized fields; e.g. an Error will become err, an
HTTP Request object will land in req, and so forth. This "primitive-to-object" process is
handled by the collect phase in the logger's transform pipeline.
These collected parameter records and any logged objects are shallowly merged into a single
record, which passed through the transform phase of the logger's transform pipeline
to simplify and clean up the record for output.
Because this merging can lead to unexpected results, if you want to log anything complex, it is best to package your information into your own object:
// to avoid merging objects, avoid this:
logger.error('failed to copy invoice', err, srcInvoice, dstInvoice);
// do this instead
logger.error('failed to copy invoice', {err, srcInvoice, dstInvoice});
You can extend the behavior of both the collect and/or transform phases by providing a
custom transform to the logger. (You can also change the names of these standardized properties
in the constructors of each default transform.)
Logger Hierarchy
Loggers can be connected as a hierarchy, and child loggers inherit their parent settings. Any context provided by the child logger is merged on top of the parent's context.
// Create a child logger with additional context to merge with all records...
const logger = new Logger('parent-name', { context: { test: true }})
const childLogger = logger.child('child-name', { context: { key: 'value' } });
childLogger.info('hello');
// output log record will have
// {
// ...,
// contextName: "parent-name/child-name",
// msg: "hello",
// key: "value",
// test: true
// }