Gathering detailed insights and metrics for winston
Gathering detailed insights and metrics for winston
Gathering detailed insights and metrics for winston
Gathering detailed insights and metrics for winston
winston-transport
Base stream implementations for winston@3 and up.
winston-daily-rotate-file
A transport for winston which logs to a rotating file each day.
winston-compat
Core functionality from winston < 3.0.0 commonly used by user-created transports.
nest-winston
A Nest module wrapper for winston
npm install winston
Typescript
Module System
Min. Node Version
Node Version
NPM Version
69
Supply Chain
98.5
Quality
89.8
Maintenance
100
Vulnerability
100
License
JavaScript (99.24%)
TypeScript (0.76%)
Total Downloads
2,592,417,419
Last Day
2,335,376
Last Week
12,065,194
Last Month
54,102,430
Last Year
578,616,831
23,024 Stars
1,622 Commits
1,817 Forks
227 Watching
17 Branches
384 Contributors
Minified
Minified + Gzipped
Latest Version
3.17.0
Package Id
winston@3.17.0
Unpacked Size
264.69 kB
Size
49.51 kB
File Count
40
NPM Version
10.8.1
Node Version
22.4.1
Publised On
10 Nov 2024
Cumulative downloads
Total Downloads
Last day
-1.5%
2,335,376
Compared to previous day
Last week
5.3%
12,065,194
Compared to previous week
Last month
6.6%
54,102,430
Compared to previous month
Last year
-2.7%
578,616,831
Compared to previous year
11
A logger for just about everything.
See the Upgrade Guide for more information. Bug reports and PRs welcome!
winston@2.x
documentation?Please note that the documentation below is for winston@3
.
Read the winston@2.x
documentation.
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.
TL;DR? Check out the quick start example in ./examples/
.
There are a number of other examples in ./examples/*.js
.
Don't see an example you think should be there? Submit a pull request
to add it!
The recommended way to use winston
is to create your own logger. The
simplest way to do this is using winston.createLogger
:
1const winston = require('winston'); 2 3const logger = winston.createLogger({ 4 level: 'info', 5 format: winston.format.json(), 6 defaultMeta: { service: 'user-service' }, 7 transports: [ 8 // 9 // - Write all logs with importance level of `error` or higher to `error.log` 10 // (i.e., error, fatal, but not other levels) 11 // 12 new winston.transports.File({ filename: 'error.log', level: 'error' }), 13 // 14 // - Write all logs with importance level of `info` or higher to `combined.log` 15 // (i.e., fatal, error, warn, and info, but not trace) 16 // 17 new winston.transports.File({ filename: 'combined.log' }), 18 ], 19}); 20 21// 22// If we're not in production then log to the `console` with the format: 23// `${info.level}: ${info.message} JSON.stringify({ ...rest }) ` 24// 25if (process.env.NODE_ENV !== 'production') { 26 logger.add(new winston.transports.Console({ 27 format: winston.format.simple(), 28 })); 29}
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.
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.
1const levels = { 2 error: 0, 3 warn: 1, 4 info: 2, 5 http: 3, 6 verbose: 4, 7 debug: 5, 8 silly: 6 9};
You get started by creating a logger using winston.createLogger
:
1const logger = winston.createLogger({
2 transports: [
3 new winston.transports.Console(),
4 new winston.transports.File({ filename: 'combined.log' })
5 ]
6});
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.
1// 2// Logging 3// 4logger.log({ 5 level: 'info', 6 message: 'Hello distributed log files!' 7}); 8 9logger.info('Hello again distributed logs');
You can add or remove transports from the logger
once it has been provided
to you from winston.createLogger
:
1const files = new winston.transports.File({ filename: 'combined.log' }); 2const console = new winston.transports.Console(); 3 4logger 5 .clear() // Remove all transports 6 .add(console) // Add console transport 7 .add(files) // Add file transport 8 .remove(console); // Remove console transport
You can also wholesale reconfigure a winston.Logger
instance using the
configure
method:
1const logger = winston.createLogger({ 2 level: 'info', 3 transports: [ 4 new winston.transports.Console(), 5 new winston.transports.File({ filename: 'combined.log' }) 6 ] 7}); 8 9// 10// Replaces the previous transports with those in the 11// new configuration wholesale. 12// 13const DailyRotateFile = require('winston-daily-rotate-file'); 14logger.configure({ 15 level: 'verbose', 16 transports: [ 17 new DailyRotateFile(opts) 18 ] 19});
You can create child loggers from existing loggers to pass metadata overrides:
1const logger = winston.createLogger({ 2 transports: [ 3 new winston.transports.Console(), 4 ] 5}); 6 7const childLogger = logger.child({ requestId: '451' });
.child
is likely to be bugged if you're also extending theLogger
class, due to some implementation details that makethis
keyword to point to unexpected things. Use with caution.
objectMode
, and info
objectsIn 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:
1const info = { 2 level: 'info', // Level of the logging message 3 message: 'Hey! Log something?' // Descriptive message being logged. 4};
Properties besides level and message are considered as "meta
". i.e.:
1const { 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 to level
property.
Is treated as immutable by all code.Symbol.for('message'):
complete string message set by "finalizing formats":
json
logstash
printf
prettyPrint
simple
Symbol.for('splat')
: additional string interpolation arguments. Used
exclusively by splat()
format.These Symbols are stored in another package: triple-beam
so that all
consumers of logform
can have the same Symbol reference. i.e.:
1const { LEVEL, MESSAGE, SPLAT } = require('triple-beam'); 2 3console.log(LEVEL === Symbol.for('level')); 4// true 5 6console.log(MESSAGE === Symbol.for('message')); 7// true 8 9console.log(SPLAT === Symbol.for('splat')); 10// true
NOTE: any
{ message }
property in ameta
object provided will automatically be concatenated to anymsg
already provided: For example the below will concatenate 'world' onto 'hello':1logger.log('error', 'hello', { message: 'world' }); 2logger.info('hello', { message: 'world' });
Formats in winston
can be accessed from winston.format
. They are
implemented in logform
, a separate
module from winston
. This allows flexibility when writing your own transports
in case you wish to include a default format with your transport.
In modern versions of node
template strings are very performant and are the
recommended way for doing most end-user formatting. If you want to bespoke
format your logs, winston.format.printf
is for you:
1const { createLogger, format, transports } = require('winston'); 2const { combine, timestamp, label, printf } = format; 3 4const myFormat = printf(({ level, message, label, timestamp }) => { 5 return `${timestamp} [${label}] ${level}: ${message}`; 6}); 7 8const logger = createLogger({ 9 format: combine( 10 label({ label: 'right meow!' }), 11 timestamp(), 12 myFormat 13 ), 14 transports: [new transports.Console()] 15});
To see what built-in formats are available and learn more about creating your
own custom logging formats, see logform
.
Any number of formats may be combined into a single format using
format.combine
. Since format.combine
takes no opts
, as a convenience it
returns pre-created instance of the combined format.
1const { createLogger, format, transports } = require('winston'); 2const { combine, timestamp, label, prettyPrint } = format; 3 4const logger = createLogger({ 5 format: combine( 6 label({ label: 'right meow!' }), 7 timestamp(), 8 prettyPrint() 9 ), 10 transports: [new transports.Console()] 11}) 12 13logger.log({ 14 level: 'info', 15 message: 'What time is the testing at?' 16}); 17// Outputs: 18// { level: 'info', 19// message: 'What time is the testing at?', 20// label: 'right meow!', 21// timestamp: '2017-09-30T03:57:26.875Z' }
The log
method provides the string interpolation using util.format. It
must be enabled using format.splat()
.
Below is an example that defines a format with string interpolation of
messages using format.splat
and then serializes the entire info
message
using format.simple
.
1const { createLogger, format, transports } = require('winston'); 2const logger = createLogger({ 3 format: format.combine( 4 format.splat(), 5 format.simple() 6 ), 7 transports: [new transports.Console()] 8}); 9 10// info: test message my string {} 11logger.log('info', 'test message %s', 'my string'); 12 13// info: test message 123 {} 14logger.log('info', 'test message %d', 123); 15 16// info: test message first second {number: 123} 17logger.log('info', 'test message %s, %s', 'first', 'second', { number: 123 });
info
ObjectsIf you wish to filter out a given info
Object completely when logging then
simply return a falsey value.
1const { createLogger, format, transports } = require('winston'); 2 3// Ignore log messages if they have { private: true } 4const ignorePrivate = format((info, opts) => { 5 if (info.private) { return false; } 6 return info; 7}); 8 9const logger = createLogger({ 10 format: format.combine( 11 ignorePrivate(), 12 format.json() 13 ), 14 transports: [new transports.Console()] 15}); 16 17// Outputs: {"level":"error","message":"Public error to share"} 18logger.log({ 19 level: 'error', 20 message: 'Public error to share' 21}); 22 23// Messages with { private: true } will not be written when logged. 24logger.log({ 25 private: true, 26 level: 'error', 27 message: 'This is super secret - hide it.' 28});
Use of format.combine
will respect any falsey values return and stop
evaluation of later formats in the series. For example:
1const { format } = require('winston'); 2const { combine, timestamp, label } = format; 3 4const willNeverThrow = format.combine( 5 format(info => { return false })(), // Ignores everything 6 format(info => { throw new Error('Never reached') })() 7);
Formats are prototypal objects (i.e. class instances) that define a single
method: transform(info, opts)
and return the mutated info
:
info
: an object representing the log message.opts
: setting specific to the current instance of the format.They are expected to return one of two things:
info
Object representing the modified info
argument. Object
references need not be preserved if immutability is preferred. All current
built-in formats consider info
mutable, but [immutablejs] is being
considered for future releases.info
argument should be ignored by the
caller. (See: Filtering info
Objects) below.winston.format
is designed to be as simple as possible. To define a new
format, simply pass it a transform(info, opts)
function to get a new
Format
.
The named Format
returned can be used to create as many copies of the given
Format
as desired:
1const { format } = require('winston'); 2 3const volume = format((info, opts) => { 4 if (opts.yell) { 5 info.message = info.message.toUpperCase(); 6 } else if (opts.whisper) { 7 info.message = info.message.toLowerCase(); 8 } 9 10 return info; 11}); 12 13// `volume` is now a function that returns instances of the format. 14const scream = volume({ yell: true }); 15console.dir(scream.transform({ 16 level: 'info', 17 message: `sorry for making you YELL in your head!` 18}, scream.options)); 19// { 20// level: 'info' 21// message: 'SORRY FOR MAKING YOU YELL IN YOUR HEAD!' 22// } 23 24// `volume` can be used multiple times to create different formats. 25const whisper = volume({ whisper: true }); 26console.dir(whisper.transform({ 27 level: 'info', 28 message: `WHY ARE THEY MAKING US YELL SO MUCH!` 29}, whisper.options)); 30// { 31// level: 'info' 32// message: 'why are they making us yell so much!' 33// }
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.
Each level
is given a specific integer priority. The higher the priority the
more important the message is considered to be, and the lower the
corresponding integer priority. For example, as specified exactly in RFC5424
the syslog
levels are prioritized from 0 to 7 (highest to lowest).
1{ 2 emerg: 0, 3 alert: 1, 4 crit: 2, 5 error: 3, 6 warning: 4, 7 notice: 5, 8 info: 6, 9 debug: 7 10}
Similarly, npm
logging levels are prioritized from 0 to 6 (highest to
lowest):
1{ 2 error: 0, 3 warn: 1, 4 info: 2, 5 http: 3, 6 verbose: 4, 7 debug: 5, 8 silly: 6 9}
If you do not explicitly define the levels that winston
should use, the
npm
levels above will be used.
Setting the level for your logging message can be accomplished in one of two ways. You can pass a string representing the logging level to the log() method or use the level specified methods defined on every winston Logger.
1// 2// Any logger instance 3// 4logger.log('silly', "127.0.0.1 - there's no place like home"); 5logger.log('debug', "127.0.0.1 - there's no place like home"); 6logger.log('verbose', "127.0.0.1 - there's no place like home"); 7logger.log('info', "127.0.0.1 - there's no place like home"); 8logger.log('warn', "127.0.0.1 - there's no place like home"); 9logger.log('error', "127.0.0.1 - there's no place like home"); 10logger.info("127.0.0.1 - there's no place like home"); 11logger.warn("127.0.0.1 - there's no place like home"); 12logger.error("127.0.0.1 - there's no place like home"); 13 14// 15// Default logger 16// 17winston.log('info', "127.0.0.1 - there's no place like home"); 18winston.info("127.0.0.1 - there's no place like home");
winston
allows you to define a level
property on each transport which
specifies the maximum level of messages that a transport should log. For
example, using the syslog
levels you could log only error
messages to the
console and everything info
and below to a file (which includes error
messages):
1const logger = winston.createLogger({
2 levels: winston.config.syslog.levels,
3 transports: [
4 new winston.transports.Console({ level: 'error' }),
5 new winston.transports.File({
6 filename: 'combined.log',
7 level: 'info'
8 })
9 ]
10});
You may also dynamically change the log level of a transport:
1const transports = { 2 console: new winston.transports.Console({ level: 'warn' }), 3 file: new winston.transports.File({ filename: 'combined.log', level: 'error' }) 4}; 5 6const logger = winston.createLogger({ 7 transports: [ 8 transports.console, 9 transports.file 10 ] 11}); 12 13logger.info('Will not be logged in either transport!'); 14transports.console.level = 'info'; 15transports.file.level = 'info'; 16logger.info('Will be logged in both transports!');
winston
supports customizable logging levels, defaulting to npm style
logging levels. Levels must be specified at the time of creating your logger.
In addition to the predefined npm
, syslog
, and cli
levels available in
winston
, you can also choose to define your own:
1const myCustomLevels = { 2 levels: { 3 foo: 0, 4 bar: 1, 5 baz: 2, 6 foobar: 3 7 }, 8 colors: { 9 foo: 'blue', 10 bar: 'green', 11 baz: 'yellow', 12 foobar: 'red' 13 } 14}; 15 16const customLevelLogger = winston.createLogger({ 17 levels: myCustomLevels.levels 18}); 19 20customLevelLogger.foobar('some foobar level-ed message');
Although there is slight repetition in this data structure, it enables simple encapsulation if you do not want to have colors. If you do wish to have colors, in addition to passing the levels to the Logger itself, you must make winston aware of them:
1winston.addColors(myCustomLevels.colors);
This enables loggers using the colorize
formatter to appropriately color and style
the output of custom levels.
Additionally, you can also change background color and font style. For example,
1baz: 'italic yellow', 2foobar: 'bold red cyanBG'
Possible options are below.
Font styles: bold
, dim
, italic
, underline
, inverse
, hidden
,
strikethrough
.
Font foreground colors: black
, red
, green
, yellow
, blue
, magenta
,
cyan
, white
, gray
, grey
.
Background colors: blackBG
, redBG
, greenBG
, yellowBG
, blueBG
magentaBG
, cyanBG
, whiteBG
To colorize the standard logging level add
1winston.format.combine( 2 winston.format.colorize(), 3 winston.format.simple() 4);
where winston.format.simple()
is whatever other formatter you want to use. The colorize
formatter must come before any formatters adding text you wish to color.
To colorize the full log line with the json formatter you can apply the following
1winston.format.combine( 2 winston.format.json(), 3 winston.format.colorize({ all: true }) 4);
There are several core transports included in winston
, which leverage the
built-in networking and file I/O offered by Node.js core. In addition, there
are additional transports written by members of the community.
It is possible to use multiple transports of the same type e.g.
winston.transports.File
when you construct the transport.
1const logger = winston.createLogger({
2 transports: [
3 new winston.transports.File({
4 filename: 'combined.log',
5 level: 'info'
6 }),
7 new winston.transports.File({
8 filename: 'errors.log',
9 level: 'error'
10 })
11 ]
12});
If you later want to remove one of these transports you can do so by using the transport itself. e.g.:
1const combinedLogs = logger.transports.find(transport => { 2 return transport.filename === 'combined.log' 3}); 4 5logger.remove(combinedLogs);
Adding a custom transport is easy. All you need to do is accept any options
you need, implement a log() method, and consume it with winston
.
1const Transport = require('winston-transport'); 2const util = require('util'); 3 4// 5// Inherit from `winston-transport` so you can take advantage 6// of the base functionality and `.exceptions.handle()`. 7// 8module.exports = class YourCustomTransport extends Transport { 9 constructor(opts) { 10 super(opts); 11 // 12 // Consume any custom options here. e.g.: 13 // - Connection information for databases 14 // - Authentication information for APIs (e.g. loggly, papertrail, 15 // logentries, etc.). 16 // 17 } 18 19 log(info, callback) { 20 setImmediate(() => { 21 this.emit('logged', info); 22 }); 23 24 // Perform the writing to the remote service 25 callback(); 26 } 27};
As every transport inherits from winston-transport, it's possible to set a custom format and a custom log level on each transport separately:
1const logger = winston.createLogger({
2 transports: [
3 new winston.transports.File({
4 filename: 'error.log',
5 level: 'error',
6 format: winston.format.json()
7 }),
8 new winston.transports.Http({
9 level: 'warn',
10 format: winston.format.json()
11 }),
12 new winston.transports.Console({
13 level: 'info',
14 format: winston.format.combine(
15 winston.format.colorize(),
16 winston.format.simple()
17 )
18 })
19 ]
20});
With winston
, it is possible to catch and log uncaughtException
events
from your process. With your own logger instance you can enable this behavior
when it's created or later on in your applications lifecycle:
1const { createLogger, transports } = require('winston'); 2 3// Enable exception handling when you create your logger. 4const logger = createLogger({ 5 transports: [ 6 new transports.File({ filename: 'combined.log' }) 7 ], 8 exceptionHandlers: [ 9 new transports.File({ filename: 'exceptions.log' }) 10 ] 11}); 12 13// Or enable it later on by adding a transport or using `.exceptions.handle` 14const logger = createLogger({ 15 transports: [ 16 new transports.File({ filename: 'combined.log' }) 17 ] 18}); 19 20// Call exceptions.handle with a transport to handle exceptions 21logger.exceptions.handle( 22 new transports.File({ filename: 'exceptions.log' }) 23);
If you want to use this feature with the default logger, simply call
.exceptions.handle()
with a transport instance.
1//
2// You can add a separate exception logger by passing it to `.exceptions.handle`
3//
4winston.exceptions.handle(
5 new winston.transports.File({ filename: 'path/to/exceptions.log' })
6);
7
8//
9// Alternatively you can set `handleExceptions` to true when adding transports
10// to winston.
11//
12winston.add(new winston.transports.File({
13 filename: 'path/to/combined.log',
14 handleExceptions: true
15}));
By default, winston will exit after logging an uncaughtException. If this is
not the behavior you want, set exitOnError = false
1const logger = winston.createLogger({ exitOnError: false }); 2 3// 4// or, like this: 5// 6logger.exitOnError = false;
When working with custom logger instances, you can pass in separate transports
to the exceptionHandlers
property or set handleExceptions
on any
transport.
1const logger = winston.createLogger({ 2 transports: [ 3 new winston.transports.File({ filename: 'path/to/combined.log' }) 4 ], 5 exceptionHandlers: [ 6 new winston.transports.File({ filename: 'path/to/exceptions.log' }) 7 ] 8});
1const logger = winston.createLogger({ 2 transports: [ 3 new winston.transports.Console({ 4 handleExceptions: true 5 }) 6 ], 7 exitOnError: false 8});
The exitOnError
option can also be a function to prevent exit on only
certain types of errors:
1function ignoreEpipe(err) {
2 return err.code !== 'EPIPE';
3}
4
5const logger = winston.createLogger({ exitOnError: ignoreEpipe });
6
7//
8// or, like this:
9//
10logger.exitOnError = ignoreEpipe;
With winston
, it is possible to catch and log unhandledRejection
events
from your process. With your own logger instance you can enable this behavior
when it's created or later on in your applications lifecycle:
1const { createLogger, transports } = require('winston'); 2 3// Enable rejection handling when you create your logger. 4const logger = createLogger({ 5 transports: [ 6 new transports.File({ filename: 'combined.log' }) 7 ], 8 rejectionHandlers: [ 9 new transports.File({ filename: 'rejections.log' }) 10 ] 11}); 12 13// Or enable it later on by adding a transport or using `.rejections.handle` 14const logger = createLogger({ 15 transports: [ 16 new transports.File({ filename: 'combined.log' }) 17 ] 18}); 19 20// Call rejections.handle with a transport to handle rejections 21logger.rejections.handle( 22 new transports.File({ filename: 'rejections.log' }) 23);
If you want to use this feature with the default logger, simply call
.rejections.handle()
with a transport instance.
1//
2// You can add a separate rejection logger by passing it to `.rejections.handle`
3//
4winston.rejections.handle(
5 new winston.transports.File({ filename: 'path/to/rejections.log' })
6);
7
8//
9// Alternatively you can set `handleRejections` to true when adding transports
10// to winston.
11//
12winston.add(new winston.transports.File({
13 filename: 'path/to/combined.log',
14 handleRejections: true
15}));
In addition to logging messages and metadata, winston
also has a simple
profiling mechanism implemented for any logger:
1// 2// Start profile of 'test' 3// 4logger.profile('test'); 5 6setTimeout(function () { 7 // 8 // Stop profile of 'test'. Logging will now take place: 9 // '17 Jan 21:00:00 - info: test duration=1000ms' 10 // 11 logger.profile('test'); 12}, 1000);
Also you can start a timer and keep a reference that you can call .done()
on:
1 // Returns an object corresponding to a specific timing. When done 2 // is called the timer will finish and log the duration. e.g.: 3 // 4 const profiler = logger.startTimer(); 5 setTimeout(function () { 6 profiler.done({ message: 'Logging message' }); 7 }, 1000);
All profile messages are set to 'info' level by default, and both message and
metadata are optional. For individual profile messages, you can override the default log level by supplying a metadata object with a level
property:
1logger.profile('test', { level: 'debug' });
winston
supports querying of logs with Loggly-like options. See Loggly
Search API. Specifically:
File
, Couchdb
, Redis
, Loggly
, Nssocket
, and Http
.
1const options = { 2 from: new Date() - (24 * 60 * 60 * 1000), 3 until: new Date(), 4 limit: 10, 5 start: 0, 6 order: 'desc', 7 fields: ['message'] 8}; 9 10// 11// Find items logged between today and yesterday. 12// 13logger.query(options, function (err, results) { 14 if (err) { 15 /* TODO: handle me */ 16 throw err; 17 } 18 19 console.log(results); 20});
Streaming allows you to stream your logs back from your chosen transport.
1// 2// Start at the end. 3// 4winston.stream({ start: -1 }).on('log', function(log) { 5 console.log(log); 6});
The default logger is accessible through the winston
module directly. Any
method that you could call on an instance of a logger is available on the
default logger:
1const winston = require('winston'); 2 3winston.log('info', 'Hello distributed log files!'); 4winston.info('Hello again distributed logs'); 5 6winston.level = 'debug'; 7winston.log('debug', 'Now my debug messages are written to console!');
By default, no transports are set on the default logger. You must
add or remove transports via the add()
and remove()
methods:
1const files = new winston.transports.File({ filename: 'combined.log' }); 2const console = new winston.transports.Console(); 3 4winston.add(console); 5winston.add(files); 6winston.remove(console);
Or do it with one call to configure():
1winston.configure({ 2 transports: [ 3 new winston.transports.File({ filename: 'somefile.log' }) 4 ] 5});
For more documentation about working with each individual transport supported
by winston
see the winston
Transports document.
winston
Often it is useful to wait for your logs to be written before exiting the
process. Each instance of winston.Logger
is also a [Node.js stream]. A
finish
event will be raised when all logs have flushed to all transports
after the stream has been ended.
1const transport = new winston.transports.Console(); 2const logger = winston.createLogger({ 3 transports: [transport] 4}); 5 6logger.on('finish', function (info) { 7 // All `info` log messages has now been logged 8}); 9 10logger.info('CHILL WINSTON!', { seriously: true }); 11logger.end();
It is also worth mentioning that the logger also emits an 'error' event if an error occurs within the logger itself which you should handle or suppress if you don't want unhandled exceptions:
1// 2// Handle errors originating in the logger itself 3// 4logger.on('error', function (err) { /* Do Something */ });
Often in larger, more complex, applications it is necessary to have multiple
logger instances with different settings. Each logger is responsible for a
different feature area (or category). This is exposed in winston
in two
ways: through winston.loggers
and instances of winston.Container
. In fact,
winston.loggers
is just a predefined instance of winston.Container
:
1const winston = require('winston'); 2const { format } = winston; 3const { combine, label, json } = format; 4 5// 6// Configure the logger for `category1` 7// 8winston.loggers.add('category1', { 9 format: combine( 10 label({ label: 'category one' }), 11 json() 12 ), 13 transports: [ 14 new winston.transports.Console({ level: 'silly' }), 15 new winston.transports.File({ filename: 'somefile.log' }) 16 ] 17}); 18 19// 20// Configure the logger for `category2` 21// 22winston.loggers.add('category2', { 23 format: combine( 24 label({ label: 'category two' }), 25 json() 26 ), 27 transports: [ 28 new winston.transports.Http({ host: 'localhost', port:8080 }) 29 ] 30});
Now that your loggers are setup, you can require winston in any file in your application and access these pre-configured loggers:
1const winston = require('winston'); 2 3// 4// Grab your preconfigured loggers 5// 6const category1 = winston.loggers.get('category1'); 7const category2 = winston.loggers.get('category2'); 8 9category1.info('logging to file and console transports'); 10category2.info('logging to http transport');
If you prefer to manage the Container
yourself, you can simply instantiate one:
1const winston = require('winston'); 2const { format } = winston; 3const { combine, label, json } = format; 4 5const container = new winston.Container(); 6 7container.add('category1', { 8 format: combine( 9 label({ label: 'category one' }), 10 json() 11 ), 12 transports: [ 13 new winston.transports.Console({ level: 'silly' }), 14 new winston.transports.File({ filename: 'somefile.log' }) 15 ] 16}); 17 18const category1 = container.get('category1'); 19category1.info('logging to file and console transports');
By default the winston.transports.Console
transport sends messages to stdout
and stderr
. This
is fine in most situations; however, there are some cases where this isn't desirable, including:
--silent
optionTo make the transport log use console.log()
, console.warn()
and console.error()
instead, set the forceConsole
option to true
:
1const logger = winston.createLogger({
2 level: 'info',
3 transports: [new winston.transports.Console({ forceConsole: true })]
4});
1npm install winston
1yarn add winston
All of the winston tests are written with mocha
, nyc
, and
assume
. They can be run with npm
.
1npm test
No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
GitHub workflow tokens follow principle of least privilege
Details
Reason
23 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
1 existing vulnerabilities detected
Details
Reason
Found 9/23 approved changesets -- score normalized to 3
Reason
security policy file detected
Details
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Score
Last Scanned on 2024-11-25
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More