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;">"CHILL WINSTON! ... I put it in the logs."</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