arnaucube
arnaucube/raspberryGPIOhtmlserverPublic Self-hosted repository
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