raspberryGPIOhtmlserver/node_modules/connect/lib/middleware/logger.js
node_modules/connect/lib/middleware/logger.jsRaw
1/*!
2 * Connect - logger
3 * Copyright(c) 2010 Sencha Inc.
4 * Copyright(c) 2011 TJ Holowaychuk
5 * MIT Licensed
6 */
7
8/**
9 * Module dependencies.
10 */
11
12var bytes = require('bytes');
13
14/*!
15 * Log buffer.
16 */
17
18var buf = [];
19
20/*!
21 * Default log buffer duration.
22 */
23
24var defaultBufferDuration = 1000;
25
26/**
27 * Logger:
28 *
29 * Log requests with the given `options` or a `format` string.
30 *
31 * Options:
32 *
33 * - `format` Format string, see below for tokens
34 * - `stream` Output stream, defaults to _stdout_
35 * - `buffer` Buffer duration, defaults to 1000ms when _true_
36 * - `immediate` Write log line on request instead of response (for response times)
37 *
38 * Tokens:
39 *
40 * - `:req[header]` ex: `:req[Accept]`
41 * - `:res[header]` ex: `:res[Content-Length]`
42 * - `:http-version`
43 * - `:response-time`
44 * - `:remote-addr`
45 * - `:date`
46 * - `:method`
47 * - `:url`
48 * - `:referrer`
49 * - `:user-agent`
50 * - `:status`
51 *
52 * Formats:
53 *
54 * Pre-defined formats that ship with connect:
55 *
56 * - `default` ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"'
57 * - `short` ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms'
58 * - `tiny` ':method :url :status :res[content-length] - :response-time ms'
59 * - `dev` concise output colored by response status for development use
60 *
61 * Examples:
62 *
63 * connect.logger() // default
64 * connect.logger('short')
65 * connect.logger('tiny')
66 * connect.logger({ immediate: true, format: 'dev' })
67 * connect.logger(':method :url - :referrer')
68 * connect.logger(':req[content-type] -> :res[content-type]')
69 * connect.logger(function(tokens, req, res){ return 'some format string' })
70 *
71 * Defining Tokens:
72 *
73 * To define a token, simply invoke `connect.logger.token()` with the
74 * name and a callback function. The value returned is then available
75 * as ":type" in this case.
76 *
77 * connect.logger.token('type', function(req, res){ return req.headers['content-type']; })
78 *
79 * Defining Formats:
80 *
81 * All default formats are defined this way, however it's public API as well:
82 *
83 * connect.logger.format('name', 'string or function')
84 *
85 * @param {String|Function|Object} format or options
86 * @return {Function}
87 * @api public
88 */
89
90exports = module.exports = function logger(options) {
91 if ('object' == typeof options) {
92 options = options || {};
93 } else if (options) {
94 options = { format: options };
95 } else {
96 options = {};
97 }
98
99 // output on request instead of response
100 var immediate = options.immediate;
101
102 // format name
103 var fmt = exports[options.format] || options.format || exports.default;
104
105 // compile format
106 if ('function' != typeof fmt) fmt = compile(fmt);
107
108 // options
109 var stream = options.stream || process.stdout
110 , buffer = options.buffer;
111
112 // buffering support
113 if (buffer) {
114 var realStream = stream
115 , interval = 'number' == typeof buffer
116 ? buffer
117 : defaultBufferDuration;
118
119 // flush interval
120 setInterval(function(){
121 if (buf.length) {
122 realStream.write(buf.join(''));
123 buf.length = 0;
124 }
125 }, interval);
126
127 // swap the stream
128 stream = {
129 write: function(str){
130 buf.push(str);
131 }
132 };
133 }
134
135 return function logger(req, res, next) {
136 req._startTime = new Date;
137
138 // immediate
139 if (immediate) {
140 var line = fmt(exports, req, res);
141 if (null == line) return;
142 stream.write(line + '\n');
143 // proxy end to output logging
144 } else {
145 var end = res.end;
146 res.end = function(chunk, encoding){
147 res.end = end;
148 res.end(chunk, encoding);
149 var line = fmt(exports, req, res);
150 if (null == line) return;
151 stream.write(line + '\n');
152 };
153 }
154
155
156 next();
157 };
158};
159
160/**
161 * Compile `fmt` into a function.
162 *
163 * @param {String} fmt
164 * @return {Function}
165 * @api private
166 */
167
168function compile(fmt) {
169 fmt = fmt.replace(/"/g, '\\"');
170 var js = ' return "' + fmt.replace(/:([-\w]{2,})(?:\[([^\]]+)\])?/g, function(_, name, arg){
171 return '"\n + (tokens["' + name + '"](req, res, "' + arg + '") || "-") + "';
172 }) + '";'
173 return new Function('tokens, req, res', js);
174};
175
176/**
177 * Define a token function with the given `name`,
178 * and callback `fn(req, res)`.
179 *
180 * @param {String} name
181 * @param {Function} fn
182 * @return {Object} exports for chaining
183 * @api public
184 */
185
186exports.token = function(name, fn) {
187 exports[name] = fn;
188 return this;
189};
190
191/**
192 * Define a `fmt` with the given `name`.
193 *
194 * @param {String} name
195 * @param {String|Function} fmt
196 * @return {Object} exports for chaining
197 * @api public
198 */
199
200exports.format = function(name, str){
201 exports[name] = str;
202 return this;
203};
204
205/**
206 * Default format.
207 */
208
209exports.format('default', ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"');
210
211/**
212 * Short format.
213 */
214
215exports.format('short', ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms');
216
217/**
218 * Tiny format.
219 */
220
221exports.format('tiny', ':method :url :status :res[content-length] - :response-time ms');
222
223/**
224 * dev (colored)
225 */
226
227exports.format('dev', function(tokens, req, res){
228 var status = res.statusCode
229 , len = parseInt(res.getHeader('Content-Length'), 10)
230 , color = 32;
231
232 if (status >= 500) color = 31
233 else if (status >= 400) color = 33
234 else if (status >= 300) color = 36;
235
236 len = isNaN(len)
237 ? ''
238 : len = ' - ' + bytes(len);
239
240 return '\033[90m' + req.method
241 + ' ' + req.originalUrl + ' '
242 + '\033[' + color + 'm' + res.statusCode
243 + ' \033[90m'
244 + (new Date - req._startTime)
245 + 'ms' + len
246 + '\033[0m';
247});
248
249/**
250 * request url
251 */
252
253exports.token('url', function(req){
254 return req.originalUrl || req.url;
255});
256
257/**
258 * request method
259 */
260
261exports.token('method', function(req){
262 return req.method;
263});
264
265/**
266 * response time in milliseconds
267 */
268
269exports.token('response-time', function(req){
270 return new Date - req._startTime;
271});
272
273/**
274 * UTC date
275 */
276
277exports.token('date', function(){
278 return new Date().toUTCString();
279});
280
281/**
282 * response status code
283 */
284
285exports.token('status', function(req, res){
286 return res.statusCode;
287});
288
289/**
290 * normalized referrer
291 */
292
293exports.token('referrer', function(req){
294 return req.headers['referer'] || req.headers['referrer'];
295});
296
297/**
298 * remote address
299 */
300
301exports.token('remote-addr', function(req){
302 if (req.ip) return req.ip;
303 var sock = req.socket;
304 if (sock.socket) return sock.socket.remoteAddress;
305 return sock.remoteAddress;
306});
307
308/**
309 * HTTP version
310 */
311
312exports.token('http-version', function(req){
313 return req.httpVersionMajor + '.' + req.httpVersionMinor;
314});
315
316/**
317 * UA string
318 */
319
320exports.token('user-agent', function(req){
321 return req.headers['user-agent'];
322});
323
324/**
325 * request header
326 */
327
328exports.token('req', function(req, res, field){
329 return req.headers[field.toLowerCase()];
330});
331
332/**
333 * response header
334 */
335
336exports.token('res', function(req, res, field){
337 return (res._headers || {})[field.toLowerCase()];
338});
339