Winston
A logger for just about everything.
Install / Use
/learn @winstonjs/WinstonREADME
winston
A logger for just about everything.
winston@3
See the Upgrade Guide for more information. Bug reports and PRs welcome!
Looking for winston@2.x documentation?
Please note that the documentation below is for winston@3.
[Read the winston@2.x documentation].
Motivation
winston is designed to be a simple and universal logging library with
support for multiple transports. A transport is essentially a storage device
for your logs. Each winston logger can have multiple transports (see:
[Transports]) configured at different levels (see: [Logging levels]). For
example, one may want error logs to be stored in a persistent remote location
(like a database), but all logs output to the console or a local file.
winston aims to decouple parts of the logging process to make it more
flexible and extensible. Attention is given to supporting flexibility in log
formatting (see: [Formats]) & levels (see: [Using custom logging levels]), and
ensuring those APIs decoupled from the implementation of transport logging
(i.e. how the logs are stored / indexed, see: [Adding Custom Transports]) to
the API that they exposed to the programmer.
Quick Start
TL;DR? Check out the [quick start example][quick-example] in ./examples/.
There are a number of other examples in [./examples/*.js][examples].
Don't see an example you think should be there? Submit a pull request
to add it!
Usage
The recommended way to use winston is to create your own logger. The
simplest way to do this is using winston.createLogger:
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
defaultMeta: { service: 'user-service' },
transports: [
//
// - Write all logs with importance level of `error` or higher to `error.log`
// (i.e., error, fatal, but not other levels)
//
new winston.transports.File({ filename: 'error.log', level: 'error' }),
//
// - Write all logs with importance level of `info` or higher to `combined.log`
// (i.e., fatal, error, warn, and info, but not trace)
//
new winston.transports.File({ filename: 'combined.log' }),
],
});
//
// If we're not in production then log to the `console` with the format:
// `${info.level}: ${info.message} JSON.stringify({ ...rest }) `
//
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.simple(),
}));
}
You may also log directly via the default logger exposed by
require('winston'), but this merely intended to be a convenient shared
logger to use throughout your application if you so choose.
Note that the default logger doesn't have any transports by default.
You need add transports by yourself, and leaving the default logger without any
transports may produce a high memory usage issue.
Table of contents
- Motivation
- Quick Start
- Usage
- Table of Contents
- Logging
- [Formats]
- [Logging levels]
- [Transports]
- Exceptions
- Rejections
- Profiling
- Streaming Logs
- Querying Logs
- Further Reading
- Installation
- Run Tests
Logging
Logging levels in winston conform to the severity ordering specified by
[RFC5424]: severity of all levels is assumed to be numerically ascending
from most important to least important.
const levels = {
error: 0,
warn: 1,
info: 2,
http: 3,
verbose: 4,
debug: 5,
silly: 6
};
Creating your own Logger
You get started by creating a logger using winston.createLogger:
const logger = winston.createLogger({
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: 'combined.log' })
]
});
A logger accepts the following parameters:
| Name | Default | Description |
| ------------- | --------------------------- | --------------- |
| level | 'info' | Log only if info.level is less than or equal to this level |
| levels | winston.config.npm.levels | Levels (and colors) representing log priorities |
| format | winston.format.json | Formatting for info messages (see: [Formats]) |
| transports | [] (No transports) | Set of logging targets for info messages |
| exitOnError | true | If false, handled exceptions will not cause process.exit |
| silent | false | If true, all logs are suppressed |
The levels provided to createLogger will be defined as convenience methods
on the logger returned.
//
// Logging
//
logger.log({
level: 'info',
message: 'Hello distributed log files!'
});
logger.info('Hello again distributed logs');
You can add or remove transports from the logger once it has been provided
to you from winston.createLogger:
const files = new winston.transports.File({ filename: 'combined.log' });
const console = new winston.transports.Console();
logger
.clear() // Remove all transports
.add(console) // Add console transport
.add(files) // Add file transport
.remove(console); // Remove console transport
You can also wholesale reconfigure a winston.Logger instance using the
configure method:
const logger = winston.createLogger({
level: 'info',
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: 'combined.log' })
]
});
//
// Replaces the previous transports with those in the
// new configuration wholesale.
//
const DailyRotateFile = require('winston-daily-rotate-file');
logger.configure({
level: 'verbose',
transports: [
new DailyRotateFile(opts)
]
});
Creating child loggers
You can create child loggers from existing loggers to pass metadata overrides:
const logger = winston.createLogger({
transports: [
new winston.transports.Console(),
]
});
const childLogger = logger.child({ requestId: '451' });
.childis likely to be bugged if you're also extending theLoggerclass, due to some implementation details that makethiskeyword to point to unexpected things. Use with caution.
Streams, objectMode, and info objects
In winston, both Logger and Transport instances are treated as
objectMode
streams that accept an info object.
The info parameter provided to a given format represents a single log
message. The object itself is mutable. Every info must have at least the
level and message properties:
const info = {
level: 'info', // Level of the logging message
message: 'Hey! Log something?' // Descriptive message being logged.
};
Properties besides level and message are considered as "meta". i.e.:
const { level, message, ...meta } = info;
Several of the formats in logform itself add additional properties:
| Property | Format added by | Description |
| ----------- | --------------- | ----------- |
| splat | splat() | String interpolation splat for %d %s-style messages. |
| timestamp | timestamp() | timestamp the message was received. |
| label | label() | Custom label associated with each message. |
| ms | ms() | Number of milliseconds since the previous log message. |
As a consumer you may add whatever properties you wish – internal state is
maintained by Symbol properties:
Symbol.for('level')(READ-ONLY): equal tolevelproperty. Is treated as immutable by all code.Symbol.for('message'):complete string message set by "finalizing formats":json- `logs

