Giter Site home page Giter Site logo

express-winston's Introduction

express-winston

Monthly Downloads Build Status

winston middleware for express.js

Changelog

CALL FOR MAINTAINERS

Installation

npm install winston express-winston

(supports node >= 6)

#BLM and 5.x breaking changes

The maintainers of this project no longer feel comfortable with the following terms:

  • whitelist
  • blacklist
  • master

Therefore, exposed configuration options, types in this library using those terms are due to be removed in the upcoming 5.x series, including the master branch, you should update your apps and your code accordingly. We've taken immediate action to make main our default branch in Git.

You can track the progress of these changes in #247.

Usage

express-winston provides middlewares for request and error logging of your express.js application. It uses 'whitelists' to select properties from the request and (new in 0.2.x) response objects.

To make use of express-winston, you need to add the following to your application:

In package.json:

{
  "dependencies": {
    "...": "...",
    "winston": "^3.0.0",
    "express-winston": "^4.0.4",
    "...": "..."
  }
}

In server.js (or wherever you need it):

var winston = require('winston'),
    expressWinston = require('express-winston');

Request Logging

Use expressWinston.logger(options) to create a middleware to log your HTTP requests.

    var router = require('./my-express-router');

    app.use(expressWinston.logger({
      transports: [
        new winston.transports.Console()
      ],
      format: winston.format.combine(
        winston.format.colorize(),
        winston.format.json()
      ),
      meta: true, // optional: control whether you want to log the meta data about the request (default to true)
      msg: "HTTP {{req.method}} {{req.url}}", // optional: customize the default logging message. E.g. "{{res.statusCode}} {{req.method}} {{res.responseTime}}ms {{req.url}}"
      expressFormat: true, // Use the default Express/morgan request formatting. Enabling this will override any msg if true. Will only output colors with colorize set to true
      colorize: false, // Color the text and status code, using the Express/morgan color palette (text: gray, status: default green, 3XX cyan, 4XX yellow, 5XX red).
      ignoreRoute: function (req, res) { return false; } // optional: allows to skip some log messages based on request and/or response
    }));

    app.use(router); // notice how the router goes after the logger.

Options

    transports: [<WinstonTransport>], // list of all winston transports instances to use.
    format: [<logform.Format>], // formatting desired for log output.
    winstonInstance: <WinstonLogger>, // a winston logger instance. If this is provided the transports and formats options are ignored.
    level: String or function(req, res) { return String; }, // log level to use, the default is "info". Assign a  function to dynamically set the level based on request and response, or a string to statically set it always at that level. statusLevels must be false for this setting to be used.
    msg: String or function, // customize the default logging message. E.g. "{{res.statusCode}} {{req.method}} {{res.responseTime}}ms {{req.url}}", "HTTP {{req.method}} {{req.url}}" or function(req, res) { return `${res.statusCode} - ${req.method}` }, // Warning: while supported, returning mustache style interpolation from an options.msg function has performance and memory implications under load.
    expressFormat: Boolean, // Use the default Express/morgan request formatting. Enabling this will override any msg if true. Will only output colors when colorize set to true
    colorize: Boolean, // Color the text and status code, using the Express/morgan color palette (text: gray, status: default green, 3XX cyan, 4XX yellow, 5XX red).
    meta: Boolean, // control whether you want to log the meta data about the request (default to true).
    baseMeta: Object, // default meta data to be added to log, this will be merged with the meta data.
    metaField: String, // if defined, the meta data will be added in this field instead of the meta root object. Defaults to 'meta'. Set to `null` to store metadata at the root of the log entry.
    requestField: [String] // the property of the metadata to store the request under (default 'req'). Set to null to exclude request from metadata
    statusLevels: Boolean or Object, // different HTTP status codes caused log messages to be logged at different levels (info/warn/error), the default is false. Use an object to control the levels various status codes are logged at. Using an object for statusLevels overrides any setting of options.level.
    ignoreRoute: function (req, res) { return false; }, // A function to determine if logging is skipped, defaults to returning false. Called _before_ any later middleware.
    skip: function(req, res) { return false; }, // A function to determine if logging is skipped, defaults to returning false. Called _after_ response has already been sent.
    requestFilter: function (req, propName) { return req[propName]; }, // A function to filter/return request values, defaults to returning all values allowed by whitelist. If the function returns undefined, the key/value will not be included in the meta.
    responseFilter: function (res, propName) { return res[propName]; }, // A function to filter/return response values, defaults to returning all values allowed by whitelist. If the function returns undefined, the key/value will not be included in the meta.
    requestWhitelist: [String], // Array of request properties to log. Overrides global requestWhitelist for this instance
    responseWhitelist: [String], // Array of response properties to log. Overrides global responseWhitelist for this instance
    bodyWhitelist: [String], // Array of body properties to log. Overrides global bodyWhitelist for this instance
    bodyBlacklist: [String], // Array of body properties to omit from logs. Overrides global bodyBlacklist for this instance
    ignoredRoutes: [String], // Array of paths to ignore/skip logging. Overrides global ignoredRoutes for this instance
    dynamicMeta: function(req, res) { return [Object]; } // Extract additional meta data from request or response (typically req.user data if using passport). meta must be true for this function to be activated
    headerBlacklist: [String], // Array of headers to omit from logs. Applied after any previous filters.

Error Logging

Use expressWinston.errorLogger(options) to create a middleware that log the errors of the pipeline.

    var router = require('./my-express-router');

    app.use(router); // notice how the router goes first.
    app.use(expressWinston.errorLogger({
      transports: [
        new winston.transports.Console()
      ],
      format: winston.format.combine(
        winston.format.colorize(),
        winston.format.json()
      )
    }));

The logger needs to be added AFTER the express router (app.router) and BEFORE any of your custom error handlers (express.handler). Since express-winston will just log the errors and not handle them, you can still use your custom error handler like express.handler, just be sure to put the logger before any of your handlers.

Options

    transports: [<WinstonTransport>], // list of all winston transports instances to use.
    format: [<logform.Format>], // formatting desired for log output
    winstonInstance: <WinstonLogger>, // a winston logger instance. If this is provided the transports and formats options are ignored.
    msg: String or function // customize the default logging message. E.g. "{{err.message}} {{res.statusCode}} {{req.method}}" or function(req, res) { return `${res.statusCode} - ${req.method}` }
    baseMeta: Object, // default meta data to be added to log, this will be merged with the error data.
    meta: Boolean, // control whether you want to log the meta data about the request (default to true).
    metaField: String, // if defined, the meta data will be added in this field instead of the meta root object. Defaults to 'meta'. Set to `null` to store metadata at the root of the log entry.
    requestField: [String] // the property of the metadata to store the request under (default 'req'). Set to null to exclude request from metadata    
    responseField: [String] // the property of the metadata to store the response under (default 'res'). If set to the same as 'requestField', filtered response and request properties will be merged. Set to null to exclude request from metadata
    requestFilter: function (req, propName) { return req[propName]; } // A function to filter/return request values, defaults to returning all values allowed by whitelist. If the function returns undefined, the key/value will not be included in the meta.
    requestWhitelist: [String] // Array of request properties to log. Overrides global requestWhitelist for this instance
    headerBlacklist: [String], // Array of headers to omit from logs. Applied after any previous filters.
    level: String or function(req, res, err) { return String; }// custom log level for errors (default is 'error'). Assign a function to dynamically set the log level based on request, response, and the exact error.
    dynamicMeta: function(req, res, err) { return [Object]; } // Extract additional meta data from request or response (typically req.user data if using passport). meta must be true for this function to be activated
    exceptionToMeta: function(error){return Object; } // Function to format the returned meta information on error log. If not given `winston.exception.getAllInfo` will be used by default
    blacklistedMetaFields: [String] // fields to blacklist from meta data
    skip: function(req, res, err) { return false; } // A function to determine if logging is skipped, defaults to returning false.

To use winston's existing transports, set transports to the values (as in key-value) of the winston.default.transports object. This may be done, for example, by using underscorejs: transports: _.values(winston.default.transports).

Alternatively, if you're using a winston logger instance elsewhere and have already set up levels and transports, pass the instance into expressWinston with the winstonInstance option. The transports option is then ignored.

metaField option

In versions of express-winston prior to 4.0.0, this field functioned differently.

Previously the log entry would always have a "meta" field which would be set to the metadata of the request/error.
If metaField was set, this information would be stored as an object with the given property on the "meta" object of the log entry. This prevented the use case where the metadata should be located at the root of the log entry.

In this version, metaField defaults to "meta" which maintains the prior versions behavior of storing the metadata at a "meta" property of the log entry.

Explicitly setting the metaField to null or "null" causes the metadata to be stored at the root of the log entry.

The metaField option now also supports dot separated and array values to store the metadata at a nested location in the log entry.

Upgrade Note: For those upgrading from a version of `express-winston` prior to 4.0.0 that use the `metaField` property, to keep the same behavior, prepend `meta.` to your current `metaField` configuration. (i.e. 'foo' would become 'meta.foo')

Examples

    var express = require('express');
    var expressWinston = require('express-winston');
    var winston = require('winston'); // for transports.Console
    var app = module.exports = express();

    app.use(express.bodyParser());
    app.use(express.methodOverride());

    // Let's make our express `Router` first.
    var router = express.Router();
    router.get('/error', function(req, res, next) {
      // here we cause an error in the pipeline so we see express-winston in action.
      return next(new Error("This is an error and it should be logged to the console"));
    });

    router.get('/', function(req, res, next) {
      res.write('This is a normal request, it should be logged to the console too');
      res.end();
    });

    // express-winston logger makes sense BEFORE the router
    app.use(expressWinston.logger({
      transports: [
        new winston.transports.Console()
      ],
      format: winston.format.combine(
        winston.format.colorize(),
        winston.format.json()
      )
    }));

    // Now we can tell the app to use our routing code:
    app.use(router);

    // express-winston errorLogger makes sense AFTER the router.
    app.use(expressWinston.errorLogger({
      transports: [
        new winston.transports.Console()
      ],
      format: winston.format.combine(
        winston.format.colorize(),
        winston.format.json()
      )
    }));

    // Optionally you can include your custom error handler after the logging.
    app.use(express.errorLogger({
      dumpExceptions: true,
      showStack: true
    }));

    app.listen(3000, function(){
      console.log("express-winston demo listening on port %d in %s mode", this.address().port, app.settings.env);
    });

Browse / to see a regular HTTP logging like this:

{
  "req": {
    "httpVersion": "1.1",
    "headers": {
      "host": "localhost:3000",
      "connection": "keep-alive",
      "accept": "*/*",
      "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
      "accept-encoding": "gzip,deflate,sdch",
      "accept-language": "en-US,en;q=0.8,es-419;q=0.6,es;q=0.4",
      "accept-charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.3",
      "cookie": "connect.sid=nGspCCSzH1qxwNTWYAoexI23.seE%2B6Whmcwd"
    },
    "url": "/",
    "method": "GET",
    "originalUrl": "/",
    "query": {}
  },
  "res": {
    "statusCode": 200
  },
  "responseTime" : 12,
  "level": "info",
  "message": "HTTP GET /favicon.ico"
}

Browse /error will show you how express-winston handles and logs the errors in the express pipeline like this:

{
  "date": "Thu Jul 19 2012 23:39:44 GMT-0500 (COT)",
  "process": {
    "pid": 35719,
    "uid": 501,
    "gid": 20,
    "cwd": "/Users/thepumpkin/Projects/testExpressWinston",
    "execPath": "/usr/local/bin/node",
    "version": "v0.6.18",
    "argv": [
      "node",
      "/Users/thepumpkin/Projects/testExpressWinston/app.js"
    ],
    "memoryUsage": {
      "rss": 14749696,
      "heapTotal": 7033664,
      "heapUsed": 5213280
    }
  },
  "os": {
    "loadavg": [
      1.95068359375,
      1.5166015625,
      1.38671875
    ],
    "uptime": 498086
  },
  "trace": [
    ...,
    {
      "column": 3,
      "file": "Object].log (/Users/thepumpkin/Projects/testExpressWinston/node_modules/winston/lib/winston/transports/console.js",
      "function": "[object",
      "line": 87,
      "method": null,
      "native": false
    }
  ],
  "stack": [
    "Error: This is an error and it should be logged to the console",
    "    at /Users/thepumpkin/Projects/testExpressWinston/app.js:39:15",
    "    at callbacks (/Users/thepumpkin/Projects/testExpressWinston/node_modules/express/lib/router/index.js:272:11)",
    "    at param (/Users/thepumpkin/Projects/testExpressWinston/node_modules/express/lib/router/index.js:246:11)",
    "    at pass (/Users/thepumpkin/Projects/testExpressWinston/node_modules/express/lib/router/index.js:253:5)",
    "    at Router._dispatch (/Users/thepumpkin/Projects/testExpressWinston/node_modules/express/lib/router/index.js:280:4)",
    "    at Object.handle (/Users/thepumpkin/Projects/testExpressWinston/node_modules/express/lib/router/index.js:45:10)",
    "    at next (/Users/thepumpkin/Projects/testExpressWinston/node_modules/express/node_modules/connect/lib/http.js:204:15)",
    "    at done (/Users/thepumpkin/Dropbox/Projects/express-winston/index.js:91:14)",
    "    at /Users/thepumpkin/Dropbox/Projects/express-winston/node_modules/async/lib/async.js:94:25",
    "    at [object Object].log (/Users/thepumpkin/Projects/testExpressWinston/node_modules/winston/lib/winston/transports/console.js:87:3)"
  ],
  "req": {
    "httpVersion": "1.1",
    "headers": {
      "host": "localhost:3000",
      "connection": "keep-alive",
      "cache-control": "max-age=0",
      "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
      "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
      "accept-encoding": "gzip,deflate,sdch",
      "accept-language": "en-US,en;q=0.8,es-419;q=0.6,es;q=0.4",
      "accept-charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.3",
      "cookie": "connect.sid=nGspCCSzH1qxwNTWYAoexI23.seE%2B6WhmcwdzFEjqhMDuIIl3mAUY7dT4vn%2BkWvRPhZc"
    },
    "url": "/error",
    "method": "GET",
    "originalUrl": "/error",
    "query": {}
  },
  "level": "error",
  "message": "middlewareError"
}

StackDriver/Google Cloud Logging

If using this library with @google-cloud/logging-winston, use the following configuration to properly store httpRequest information.

See https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry

var express = require('express');
var expressWinston = require('express-winston');
var LoggingWinston = require('@google-cloud/logging-winston').LoggingWinston;

const app = express()

app.use(expressWinston.logger({
    transports: [new LoggingWinston({})],
    metaField: null, //this causes the metadata to be stored at the root of the log entry
    responseField: null, // this prevents the response from being included in the metadata (including body and status code)
    requestWhitelist: ['headers', 'query'],  //these are not included in the standard StackDriver httpRequest
    responseWhitelist: ['body'], // this populates the `res.body` so we can get the response size (not required)
    dynamicMeta:  (req, res) => {
      const httpRequest = {}
      const meta = {}
      if (req) {
        meta.httpRequest = httpRequest
        httpRequest.requestMethod = req.method
        httpRequest.requestUrl = `${req.protocol}://${req.get('host')}${req.originalUrl}`
        httpRequest.protocol = `HTTP/${req.httpVersion}`
        // httpRequest.remoteIp = req.ip // this includes both ipv6 and ipv4 addresses separated by ':'
        httpRequest.remoteIp = req.ip.indexOf(':') >= 0 ? req.ip.substring(req.ip.lastIndexOf(':') + 1) : req.ip   // just ipv4
        httpRequest.requestSize = req.socket.bytesRead
        httpRequest.userAgent = req.get('User-Agent')
        httpRequest.referrer = req.get('Referrer')
      }
    
      if (res) {
        meta.httpRequest = httpRequest
        httpRequest.status = res.statusCode
        httpRequest.latency = {
          seconds: Math.floor(res.responseTime / 1000),
          nanos: ( res.responseTime % 1000 ) * 1000000
        }
        if (res.body) {
          if (typeof res.body === 'object') {
            httpRequest.responseSize = JSON.stringify(res.body).length
          } else if (typeof res.body === 'string') {
            httpRequest.responseSize = res.body.length
          }
        }
      }
      return meta
    }
}));

Global Whitelists and Blacklists

Express-winston exposes three whitelists that control which properties of the request, body, and response are logged:

  • requestWhitelist
  • bodyWhitelist, bodyBlacklist
  • responseWhitelist

For example, requestWhitelist defaults to:

['url', 'headers', 'method', 'httpVersion', 'originalUrl', 'query'];

Only those properties of the request object will be logged. Set or modify the whitelist as necessary.

For example, to include the session property (the session data), add the following during logger setup:

expressWinston.requestWhitelist.push('session');

The blacklisting excludes certain properties and keeps all others. If both bodyWhitelist and bodyBlacklist are set the properties excluded by the blacklist are not included even if they are listed in the whitelist!

Example:

expressWinston.bodyBlacklist.push('secretid', 'secretproperty');

Note that you can log the whole request and/or response body:

expressWinston.requestWhitelist.push('body');
expressWinston.responseWhitelist.push('body');

Nested Whitelists

requestWhitelist and responseWhitelist also support nested whitelist values, allowing access to parts of an object.

For example, using the following during logger setup:

expressWinston.responseWhitelist.push('body.important.value');

A response that looks like this :

{
    body: {
        important: {
            value: 5
        },
        notImportant: {
            value: 7
        }
    },
    other: {
        value: 3
    }
}

Would only log the following value :

{
    body: {
        important: {
            value: 5
        }
    }
}

Route-Specific Whitelists and Blacklists

New in version 0.2.x is the ability to add whitelist elements in a route. express-winston adds a _routeWhitelists object to the request, containing .body, .req and .res properties, to which you can set an array of 'whitelist' parameters to include in the log, specific to the route in question:

    router.post('/user/register', function(req, res, next) {
      req._routeWhitelists.body = ['username', 'email', 'age']; // But not 'password' or 'confirm-password' or 'top-secret'
      req._routeWhitelists.res = ['_headers'];
    });

Post to /user/register would give you something like the following:

{
  "req": {
    "httpVersion": "1.1",
    "headers": {
      "host": "localhost:3000",
      "connection": "keep-alive",
      "accept": "*/*",
      "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
      "accept-encoding": "gzip,deflate,sdch",
      "accept-language": "en-US,en;q=0.8,es-419;q=0.6,es;q=0.4",
      "accept-charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.3",
      "cookie": "connect.sid=nGspCCSzH1qxwNTWYAoexI23.seE%2B6Whmcwd"
    },
    "url": "/",
    "method": "GET",
    "originalUrl": "/",
    "query": {},
    "body": {
      "username": "foo",
      "email": "[email protected]",
      "age": "72"
    }
  },
  "res": {
    "statusCode": 200
  },
  "responseTime" : 12,
  "level": "info",
  "message": "HTTP GET /favicon.ico"
}

Blacklisting supports only the body property.

    router.post('/user/register', function(req, res, next) {
      req._routeWhitelists.body = ['username', 'email', 'age']; // But not 'password' or 'confirm-password' or 'top-secret'
      req._routeBlacklists.body = ['username', 'password', 'confirm-password', 'top-secret'];
      req._routeWhitelists.res = ['_headers'];
    });

If both req._routeWhitelists.body and req._routeBlacklists.body are set the result will be the white listed properties excluding any black listed ones. In the above example, only 'email' and 'age' would be included.

Custom Status Levels

If you set statusLevels to true express-winston will log sub 400 responses at info level, sub 500 responses as warnings and 500+ responses as errors. To change these levels specify an object as follows

  "statusLevels": {
    "success": "debug",
    "warn": "debug",
    "error": "info"
  }

Dynamic Status Levels

If you set statusLevels to false and assign a function to level, you can customize the log level for any scenario.

  statusLevels: false // default value
  level: function (req, res) {
    var level = "";
    if (res.statusCode >= 100) { level = "info"; }
    if (res.statusCode >= 400) { level = "warn"; }
    if (res.statusCode >= 500) { level = "error"; }
    // Ops is worried about hacking attempts so make Unauthorized and Forbidden critical
    if (res.statusCode == 401 || res.statusCode == 403) { level = "critical"; }
    // No one should be using the old path, so always warn for those
    if (req.path === "/v1" && level === "info") { level = "warn"; }
    return level;
  }

Dynamic meta data from request or response

If you set dynamicMeta function you can extract additional meta data fields from request or response objects. The function can be used to either select relevant elements in request or response body without logging them as a whole or to extract runtime data like the user making the request. The example below logs the user name and role as assigned by the passport authentication middleware.

   meta: true,
   dynamicMeta: function(req, res) {
     return {
       user: req.user ? req.user.username : null,
       role: req.user ? req.user.role : null,
       ...
   }
}

Tests

Run the basic Mocha tests:

npm test

View the coverage report:

npx http-server coverage/lcov-report

Issues and Collaboration

If you ran into any problems, please use the project Issues section to search or post any bug.

Contributors

Also see AUTHORS file, add yourself if you are missing.

MIT License

Copyright (c) 2012 Bithavoc.io and Contributors - http://bithavoc.io

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

express-winston's People

Contributors

bithavoc avatar crellison avatar cubbuk avatar damasfoux avatar floatinglomas avatar golopot avatar jaclar avatar johanfirebase avatar kapalex avatar liranbri avatar ltegman avatar makrandgupta avatar maxday avatar mdarveau avatar mikelax avatar nati-mask avatar ppitonak avatar prototypealex avatar q2s2t avatar rafatcb avatar richardmisiak avatar rictorres avatar robbiet480 avatar rosston avatar rush avatar ryanleecode avatar slickmb avatar tsheaff avatar xdamman avatar yinzara avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

express-winston's Issues

Using with Express 4

Does express-winston work with Express 4? I seem to almost have it working but not fully. The README says "The logger needs to be added AFTER the express router(app.router))", but in Express 4, you don't explicitly use app.router anymore. So where does express-winston need to be in the sequence of middleware?

Basically, I'm trying to use winston to log requests. I've tried it both before and after my routes. When I place it before my routes, requests are logged and it seems to work fine, but I cannot filter by log level. Here's my logger:

  app.use(expressWinston.logger({
    transports: [
      new(winston.transports.Console)({
        level: 'error',
        colorize: true
      })
    ],
    statusLevel: true,
    meta: false,
    msg: "{{res.statusCode}}\t{{req.method}}\t{{res.responseTime}}ms\t{{req.url}}"
  }));

Even though I set level: 'error', all info messages still get logged. Am I missing something? Thanks.

Setting requestWhitelist doesn't seem to work

I can add to requestWhitelist like the docs suggest, but if I remove from requestWhitelist, it doesn't seem to work.

I've tried setting the white list like so:

expressWinston.requestWhitelist = [
  "url"
];

But the whitelist on line 216 of index.js still has the full requestWhitelist, so I'm still getting all of the data.

Throws exception in strict mode

Hi,

running node with --use-strict I get the following error.

./node_modules/express-winston/node_modules/winston/lib/winston/common.js:367
  fs.open(options.file, 'a+', 0644, function(err, fd) {
                              ^^^^
SyntaxError: Octal literals are not allowed in strict mode

This probably happens because of an outdated version of winston.

Could you please a look at this?

Thanks,

npm install fails for 0.2.2

npm ERR! Error: shasum check failed for /home/aoviedo/tmp/npm-7212-5ofRw203/1392314613089-0.2782984636723995/tmp.tgz
npm ERR! Expected: d7c1f685e36dee954a6a02d38e8796524ec2b86f
npm ERR! Actual:   904e49131c69cfdcd13b70cd798094dad2b4ff04
npm ERR! From:     https://registry.npmjs.org/express-winston/-/express-winston-0.2.2.tgz
npm ERR!     at /usr/lib/node_modules/npm/node_modules/sha/index.js:38:8
npm ERR!     at ReadStream.<anonymous> (/usr/lib/node_modules/npm/node_modules/sha/index.js:85:7)
npm ERR!     at ReadStream.EventEmitter.emit (events.js:117:20)
npm ERR!     at _stream_readable.js:920:16
npm ERR!     at process._tickCallback (node.js:415:13)
npm ERR! If you need help, you may report this *entire* log,
npm ERR! including the npm and node versions, at:
npm ERR!     <http://github.com/isaacs/npm/issues>

npm ERR! System Linux 3.11.0-15-generic
npm ERR! command "/usr/bin/node" "/usr/bin/npm" "install"
npm ERR! cwd /home/aoviedo/Documents/iamat/nodeserver
npm ERR! node -v v0.10.25
npm ERR! npm -v 1.3.24

Option 'statusLevels' in errorLogger

For the Error Logging an option 'statusLevels' is described as

different HTTP status codes caused log messages to be logged at different levels (info/warn/error), the default is false

The Option is not working for me and I didn't see an implementation in the code of the errorLogger. Is there a plan to implement this? This would be a very nice feature to have and I'm looking forward to use it when implemented.

Many thanks.

Response body is logging only the last char: "body":"}"

Hi, I am trying to log my response body (with the latest version 2.0.0).
I think I followed the documentation (which is awesome by the way!), and got the following code:

const winston = require('winston');
const expressWinston = require('express-winston');

expressWinston.requestWhitelist.push('body');
expressWinston.responseWhitelist.push('body');

module.exports = expressWinston.logger({
  transports: [
    new winston.transports.File({
      name: 'req-res',
      filename: '/var/log/nodejs/req-res.log',
      level: 'info',
    }),
  ],
  bodyBlacklist: ['password', 'pass', 'hash'],
});

The result is:
"res":{"statusCode":401,"body":"}"}

After review the source code I think I found a bug, the chunk
res.end = function(chunk, encoding) {
parameter will get only the last char.

The following code:

function logResponseBody(req, res, next) {

    var oldWrite = res.write,
        oldEnd = res.end;

    var chunks = [];

    res.write = function (chunk) {
        chunks.push(chunk);

        oldWrite.apply(res, arguments);
    };

    res.end = function (chunk) {
        if (chunk)
            chunks.push(chunk);

        var body = Buffer.concat(chunks).toString('utf8');
        console.log(req.path, body);

        oldEnd.apply(res, arguments);
    };

    next();
}

manage to log the entire response, maybe the code should also aggregate the entire chunks?
Do you want me to try fix the code and pull request it?

Thanks a lot,
Michael.

Filter authorization header by default

Currently it is not straight forward to filter the authorization header. It would be nice if there was a flag or an easy way to do this.

Perhaps this should be on by default.

Here is what i am currently doing

function customRequestFilter(req, propName){
  if(propName === "headers"){
    return Object.keys(req.headers).reduce(function(filteredHeaders, key){
      if(key !== "authorization"){
        filteredHeaders[key] = req.headers[key]
      }
      return filteredHeaders
    }, {})
  } else {
    return req[propName]
  }
}

module.exports = expressWinston.logger({
    transports: transports,
    requestFilter: customRequestFilter
 })

Minimal configuration in README

In my Express.js application I had to add these settings:

In package.json,

{
  "dependencies": {
    "winston": "0.6.x",
    "underscore": "1.5.x",
    "express-winston": "0.2.x"
  }
}

In server.js:

var winston = require('winston'),
    expressWinston = require('express-winston');

So minimal configuration for express-winston does not present in README, or there is something wrong in my configuration, so I had to add these requires into server.js.

Dependency on Winston 0.7.x

When I install express-winston (npm install express-winston), I see the package.json file that shows a dependency on winston 0.7.x rather than the newer ~0.9.0 dependency based on the following commit:

6fd3c89#diff-b9cfc7f2cdf78a7f4b91a753d10865a2

Is the public npm registry not up-to-date with the latest, or is the issue on my end?

response header content-type might be undefined

https://github.com/bithavoc/express-winston/blob/master/index.js#L201

res._headers['content-type'].indexOf('json') >= 0 ? JSON.parse(chunk) : chunk

res._headers['content-type'] might be undefined. indexOf throws an error.
The code should be replaced with:

(res._headers['content-type'] || '').indexOf('json') >= 0 ? JSON.parse(chunk) : chunk

Or in order to catch content-types that contain json\jsonp but not lalalajsonlalala:

/(\W|^)jsonp?(\W|$)/i.test(res._headers['content-type'] || '') ? JSON.parse(chunk) : chunk

Also, consider changing res._headers[...] with res.get(...).
Furthermore, In my opinion there is no need to wrap the JSON.parse with try-catch because I don't see a reason to use a json content-type and not returning a json object in the body...

Add Test Coverage

I'm pretty sure we're missing coverage on a bunch of code - I know for sure that some of the [white|black]list items are being skipped. Probably a good idea to add some type of coverage mechanism.

I use Mocha and Blanket for most of my projects, so I'm not sure what fits with vows, but I just wanted to put it out there.

app.router is deprecated

How do you handle exceptions like in your example section without using app.router because it's deprecated since 4.x...

Thanks !

Any way to include optional values in message?

I have some req that come in with session information, and would like to be able to display that. But the value doesn't always exist.

Specifically, when my users are logged in there is a session token I want to display: req.user.sessionID

But the value doesn't always exist...

How would I express that in the msg?

cpu usage increase when using _routeWhitelists

After a recent release we noticed that the cpu usage on our node servers was increasing until it reached 100%, whereas before it sat around 11%. We eventually tracked it down to this line:

req._routeWhitelists.req.push('request_id');

If we comment that line out, the cpu issues disappear.

expressFormat logging formatting error

I am using this awesome logger in my express app. But when I start my express server and hit an endpoint, the debug info which is showing up in the console looks like this:

GET /test 200 7msGET /test 200 7ms
PUT /test 200 12ms
PUT /test 200 11msGET /test 200 8ms

See the error? It looks like every GET request log is not prepended with a newline character. I looked into the source code and tried to edit line 246 of express-winston/index.js

// before
var msg = chalk.grey(req.method + " " + req.url || req.url)

// after
var msg = chalk.grey("\n" + req.method + " " + req.url || req.url)

After that edit, my output looked like this:


GET /test 200 7ms
GET /test 200 7ms

PUT /test 200 12ms

PUT /test 200 11ms
GET /test 200 8ms

So yeah.. somewhere in the code the GET request is not getting a newline.


I am using version 0.3.1 of express-winston, and this is the configuration I am using for the logger:

expressWinston.logger({
        transports: [
          new winston.transports.Console({
            json: false,
            colorize: true,
            showLevel: false
          })
        ],
        expressFormat: true,
        meta: false

Add raw error to errorLogger?

I'd like to put the raw error/exception object on the meta data that gets logged. I'd be happy to make a PR with the feature, but I feel like it can be done in a couple different ways.

Here's my problem:

Mongoose's ValidationError stores the specifics of each individual validation error within an errors property on the exception. However, errorLogger (using winston.exception.getAllInfo) only extracts the stack trace from the exception. This makes any error logs with a ValidationError difficult to work with since it's not possible to know what field is causing the error.

So, I can see two useful ways of adding the raw error/exception to the meta data:

  1. Just add a rawError (or similar) field to the meta data that gets included on every logged error
  2. Accept a function on the baseMeta property (or some other one?) that the user can provide to add custom fields that would take precedence over the default meta data fields. That gives a lot of flexibility (too much? right amount?), like this:
app.use(expressWinston.errorLogger({
  transports: [
    new winston.transports.Console({})
  ],
  <newMetaPropertyHandler>: function(err) {
    return {
      errors: err.errors,
      foo: err.foo,
      stack: err.mySpecialStackTrace // This will take precedence over the default `stack` property
    };
  }
}));

Like I said, I'd be happy to add a PR (with tests!), but I didn't want to go making changes when it seems like there are other valid options. So any feedback would be appreciated!

Upgrade winston dependency to 1.0.0

Winston < 1.0.0 uses the colors npm package in a way that makes it monkey patch String.prototype. As a change to String.prototype will be global to the whole runtime, usage of express-winston modifies the behaviour of strings for all other code.

status code colorized

hi,
is it possible to colorize the status code for the request middleware, as morgan/logger does?
thanks

Expose winston instance?

Preface: This is my first time using winston/express-winston but Google did not seem to help with my issue.

I would like to use winston in my express project for both the HTTP request logging via the express-winston middleware but also use it as a general logger in other modules.

I believe to do that I would need to have the instance of the winston logger exposed via express-winston?
Unless I can have multiple instances of winston writing to the same log files and not cause issues.

It'd be nice if different status codes caused log messages to be logged at different levels...

It'd be nice if different status codes caused log messages to be logged at different levels...

For example, if there's a 500 status, I'd like for it to be logged at the 'error' level, but if the status is 404, I only want 'warn', whereas for a 200 status, 'info' is sufficient.

This might be customizable as a mapping provided in the options to the logger method, i.e:

app.use(expressWinston.logger({
    transports: [ foo, bar ],
        statusLevels: {
            '200>399': 'info',
            '400>499': 'warn',
            '500>': 'error'
        }
     });

Make sense?

Blocking certain routes

I have the kue admin interface mounted, but it spams my logs because they are constantly requesting the queue state. It would be nice to have a blacklist of routes to not log.

Format error message

It whould be nice to allow formatting the error message in the same way it is possible with the log message (at least with the req object).

responseWhitelist.push('body') crashes

I'm trying to log the body of the response and apparently the lib crashes when trying to get it from the headers.

Simple example app:

var express = require('express');
var expressWinston = require('express-winston');
var winston = require('winston');
var app = express();

expressWinston.responseWhitelist.push('body');
app.use(expressWinston.logger({
    transports: [
        new winston.transports.Console({})
    ]
}));

app.get('/', function (req, res) {
    res.send('Hello World!')
});

var server = app.listen(3000, function () {

    var host = server.address().address;
    var port = server.address().port;

    console.log('Example app listening at http://%s:%s', host, port)

});

Accessing the defined route results in a crash

> node app.js
Example app listening at http://0.0.0.0:3000
TypeError: Cannot call method 'indexOf' of undefined
    at ServerResponse.res.end (/home/arnau/code/myapp/node_modules/express-winston/index.js:201:64)
    at ServerResponse.res.send (/home/arnau/code/myapp/node_modules/express/lib/response.js:154:8)
    at app.listen.host (/home/arnau/code/myapp/app.js:14:9)
    at callbacks (/home/arnau/code/myapp/node_modules/express/lib/router/index.js:164:37)
    at param (/home/arnau/code/myapp/node_modules/express/lib/router/index.js:138:11)
    at pass (/home/arnau/code/myapp/node_modules/express/lib/router/index.js:145:5)
    at Router._dispatch (/home/arnau/code/myapp/node_modules/express/lib/router/index.js:173:5)
    at Object.router (/home/arnau/code/myapp/node_modules/express/lib/router/index.js:33:10)
    at next (/home/arnau/code/myapp/node_modules/express/node_modules/connect/lib/proto.js:193:15)
    at Object.handle (/home/arnau/code/myapp/node_modules/express-winston/index.js:231:9)

Refactor tests

They're a bit of a mess - it's actually my fault for splitting 'v0.1.0' and 'v0.2.0' apis into sections way back - so I'll clean it up when I can - just wanted to make note of it here. Now that there's coverage checking, this can finally be done without missing anything.

  • The structure of the tests - the describes and its - should better follow the structure of the module with a describe for each exports-ed item;
  • All the functionality should be explicitly tested for, as some is currently just 'coincidentally' tested;
  • Most of the setup code can probably be refactored and better reused;

request body missing

I haven't had luck in getting req.body to print out in the log.

Here's what I'm getting:

{
  "req": {
    "url": "/user/invite",
    "headers": {
      "host": "192.168.1.223:3000",
      "connection": "keep-alive",
      "content-length": "164",
      "cache-control": "no-cache",
      "origin": "chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop",
      "content-type": "application/json",
      "user-agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2202.3 Safari/537.36",
      "postman-token": "d3e5d8db-4a65-d10f-02e9-2fa2c4692838",
      "accept": "*/*",
      "dnt": "1",
      "accept-encoding": "gzip, deflate",
      "accept-language": "en-US,en;q=0.8"
    },
    "method": "POST",
    "httpVersion": "1.1",
    "originalUrl": "/user/invite",
    "query": {}
  },
  "res": {
    "statusCode": 200
  },
  "responseTime": 82,
  "level": "info",
  "message": "HTTP POST /user/invite { product: 'TouchCare' }",
  "timestamp": "2014-10-28T20:49:40.212Z"
}

expressFormat option seems to ignore colorize: false

I'm using a winston logger in my app:

var logger = new winston.Logger({
  transports: [ new winston.transports.File({
          filename: 'test.log',
          level: 'debug',
          prettyPrint: true,
          colorize: false,
          timestamp: true,
          json: false
        })
  ]
});

In addition, I use a request logger with express-winston configured to use the same winston instance:

var requestLogger = expressWinston.logger({
  winstonInstance: logger,
  expressFormat: true
});

Despite colorize: false being set the requestLogger seems to produce ANSI escape sequences for colors:

info: ESC[90mPOST /clientsESC[39m ESC[33m400ESC[39m ESC[90m1123msESC[39m
{ req:
   { url: '/clients',
...

My understanding of the option (based on the comment in the code sample:
"Use the default Express/morgan request formatting, with the same colors. Enabling this will override any msg and colorStatus if true. Will only output colors on transports with colorize set to true") was that it should not output these escape sequences for a transport with the given config. Is this correct?

errorHandler has become errorLogger

Hi,

I used express-winston following the documentation of the main page of this project, and I have realized that the expressHandler function doesn' t exist, but taking a look into the code it was easy to see that the name of the function is errorLogger, so it is an stupid mistyped mistake, but it can save time for the future users.

Thanks for your endeavours in this module.

"/?%2E" causes a server crash.

The following server code with request to http://localhost:3000/?%2E crashes the server:

var express = require('express'),
    expressWinston = require('express-winston');
    winstonMongoDB = require('winston-mongodb');

var app = express();

app.use(expressWinston.logger({
  transports: [
    new (winstonMongoDB.MongoDB)({
      level: 'error',
      db: 'test',
      collection: 'test'
    })
  ]
}));

app.listen(3000);

The exception thrown:

/node_modules/winston-mongodb/node_modules/mongodb/lib/mongodb/connection/base.js:242
        throw message;
              ^
Error: key . must not contain '.'
    at Error (<anonymous>)
    at Function.checkKey (/node_modules/winston-mongodb/node_modules/mongodb/node_modules/bson/lib/bson/bson.js:1444:13)
    at serializeObject (/node_modules/winston-mongodb/node_modules/mongodb/node_modules/bson/lib/bson/bson.js:356:14)
    at packElement (/node_modules/winston-mongodb/node_modules/mongodb/node_modules/bson/lib/bson/bson.js:855:23)
    at serializeObject (/node_modules/winston-mongodb/node_modules/mongodb/node_modules/bson/lib/bson/bson.js:360:15)
    at packElement (/node_modules/winston-mongodb/node_modules/mongodb/node_modules/bson/lib/bson/bson.js:855:23)
    at serializeObject (/node_modules/winston-mongodb/node_modules/mongodb/node_modules/bson/lib/bson/bson.js:360:15)
    at Function.serializeWithBufferAndIndex (/node_modules/winston-mongodb/node_modules/mongodb/node_modules/bson/lib/bson/bson.js:332:10)
    at BSON.serializeWithBufferAndIndex (/node_modules/winston-mongodb/node_modules/mongodb/node_modules/bson/lib/bson/bson.js:1526:15)
    at InsertCommand.toBinary (/node_modules/winston-mongodb/node_modules/mongodb/lib/mongodb/commands/insert_command.js:146:37)

Why an empty callback is sent to winston.log?

I just want to have a better understanding of this:

// This is fire and forget, we don't want logging to hold up the request so don't wait for the callback
options.winstonInstance.log('error', 'middlewareError', exceptionMeta, function () {
    // Nothing to do here
});

"Implement a chain of requestFilters" - Uhhh, why?

I see that there's a feature request in the README to 'implement a chain of requestFilters'; do you remember what this was about?

I can't figure out a valid use case for it, so I can't really implement it. And I'm bored, so I wanted to implement it. :P

Handling Uncaught Exceptions and Meanjs

I've been programming in node for a couple of months now and just a few days I found out about winstong and express-winston
So looking into winston doc I see that there is a way to handle uncaught Exceptions, so my question is how does that work here?

Publish on NPM

version 0.2.0 hasn't been published on NPM, the latest is 0.1.3

Broken

Hi all,

This library looked great for express logging, we are already using winston for simultaneously logging to the console and to Loggly.

After putting this library in to push express logging through winston our app slowed to a crawl when running locally.

I had a look at the code of the library and it's a bit of a disaster to be honest.

  1. The express chain of middlewares gets invoked once for each transport that was passed to the logger/error logger. This will cause extremely random behaviour and effectively breaks express. (Have a look at how next() gets called).
  2. Even though next() is called multiple times, it isn't invoked initially until winston fires the logging call back to say the transport has logged the message, in our case as we're using Loggly this can take a while. So every web request waits on disk or network I/O for logging before being processed. This is a disaster.
  3. You're using the async library because presumably you thought winston logged things synchronously? Well it doesn't, the whole point of it is to be async. There's no need to use the async library.

Sorry for the rant but I hope others can see this message before they decide to use this library. It's not worth a pull request so I'll just make a new one from scratch. Thanks.

ignoredRoutes Doesn't Work

I know the ignoredRoutes property is undocumented, but it doesn't seem to work as currently implemented. It uses req.route, which is apparently only available after requests are handled or in route-specific middleware (according to this Stack Overflow question).

Maybe testing req.url against a regex or an array of strings would work? I'd be happy to submit a PR.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.