Upgrading to [email protected]
This document is a work in progress. Having trouble upgrading to
[email protected]
? Open an issue so we can improve this guide!
winston.Logger
has been replaced withwinston.createLogger
.winston.setLevels
has been removed. Levels are frozen at the time of Logger creation.- Setting the level on the default
winston
logger no longer sets the level on the transports associated with the defaultwinston
logger.
winston.transports.Memory
was removed. Use any Node.jsstream.Writeable
with a largehighWaterMark
instance instead.- When writing transports use
winston-transport
instead ofwinston.Transport
winston.Container
instances no longer have defaultConsole
transportswinston.Container.prototype.add
no longer does crazy options parsing. Implementation inspired by segmentio/winston-logger
winston.Logger.add
no longer accepts prototypes / classes. Pass an instance of our transport instead.
Don't do this
// DON'T DO THIS. It will no longer work
logger.add(winston.transports.Console);
// Do this instead.
logger.add(new winston.transports.Console());
winston.Logger
will no longer respond with an error when logging with no transportswinston.Logger
will no longer respond with an error if the same transports are added twice.Logger.prototype.stream
options.transport
is removed. Use the transport instance on the logger directly.
Logger.prototype.query
options.transport
is removed. Use the transport instance on the logger directly.
winston.exception
has been removed. Use:
const exception = winston.ExceptionHandler();
humanReadableUnhandledException
is now the default exception format..unhandleExceptions()
will no longer modify transports state, merely just add / remove theprocess.on('uncaughtException')
handler.- Call close on any explicit
ExceptionHandlers
. - Set
handleExceptions = false
on all transports.
- Call close on any explicit
winston.hash
was removed.winston.common.pad
was removed.winston.common.serialized
was removed (usewinston-compat
).winston.common.log
was removed (usewinston-compat
).
The biggest issue with winston@2
and previous major releases was that any new formatting options required changes to winston
itself. All formatting is now handled by formats.
Custom formats can now be created with no changes to winston
core. We encourage you to consider a custom format before opening an issue.
- The default output format is now
formats.json()
. filters
: Use a customformat
. See: Filters and Rewriters below.rewriters
: Use a customformat
. See: Filters and Rewriters below.
stringify
: Use a custom format.formatter
: Use a custom format.json
: Useformats.json()
.raw
: Useformats.json()
.prettyPrint
: Useformats.prettyPrint()
or a custom format.colorize
: Useformats.colorize()
.timestamp
: Useformats.timestamp()
.logstash
: Useformats.logstash()
.align
: Useformats.align()
.showLevel
: Use a custom format.
In [email protected]
info
objects are considered mutable. The API combined
formatters and rewriters into a single, new concept: formats.
If you are looking to upgrade your filter
behavior please read on. In
[email protected]
this filter behavior:
const isSecret = /super secret/;
const logger = new winston.Logger(options);
logger.filters.push(function(level, msg, meta) {
return msg.replace(isSecret, 'su*** se****');
});
// Outputs: {"level":"error","message":"Public error to share"}
logger.error('Public error to share');
// Outputs: {"level":"error","message":"This is su*** se**** - hide it."}
logger.error('This is super secret - hide it.');
Can be modeled as a custom format that you combine with other formats:
const { createLogger, format, transports } = require('winston');
// Ignore log messages if the have { private: true }
const isSecret = /super secret/;
const filterSecret = format((info, opts) => {
info.message = info.message.replace(isSecret, 'su*** se****');
return info;
});
const logger = createLogger({
format: format.combine(
filterSecret(),
format.json()
),
transports: [new transports.Console()]
});
// Outputs: {"level":"error","message":"Public error to share"}
logger.log({
level: 'error',
message: 'Public error to share'
});
// Outputs: {"level":"error","message":"This is su*** se**** - hide it."}
logger.log({
level: 'error',
message: 'This is super secret - hide it.'
});
If you are looking to upgrade your rewriter
behavior please read on. In
[email protected]
this rewriter behavior:
const logger = new winston.Logger(options);
logger.rewriters.push(function(level, msg, meta) {
if (meta.creditCard) {
meta.creditCard = maskCardNumbers(meta.creditCard)
}
return meta;
});
logger.info('transaction ok', { creditCard: 123456789012345 });
Can be modeled as a custom format that you combine with other formats:
const maskFormat = winston.format(info => {
// You can CHANGE existing property values
if (info.creditCard) {
info.creditCard = maskCardNumbers(info.creditCard);
}
// You can also ADD NEW properties if you wish
info.hasCreditCard = !!info.creditCard;
return info;
});
const logger = winston.createLogger({
format: winston.formats.combine(
maskFormat(),
winston.formats.json()
)
});
logger.info('transaction ok', { creditCard: 123456789012345 });
See examples/format-mutate.js for a complete end-to-end example that covers both filtering and rewriting behavior in [email protected]
.
As of [email protected]
the project has been broken out into a few modules:
- winston-transport:
Transport
stream implementation & legacyTransport
wrapper. - logform: All formats exports through
winston.format
LEVEL
andMESSAGE
symbols exposed through triple-beam.- Shared test suite for community transports
Let's dig in deeper. The example below has been annotated to demonstrate the different packages that compose the example itself:
const { createLogger, transports, format } = require('winston');
const Transport = require('winston-transport');
const logform = require('logform');
const { combine, timestamp, label, printf } = logform.format;
// winston.format is require('logform')
console.log(logform.format === format) // true
const logger = createLogger({
format: combine(
label({ label: 'right meow!' }),
timestamp(),
printf(nfo => {
return `${nfo.timestamp} [${nfo.label}] ${nfo.level}: ${nfo.message}`;
})
),
transports: [new transports.Console()]
});