UNPKG

34.7 kBMarkdownView Raw
1# winston
2
3A logger for just about everything.
4
5[![Version npm](https://img.shields.io/npm/v/winston.svg?style=flat-square)](https://www.npmjs.com/package/winston)
6[![npm Downloads](https://img.shields.io/npm/dm/winston.svg?style=flat-square)](https://npmcharts.com/compare/winston?minimal=true)
7[![build status](https://github.com/winstonjs/winston/actions/workflows/ci.yml/badge.svg)](https://github.com/winstonjs/winston/actions/workflows/ci.yml)
8[![coverage status](https://coveralls.io/repos/github/winstonjs/winston/badge.svg?branch=master)](https://coveralls.io/github/winstonjs/winston?branch=master)
9
10[![NPM](https://nodei.co/npm/winston.png?downloads=true&downloadRank=true)](https://nodei.co/npm/winston/)
11
12## winston@3
13
14See the [Upgrade Guide](UPGRADE-3.0.md) for more information. Bug reports and
15PRs welcome!
16
17## Looking for `winston@2.x` documentation?
18
19Please note that the documentation below is for `winston@3`.
20[Read the `winston@2.x` documentation].
21
22## Motivation
23
24`winston` is designed to be a simple and universal logging library with
25support for multiple transports. A transport is essentially a storage device
26for your logs. Each `winston` logger can have multiple transports (see:
27[Transports]) configured at different levels (see: [Logging levels]). For
28example, one may want error logs to be stored in a persistent remote location
29(like a database), but all logs output to the console or a local file.
30
31`winston` aims to decouple parts of the logging process to make it more
32flexible and extensible. Attention is given to supporting flexibility in log
33formatting (see: [Formats]) & levels (see: [Using custom logging levels]), and
34ensuring those APIs decoupled from the implementation of transport logging
35(i.e. how the logs are stored / indexed, see: [Adding Custom Transports]) to
36the API that they exposed to the programmer.
37
38## Quick Start
39
40TL;DR? Check out the [quick start example][quick-example] in `./examples/`.
41There are a number of other examples in [`./examples/*.js`][examples].
42Don't see an example you think should be there? Submit a pull request
43to add it!
44
45## Usage
46
47The recommended way to use `winston` is to create your own logger. The
48simplest way to do this is using `winston.createLogger`:
49
50``` js
51const winston = require('winston');
52
53const logger = winston.createLogger({
54 level: 'info',
55 format: winston.format.json(),
56 defaultMeta: { service: 'user-service' },
57 transports: [
58 //
59 // - Write all logs with importance level of `error` or less to `error.log`
60 // - Write all logs with importance level of `info` or less to `combined.log`
61 //
62 new winston.transports.File({ filename: 'error.log', level: 'error' }),
63 new winston.transports.File({ filename: 'combined.log' }),
64 ],
65});
66
67//
68// If we're not in production then log to the `console` with the format:
69// `${info.level}: ${info.message} JSON.stringify({ ...rest }) `
70//
71if (process.env.NODE_ENV !== 'production') {
72 logger.add(new winston.transports.Console({
73 format: winston.format.simple(),
74 }));
75}
76```
77
78You may also log directly via the default logger exposed by
79`require('winston')`, but this merely intended to be a convenient shared
80logger to use throughout your application if you so choose.
81
82## Table of contents
83
84* [Motivation](#motivation)
85* [Quick Start](#quick-start)
86* [Usage](#usage)
87* [Table of Contents](#table-of-contents)
88* [Logging](#logging)
89 * [Creating your logger](#creating-your-own-logger)
90 * [Streams, `objectMode`, and `info` objects](#streams-objectmode-and-info-objects)
91* [Formats]
92 * [Combining formats](#combining-formats)
93 * [String interpolation](#string-interpolation)
94 * [Filtering `info` Objects](#filtering-info-objects)
95 * [Creating custom formats](#creating-custom-formats)
96* [Logging levels]
97 * [Using logging levels](#using-logging-levels)
98 * [Using custom logging levels](#using-custom-logging-levels)
99* [Transports]
100 * [Multiple transports of the same type](#multiple-transports-of-the-same-type)
101 * [Adding Custom Transports](#adding-custom-transports)
102 * [Common Transport options](#common-transport-options)
103* [Exceptions](#exceptions)
104 * [Handling Uncaught Exceptions with winston](#handling-uncaught-exceptions-with-winston)
105 * [To Exit or Not to Exit](#to-exit-or-not-to-exit)
106* [Rejections](#rejections)
107 * [Handling Uncaught Promise Rejections with winston](#handling-uncaught-promise-rejections-with-winston)
108* [Profiling](#profiling)
109* [Streaming Logs](#streaming-logs)
110* [Querying Logs](#querying-logs)
111* [Further Reading](#further-reading)
112 * [Using the default logger](#using-the-default-logger)
113 * [Awaiting logs to be written in `winston`](#awaiting-logs-to-be-written-in-winston)
114 * [Working with multiple Loggers in `winston`](#working-with-multiple-loggers-in-winston)
115* [Installation](#installation)
116* [Run Tests](#run-tests)
117
118## Logging
119
120Logging levels in `winston` conform to the severity ordering specified by
121[RFC5424]: _severity of all levels is assumed to be numerically **ascending**
122from most important to least important._
123
124``` js
125const levels = {
126 error: 0,
127 warn: 1,
128 info: 2,
129 http: 3,
130 verbose: 4,
131 debug: 5,
132 silly: 6
133};
134```
135
136### Creating your own Logger
137You get started by creating a logger using `winston.createLogger`:
138
139``` js
140const logger = winston.createLogger({
141 transports: [
142 new winston.transports.Console(),
143 new winston.transports.File({ filename: 'combined.log' })
144 ]
145});
146```
147
148A logger accepts the following parameters:
149
150| Name | Default | Description |
151| ------------- | --------------------------- | --------------- |
152| `level` | `'info'` | Log only if [`info.level`](#streams-objectmode-and-info-objects) less than or equal to this level |
153| `levels` | `winston.config.npm.levels` | Levels (and colors) representing log priorities |
154| `format` | `winston.format.json` | Formatting for `info` messages (see: [Formats]) |
155| `transports` | `[]` _(No transports)_ | Set of logging targets for `info` messages |
156| `exitOnError` | `true` | If false, handled exceptions will not cause `process.exit` |
157| `silent` | `false` | If true, all logs are suppressed |
158
159The levels provided to `createLogger` will be defined as convenience methods
160on the `logger` returned.
161
162``` js
163//
164// Logging
165//
166logger.log({
167 level: 'info',
168 message: 'Hello distributed log files!'
169});
170
171logger.info('Hello again distributed logs');
172```
173
174You can add or remove transports from the `logger` once it has been provided
175to you from `winston.createLogger`:
176
177``` js
178const files = new winston.transports.File({ filename: 'combined.log' });
179const console = new winston.transports.Console();
180
181logger
182 .clear() // Remove all transports
183 .add(console) // Add console transport
184 .add(files) // Add file transport
185 .remove(console); // Remove console transport
186```
187
188You can also wholesale reconfigure a `winston.Logger` instance using the
189`configure` method:
190
191``` js
192const logger = winston.createLogger({
193 level: 'info',
194 transports: [
195 new winston.transports.Console(),
196 new winston.transports.File({ filename: 'combined.log' })
197 ]
198});
199
200//
201// Replaces the previous transports with those in the
202// new configuration wholesale.
203//
204const DailyRotateFile = require('winston-daily-rotate-file');
205logger.configure({
206 level: 'verbose',
207 transports: [
208 new DailyRotateFile(opts)
209 ]
210});
211```
212
213### Creating child loggers
214
215You can create child loggers from existing loggers to pass metadata overrides:
216
217``` js
218const logger = winston.createLogger({
219 transports: [
220 new winston.transports.Console(),
221 ]
222});
223
224const childLogger = logger.child({ requestId: '451' });
225```
226
227### Streams, `objectMode`, and `info` objects
228
229In `winston`, both `Logger` and `Transport` instances are treated as
230[`objectMode`](https://nodejs.org/api/stream.html#stream_object_mode)
231streams that accept an `info` object.
232
233The `info` parameter provided to a given format represents a single log
234message. The object itself is mutable. Every `info` must have at least the
235`level` and `message` properties:
236
237``` js
238const info = {
239 level: 'info', // Level of the logging message
240 message: 'Hey! Log something?' // Descriptive message being logged.
241};
242```
243
244Properties **besides level and message** are considered as "`meta`". i.e.:
245
246``` js
247const { level, message, ...meta } = info;
248```
249
250Several of the formats in `logform` itself add additional properties:
251
252| Property | Format added by | Description |
253| ----------- | --------------- | ----------- |
254| `splat` | `splat()` | String interpolation splat for `%d %s`-style messages. |
255| `timestamp` | `timestamp()` | timestamp the message was received. |
256| `label` | `label()` | Custom label associated with each message. |
257| `ms` | `ms()` | Number of milliseconds since the previous log message. |
258
259As a consumer you may add whatever properties you wish – _internal state is
260maintained by `Symbol` properties:_
261
262- `Symbol.for('level')` _**(READ-ONLY)**:_ equal to `level` property.
263 **Is treated as immutable by all code.**
264- `Symbol.for('message'):` complete string message set by "finalizing formats":
265 - `json`
266 - `logstash`
267 - `printf`
268 - `prettyPrint`
269 - `simple`
270- `Symbol.for('splat')`: additional string interpolation arguments. _Used
271 exclusively by `splat()` format._
272
273These Symbols are stored in another package: `triple-beam` so that all
274consumers of `logform` can have the same Symbol reference. i.e.:
275
276``` js
277const { LEVEL, MESSAGE, SPLAT } = require('triple-beam');
278
279console.log(LEVEL === Symbol.for('level'));
280// true
281
282console.log(MESSAGE === Symbol.for('message'));
283// true
284
285console.log(SPLAT === Symbol.for('splat'));
286// true
287```
288
289> **NOTE:** any `{ message }` property in a `meta` object provided will
290> automatically be concatenated to any `msg` already provided: For
291> example the below will concatenate 'world' onto 'hello':
292>
293> ``` js
294> logger.log('error', 'hello', { message: 'world' });
295> logger.info('hello', { message: 'world' });
296> ```
297
298## Formats
299
300Formats in `winston` can be accessed from `winston.format`. They are
301implemented in [`logform`](https://github.com/winstonjs/logform), a separate
302module from `winston`. This allows flexibility when writing your own transports
303in case you wish to include a default format with your transport.
304
305In modern versions of `node` template strings are very performant and are the
306recommended way for doing most end-user formatting. If you want to bespoke
307format your logs, `winston.format.printf` is for you:
308
309``` js
310const { createLogger, format, transports } = require('winston');
311const { combine, timestamp, label, printf } = format;
312
313const myFormat = printf(({ level, message, label, timestamp }) => {
314 return `${timestamp} [${label}] ${level}: ${message}`;
315});
316
317const logger = createLogger({
318 format: combine(
319 label({ label: 'right meow!' }),
320 timestamp(),
321 myFormat
322 ),
323 transports: [new transports.Console()]
324});
325```
326
327To see what built-in formats are available and learn more about creating your
328own custom logging formats, see [`logform`][logform].
329
330### Combining formats
331
332Any number of formats may be combined into a single format using
333`format.combine`. Since `format.combine` takes no `opts`, as a convenience it
334returns pre-created instance of the combined format.
335
336``` js
337const { createLogger, format, transports } = require('winston');
338const { combine, timestamp, label, prettyPrint } = format;
339
340const logger = createLogger({
341 format: combine(
342 label({ label: 'right meow!' }),
343 timestamp(),
344 prettyPrint()
345 ),
346 transports: [new transports.Console()]
347})
348
349logger.log({
350 level: 'info',
351 message: 'What time is the testing at?'
352});
353// Outputs:
354// { level: 'info',
355// message: 'What time is the testing at?',
356// label: 'right meow!',
357// timestamp: '2017-09-30T03:57:26.875Z' }
358```
359
360### String interpolation
361
362The `log` method provides the string interpolation using [util.format]. **It
363must be enabled using `format.splat()`.**
364
365Below is an example that defines a format with string interpolation of
366messages using `format.splat` and then serializes the entire `info` message
367using `format.simple`.
368
369``` js
370const { createLogger, format, transports } = require('winston');
371const logger = createLogger({
372 format: format.combine(
373 format.splat(),
374 format.simple()
375 ),
376 transports: [new transports.Console()]
377});
378
379// info: test message my string {}
380logger.log('info', 'test message %s', 'my string');
381
382// info: test message 123 {}
383logger.log('info', 'test message %d', 123);
384
385// info: test message first second {number: 123}
386logger.log('info', 'test message %s, %s', 'first', 'second', { number: 123 });
387```
388
389### Filtering `info` Objects
390
391If you wish to filter out a given `info` Object completely when logging then
392simply return a falsey value.
393
394``` js
395const { createLogger, format, transports } = require('winston');
396
397// Ignore log messages if they have { private: true }
398const ignorePrivate = format((info, opts) => {
399 if (info.private) { return false; }
400 return info;
401});
402
403const logger = createLogger({
404 format: format.combine(
405 ignorePrivate(),
406 format.json()
407 ),
408 transports: [new transports.Console()]
409});
410
411// Outputs: {"level":"error","message":"Public error to share"}
412logger.log({
413 level: 'error',
414 message: 'Public error to share'
415});
416
417// Messages with { private: true } will not be written when logged.
418logger.log({
419 private: true,
420 level: 'error',
421 message: 'This is super secret - hide it.'
422});
423```
424
425Use of `format.combine` will respect any falsey values return and stop
426evaluation of later formats in the series. For example:
427
428``` js
429const { format } = require('winston');
430const { combine, timestamp, label } = format;
431
432const willNeverThrow = format.combine(
433 format(info => { return false })(), // Ignores everything
434 format(info => { throw new Error('Never reached') })()
435);
436```
437
438### Creating custom formats
439
440Formats are prototypal objects (i.e. class instances) that define a single
441method: `transform(info, opts)` and return the mutated `info`:
442
443- `info`: an object representing the log message.
444- `opts`: setting specific to the current instance of the format.
445
446They are expected to return one of two things:
447
448- **An `info` Object** representing the modified `info` argument. Object
449references need not be preserved if immutability is preferred. All current
450built-in formats consider `info` mutable, but [immutablejs] is being
451considered for future releases.
452- **A falsey value** indicating that the `info` argument should be ignored by the
453caller. (See: [Filtering `info` Objects](#filtering-info-objects)) below.
454
455`winston.format` is designed to be as simple as possible. To define a new
456format simple pass it a `transform(info, opts)` function to get a new
457`Format`.
458
459The named `Format` returned can be used to create as many copies of the given
460`Format` as desired:
461
462``` js
463const { format } = require('winston');
464
465const volume = format((info, opts) => {
466 if (opts.yell) {
467 info.message = info.message.toUpperCase();
468 } else if (opts.whisper) {
469 info.message = info.message.toLowerCase();
470 }
471
472 return info;
473});
474
475// `volume` is now a function that returns instances of the format.
476const scream = volume({ yell: true });
477console.dir(scream.transform({
478 level: 'info',
479 message: `sorry for making you YELL in your head!`
480}, scream.options));
481// {
482// level: 'info'
483// message: 'SORRY FOR MAKING YOU YELL IN YOUR HEAD!'
484// }
485
486// `volume` can be used multiple times to create different formats.
487const whisper = volume({ whisper: true });
488console.dir(whisper.transform({
489 level: 'info',
490 message: `WHY ARE THEY MAKING US YELL SO MUCH!`
491}, whisper.options));
492// {
493// level: 'info'
494// message: 'why are they making us yell so much!'
495// }
496```
497
498## Logging Levels
499
500Logging levels in `winston` conform to the severity ordering specified by
501[RFC5424]: _severity of all levels is assumed to be numerically **ascending**
502from most important to least important._
503
504Each `level` is given a specific integer priority. The higher the priority the
505more important the message is considered to be, and the lower the
506corresponding integer priority. For example, as specified exactly in RFC5424
507the `syslog` levels are prioritized from 0 to 7 (highest to lowest).
508
509```js
510{
511 emerg: 0,
512 alert: 1,
513 crit: 2,
514 error: 3,
515 warning: 4,
516 notice: 5,
517 info: 6,
518 debug: 7
519}
520```
521
522Similarly, `npm` logging levels are prioritized from 0 to 6 (highest to
523lowest):
524
525``` js
526{
527 error: 0,
528 warn: 1,
529 info: 2,
530 http: 3,
531 verbose: 4,
532 debug: 5,
533 silly: 6
534}
535```
536
537If you do not explicitly define the levels that `winston` should use, the
538`npm` levels above will be used.
539
540### Using Logging Levels
541
542Setting the level for your logging message can be accomplished in one of two
543ways. You can pass a string representing the logging level to the log() method
544or use the level specified methods defined on every winston Logger.
545
546``` js
547//
548// Any logger instance
549//
550logger.log('silly', "127.0.0.1 - there's no place like home");
551logger.log('debug', "127.0.0.1 - there's no place like home");
552logger.log('verbose', "127.0.0.1 - there's no place like home");
553logger.log('info', "127.0.0.1 - there's no place like home");
554logger.log('warn', "127.0.0.1 - there's no place like home");
555logger.log('error', "127.0.0.1 - there's no place like home");
556logger.info("127.0.0.1 - there's no place like home");
557logger.warn("127.0.0.1 - there's no place like home");
558logger.error("127.0.0.1 - there's no place like home");
559
560//
561// Default logger
562//
563winston.log('info', "127.0.0.1 - there's no place like home");
564winston.info("127.0.0.1 - there's no place like home");
565```
566
567`winston` allows you to define a `level` property on each transport which
568specifies the **maximum** level of messages that a transport should log. For
569example, using the `syslog` levels you could log only `error` messages to the
570console and everything `info` and below to a file (which includes `error`
571messages):
572
573``` js
574const logger = winston.createLogger({
575 levels: winston.config.syslog.levels,
576 transports: [
577 new winston.transports.Console({ level: 'error' }),
578 new winston.transports.File({
579 filename: 'combined.log',
580 level: 'info'
581 })
582 ]
583});
584```
585
586You may also dynamically change the log level of a transport:
587
588``` js
589const transports = {
590 console: new winston.transports.Console({ level: 'warn' }),
591 file: new winston.transports.File({ filename: 'combined.log', level: 'error' })
592};
593
594const logger = winston.createLogger({
595 transports: [
596 transports.console,
597 transports.file
598 ]
599});
600
601logger.info('Will not be logged in either transport!');
602transports.console.level = 'info';
603transports.file.level = 'info';
604logger.info('Will be logged in both transports!');
605```
606
607`winston` supports customizable logging levels, defaulting to npm style
608logging levels. Levels must be specified at the time of creating your logger.
609
610### Using Custom Logging Levels
611
612In addition to the predefined `npm`, `syslog`, and `cli` levels available in
613`winston`, you can also choose to define your own:
614
615``` js
616const myCustomLevels = {
617 levels: {
618 foo: 0,
619 bar: 1,
620 baz: 2,
621 foobar: 3
622 },
623 colors: {
624 foo: 'blue',
625 bar: 'green',
626 baz: 'yellow',
627 foobar: 'red'
628 }
629};
630
631const customLevelLogger = winston.createLogger({
632 levels: myCustomLevels.levels
633});
634
635customLevelLogger.foobar('some foobar level-ed message');
636```
637
638Although there is slight repetition in this data structure, it enables simple
639encapsulation if you do not want to have colors. If you do wish to have
640colors, in addition to passing the levels to the Logger itself, you must make
641winston aware of them:
642
643``` js
644winston.addColors(myCustomLevels.colors);
645```
646
647This enables loggers using the `colorize` formatter to appropriately color and style
648the output of custom levels.
649
650Additionally, you can also change background color and font style.
651For example,
652``` js
653baz: 'italic yellow',
654foobar: 'bold red cyanBG'
655```
656
657Possible options are below.
658
659* Font styles: `bold`, `dim`, `italic`, `underline`, `inverse`, `hidden`,
660 `strikethrough`.
661
662* Font foreground colors: `black`, `red`, `green`, `yellow`, `blue`, `magenta`,
663 `cyan`, `white`, `gray`, `grey`.
664
665* Background colors: `blackBG`, `redBG`, `greenBG`, `yellowBG`, `blueBG`
666 `magentaBG`, `cyanBG`, `whiteBG`
667
668### Colorizing Standard logging levels
669
670To colorize the standard logging level add
671```js
672winston.format.combine(
673 winston.format.colorize(),
674 winston.format.json()
675);
676```
677where `winston.format.json()` is whatever other formatter you want to use. The `colorize` formatter must come before any formatters adding text you wish to color.
678
679## Transports
680
681There are several [core transports] included in `winston`, which leverage the
682built-in networking and file I/O offered by Node.js core. In addition, there
683are [additional transports] written by members of the community.
684
685## Multiple transports of the same type
686
687It is possible to use multiple transports of the same type e.g.
688`winston.transports.File` when you construct the transport.
689
690``` js
691const logger = winston.createLogger({
692 transports: [
693 new winston.transports.File({
694 filename: 'combined.log',
695 level: 'info'
696 }),
697 new winston.transports.File({
698 filename: 'errors.log',
699 level: 'error'
700 })
701 ]
702});
703```
704
705If you later want to remove one of these transports you can do so by using the
706transport itself. e.g.:
707
708``` js
709const combinedLogs = logger.transports.find(transport => {
710 return transport.filename === 'combined.log'
711});
712
713logger.remove(combinedLogs);
714```
715
716## Adding Custom Transports
717
718Adding a custom transport is easy. All you need to do is accept any options
719you need, implement a log() method, and consume it with `winston`.
720
721``` js
722const Transport = require('winston-transport');
723const util = require('util');
724
725//
726// Inherit from `winston-transport` so you can take advantage
727// of the base functionality and `.exceptions.handle()`.
728//
729module.exports = class YourCustomTransport extends Transport {
730 constructor(opts) {
731 super(opts);
732 //
733 // Consume any custom options here. e.g.:
734 // - Connection information for databases
735 // - Authentication information for APIs (e.g. loggly, papertrail,
736 // logentries, etc.).
737 //
738 }
739
740 log(info, callback) {
741 setImmediate(() => {
742 this.emit('logged', info);
743 });
744
745 // Perform the writing to the remote service
746 callback();
747 }
748};
749```
750
751## Common Transport options
752
753As every transport inherits from [winston-transport], it's possible to set
754a custom format and a custom log level on each transport separately:
755
756``` js
757const logger = winston.createLogger({
758 transports: [
759 new winston.transports.File({
760 filename: 'error.log',
761 level: 'error',
762 format: winston.format.json()
763 }),
764 new transports.Http({
765 level: 'warn',
766 format: winston.format.json()
767 }),
768 new transports.Console({
769 level: 'info',
770 format: winston.format.combine(
771 winston.format.colorize(),
772 winston.format.simple()
773 )
774 })
775 ]
776});
777```
778
779## Exceptions
780
781### Handling Uncaught Exceptions with winston
782
783With `winston`, it is possible to catch and log `uncaughtException` events
784from your process. With your own logger instance you can enable this behavior
785when it's created or later on in your applications lifecycle:
786
787``` js
788const { createLogger, transports } = require('winston');
789
790// Enable exception handling when you create your logger.
791const logger = createLogger({
792 transports: [
793 new transports.File({ filename: 'combined.log' })
794 ],
795 exceptionHandlers: [
796 new transports.File({ filename: 'exceptions.log' })
797 ]
798});
799
800// Or enable it later on by adding a transport or using `.exceptions.handle`
801const logger = createLogger({
802 transports: [
803 new transports.File({ filename: 'combined.log' })
804 ]
805});
806
807// Call exceptions.handle with a transport to handle exceptions
808logger.exceptions.handle(
809 new transports.File({ filename: 'exceptions.log' })
810);
811```
812
813If you want to use this feature with the default logger, simply call
814`.exceptions.handle()` with a transport instance.
815
816``` js
817//
818// You can add a separate exception logger by passing it to `.exceptions.handle`
819//
820winston.exceptions.handle(
821 new winston.transports.File({ filename: 'path/to/exceptions.log' })
822);
823
824//
825// Alternatively you can set `handleExceptions` to true when adding transports
826// to winston.
827//
828winston.add(new winston.transports.File({
829 filename: 'path/to/combined.log',
830 handleExceptions: true
831}));
832```
833
834### To Exit or Not to Exit
835
836By default, winston will exit after logging an uncaughtException. If this is
837not the behavior you want, set `exitOnError = false`
838
839``` js
840const logger = winston.createLogger({ exitOnError: false });
841
842//
843// or, like this:
844//
845logger.exitOnError = false;
846```
847
848When working with custom logger instances, you can pass in separate transports
849to the `exceptionHandlers` property or set `handleExceptions` on any
850transport.
851
852##### Example 1
853
854``` js
855const logger = winston.createLogger({
856 transports: [
857 new winston.transports.File({ filename: 'path/to/combined.log' })
858 ],
859 exceptionHandlers: [
860 new winston.transports.File({ filename: 'path/to/exceptions.log' })
861 ]
862});
863```
864
865##### Example 2
866
867``` js
868const logger = winston.createLogger({
869 transports: [
870 new winston.transports.Console({
871 handleExceptions: true
872 })
873 ],
874 exitOnError: false
875});
876```
877
878The `exitOnError` option can also be a function to prevent exit on only
879certain types of errors:
880
881``` js
882function ignoreEpipe(err) {
883 return err.code !== 'EPIPE';
884}
885
886const logger = winston.createLogger({ exitOnError: ignoreEpipe });
887
888//
889// or, like this:
890//
891logger.exitOnError = ignoreEpipe;
892```
893
894## Rejections
895
896### Handling Uncaught Promise Rejections with winston
897
898With `winston`, it is possible to catch and log `uncaughtRejection` events
899from your process. With your own logger instance you can enable this behavior
900when it's created or later on in your applications lifecycle:
901
902``` js
903const { createLogger, transports } = require('winston');
904
905// Enable rejection handling when you create your logger.
906const logger = createLogger({
907 transports: [
908 new transports.File({ filename: 'combined.log' })
909 ],
910 rejectionHandlers: [
911 new transports.File({ filename: 'rejections.log' })
912 ]
913});
914
915// Or enable it later on by adding a transport or using `.rejections.handle`
916const logger = createLogger({
917 transports: [
918 new transports.File({ filename: 'combined.log' })
919 ]
920});
921
922// Call rejections.handle with a transport to handle rejections
923logger.rejections.handle(
924 new transports.File({ filename: 'rejections.log' })
925);
926```
927
928If you want to use this feature with the default logger, simply call
929`.rejections.handle()` with a transport instance.
930
931``` js
932//
933// You can add a separate rejection logger by passing it to `.rejections.handle`
934//
935winston.rejections.handle(
936 new winston.transports.File({ filename: 'path/to/rejections.log' })
937);
938
939//
940// Alternatively you can set `handleRejections` to true when adding transports
941// to winston.
942//
943winston.add(new winston.transports.File({
944 filename: 'path/to/combined.log',
945 handleRejections: true
946}));
947```
948
949## Profiling
950
951In addition to logging messages and metadata, `winston` also has a simple
952profiling mechanism implemented for any logger:
953
954``` js
955//
956// Start profile of 'test'
957//
958logger.profile('test');
959
960setTimeout(function () {
961 //
962 // Stop profile of 'test'. Logging will now take place:
963 // '17 Jan 21:00:00 - info: test duration=1000ms'
964 //
965 logger.profile('test');
966}, 1000);
967```
968
969Also you can start a timer and keep a reference that you can call `.done()``
970on:
971
972``` js
973 // Returns an object corresponding to a specific timing. When done
974 // is called the timer will finish and log the duration. e.g.:
975 //
976 const profiler = logger.startTimer();
977 setTimeout(function () {
978 profiler.done({ message: 'Logging message' });
979 }, 1000);
980```
981
982All profile messages are set to 'info' level by default, and both message and
983metadata are optional. For individual profile messages, you can override the default log level by supplying a metadata object with a `level` property:
984
985```js
986logger.profile('test', { level: 'debug' });
987```
988
989## Querying Logs
990
991`winston` supports querying of logs with Loggly-like options. [See Loggly
992Search API](https://www.loggly.com/docs/api-retrieving-data/). Specifically:
993`File`, `Couchdb`, `Redis`, `Loggly`, `Nssocket`, and `Http`.
994
995``` js
996const options = {
997 from: new Date() - (24 * 60 * 60 * 1000),
998 until: new Date(),
999 limit: 10,
1000 start: 0,
1001 order: 'desc',
1002 fields: ['message']
1003};
1004
1005//
1006// Find items logged between today and yesterday.
1007//
1008logger.query(options, function (err, results) {
1009 if (err) {
1010 /* TODO: handle me */
1011 throw err;
1012 }
1013
1014 console.log(results);
1015});
1016```
1017
1018## Streaming Logs
1019Streaming allows you to stream your logs back from your chosen transport.
1020
1021``` js
1022//
1023// Start at the end.
1024//
1025winston.stream({ start: -1 }).on('log', function(log) {
1026 console.log(log);
1027});
1028```
1029
1030## Further Reading
1031
1032### Using the Default Logger
1033
1034The default logger is accessible through the `winston` module directly. Any
1035method that you could call on an instance of a logger is available on the
1036default logger:
1037
1038``` js
1039const winston = require('winston');
1040
1041winston.log('info', 'Hello distributed log files!');
1042winston.info('Hello again distributed logs');
1043
1044winston.level = 'debug';
1045winston.log('debug', 'Now my debug messages are written to console!');
1046```
1047
1048By default, no transports are set on the default logger. You must
1049add or remove transports via the `add()` and `remove()` methods:
1050
1051``` js
1052const files = new winston.transports.File({ filename: 'combined.log' });
1053const console = new winston.transports.Console();
1054
1055winston.add(console);
1056winston.add(files);
1057winston.remove(console);
1058```
1059
1060Or do it with one call to configure():
1061
1062``` js
1063winston.configure({
1064 transports: [
1065 new winston.transports.File({ filename: 'somefile.log' })
1066 ]
1067});
1068```
1069
1070For more documentation about working with each individual transport supported
1071by `winston` see the [`winston` Transports](docs/transports.md) document.
1072
1073### Awaiting logs to be written in `winston`
1074
1075Often it is useful to wait for your logs to be written before exiting the
1076process. Each instance of `winston.Logger` is also a [Node.js stream]. A
1077`finish` event will be raised when all logs have flushed to all transports
1078after the stream has been ended.
1079
1080``` js
1081const transport = new winston.transports.Console();
1082const logger = winston.createLogger({
1083 transports: [transport]
1084});
1085
1086logger.on('finish', function (info) {
1087 // All `info` log messages has now been logged
1088});
1089
1090logger.info('CHILL WINSTON!', { seriously: true });
1091logger.end();
1092```
1093
1094It is also worth mentioning that the logger also emits an 'error' event which
1095you should handle or suppress if you don't want unhandled exceptions:
1096
1097``` js
1098//
1099// Handle errors
1100//
1101logger.on('error', function (err) { /* Do Something */ });
1102```
1103
1104### Working with multiple Loggers in winston
1105
1106Often in larger, more complex, applications it is necessary to have multiple
1107logger instances with different settings. Each logger is responsible for a
1108different feature area (or category). This is exposed in `winston` in two
1109ways: through `winston.loggers` and instances of `winston.Container`. In fact,
1110`winston.loggers` is just a predefined instance of `winston.Container`:
1111
1112``` js
1113const winston = require('winston');
1114const { format } = winston;
1115const { combine, label, json } = format;
1116
1117//
1118// Configure the logger for `category1`
1119//
1120winston.loggers.add('category1', {
1121 format: combine(
1122 label({ label: 'category one' }),
1123 json()
1124 ),
1125 transports: [
1126 new winston.transports.Console({ level: 'silly' }),
1127 new winston.transports.File({ filename: 'somefile.log' })
1128 ]
1129});
1130
1131//
1132// Configure the logger for `category2`
1133//
1134winston.loggers.add('category2', {
1135 format: combine(
1136 label({ label: 'category two' }),
1137 json()
1138 ),
1139 transports: [
1140 new winston.transports.Http({ host: 'localhost', port:8080 })
1141 ]
1142});
1143```
1144
1145Now that your loggers are setup, you can require winston _in any file in your
1146application_ and access these pre-configured loggers:
1147
1148``` js
1149const winston = require('winston');
1150
1151//
1152// Grab your preconfigured loggers
1153//
1154const category1 = winston.loggers.get('category1');
1155const category2 = winston.loggers.get('category2');
1156
1157category1.info('logging to file and console transports');
1158category2.info('logging to http transport');
1159```
1160
1161If you prefer to manage the `Container` yourself, you can simply instantiate one:
1162
1163``` js
1164const winston = require('winston');
1165const { format } = winston;
1166const { combine, label, json } = format;
1167
1168const container = new winston.Container();
1169
1170container.add('category1', {
1171 format: combine(
1172 label({ label: 'category one' }),
1173 json()
1174 ),
1175 transports: [
1176 new winston.transports.Console({ level: 'silly' }),
1177 new winston.transports.File({ filename: 'somefile.log' })
1178 ]
1179});
1180
1181const category1 = container.get('category1');
1182category1.info('logging to file and console transports');
1183```
1184
1185## Installation
1186
1187``` bash
1188npm install winston
1189```
1190
1191``` bash
1192yarn add winston
1193```
1194
1195## Run Tests
1196
1197All of the winston tests are written with [`mocha`][mocha], [`nyc`][nyc], and
1198[`assume`][assume]. They can be run with `npm`.
1199
1200``` bash
1201npm test
1202```
1203
1204#### Author: [Charlie Robbins]
1205#### Contributors: [Jarrett Cruger], [David Hyde], [Chris Alderson]
1206
1207[Transports]: #transports
1208[Logging levels]: #logging-levels
1209[Formats]: #formats
1210[Using custom logging levels]: #using-custom-logging-levels
1211[Adding Custom Transports]: #adding-custom-transports
1212[core transports]: docs/transports.md#winston-core
1213[additional transports]: docs/transports.md#additional-transports
1214
1215[RFC5424]: https://tools.ietf.org/html/rfc5424
1216[util.format]: https://nodejs.org/dist/latest/docs/api/util.html#util_util_format_format_args
1217[mocha]: https://mochajs.org
1218[nyc]: https://github.com/istanbuljs/nyc
1219[assume]: https://github.com/bigpipe/assume
1220[logform]: https://github.com/winstonjs/logform#readme
1221[winston-transport]: https://github.com/winstonjs/winston-transport
1222
1223[Read the `winston@2.x` documentation]: https://github.com/winstonjs/winston/tree/2.x
1224
1225[quick-example]: https://github.com/winstonjs/winston/blob/master/examples/quick-start.js
1226[examples]: https://github.com/winstonjs/winston/tree/master/examples
1227
1228[Charlie Robbins]: http://github.com/indexzero
1229[Jarrett Cruger]: https://github.com/jcrugzz
1230[David Hyde]: https://github.com/dabh
1231[Chris Alderson]: https://github.com/chrisalderson