winston-middleware 0.1.3 → 0.2.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.
- package/Readme.md +54 -7
- package/index.js +142 -59
- package/package.json +3 -4
- package/test/test.js +149 -8
package/Readme.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
## Usage
|
|
11
11
|
|
|
12
|
-
winston-middleware provides middlewares for request and error logging of your express.js application.
|
|
12
|
+
winston-middleware 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.
|
|
13
13
|
|
|
14
14
|
### Error Logging
|
|
15
15
|
|
|
@@ -53,9 +53,9 @@ Use `expressWinston.logger(options)` to create a middleware to log your HTTP req
|
|
|
53
53
|
app.use(app.router); // notice how the router goes after the logger.
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
##
|
|
56
|
+
## Examples
|
|
57
57
|
|
|
58
|
-
``` js
|
|
58
|
+
``` js
|
|
59
59
|
var express = require('express');
|
|
60
60
|
var expressWinston = require('winston-middleware');
|
|
61
61
|
var winston = require('winston'); // for transports.Console
|
|
@@ -127,9 +127,13 @@ Browse `/` to see a regular HTTP logging like this:
|
|
|
127
127
|
"originalUrl": "/",
|
|
128
128
|
"query": {}
|
|
129
129
|
},
|
|
130
|
+
"res": {
|
|
131
|
+
"statusCode": 200
|
|
132
|
+
},
|
|
133
|
+
"responseTime" : 12,
|
|
130
134
|
"level": "info",
|
|
131
135
|
"message": "HTTP GET /favicon.ico"
|
|
132
|
-
}
|
|
136
|
+
}
|
|
133
137
|
|
|
134
138
|
Browse `/error` will show you how winston-middleware handles and logs the errors in the express pipeline like this:
|
|
135
139
|
|
|
@@ -206,13 +210,55 @@ Browse `/error` will show you how winston-middleware handles and logs the errors
|
|
|
206
210
|
"message": "middlewareError"
|
|
207
211
|
}
|
|
208
212
|
|
|
213
|
+
## Whitelists
|
|
214
|
+
New in version 0.2.x is the ability to add whitelist elements in a route. winston-middleware adds a `_routeWhitelists` object to the `req`uest, 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:
|
|
215
|
+
|
|
216
|
+
``` js
|
|
217
|
+
app.post('/user/register', function(req, res, next) {
|
|
218
|
+
req._routeWhitelists.body = ['username', 'email', 'age']; // But not 'password' or 'confirm-password' or 'top-secret'
|
|
219
|
+
req._routeWhitelists.res = ['_headers'];
|
|
220
|
+
});
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Post to `/user/register` would give you something like the following:
|
|
224
|
+
|
|
225
|
+
{
|
|
226
|
+
"req": {
|
|
227
|
+
"httpVersion": "1.1",
|
|
228
|
+
"headers": {
|
|
229
|
+
"host": "localhost:3000",
|
|
230
|
+
"connection": "keep-alive",
|
|
231
|
+
"accept": "*/*",
|
|
232
|
+
"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",
|
|
233
|
+
"accept-encoding": "gzip,deflate,sdch",
|
|
234
|
+
"accept-language": "en-US,en;q=0.8,es-419;q=0.6,es;q=0.4",
|
|
235
|
+
"accept-charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.3",
|
|
236
|
+
"cookie": "connect.sid=nGspCCSzH1qxwNTWYAoexI23.seE%2B6Whmcwd"
|
|
237
|
+
},
|
|
238
|
+
"url": "/",
|
|
239
|
+
"method": "GET",
|
|
240
|
+
"originalUrl": "/",
|
|
241
|
+
"query": {},
|
|
242
|
+
"body": {
|
|
243
|
+
"username": "foo",
|
|
244
|
+
"email": "foo@bar.com",
|
|
245
|
+
"age": "72"
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
"res": {
|
|
249
|
+
"statusCode": 200
|
|
250
|
+
},
|
|
251
|
+
"responseTime" : 12,
|
|
252
|
+
"level": "info",
|
|
253
|
+
"message": "HTTP GET /favicon.ico"
|
|
254
|
+
}
|
|
255
|
+
|
|
209
256
|
## Tests
|
|
210
257
|
|
|
211
258
|
npm test
|
|
212
259
|
|
|
213
260
|
## Issues and Collaboration
|
|
214
261
|
|
|
215
|
-
* Add support for filtering of __req.body__. At this moment `body` is not included in the logging because it can contain sensitive fields like 'password' or 'password_confirmation'.
|
|
216
262
|
* Implement a chain of requestFilters. Currently only one requestFilter is allowed in the options.
|
|
217
263
|
|
|
218
264
|
We are accepting pull-request for these features.
|
|
@@ -221,8 +267,9 @@ If you ran into any problems, please use the project [Issues section](https://gi
|
|
|
221
267
|
|
|
222
268
|
## Contributors
|
|
223
269
|
|
|
224
|
-
* [Johan Hernandez](https://github.com/thepumpkin1979)
|
|
225
|
-
* [Lars Jacob](
|
|
270
|
+
* [Johan Hernandez](https://github.com/thepumpkin1979) (https://github.com/thepumpkin1979)
|
|
271
|
+
* [Lars Jacob](https://github.com/jaclar) (https://github.com/jaclar)
|
|
272
|
+
* [Jonathan Lomas](https://github.com/floatingLomas) (https://github.com/floatingLomas)
|
|
226
273
|
|
|
227
274
|
## MIT License
|
|
228
275
|
|
package/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
// Copyright (c) 2012 Firebase.co and Contributors - http://www.firebase.co
|
|
2
|
-
//
|
|
2
|
+
//
|
|
3
3
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
4
|
// of this software and associated documentation files (the "Software"), to deal
|
|
5
5
|
// in the Software without restriction, including without limitation the rights
|
|
6
6
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
7
|
// copies of the Software, and to permit persons to whom the Software is
|
|
8
8
|
// furnished to do so, subject to the following conditions:
|
|
9
|
-
//
|
|
9
|
+
//
|
|
10
10
|
// The above copyright notice and this permission notice shall be included in
|
|
11
11
|
// all copies or substantial portions of the Software.
|
|
12
|
-
//
|
|
12
|
+
//
|
|
13
13
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
14
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
15
|
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
|
@@ -18,88 +18,171 @@
|
|
|
18
18
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
19
|
// THE SOFTWARE.
|
|
20
20
|
//
|
|
21
|
-
|
|
22
21
|
var winston = require('winston');
|
|
23
|
-
var async = require('async');
|
|
24
22
|
var util = require('util');
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
/**
|
|
25
|
+
* A default list of properties in the request object that are allowed to be logged.
|
|
26
|
+
* These properties will be safely included in the meta of the log.
|
|
27
|
+
* 'body' is not included in this list because it can contains passwords and stuff that are sensitive for logging.
|
|
28
|
+
* TODO: Include 'body' and get the defaultRequestFilter to filter the inner properties like 'password' or 'password_confirmation', etc. Pull requests anyone?
|
|
29
|
+
* @type {Array}
|
|
30
|
+
*/
|
|
30
31
|
var requestWhitelist = ['url', 'headers', 'method', 'httpVersion', 'originalUrl', 'query'];
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
/**
|
|
34
|
+
* A default list of properties in the request body that are allowed to be logged.
|
|
35
|
+
* This will normally be empty here, since it should be done at the route level.
|
|
36
|
+
* @type {Array}
|
|
37
|
+
*/
|
|
38
|
+
var bodyWhitelist = [];
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* A default list of properties in the response object that are allowed to be logged.
|
|
42
|
+
* These properties will be safely included in the meta of the log.
|
|
43
|
+
* @type {Array}
|
|
44
|
+
*/
|
|
45
|
+
var responseWhitelist = ['statusCode'];
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* A default function to filter the properties of the req object.
|
|
49
|
+
* @param req
|
|
50
|
+
* @param propName
|
|
51
|
+
* @return {*}
|
|
52
|
+
*/
|
|
53
|
+
var defaultRequestFilter = function (req, propName) {
|
|
54
|
+
return req[propName];
|
|
35
55
|
};
|
|
36
56
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
return req;
|
|
57
|
+
/**
|
|
58
|
+
* A default function to filter the properties of the res object.
|
|
59
|
+
* @param res
|
|
60
|
+
* @param propName
|
|
61
|
+
* @return {*}
|
|
62
|
+
*/
|
|
63
|
+
var defaultResponseFilter = function (req, propName) {
|
|
64
|
+
return req[propName];
|
|
48
65
|
};
|
|
49
66
|
|
|
50
|
-
|
|
67
|
+
function filterObject(originalObj, whiteList, initialFilter) {
|
|
68
|
+
|
|
69
|
+
var obj = {};
|
|
70
|
+
|
|
71
|
+
[].concat(whiteList).forEach(function (propName) {
|
|
72
|
+
var value = initialFilter(originalObj, propName);
|
|
73
|
+
|
|
74
|
+
if(typeof (value) !== 'undefined') {
|
|
75
|
+
obj[propName] = value;
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
return obj;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
//
|
|
51
83
|
// ### function errorLogger(options)
|
|
52
84
|
// #### @options {Object} options to initialize the middleware.
|
|
53
85
|
//
|
|
86
|
+
|
|
87
|
+
|
|
54
88
|
function errorLogger(options) {
|
|
55
|
-
if(!options) throw new Error("options are required by winston-middleware middleware");
|
|
56
|
-
if(!options.transports || !(options.transports.length > 0)) throw new Error("transports are required by winston-middleware middleware");
|
|
57
|
-
options.requestFilter = options.requestFilter || defaultRequestFilter;
|
|
58
|
-
return function(err, req, res, next) {
|
|
59
|
-
// let winston gather all the error data.
|
|
60
|
-
var exceptionMeta = winston.exception.getAllInfo(err);
|
|
61
|
-
exceptionMeta.req = filterRequest(req, options.requestFilter);
|
|
62
|
-
|
|
63
|
-
function logOnTransport(transport, nextTransport) {
|
|
64
|
-
return transport.logException('middlewareError', exceptionMeta, nextTransport);
|
|
65
|
-
};
|
|
66
89
|
|
|
67
|
-
|
|
68
|
-
|
|
90
|
+
ensureValidOptions(options);
|
|
91
|
+
|
|
92
|
+
options.requestFilter = options.requestFilter || defaultRequestFilter;
|
|
93
|
+
|
|
94
|
+
return function (err, req, res, next) {
|
|
95
|
+
|
|
96
|
+
// Let winston gather all the error data.
|
|
97
|
+
var exceptionMeta = winston.exception.getAllInfo(err);
|
|
98
|
+
exceptionMeta.req = filterObject(req, requestWhitelist, options.requestFilter);
|
|
99
|
+
|
|
100
|
+
// This is fire and forget, we don't want logging to hold up the request so don't wait for the callback
|
|
101
|
+
for(var i = 0; i < options.transports.length; i++) {
|
|
102
|
+
var transport = options.transports[i];
|
|
103
|
+
transport.logException('middlewareError', exceptionMeta, function () {
|
|
104
|
+
// Nothing to do here
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
next(err);
|
|
69
109
|
};
|
|
70
|
-
|
|
71
|
-
async.forEach(options.transports, logOnTransport, done);
|
|
72
|
-
};
|
|
73
|
-
};
|
|
110
|
+
}
|
|
74
111
|
|
|
75
|
-
//
|
|
112
|
+
//
|
|
76
113
|
// ### function logger(options)
|
|
77
114
|
// #### @options {Object} options to initialize the middleware.
|
|
78
115
|
//
|
|
116
|
+
|
|
117
|
+
|
|
79
118
|
function logger(options) {
|
|
80
|
-
if(!options) throw new Error("options are required by winston-middleware middleware");
|
|
81
|
-
if(!options.transports || !(options.transports.length > 0)) throw new Error("transports are required by winston-middleware middleware");
|
|
82
|
-
options.requestFilter = options.requestFilter || defaultRequestFilter;
|
|
83
|
-
options.level = options.level || "info";
|
|
84
|
-
return function(req, res, next) {
|
|
85
|
-
var meta = {
|
|
86
|
-
req: filterRequest(req, options.requestFilter)
|
|
87
|
-
};
|
|
88
|
-
var msg = util.format("HTTP %s %s", req.method, req.url);
|
|
89
119
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
120
|
+
ensureValidOptions(options);
|
|
121
|
+
|
|
122
|
+
options.requestFilter = options.requestFilter || defaultRequestFilter;
|
|
123
|
+
options.responseFilter = options.responseFilter || defaultResponseFilter;
|
|
124
|
+
options.level = options.level || "info";
|
|
125
|
+
|
|
126
|
+
return function (req, res, next) {
|
|
127
|
+
|
|
128
|
+
req._startTime = (new Date);
|
|
129
|
+
|
|
130
|
+
req._routeWhitelists = {
|
|
131
|
+
req: [],
|
|
132
|
+
res: [],
|
|
133
|
+
body: []
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// Manage to get information from the response too, just like Connect.logger does:
|
|
137
|
+
var end = res.end;
|
|
138
|
+
res.end = function(chunk, encoding) {
|
|
139
|
+
var responseTime = (new Date) - req._startTime;
|
|
140
|
+
|
|
141
|
+
res.end = end;
|
|
142
|
+
res.end(chunk, encoding);
|
|
93
143
|
|
|
94
|
-
|
|
95
|
-
|
|
144
|
+
var meta = {};
|
|
145
|
+
|
|
146
|
+
var bodyWhitelist;
|
|
147
|
+
|
|
148
|
+
requestWhitelist = requestWhitelist.concat(req._routeWhitelists.req || []);
|
|
149
|
+
responseWhitelist = responseWhitelist.concat(req._routeWhitelists.res || []);
|
|
150
|
+
|
|
151
|
+
meta.req = filterObject(req, requestWhitelist, options.requestFilter);
|
|
152
|
+
meta.res = filterObject(res, responseWhitelist, options.responseFilter);
|
|
153
|
+
|
|
154
|
+
bodyWhitelist = req._routeWhitelists.body || [];
|
|
155
|
+
|
|
156
|
+
if (bodyWhitelist) {
|
|
157
|
+
meta.req.body = filterObject(req.body, bodyWhitelist, options.requestFilter);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
meta.responseTime = responseTime;
|
|
161
|
+
|
|
162
|
+
var msg = util.format("HTTP %s %s", req.method, req.url);
|
|
163
|
+
|
|
164
|
+
// This is fire and forget, we don't want logging to hold up the request so don't wait for the callback
|
|
165
|
+
for(var i = 0; i < options.transports.length; i++) {
|
|
166
|
+
var transport = options.transports[i];
|
|
167
|
+
transport.log(options.level, msg, meta, function () {
|
|
168
|
+
// Nothing to do here
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
next();
|
|
96
174
|
};
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function ensureValidOptions(options) {
|
|
178
|
+
if(!options) throw new Error("options are required by winston-middleware middleware");
|
|
179
|
+
if(!options.transports || !(options.transports.length > 0)) throw new Error("transports are required by winston-middleware middleware");
|
|
100
180
|
};
|
|
101
181
|
|
|
102
182
|
module.exports.errorLogger = errorLogger;
|
|
103
183
|
module.exports.logger = logger;
|
|
104
184
|
module.exports.requestWhitelist = requestWhitelist;
|
|
185
|
+
module.exports.bodyWhitelist = bodyWhitelist;
|
|
186
|
+
module.exports.responseWhitelist = responseWhitelist;
|
|
105
187
|
module.exports.defaultRequestFilter = defaultRequestFilter;
|
|
188
|
+
module.exports.defaultResponseFilter = defaultResponseFilter;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "winston-middleware",
|
|
4
4
|
"description": "express.js middleware for flatiron/winston",
|
|
5
5
|
"keywords": ["winston", "flatiron", "logging", "express", "log", "error", "handler", "middleware"],
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.2.0",
|
|
7
7
|
"repository": {
|
|
8
8
|
"url": "https://github.com/firebaseco/winston-middleware.git"
|
|
9
9
|
},
|
|
@@ -12,8 +12,7 @@
|
|
|
12
12
|
"test": "node test/test.js"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"winston": "0.6.x"
|
|
16
|
-
"async": "0.1.x"
|
|
15
|
+
"winston": "0.6.x"
|
|
17
16
|
},
|
|
18
17
|
"devDependencies": {
|
|
19
18
|
"vows": "0.6.x"
|
|
@@ -23,7 +22,7 @@
|
|
|
23
22
|
},
|
|
24
23
|
"licenses" : [
|
|
25
24
|
{
|
|
26
|
-
"type" : "MIT",
|
|
25
|
+
"type" : "MIT",
|
|
27
26
|
"url" : "https://github.com/firebaseco/winston-middleware/blob/master/LICENSE"
|
|
28
27
|
}
|
|
29
28
|
]
|
package/test/test.js
CHANGED
|
@@ -15,12 +15,21 @@ vows.describe("exports").addBatch({
|
|
|
15
15
|
topic: function() {
|
|
16
16
|
return expressWinston;
|
|
17
17
|
},
|
|
18
|
-
"an array with all the properties
|
|
18
|
+
"an array with all the properties whitelisted in the req object": function(exports) {
|
|
19
19
|
assert.isArray(exports.requestWhitelist);
|
|
20
20
|
},
|
|
21
|
+
"an array with all the properties whitelisted in the res object": function(exports) {
|
|
22
|
+
assert.isArray(exports.responseWhitelist);
|
|
23
|
+
},
|
|
24
|
+
"an array with all the properties whitelisted in the body object": function(exports) {
|
|
25
|
+
assert.isArray(exports.bodyWhitelist);
|
|
26
|
+
},
|
|
21
27
|
"and the factory should contain a default request filter function": function(exports) {
|
|
22
28
|
assert.isFunction(exports.defaultRequestFilter);
|
|
23
29
|
},
|
|
30
|
+
"and the factory should contain a default response filter function": function(exports) {
|
|
31
|
+
assert.isFunction(exports.defaultResponseFilter);
|
|
32
|
+
},
|
|
24
33
|
"it should export a function for the creation of error loggers middlewares": function(exports) {
|
|
25
34
|
assert.isFunction(exports.errorLogger);
|
|
26
35
|
},
|
|
@@ -61,7 +70,7 @@ vows.describe("errorLogger").addBatch({
|
|
|
61
70
|
var middleware = factory({
|
|
62
71
|
transports: [
|
|
63
72
|
new MockTransport({
|
|
64
|
-
|
|
73
|
+
|
|
65
74
|
})
|
|
66
75
|
]
|
|
67
76
|
});
|
|
@@ -86,7 +95,7 @@ vows.describe("errorLogger").addBatch({
|
|
|
86
95
|
params: {
|
|
87
96
|
id: 20
|
|
88
97
|
},
|
|
89
|
-
|
|
98
|
+
nonWhitelistedProperty: "value that should not be logged"
|
|
90
99
|
};
|
|
91
100
|
var res = {
|
|
92
101
|
|
|
@@ -134,7 +143,7 @@ vows.describe("errorLogger").addBatch({
|
|
|
134
143
|
assert.deepEqual(result.log.meta.req.query, {
|
|
135
144
|
val: '1'
|
|
136
145
|
});
|
|
137
|
-
assert.isUndefined(result.log.meta.req.
|
|
146
|
+
assert.isUndefined(result.log.meta.req.nonWhitelistedProperty);
|
|
138
147
|
},
|
|
139
148
|
"the winston-middleware middleware should not swallow the pipeline error": function(result) {
|
|
140
149
|
assert.isNotNull(result.pipelineError);
|
|
@@ -143,7 +152,7 @@ vows.describe("errorLogger").addBatch({
|
|
|
143
152
|
}
|
|
144
153
|
}).export(module);
|
|
145
154
|
|
|
146
|
-
vows.describe("logger").addBatch({
|
|
155
|
+
vows.describe("logger 0.1.x").addBatch({
|
|
147
156
|
"when I run the middleware factory": {
|
|
148
157
|
topic: function() {
|
|
149
158
|
return expressWinston.logger;
|
|
@@ -174,7 +183,7 @@ vows.describe("logger").addBatch({
|
|
|
174
183
|
var middleware = factory({
|
|
175
184
|
transports: [
|
|
176
185
|
new MockTransport({
|
|
177
|
-
|
|
186
|
+
|
|
178
187
|
})
|
|
179
188
|
]
|
|
180
189
|
});
|
|
@@ -202,14 +211,15 @@ vows.describe("logger").addBatch({
|
|
|
202
211
|
filteredProperty: "value that should not be logged"
|
|
203
212
|
};
|
|
204
213
|
var res = {
|
|
205
|
-
|
|
214
|
+
end: function(chunk, encoding) {}
|
|
206
215
|
};
|
|
207
216
|
var test = {
|
|
208
217
|
req: req,
|
|
209
218
|
res: res,
|
|
210
219
|
log: {}
|
|
211
220
|
};
|
|
212
|
-
var next = function() {
|
|
221
|
+
var next = function(_req, _res, next) {
|
|
222
|
+
res.end();
|
|
213
223
|
return callback(null, test);
|
|
214
224
|
};
|
|
215
225
|
|
|
@@ -241,3 +251,134 @@ vows.describe("logger").addBatch({
|
|
|
241
251
|
}
|
|
242
252
|
}
|
|
243
253
|
}).export(module);
|
|
254
|
+
|
|
255
|
+
vows.describe("logger 0.2.x").addBatch({
|
|
256
|
+
"when I run the middleware factory": {
|
|
257
|
+
topic: function() {
|
|
258
|
+
return expressWinston.logger;
|
|
259
|
+
},
|
|
260
|
+
"without options": {
|
|
261
|
+
"an error should be raised": function(factory) {
|
|
262
|
+
assert.throws(function() {
|
|
263
|
+
factory();
|
|
264
|
+
}, Error);
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
"without any transport specified": {
|
|
268
|
+
"an error should be raised": function(factory) {
|
|
269
|
+
assert.throws(function() {
|
|
270
|
+
factory({});
|
|
271
|
+
}, Error);
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
"with an empty list of transports": {
|
|
275
|
+
"an error should be raised": function(factory) {
|
|
276
|
+
assert.throws(function() {
|
|
277
|
+
factory({transports:[]});
|
|
278
|
+
}, Error);
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
"with proper options": {
|
|
282
|
+
"the result should be a function with three arguments that fit req, res, next": function (factory) {
|
|
283
|
+
var middleware = factory({
|
|
284
|
+
transports: [
|
|
285
|
+
new MockTransport({
|
|
286
|
+
|
|
287
|
+
})
|
|
288
|
+
]
|
|
289
|
+
});
|
|
290
|
+
assert.equal(middleware.length, 3);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
"When the winston-middleware middleware is invoked in pipeline": {
|
|
295
|
+
topic: function() {
|
|
296
|
+
var factory = expressWinston.logger;
|
|
297
|
+
var callback = this.callback;
|
|
298
|
+
var req = {
|
|
299
|
+
url: "/hello?val=1",
|
|
300
|
+
headers: {
|
|
301
|
+
'header-1': 'value 1'
|
|
302
|
+
},
|
|
303
|
+
method: 'GET',
|
|
304
|
+
query: {
|
|
305
|
+
val: '2'
|
|
306
|
+
},
|
|
307
|
+
originalUrl: "/hello?val=2",
|
|
308
|
+
params: {
|
|
309
|
+
id: 20
|
|
310
|
+
},
|
|
311
|
+
nonWhitelistedProperty: "value that should not be logged",
|
|
312
|
+
routeLevelAddedProperty: "value that should be logged",
|
|
313
|
+
body: {
|
|
314
|
+
username: 'bobby',
|
|
315
|
+
password: 'top-secret'
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
var res = {
|
|
319
|
+
statusCode: 200,
|
|
320
|
+
nonWhitelistedProperty: "value that should not be logged",
|
|
321
|
+
routeLevelAddedProperty: "value that should be logged",
|
|
322
|
+
end: function(chunk, encoding) {
|
|
323
|
+
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
var test = {
|
|
327
|
+
req: req,
|
|
328
|
+
res: res,
|
|
329
|
+
log: {}
|
|
330
|
+
};
|
|
331
|
+
var next = function(_req, _res, next) {
|
|
332
|
+
req._startTime = (new Date) - 125;
|
|
333
|
+
|
|
334
|
+
req._routeWhitelists.req = [ 'routeLevelAddedProperty' ];
|
|
335
|
+
req._routeWhitelists.body = [ 'username' ];
|
|
336
|
+
|
|
337
|
+
res.end();
|
|
338
|
+
return callback(null, test);
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
var transport = new MockTransport({});
|
|
342
|
+
transport.log = function(level, msg, meta, cb) {
|
|
343
|
+
test.transportInvoked = true;
|
|
344
|
+
test.log.level = level;
|
|
345
|
+
test.log.msg = msg;
|
|
346
|
+
test.log.meta = meta;
|
|
347
|
+
this.emit('logged');
|
|
348
|
+
return cb();
|
|
349
|
+
};
|
|
350
|
+
var middleware = factory({
|
|
351
|
+
transports: [transport]
|
|
352
|
+
});
|
|
353
|
+
middleware(req, res, next);
|
|
354
|
+
}
|
|
355
|
+
, "then the transport should be invoked": function(result){
|
|
356
|
+
assert.isTrue(result.transportInvoked);
|
|
357
|
+
}
|
|
358
|
+
, "the meta should contain a filtered request": function(result){
|
|
359
|
+
assert.isTrue(!!result.log.meta.req, "req should be defined in meta");
|
|
360
|
+
assert.isNotNull(result.log.meta.req);
|
|
361
|
+
assert.equal(result.log.meta.req.method, "GET");
|
|
362
|
+
assert.deepEqual(result.log.meta.req.query, { val: '2' });
|
|
363
|
+
assert.isUndefined(result.log.meta.req.nonWhitelistedProperty);
|
|
364
|
+
|
|
365
|
+
assert.isNotNull(result.log.meta.req.routeLevelAddedProperty);
|
|
366
|
+
}
|
|
367
|
+
, "the meta should contain a filtered request body": function(result) {
|
|
368
|
+
assert.deepEqual(result.log.meta.req.body, {username: 'bobby'});
|
|
369
|
+
assert.isUndefined(result.log.meta.req.body.password);
|
|
370
|
+
}
|
|
371
|
+
, "the meta should contain a filtered response": function(result){
|
|
372
|
+
assert.isTrue(!!result.log.meta.res, "res should be defined in meta");
|
|
373
|
+
assert.isNotNull(result.log.meta.res);
|
|
374
|
+
assert.equal(result.log.meta.res.statusCode, 200);
|
|
375
|
+
assert.isNotNull(result.log.meta.res.routeLevelAddedProperty);
|
|
376
|
+
}
|
|
377
|
+
, "the meta should contain a response time": function(result){
|
|
378
|
+
assert.isTrue(!!result.log.meta.responseTime, "responseTime should be defined in meta");
|
|
379
|
+
assert.isNotNull(result.log.meta.responseTime);
|
|
380
|
+
assert.isTrue(result.log.meta.responseTime > 120);
|
|
381
|
+
assert.isTrue(result.log.meta.responseTime < 130);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}).export(module);
|