1# winston
2
3[![Join the chat at https://gitter.im/winstonjs/winston](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/winstonjs/winston?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4
5[![Version npm](https://img.shields.io/npm/v/winston.svg?style=flat-square)](https://www.npmjs.com/package/winston)[![npm Downloads](https://img.shields.io/npm/dm/winston.svg?style=flat-square)](https://www.npmjs.com/package/winston)[![Build Status](https://img.shields.io/travis/winstonjs/winston/master.svg?style=flat-square)](https://travis-ci.org/winstonjs/winston)[![Dependencies](https://img.shields.io/david/winstonjs/winston.svg?style=flat-square)](https://david-dm.org/winstonjs/winston)
6
7[![NPM](https://nodei.co/npm/winston.png?downloads=true&downloadRank=true)](https://nodei.co/npm/winston/)
8
9A multi-transport async logging library for node.js. <span style="font-size:28px; font-weight:bold;">&quot;CHILL WINSTON! ... I put it in the logs.&quot;</span>
10
11## Motivation
12Winston 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 instance of a winston logger can have multiple transports configured at different 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.
13
14There also seemed to be a lot of logging libraries out there that coupled their implementation of logging (i.e. how the logs are stored / indexed) to the API that they exposed to the programmer. This library aims to decouple those parts of the process to make it more flexible and extensible.
15
16## Installation
17
18```bashp
19npm install winston
20```
21
22## Usage
23There are two different ways to use winston: directly via the default logger, or by instantiating your own Logger. The former is merely intended to be a convenient shared logger to use throughout your application if you so choose.
24
25* [Logging](#logging)
26  * [Using the Default Logger](#using-the-default-logger)
27  * [Instantiating your own Logger](#instantiating-your-own-logger)
28  * [Logging with Metadata](#logging-with-metadata)
29  * [String interpolation](#string-interpolation)
30* [Transports](https://github.com/winstonjs/winston/blob/2.4.0/docs/transports.md)
31  * [Multiple transports of the same type](#multiple-transports-of-the-same-type)
32* [Profiling](#profiling)
33* [Streaming Logs](#streaming-logs)
34* [Querying Logs](#querying-logs)
35* [Exceptions](#exceptions)
36  * [Handling Uncaught Exceptions with winston](#handling-uncaught-exceptions-with-winston)
37  * [To Exit or Not to Exit](#to-exit-or-not-to-exit)
38* [Logging Levels](#logging-levels)
39  * [Using Logging Levels](#using-logging-levels)
40  * [Using Custom Logging Levels](#using-custom-logging-levels)
41* [Further Reading](#further-reading)
42  * [Events and Callbacks in Winston](#events-and-callbacks-in-winston)
43  * [Working with multiple Loggers in winston](#working-with-multiple-loggers-in-winston)
44  * [Using winston in a CLI tool](#using-winston-in-a-cli-tool)
45  * [Filters and Rewriters](#filters-and-rewriters)
46  * [Adding Custom Transports](#adding-custom-transports)
47* [Installation](#installation)
48* [Run Tests](#run-tests)
49
50
51## Logging
52
53Logging levels in `winston` conform to the severity ordering specified by [RFC5424](https://tools.ietf.org/html/rfc5424): _severity of all levels is assumed to be numerically **ascending** from most important to least important._
54
55### Using the Default Logger
56The 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:
57
58``` js
59  var winston = require('winston');
60
61  winston.log('info', 'Hello distributed log files!');
62  winston.info('Hello again distributed logs');
63
64  winston.level = 'debug';
65  winston.log('debug', 'Now my debug messages are written to console!');
66```
67
68By default, only the Console transport is set on the default logger. You can add or remove transports via the add() and remove() methods:
69
70``` js
71  winston.add(winston.transports.File, { filename: 'somefile.log' });
72  winston.remove(winston.transports.Console);
73```
74
75Or do it with one call to configure():
76
77``` js
78  winston.configure({
79    transports: [
80      new (winston.transports.File)({ filename: 'somefile.log' })
81    ]
82  });
83```
84
85For more documentation about working with each individual transport supported by Winston see the [Winston Transports](docs/transports.md) document.
86
87### Instantiating your own Logger
88If you would prefer to manage the object lifetime of loggers you are free to instantiate them yourself:
89
90``` js
91  var logger = new (winston.Logger)({
92    transports: [
93      new (winston.transports.Console)(),
94      new (winston.transports.File)({ filename: 'somefile.log' })
95    ]
96  });
97```
98
99You can work with this logger in the same way that you work with the default logger:
100
101``` js
102  //
103  // Logging
104  //
105  logger.log('info', 'Hello distributed log files!');
106  logger.info('Hello again distributed logs');
107
108  //
109  // Adding / Removing Transports
110  //   (Yes It's chainable)
111  //
112  logger
113    .add(winston.transports.File)
114    .remove(winston.transports.Console);
115```
116
117You can also wholesale reconfigure a `winston.Logger` instance using the `configure` method:
118
119``` js
120  var logger = new winston.Logger({
121    level: 'info',
122    transports: [
123      new (winston.transports.Console)(),
124      new (winston.transports.File)({ filename: 'somefile.log' })
125    ]
126  });
127
128  //
129  // Replaces the previous transports with those in the
130  // new configuration wholesale.
131  //
132  logger.configure({
133    level: 'verbose',
134    transports: [
135      new (require('winston-daily-rotate-file'))(opts)
136    ]
137  });
138```
139
140
141### Logging with Metadata
142In addition to logging string messages, winston will also optionally log additional JSON metadata objects. Adding metadata is simple:
143
144``` js
145  winston.log('info', 'Test Log Message', { anything: 'This is metadata' });
146```
147
148The way these objects are stored varies from transport to transport (to best support the storage mechanisms offered). Here's a quick summary of how each transports handles metadata:
149
1501. __Console:__ Logged via util.inspect(meta)
1512. __File:__ Logged via util.inspect(meta)
152
153## Multiple transports of the same type
154
155It is possible to use multiple transports of the same type e.g. `winston.transports.File` by passing in a custom `name` when you construct the transport.
156
157``` js
158var logger = new (winston.Logger)({
159  transports: [
160    new (winston.transports.File)({
161      name: 'info-file',
162      filename: 'filelog-info.log',
163      level: 'info'
164    }),
165    new (winston.transports.File)({
166      name: 'error-file',
167      filename: 'filelog-error.log',
168      level: 'error'
169    })
170  ]
171});
172```
173
174If you later want to remove one of these transports you can do so by using the string name. e.g.:
175
176``` js
177logger.remove('info-file');
178```
179
180In this example, one could also remove by passing in the instance of the Transport itself. e.g. this is equivalent to the string example above:
181
182``` js
183// Notice it was first in the Array above
184var infoFile = logger.transports[0];
185logger.remove(infoFile);
186```
187
188## Profiling
189In addition to logging messages and metadata, winston also has a simple profiling mechanism implemented for any logger:
190
191``` js
192  //
193  // Start profile of 'test'
194  // Remark: Consider using Date.now() or winston.startTimer() with async operations
195  //
196  winston.profile('test');
197
198  setTimeout(function () {
199    //
200    // Stop profile of 'test'. Logging will now take place:
201    //   "17 Jan 21:00:00 - info: test duration=1000ms"
202    //
203    winston.profile('test');
204  }, 1000);
205```
206
207Also you can start a timer and keep a reference that you can call .done() on
208``` js
209   // Returns an object corresponding to a specific timing. When done
210   // is called the timer will finish and log the duration. e.g.:
211   //
212   var timer = winston.startTimer()
213   setTimeout(function(){
214     timer.done("Logging message");
215   }, 1000);
216```
217
218All profile messages are set to 'info' level by default and both message and metadata are optional. There are no plans in the Roadmap to make this configurable, but I'm open to suggestions / issues.
219
220### String interpolation
221The `log` method provides the same string interpolation methods like [`util.format`][10].
222
223This allows for the following log messages.
224``` js
225logger.log('info', 'test message %s', 'my string');
226// info: test message my string
227
228logger.log('info', 'test message %d', 123);
229// info: test message 123
230
231logger.log('info', 'test message %j', {number: 123}, {});
232// info: test message {"number":123}
233// meta = {}
234
235logger.log('info', 'test message %s, %s', 'first', 'second', {number: 123});
236// info: test message first, second
237// meta = {number: 123}
238
239logger.log('info', 'test message', 'first', 'second', {number: 123});
240// info: test message first second
241// meta = {number: 123}
242
243logger.log('info', 'test message %s, %s', 'first', 'second', {number: 123}, function(){});
244// info: test message first, second
245// meta = {number: 123}
246// callback = function(){}
247
248logger.log('info', 'test message', 'first', 'second', {number: 123}, function(){});
249// info: test message first second
250// meta = {number: 123}
251// callback = function(){}
252```
253
254
255
256
257
258## Querying Logs
259Winston supports querying of logs with Loggly-like options. [See Loggly Search API](https://www.loggly.com/docs/api-retrieving-data/).
260Specifically: `File`, `Couchdb`, `Redis`, `Loggly`, `Nssocket`, and `Http`.
261
262``` js
263  var options = {
264    from: new Date - 24 * 60 * 60 * 1000,
265    until: new Date,
266    limit: 10,
267    start: 0,
268    order: 'desc',
269    fields: ['message']
270  };
271
272  //
273  // Find items logged between today and yesterday.
274  //
275  winston.query(options, function (err, results) {
276    if (err) {
277      throw err;
278    }
279
280    console.log(results);
281  });
282```
283
284## Streaming Logs
285Streaming allows you to stream your logs back from your chosen transport.
286
287``` js
288  //
289  // Start at the end.
290  //
291  winston.stream({ start: -1 }).on('log', function(log) {
292    console.log(log);
293  });
294```
295
296## Exceptions
297
298### Handling Uncaught Exceptions with winston
299
300With `winston`, it is possible to catch and log `uncaughtException` events from your process. There are two distinct ways of enabling this functionality either through the default winston logger or your own logger instance.
301
302If you want to use this feature with the default logger, simply call `.handleExceptions()` with a transport instance.
303
304``` js
305  //
306  // You can add a separate exception logger by passing it to `.handleExceptions`
307  //
308  winston.handleExceptions(new winston.transports.File({ filename: 'path/to/exceptions.log' }));
309
310  //
311  // Alternatively you can set `.handleExceptions` to true when adding transports to winston.
312  // You can use the `.humanReadableUnhandledException` option to get more readable exceptions.
313  //
314  winston.add(winston.transports.File, {
315    filename: 'path/to/all-logs.log',
316    handleExceptions: true,
317    humanReadableUnhandledException: true
318  });
319
320  //
321  // Exceptions can also be handled by multiple transports.
322  //
323  winston.handleExceptions([ transport1, transport2, ... ]);
324```
325
326### To Exit or Not to Exit
327
328By default, winston will exit after logging an uncaughtException. If this is not the behavior you want,
329set `exitOnError = false`
330
331``` js
332  var logger = new (winston.Logger)({ exitOnError: false });
333
334  //
335  // or, like this:
336  //
337  logger.exitOnError = false;
338```
339
340When working with custom logger instances, you can pass in separate transports to the `exceptionHandlers` property or set `.handleExceptions` on any transport.
341
342Example 1
343
344``` js
345  var logger = new (winston.Logger)({
346    transports: [
347      new winston.transports.File({ filename: 'path/to/all-logs.log' })
348    ],
349    exceptionHandlers: [
350      new winston.transports.File({ filename: 'path/to/exceptions.log' })
351    ]
352  });
353```
354
355Example 2
356
357``` js
358var logger = new winston.Logger({
359  transports: [
360    new winston.transports.Console({
361      handleExceptions: true,
362      json: true
363    })
364  ],
365  exitOnError: false
366});
367```
368
369The `exitOnError` option can also be a function to prevent exit on only certain types of errors:
370
371``` js
372  function ignoreEpipe(err) {
373    return err.code !== 'EPIPE';
374  }
375
376  var logger = new (winston.Logger)({ exitOnError: ignoreEpipe });
377
378  //
379  // or, like this:
380  //
381  logger.exitOnError = ignoreEpipe;
382```
383
384## Logging Levels
385
386Each `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. Severity of all levels is assumed to be numerically **ascending** from most important to least important. For example, `npm` logging levels are prioritized from 0 to 5 (highest to lowest):
387
388``` js
389{ error: 0, warn: 1, info: 2, verbose: 3, debug: 4, silly: 5 }
390```
391
392Similarly, as specified exactly in RFC5424 the `syslog` levels are prioritized from 0 to 7 (highest to lowest).
393
394```js
395{ emerg: 0, alert: 1, crit: 2, error: 3, warning: 4, notice: 5, info: 6, debug: 7 }
396```
397
398If you do not explicitly define the levels that `winston` should use the `npm` levels above will be used.
399
400### Using Logging Levels
401Setting 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.
402
403``` js
404  //
405  // Any logger instance
406  //
407  logger.log('silly', "127.0.0.1 - there's no place like home");
408  logger.log('debug', "127.0.0.1 - there's no place like home");
409  logger.log('verbose', "127.0.0.1 - there's no place like home");
410  logger.log('info', "127.0.0.1 - there's no place like home");
411  logger.log('warn', "127.0.0.1 - there's no place like home");
412  logger.log('error', "127.0.0.1 - there's no place like home");
413  logger.info("127.0.0.1 - there's no place like home");
414  logger.warn("127.0.0.1 - there's no place like home");
415  logger.error("127.0.0.1 - there's no place like home");
416
417  //
418  // Default logger
419  //
420  winston.log('info', "127.0.0.1 - there's no place like home");
421  winston.info("127.0.0.1 - there's no place like home");
422```
423
424`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 `npm` levels you could log only `error` messages to the console and everything `info` and below to a file (which includes `error` messages):
425
426``` js
427  var logger = new (winston.Logger)({
428    transports: [
429      new (winston.transports.Console)({ level: 'error' }),
430      new (winston.transports.File)({
431        filename: 'somefile.log',
432        level: 'info'
433      })
434    ]
435  });
436```
437
438You may also dynamically change the log level of a transport:
439
440``` js
441  var logger = new (winston.Logger)({
442    transports: [
443      new (winston.transports.Console)({ level: 'warn' }),
444      new (winston.transports.File)({ filename: 'somefile.log', level: 'error' })
445    ]
446  });
447  logger.debug("Will not be logged in either transport!");
448  logger.transports.console.level = 'debug';
449  logger.transports.file.level = 'verbose';
450  logger.verbose("Will be logged in both transports!");
451```
452
453As of 0.2.0, winston supports customizable logging levels, defaulting to [npm][0] style logging levels. Changing logging levels is easy:
454
455``` js
456  //
457  // Change levels on the default winston logger
458  //
459  winston.setLevels(winston.config.syslog.levels);
460
461  //
462  // Change levels on an instance of a logger
463  //
464  logger.setLevels(winston.config.syslog.levels);
465```
466
467Calling `.setLevels` on a logger will remove all of the previous helper methods for the old levels and define helper methods for the new levels. Thus, you should be careful about the logging statements you use when changing levels. For example, if you ran this code after changing to the syslog levels:
468
469``` js
470  //
471  // Logger does not have 'silly' defined since that level is not in the syslog levels
472  //
473  logger.silly('some silly message');
474```
475
476### Using Custom Logging Levels
477In addition to the predefined `npm` and `syslog` levels available in Winston, you can also choose to define your own:
478
479``` js
480  var myCustomLevels = {
481    levels: {
482      foo: 0,
483      bar: 1,
484      baz: 2,
485      foobar: 3
486    },
487    colors: {
488      foo: 'blue',
489      bar: 'green',
490      baz: 'yellow',
491      foobar: 'red'
492    }
493  };
494
495  var customLevelLogger = new (winston.Logger)({ levels: myCustomLevels.levels });
496  customLevelLogger.foobar('some foobar level-ed message');
497```
498
499Although 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:
500
501``` js
502  //
503  // Make winston aware of these colors
504  //
505  winston.addColors(myCustomLevels.colors);
506```
507
508This enables transports with the 'colorize' option set to appropriately color the output of custom levels.
509
510## Further Reading
511
512### Events and Callbacks in Winston
513Each instance of winston.Logger is also an instance of an [EventEmitter][1]. A log event will be raised each time a transport successfully logs a message:
514
515``` js
516  logger.on('logging', function (transport, level, msg, meta) {
517    // [msg] and [meta] have now been logged at [level] to [transport]
518  });
519
520  logger.info('CHILL WINSTON!', { seriously: true });
521```
522
523It is also worth mentioning that the logger also emits an 'error' event which you should handle or suppress if you don't want unhandled exceptions:
524
525``` js
526  //
527  // Handle errors
528  //
529  logger.on('error', function (err) { /* Do Something */ });
530
531  //
532  // Or just suppress them.
533  //
534  logger.emitErrs = false;
535```
536
537Every logging method described in the previous section also takes an optional callback which will be called only when all of the transports have logged the specified message.
538
539``` js
540  logger.info('CHILL WINSTON!', { seriously: true }, function (err, level, msg, meta) {
541    // [msg] and [meta] have now been logged at [level] to **every** transport.
542  });
543```
544
545### Working with multiple Loggers in winston
546
547Often 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`:
548
549``` js
550  var winston = require('winston');
551
552  //
553  // Configure the logger for `category1`
554  //
555  winston.loggers.add('category1', {
556    console: {
557      level: 'silly',
558      colorize: true,
559      label: 'category one'
560    },
561    file: {
562      filename: '/path/to/some/file'
563    }
564  });
565
566  //
567  // Configure the logger for `category2`
568  //
569  winston.loggers.add('category2', {
570    couchdb: {
571      host: '127.0.0.1',
572      port: 5984
573    }
574  });
575```
576
577Now that your loggers are setup, you can require winston _in any file in your application_ and access these pre-configured loggers:
578
579``` js
580  var winston = require('winston');
581
582  //
583  // Grab your preconfigured logger
584  //
585  var category1 = winston.loggers.get('category1');
586
587  category1.info('logging from your IoC container-based logger');
588```
589
590If you prefer to manage the `Container` yourself, you can simply instantiate one:
591
592``` js
593  var winston = require('winston'),
594      container = new winston.Container();
595
596  container.add('category1', {
597    console: {
598      level: 'silly',
599      colorize: true
600    },
601    file: {
602      filename: '/path/to/some/file'
603    }
604  });
605```
606
607### Sharing transports between Loggers in winston
608
609``` js
610  var winston = require('winston');
611
612  //
613  // Setup transports to be shared across all loggers
614  // in three ways:
615  //
616  // 1. By setting it on the default Container
617  // 2. By passing `transports` into the constructor function of winston.Container
618  // 3. By passing `transports` into the `.get()` or `.add()` methods
619  //
620
621  //
622  // 1. By setting it on the default Container
623  //
624  winston.loggers.options.transports = [
625    // Setup your shared transports here
626  ];
627
628  //
629  // 2. By passing `transports` into the constructor function of winston.Container
630  //
631  var container = new winston.Container({
632    transports: [
633      // Setup your shared transports here
634    ]
635  });
636
637  //
638  // 3. By passing `transports` into the `.get()` or `.add()` methods
639  //
640  winston.loggers.add('some-category', {
641    transports: [
642      // Setup your shared transports here
643    ]
644  });
645
646  container.add('some-category', {
647    transports: [
648      // Setup your shared transports here
649    ]
650  });
651```
652
653### Using winston in a CLI tool
654A common use-case for logging is output to a CLI tool. Winston has a special helper method which will pretty print output from your CLI tool. Here's an example from the [require-analyzer][2] written by [Nodejitsu][3]:
655
656```
657  info:   require-analyzer starting in /Users/Charlie/Nodejitsu/require-analyzer
658  info:   Found existing dependencies
659  data:   {
660  data:     colors: '0.x.x',
661  data:     eyes: '0.1.x',
662  data:     findit: '0.0.x',
663  data:     npm: '1.0.x',
664  data:     optimist: '0.2.x',
665  data:     semver: '1.0.x',
666  data:     winston: '0.2.x'
667  data:   }
668  info:   Analyzing dependencies...
669  info:   Done analyzing raw dependencies
670  info:   Retrieved packages from npm
671  warn:   No additional dependencies found
672```
673
674Configuring output for this style is easy, just use the `.cli()` method on `winston` or an instance of `winston.Logger`:
675
676``` js
677  var winston = require('winston');
678
679  //
680  // Configure CLI output on the default logger
681  //
682  winston.cli();
683
684  //
685  // Configure CLI on an instance of winston.Logger
686  //
687  var logger = new winston.Logger({
688    transports: [
689      new (winston.transports.Console)()
690    ]
691  });
692
693  logger.cli();
694```
695
696### Filters and Rewriters
697Filters allow modifying the contents of **log messages**, and Rewriters allow modifying the contents of **log meta** e.g. to mask data that should not appear in logs.
698
699Both filters and rewriters are simple Arrays of functions which can be provided when creating a `new winston.Logger(options)`. e.g.:
700
701``` js
702var logger = new winston.Logger({
703  rewriters: [function (level, msg, meta) { /* etc etc */ }],
704  filters:   [function (level, msg, meta) { /* etc etc */ }]
705})
706```
707
708Like any Array, they can also be modified at runtime with no adverse side-effects to the `winston` internals.
709
710``` js
711logger.filters.push(function(level, msg, meta) {
712  return meta.production
713    ? maskCardNumbers(msg)
714    : msg;
715});
716
717logger.info('transaction with card number 123456789012345 successful.');
718```
719
720This may result in this output:
721
722```
723info: transaction with card number 123456****2345 successful.
724```
725
726Where as for rewriters, if you wanted to sanitize the `creditCard` field of your `meta` you could:
727
728``` js
729logger.rewriters.push(function(level, msg, meta) {
730  if (meta.creditCard) {
731    meta.creditCard = maskCardNumbers(meta.creditCard)
732  }
733
734  return meta;
735});
736
737logger.info('transaction ok', { creditCard: 123456789012345 });
738```
739
740which may result in this output:
741
742```
743info: transaction ok creditCard=123456****2345
744```
745
746See [log-filter-test.js](./test/log-filter-test.js), where card number masking is implemented as an example along with [log-rewriter-test.js](./test/log-rewriter-test.js)
747
748## Adding Custom Transports
749Adding a custom transport is actually pretty easy. All you need to do is accept a couple of options, set a name, implement a log() method, and add it to the set of transports exposed by winston.
750
751``` js
752  var util = require('util'),
753      winston = require('winston');
754
755  var CustomLogger = winston.transports.CustomLogger = function (options) {
756    //
757    // Name this logger
758    //
759    this.name = 'customLogger';
760
761    //
762    // Set the level from your options
763    //
764    this.level = options.level || 'info';
765
766    //
767    // Configure your storage backing as you see fit
768    //
769  };
770
771  //
772  // Inherit from `winston.Transport` so you can take advantage
773  // of the base functionality and `.handleExceptions()`.
774  //
775  util.inherits(CustomLogger, winston.Transport);
776
777  CustomLogger.prototype.log = function (level, msg, meta, callback) {
778    //
779    // Store this message and metadata, maybe use some custom logic
780    // then callback indicating success.
781    //
782    callback(null, true);
783  };
784```
785
786### Custom Log Format
787To specify a custom log format for a transport, you should set a formatter function. Currently supported transports are: Console, File, Memory.
788An options object will be passed to the formatter function. Its general properties are: timestamp, level, message, meta. Depending on the transport type, there may be additional properties.
789
790``` js
791var config = winston.config;
792var logger = new (winston.Logger)({
793  transports: [
794    new (winston.transports.Console)({
795      timestamp: function() {
796        return Date.now();
797      },
798      formatter: function(options) {
799        // - Return string will be passed to logger.
800        // - Optionally, use options.colorize(options.level, <string>) to
801        //   colorize output based on the log level.
802        return options.timestamp() + ' ' +
803          config.colorize(options.level, options.level.toUpperCase()) + ' ' +
804          (options.message ? options.message : '') +
805          (options.meta && Object.keys(options.meta).length ? '\n\t'+ JSON.stringify(options.meta) : '' );
806      }
807    })
808  ]
809});
810logger.info('Data to log.');
811```
812
813### Inspirations
8141. [npm][0]
8152. [log.js][4]
8163. [socket.io][5]
8174. [node-rlog][6]
8185. [BigBrother][7]
8196. [Loggly][8]
820
821## Installation
822
823### Installing npm (node package manager)
824```
825  curl https://npmjs.org/install.sh | sh
826```
827
828### Installing winston
829```
830  [sudo] npm install winston
831```
832
833## Run Tests
834All of the winston tests are written in [vows][9], and designed to be run with npm.
835
836``` bash
837  $ npm test
838```
839
840#### Author: [Charlie Robbins](http://twitter.com/indexzero)
841#### Contributors: [Matthew Bergman](http://github.com/fotoverite), [Marak Squires](http://github.com/marak)
842
843[0]: https://github.com/npm/npmlog/blob/master/log.js
844[1]: http://nodejs.org/docs/v0.3.5/api/events.html#events.EventEmitter
845[2]: http://github.com/nodejitsu/require-analyzer
846[3]: http://nodejitsu.com
847[4]: https://github.com/visionmedia/log.js
848[5]: http://socket.io
849[6]: https://github.com/jbrisbin/node-rlog
850[7]: https://github.com/feisty/BigBrother
851[8]: http://loggly.com
852[9]: http://vowsjs.org
853[10]: http://nodejs.org/api/util.html#util_util_format_format
854[14]: http://nodejs.org/api/stream.html#stream_class_stream_writable
855[16]: https://github.com/indexzero/winston-mongodb
856[17]: https://github.com/indexzero/winston-riak
857[18]: https://github.com/appsattic/winston-simpledb
858[19]: https://github.com/wavded/winston-mail
859[21]: https://github.com/jesseditson/winston-sns
860[22]: https://github.com/flite/winston-graylog2
861[23]: https://github.com/kenperkins/winston-papertrail
862[24]: https://github.com/jorgebay/winston-cassandra
863[25]: https://github.com/jesseditson/winston-sns
864[26]: https://github.com/inspiredjw/winston-dynamodb/
865