]> git.cworth.org Git - obsolete/notmuch-web/blob - node_modules/express/node_modules/connect/lib/middleware/logger.js
Install the "express" node module via npm
[obsolete/notmuch-web] / node_modules / express / node_modules / connect / lib / middleware / logger.js
1
2 /*!
3  * Connect - logger
4  * Copyright(c) 2010 Sencha Inc.
5  * Copyright(c) 2011 TJ Holowaychuk
6  * MIT Licensed
7  */
8
9 /**
10  * Log buffer.
11  */
12
13 var buf = [];
14
15 /**
16  * Default log buffer duration.
17  */
18
19 var defaultBufferDuration = 1000;
20
21 /**
22  * Log requests with the given `options` or a `format` string.
23  *
24  * Options:
25  *
26  *   - `format`  Format string, see below for tokens
27  *   - `stream`  Output stream, defaults to _stdout_
28  *   - `buffer`  Buffer duration, defaults to 1000ms when _true_
29  *
30  * Tokens:
31  *
32  *   - `:req[header]` ex: `:req[Accept]`
33  *   - `:res[header]` ex: `:res[Content-Length]`
34  *   - `:http-version`
35  *   - `:response-time`
36  *   - `:remote-addr`
37  *   - `:date`
38  *   - `:method`
39  *   - `:url`
40  *   - `:referrer`
41  *   - `:user-agent`
42  *   - `:status`
43  *
44  * @param {String|Function|Object} format or options
45  * @return {Function}
46  * @api public
47  */
48
49 module.exports = function logger(options) {
50   if ('object' == typeof options) {
51     options = options || {};
52   } else if (options) {
53     options = { format: options };
54   } else {
55     options = {};
56   }
57
58   var fmt = options.format
59     , stream = options.stream || process.stdout
60     , buffer = options.buffer;
61
62   // buffering support
63   if (buffer) {
64     var realStream = stream
65       , interval = 'number' == typeof buffer
66         ? buffer
67         : defaultBufferDuration;
68
69     // flush interval
70     setInterval(function(){
71       if (buf.length) {
72         realStream.write(buf.join(''), 'ascii');
73         buf.length = 0;
74       }
75     }, interval); 
76
77     // swap the stream
78     stream = {
79       write: function(str){
80         buf.push(str);
81       }
82     };
83   }
84
85   return function logger(req, res, next) {
86     var start = +new Date
87       , statusCode
88       , writeHead = res.writeHead
89       , end = res.end
90       , url = req.originalUrl;
91
92     // mount safety
93     if (req._logging) return next();
94
95     // flag as logging
96     req._logging = true;
97
98     // proxy for statusCode.
99     res.writeHead = function(code, headers){
100       res.writeHead = writeHead;
101       res.writeHead(code, headers);
102       res.__statusCode = statusCode = code;
103       res.__headers = headers || {};
104     };
105
106     // proxy end to output a line to the provided logger.
107     if (fmt) {
108       res.end = function(chunk, encoding) {
109         res.end = end;
110         res.end(chunk, encoding);
111         res.responseTime = +new Date - start;
112         if ('function' == typeof fmt) {
113           var line = fmt(req, res, function(str){ return format(str, req, res); });
114           if (line) stream.write(line + '\n', 'ascii');
115         } else {
116           stream.write(format(fmt, req, res) + '\n', 'ascii');
117         }
118       };
119     } else {
120       res.end = function(chunk, encoding) {
121         var contentLength = (res._headers && res._headers['content-length'])
122           || (res.__headers && res.__headers['Content-Length'])
123           || '-';
124
125         res.end = end;
126         res.end(chunk, encoding);
127
128         stream.write((req.socket && (req.socket.remoteAddress || (req.socket.socket && req.socket.socket.remoteAddress)))
129            + ' - - [' + (new Date).toUTCString() + ']'
130            + ' "' + req.method + ' ' + url
131            + ' HTTP/' + req.httpVersionMajor + '.' + req.httpVersionMinor + '" '
132            + (statusCode || res.statusCode) + ' ' + contentLength
133            + ' "' + (req.headers['referer'] || req.headers['referrer'] || '')
134            + '" "' + (req.headers['user-agent'] || '') + '"\n', 'ascii');
135       };
136     }
137
138     next();
139   };
140 };
141
142 /**
143  * Return formatted log line.
144  *
145  * @param  {String} str
146  * @param  {IncomingMessage} req
147  * @param  {ServerResponse} res
148  * @return {String}
149  * @api private
150  */
151  
152 function format(str, req, res) {
153   return str
154     .replace(':url', req.originalUrl)
155     .replace(':method', req.method)
156     .replace(':status', res.__statusCode || res.statusCode)
157     .replace(':response-time', res.responseTime)
158     .replace(':date', new Date().toUTCString())
159     .replace(':referrer', req.headers['referer'] || req.headers['referrer'] || '')
160     .replace(':http-version', req.httpVersionMajor + '.' + req.httpVersionMinor)
161     .replace(':remote-addr', req.socket && (req.socket.remoteAddress || (req.socket.socket && req.socket.socket.remoteAddress)))
162     .replace(':user-agent', req.headers['user-agent'] || '')
163     .replace(/:req\[([^\]]+)\]/g, function(_, field){ return req.headers[field.toLowerCase()]; })
164     .replace(/:res\[([^\]]+)\]/g, function(_, field){
165       return res._headers
166         ? (res._headers[field.toLowerCase()] || res.__headers[field])
167         : (res.__headers && res.__headers[field]);
168     });
169 }