winston-middleware 1.3.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of winston-middleware might be problematic. Click here for more details.

package/CHANGELOG.md ADDED
@@ -0,0 +1,28 @@
1
+ ## 2.0.0
2
+ #### Breaking changes
3
+ * Make winston a peer dependency. `npm install --save winston` if you haven't already.
4
+ * `expressFormat` has no color by default. Add `colorize: true` to winston-middleware
5
+ options to enable the previous colorized output. ([#86](https://github.com/bithavoc/winston-middleware/issues/86))
6
+ * Drop support for inherited properties on the object provided to the `baseMeta` option. This is unlikely to actually break anyone's real-world setup.
7
+
8
+ ## 1.4.2
9
+ * Upgrade winston to 1.1 ([#114](https://github.com/bithavoc/winston-middleware/issues/114))
10
+
11
+ ## 1.4.1
12
+ * Don't throw exception on invalid JSON in response body ([#112](https://github.com/bithavoc/winston-middleware/issues/112))
13
+
14
+ ## 1.4.0
15
+ * Allow custom log level for error logger ([#111](https://github.com/bithavoc/winston-middleware/pull/111))
16
+
17
+ ## 1.3.1
18
+ * underscore -> lodash ([#88](https://github.com/bithavoc/winston-middleware/issues/88))
19
+
20
+ ## 1.3.0
21
+ * Allow custom status levels ([#102](https://github.com/bithavoc/winston-middleware/pull/102))
22
+ * Add per-instance equivalents of all global white/blacklists ([#105](https://github.com/bithavoc/winston-middleware/pull/105))
23
+ * Allow user to override module-level whitelists and functions without having to worry about using the right object reference ([#92](https://github.com/bithavoc/winston-middleware/issues/92))
24
+
25
+ ## 1.2.0
26
+ * Add `baseMeta` and `metaField` options ([#91](https://github.com/bithavoc/winston-middleware/pull/91))
27
+ * Document `requestFilter` and `responseFilter` options
28
+ * Drop support for node 0.6 and 0.8
package/Readme.md CHANGED
@@ -5,13 +5,9 @@
5
5
 
6
6
  ## Installation
7
7
 
8
- Newcomers should start with the latest branch which makes use of winston 1.x.x and supports node >= 0.10:
8
+ npm install winston winston-middleware
9
9
 
10
- npm install winston-middleware
11
-
12
- If you're already using winston-middleware, and want to stick with the stable version based on winston 0.9.x, you should instead do:
13
-
14
- npm install winston-middleware@0.x.x --save
10
+ (supports node >= 0.10)
15
11
 
16
12
  ## Usage
17
13
 
@@ -25,8 +21,8 @@ In `package.json`:
25
21
  {
26
22
  "dependencies": {
27
23
  "...": "...",
28
- "winston": "0.6.x",
29
- "winston-middleware": "0.2.x",
24
+ "winston": "^2.0.0",
25
+ "winston-middleware": "^2.0.0",
30
26
  "...": "..."
31
27
  }
32
28
  }
@@ -55,8 +51,8 @@ Use `expressWinston.logger(options)` to create a middleware to log your HTTP req
55
51
  ],
56
52
  meta: true, // optional: control whether you want to log the meta data about the request (default to true)
57
53
  msg: "HTTP {{req.method}} {{req.url}}", // optional: customize the default logging message. E.g. "{{res.statusCode}} {{req.method}} {{res.responseTime}}ms {{req.url}}"
58
- expressFormat: true, // 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
59
- colorStatus: true, // Color the status code, using the Express/morgan color palette (default green, 3XX cyan, 4XX yellow, 5XX red). Will not be recognized if expressFormat is true
54
+ 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
55
+ colorize: true, // Color the text and status code, using the Express/morgan color palette (text: gray, status: default green, 3XX cyan, 4XX yellow, 5XX red).
60
56
  ignoreRoute: function (req, res) { return false; } // optional: allows to skip some log messages based on request and/or response
61
57
  }));
62
58
 
@@ -70,8 +66,8 @@ Use `expressWinston.logger(options)` to create a middleware to log your HTTP req
70
66
  winstonInstance: <WinstonLogger>, // a winston logger instance. If this is provided the transports option is ignored.
71
67
  level: String, // log level to use, the default is "info".
72
68
  msg: String // customize the default logging message. E.g. "{{res.statusCode}} {{req.method}} {{res.responseTime}}ms {{req.url}}", "HTTP {{req.method}} {{req.url}}".
73
- expressFormat: Boolean, // 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
74
- colorStatus: Boolean, // Color the status code, using the Express/morgan color palette (default green, 3XX cyan, 4XX yellow, 5XX red). Will not be recognized if expressFormat is true
69
+ 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
70
+ 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).
75
71
  meta: Boolean, // control whether you want to log the meta data about the request (default to true).
76
72
  baseMeta: Object, // default meta data to be added to log, this will be merged with the meta data.
77
73
  metaField: String, // if defined, the meta data will be added in this field instead of the meta root object.
@@ -118,6 +114,7 @@ The logger needs to be added AFTER the express router(`app.router)`) and BEFORE
118
114
  metaField: String, // if defined, the meta data will be added in this field instead of the meta root object.
119
115
  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.
120
116
  requestWhitelist: [String] // Array of request properties to log. Overrides global requestWhitelist for this instance
117
+ level: String // custom log level for errors (default is 'error')
121
118
  ```
122
119
 
123
120
  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)`.
package/index.js CHANGED
@@ -121,6 +121,7 @@ exports.errorLogger = function errorLogger(options) {
121
121
  options.msg = options.msg || 'middlewareError';
122
122
  options.baseMeta = options.baseMeta || {};
123
123
  options.metaField = options.metaField || null;
124
+ options.level = options.level || 'error';
124
125
 
125
126
  // Using mustache style templating
126
127
  var template = _.template(options.msg, {
@@ -139,10 +140,10 @@ exports.errorLogger = function errorLogger(options) {
139
140
  exceptionMeta = newMeta;
140
141
  }
141
142
 
142
- exceptionMeta = _.extend(exceptionMeta, options.baseMeta);
143
+ exceptionMeta = _.assign(exceptionMeta, options.baseMeta);
143
144
 
144
145
  // This is fire and forget, we don't want logging to hold up the request so don't wait for the callback
145
- options.winstonInstance.log('error', template({err: err, req: req, res: res}), exceptionMeta);
146
+ options.winstonInstance.log(options.level, template({err: err, req: req, res: res}), exceptionMeta);
146
147
 
147
148
  next(err);
148
149
  };
@@ -172,16 +173,11 @@ exports.logger = function logger(options) {
172
173
  options.msg = options.msg || "HTTP {{req.method}} {{req.url}}";
173
174
  options.baseMeta = options.baseMeta || {};
174
175
  options.metaField = options.metaField || null;
175
- options.colorStatus = options.colorStatus || false;
176
+ options.colorize = options.colorize || false;
176
177
  options.expressFormat = options.expressFormat || false;
177
178
  options.ignoreRoute = options.ignoreRoute || function () { return false; };
178
179
  options.skip = options.skip || exports.defaultSkip;
179
180
 
180
- // Using mustache style templating
181
- var template = _.template(options.msg, {
182
- interpolate: /\{\{(.+?)\}\}/g
183
- });
184
-
185
181
  return function (req, res, next) {
186
182
  var currentUrl = req.originalUrl || req.url;
187
183
  if (currentUrl && _.includes(options.ignoredRoutes, currentUrl)) return next();
@@ -215,15 +211,6 @@ exports.logger = function logger(options) {
215
211
  if (res.statusCode >= 500) { options.level = options.statusLevels.error || "error"; }
216
212
  };
217
213
 
218
- if (options.colorStatus || options.expressFormat) {
219
- // Palette from https://github.com/expressjs/morgan/blob/master/index.js#L205
220
- var statusColor = 'green';
221
- if (res.statusCode >= 500) statusColor = 'red';
222
- else if (res.statusCode >= 400) statusColor = 'yellow';
223
- else if (res.statusCode >= 300) statusColor = 'cyan';
224
- var coloredStatusCode = chalk[statusColor](res.statusCode);
225
- }
226
-
227
214
  var meta = {};
228
215
 
229
216
  if(options.meta !== false) {
@@ -239,7 +226,7 @@ exports.logger = function logger(options) {
239
226
  var isJson = (res._headers && res._headers['content-type']
240
227
  && res._headers['content-type'].indexOf('json') >= 0);
241
228
 
242
- logData.res.body = isJson ? JSON.parse(chunk) : chunk.toString();
229
+ logData.res.body = bodyToString(chunk, isJson);
243
230
  }
244
231
  }
245
232
 
@@ -269,18 +256,32 @@ exports.logger = function logger(options) {
269
256
  newMeta[options.metaField] = logData;
270
257
  logData = newMeta;
271
258
  }
272
- meta = _.extend(meta, logData);
259
+ meta = _.assign(meta, logData);
273
260
  }
274
261
 
275
- meta = _.extend(meta, options.baseMeta);
262
+ meta = _.assign(meta, options.baseMeta);
276
263
 
277
- if(options.expressFormat) {
278
- var msg = chalk.grey(req.method + " " + req.url || req.url)
279
- + " " + chalk[statusColor](res.statusCode)
280
- + " " + chalk.grey(res.responseTime+"ms");
281
- } else {
282
- var msg = template({req: req, res: res});
264
+ var expressMsgFormat = "{{req.method}} {{req.url}} {{res.statusCode}} {{res.responseTime}}ms";
265
+ if (options.colorize) {
266
+ // Palette from https://github.com/expressjs/morgan/blob/master/index.js#L205
267
+ var statusColor = 'green';
268
+ if (res.statusCode >= 500) statusColor = 'red';
269
+ else if (res.statusCode >= 400) statusColor = 'yellow';
270
+ else if (res.statusCode >= 300) statusColor = 'cyan';
271
+
272
+ expressMsgFormat = chalk.grey("{{req.method}} {{req.url}}") +
273
+ " " + chalk[statusColor]("{{res.statusCode}}") + " " +
274
+ chalk.grey("{{res.responseTime}}ms");
283
275
  }
276
+ var msgFormat = !options.expressFormat ? options.msg : expressMsgFormat;
277
+
278
+ // Using mustache style templating
279
+ var template = _.template(msgFormat, {
280
+ interpolate: /\{\{(.+?)\}\}/g
281
+ });
282
+
283
+ var msg = template({req: req, res: res});
284
+
284
285
  // This is fire and forget, we don't want logging to hold up the request so don't wait for the callback
285
286
  if (!options.skip(req, res)) {
286
287
  options.winstonInstance.log(options.level, msg, meta);
@@ -291,6 +292,22 @@ exports.logger = function logger(options) {
291
292
  };
292
293
  };
293
294
 
295
+ function safeJSONParse(string) {
296
+ try {
297
+ return JSON.parse(string);
298
+ } catch (e) {
299
+ return undefined;
300
+ }
301
+ }
302
+
303
+ function bodyToString(body, isJSON) {
304
+ var stringBody = body && body.toString();
305
+ if (isJSON) {
306
+ return (safeJSONParse(body) || stringBody);
307
+ }
308
+ return stringBody;
309
+ }
310
+
294
311
  function ensureValidOptions(options) {
295
312
  if(!options) throw new Error("options are required by winston-middleware middleware");
296
313
  if(!((options.transports && (options.transports.length > 0)) || options.winstonInstance))
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "middleware",
18
18
  "colors"
19
19
  ],
20
- "version": "1.3.1",
20
+ "version": "2.0.0",
21
21
  "repository": {
22
22
  "type": "git",
23
23
  "url": "https://github.com/bithavoc/winston-middleware.git"
@@ -48,8 +48,7 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "chalk": "~0.4.0",
51
- "lodash": "~4.11.1",
52
- "winston": "~1.0.0"
51
+ "lodash": "~4.11.1"
53
52
  },
54
53
  "devDependencies": {
55
54
  "blanket": "^1.2.2",
@@ -57,7 +56,11 @@
57
56
  "node-mocks-http": "^1.5.1",
58
57
  "promise": "^7.1.1",
59
58
  "should": "^8.2.2",
60
- "travis-cov": "^0.2.5"
59
+ "travis-cov": "^0.2.5",
60
+ "winston": ">=1.x"
61
+ },
62
+ "peerDependencies": {
63
+ "winston": ">=1.x"
61
64
  },
62
65
  "engines": {
63
66
  "node": ">=0.10.0"
package/test/test.js CHANGED
@@ -189,12 +189,19 @@ describe('winston-middleware', function () {
189
189
  });
190
190
  });
191
191
 
192
- it('should find an error level of "error"', function () {
192
+ it('should find the default level of "error"', function () {
193
193
  return errorLoggerTestHelper().then(function (result) {
194
194
  result.log.level.should.eql('error');
195
195
  });
196
196
  });
197
197
 
198
+ it('should find a custom level of "warn"', function () {
199
+ var testHelperOptions = {loggerOptions: {level:'warn'}};
200
+ return errorLoggerTestHelper(testHelperOptions).then(function (result) {
201
+ result.log.level.should.eql('warn');
202
+ });
203
+ });
204
+
198
205
  it('should find a message of "middlewareError"', function () {
199
206
  return errorLoggerTestHelper().then(function (result) {
200
207
  result.log.msg.should.eql('middlewareError');
@@ -528,6 +535,35 @@ describe('winston-middleware', function () {
528
535
  });
529
536
  });
530
537
 
538
+ describe('when middleware function is invoked on a route that returns JSON', function() {
539
+ it('should parse JSON in response body', function() {
540
+ var bodyObject = { "message": "Hi! I\'m a chunk!" };
541
+ function next(req, res, next) {
542
+ // Set Content-Type in a couple different case types, just in case.
543
+ // Seems like the mock response doesn't quite handle the case
544
+ // translation on these right.
545
+ res.setHeader('Content-Type', 'application/json');
546
+ res.setHeader('content-type', 'application/json');
547
+ res.end(JSON.stringify(bodyObject));
548
+ }
549
+ return loggerTestHelper({next: next}).then(function(result) {
550
+ result.log.meta.res.body.should.eql(bodyObject);
551
+ });
552
+ });
553
+
554
+ it('should not blow up when response body is invalid JSON', function() {
555
+ function next(req, res, next) {
556
+ // Set Content-Type in a couple different case types, just in case.
557
+ // Seems like the mock response doesn't quite handle the case
558
+ // translation on these right.
559
+ res.setHeader('Content-Type', 'application/json');
560
+ res.setHeader('content-type', 'application/json');
561
+ res.end('}');
562
+ }
563
+ return loggerTestHelper({next: next});
564
+ });
565
+ });
566
+
531
567
  describe('when middleware function is invoked on a route that should be ignored (by .ignoredRoutes)', function () {
532
568
  var testHelperOptions = {
533
569
  req: {url: '/ignored'}
@@ -550,6 +586,7 @@ describe('winston-middleware', function () {
550
586
  it('should match the Express format when logging', function () {
551
587
  var testHelperOptions = {
552
588
  loggerOptions: {
589
+ colorize: true,
553
590
  expressFormat: true
554
591
  },
555
592
  req: {
@@ -562,6 +599,40 @@ describe('winston-middleware', function () {
562
599
  resultMsg.should.endWith('ms\u001b[39m');
563
600
  });
564
601
  });
602
+
603
+ it('should not emit colors when colorize option is false', function() {
604
+ var testHelperOptions = {
605
+ loggerOptions: {
606
+ colorize: false,
607
+ expressFormat: true
608
+ },
609
+ req: {
610
+ url: '/all-the-things'
611
+ }
612
+ };
613
+ return loggerTestHelper(testHelperOptions).then(function (result) {
614
+ var resultMsg = result.log.msg;
615
+ resultMsg.should.startWith('GET /all-the-things 200 ');
616
+ resultMsg.should.endWith('ms');
617
+ });
618
+ });
619
+
620
+ it('should not emit colors when colorize option is not present', function() {
621
+ var testHelperOptions = {
622
+ loggerOptions: {
623
+ colorize: false,
624
+ expressFormat: true
625
+ },
626
+ req: {
627
+ url: '/all-the-things'
628
+ }
629
+ };
630
+ return loggerTestHelper(testHelperOptions).then(function (result) {
631
+ var resultMsg = result.log.msg;
632
+ resultMsg.should.startWith('GET /all-the-things 200 ');
633
+ resultMsg.should.endWith('ms');
634
+ });
635
+ });
565
636
  });
566
637
 
567
638
  describe('msg option', function () {