1 | # morgan
|
2 |
|
3 | [![NPM Version][npm-version-image]][npm-url]
|
4 | [![NPM Downloads][npm-downloads-image]][npm-url]
|
5 | [![Build Status][travis-image]][travis-url]
|
6 | [![Test Coverage][coveralls-image]][coveralls-url]
|
7 |
|
8 | HTTP request logger middleware for node.js
|
9 |
|
10 | > Named after [Dexter](http://en.wikipedia.org/wiki/Dexter_Morgan), a show you should not watch until completion.
|
11 |
|
12 | ## API
|
13 |
|
14 |
|
15 |
|
16 | ```js
|
17 | var morgan = require('morgan')
|
18 | ```
|
19 |
|
20 | ### morgan(format, options)
|
21 |
|
22 | Create a new morgan logger middleware function using the given `format` and `options`.
|
23 | The `format` argument may be a string of a predefined name (see below for the names),
|
24 | a string of a format string, or a function that will produce a log entry.
|
25 |
|
26 | The `format` function will be called with three arguments `tokens`, `req`, and `res`,
|
27 | where `tokens` is an object with all defined tokens, `req` is the HTTP request and `res`
|
28 | is the HTTP response. The function is expected to return a string that will be the log
|
29 | line, or `undefined` / `null` to skip logging.
|
30 |
|
31 | #### Using a predefined format string
|
32 |
|
33 |
|
34 |
|
35 | ```js
|
36 | morgan('tiny')
|
37 | ```
|
38 |
|
39 | #### Using format string of predefined tokens
|
40 |
|
41 |
|
42 |
|
43 | ```js
|
44 | morgan(':method :url :status :res[content-length] - :response-time ms')
|
45 | ```
|
46 |
|
47 | #### Using a custom format function
|
48 |
|
49 |
|
50 |
|
51 | ``` js
|
52 | morgan(function (tokens, req, res) {
|
53 | return [
|
54 | tokens.method(req, res),
|
55 | tokens.url(req, res),
|
56 | tokens.status(req, res),
|
57 | tokens.res(req, res, 'content-length'), '-',
|
58 | tokens['response-time'](req, res), 'ms'
|
59 | ].join(' ')
|
60 | })
|
61 | ```
|
62 |
|
63 | #### Options
|
64 |
|
65 | Morgan accepts these properties in the options object.
|
66 |
|
67 | ##### immediate
|
68 |
|
69 | Write log line on request instead of response. This means that a requests will
|
70 | be logged even if the server crashes, _but data from the response (like the
|
71 | response code, content length, etc.) cannot be logged_.
|
72 |
|
73 | ##### skip
|
74 |
|
75 | Function to determine if logging is skipped, defaults to `false`. This function
|
76 | will be called as `skip(req, res)`.
|
77 |
|
78 |
|
79 |
|
80 | ```js
|
81 | // EXAMPLE: only log error responses
|
82 | morgan('combined', {
|
83 | skip: function (req, res) { return res.statusCode < 400 }
|
84 | })
|
85 | ```
|
86 |
|
87 | ##### stream
|
88 |
|
89 | Output stream for writing log lines, defaults to `process.stdout`.
|
90 |
|
91 | #### Predefined Formats
|
92 |
|
93 | There are various pre-defined formats provided:
|
94 |
|
95 | ##### combined
|
96 |
|
97 | Standard Apache combined log output.
|
98 |
|
99 | ```
|
100 | :remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"
|
101 | ```
|
102 |
|
103 | ##### common
|
104 |
|
105 | Standard Apache common log output.
|
106 |
|
107 | ```
|
108 | :remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length]
|
109 | ```
|
110 |
|
111 | ##### dev
|
112 |
|
113 | Concise output colored by response status for development use. The `:status`
|
114 | token will be colored green for success codes, red for server error codes,
|
115 | yellow for client error codes, cyan for redirection codes, and uncolored
|
116 | for information codes.
|
117 |
|
118 | ```
|
119 | :method :url :status :response-time ms - :res[content-length]
|
120 | ```
|
121 |
|
122 | ##### short
|
123 |
|
124 | Shorter than default, also including response time.
|
125 |
|
126 | ```
|
127 | :remote-addr :remote-user :method :url HTTP/:http-version :status :res[content-length] - :response-time ms
|
128 | ```
|
129 |
|
130 | ##### tiny
|
131 |
|
132 | The minimal output.
|
133 |
|
134 | ```
|
135 | :method :url :status :res[content-length] - :response-time ms
|
136 | ```
|
137 |
|
138 | #### Tokens
|
139 |
|
140 | ##### Creating new tokens
|
141 |
|
142 | To define a token, simply invoke `morgan.token()` with the name and a callback function.
|
143 | This callback function is expected to return a string value. The value returned is then
|
144 | available as ":type" in this case:
|
145 |
|
146 |
|
147 |
|
148 | ```js
|
149 | morgan.token('type', function (req, res) { return req.headers['content-type'] })
|
150 | ```
|
151 |
|
152 | Calling `morgan.token()` using the same name as an existing token will overwrite that
|
153 | token definition.
|
154 |
|
155 | The token function is expected to be called with the arguments `req` and `res`, representing
|
156 | the HTTP request and HTTP response. Additionally, the token can accept further arguments of
|
157 | it's choosing to customize behavior.
|
158 |
|
159 | ##### :date[format]
|
160 |
|
161 | The current date and time in UTC. The available formats are:
|
162 |
|
163 | - `clf` for the common log format (`"10/Oct/2000:13:55:36 +0000"`)
|
164 | - `iso` for the common ISO 8601 date time format (`2000-10-10T13:55:36.000Z`)
|
165 | - `web` for the common RFC 1123 date time format (`Tue, 10 Oct 2000 13:55:36 GMT`)
|
166 |
|
167 | If no format is given, then the default is `web`.
|
168 |
|
169 | ##### :http-version
|
170 |
|
171 | The HTTP version of the request.
|
172 |
|
173 | ##### :method
|
174 |
|
175 | The HTTP method of the request.
|
176 |
|
177 | ##### :referrer
|
178 |
|
179 | The Referrer header of the request. This will use the standard mis-spelled Referer header if exists, otherwise Referrer.
|
180 |
|
181 | ##### :remote-addr
|
182 |
|
183 | The remote address of the request. This will use `req.ip`, otherwise the standard `req.connection.remoteAddress` value (socket address).
|
184 |
|
185 | ##### :remote-user
|
186 |
|
187 | The user authenticated as part of Basic auth for the request.
|
188 |
|
189 | ##### :req[header]
|
190 |
|
191 | The given `header` of the request. If the header is not present, the
|
192 | value will be displayed as `"-"` in the log.
|
193 |
|
194 | ##### :res[header]
|
195 |
|
196 | The given `header` of the response. If the header is not present, the
|
197 | value will be displayed as `"-"` in the log.
|
198 |
|
199 | ##### :response-time[digits]
|
200 |
|
201 | The time between the request coming into `morgan` and when the response
|
202 | headers are written, in milliseconds.
|
203 |
|
204 | The `digits` argument is a number that specifies the number of digits to
|
205 | include on the number, defaulting to `3`, which provides microsecond precision.
|
206 |
|
207 | ##### :status
|
208 |
|
209 | The status code of the response.
|
210 |
|
211 | If the request/response cycle completes before a response was sent to the
|
212 | client (for example, the TCP socket closed prematurely by a client aborting
|
213 | the request), then the status will be empty (displayed as `"-"` in the log).
|
214 |
|
215 | ##### :total-time[digits]
|
216 |
|
217 | The time between the request coming into `morgan` and when the response
|
218 | has finished being written out to the connection, in milliseconds.
|
219 |
|
220 | The `digits` argument is a number that specifies the number of digits to
|
221 | include on the number, defaulting to `3`, which provides microsecond precision.
|
222 |
|
223 | ##### :url
|
224 |
|
225 | The URL of the request. This will use `req.originalUrl` if exists, otherwise `req.url`.
|
226 |
|
227 | ##### :user-agent
|
228 |
|
229 | The contents of the User-Agent header of the request.
|
230 |
|
231 | ### morgan.compile(format)
|
232 |
|
233 | Compile a format string into a `format` function for use by `morgan`. A format string
|
234 | is a string that represents a single log line and can utilize token syntax.
|
235 | Tokens are references by `:token-name`. If tokens accept arguments, they can
|
236 | be passed using `[]`, for example: `:token-name[pretty]` would pass the string
|
237 | `'pretty'` as an argument to the token `token-name`.
|
238 |
|
239 | The function returned from `morgan.compile` takes three arguments `tokens`, `req`, and
|
240 | `res`, where `tokens` is object with all defined tokens, `req` is the HTTP request and
|
241 | `res` is the HTTP response. The function will return a string that will be the log line,
|
242 | or `undefined` / `null` to skip logging.
|
243 |
|
244 | Normally formats are defined using `morgan.format(name, format)`, but for certain
|
245 | advanced uses, this compile function is directly available.
|
246 |
|
247 | ## Examples
|
248 |
|
249 | ### express/connect
|
250 |
|
251 | Simple app that will log all request in the Apache combined format to STDOUT
|
252 |
|
253 | ```js
|
254 | var express = require('express')
|
255 | var morgan = require('morgan')
|
256 |
|
257 | var app = express()
|
258 |
|
259 | app.use(morgan('combined'))
|
260 |
|
261 | app.get('/', function (req, res) {
|
262 | res.send('hello, world!')
|
263 | })
|
264 | ```
|
265 |
|
266 | ### vanilla http server
|
267 |
|
268 | Simple app that will log all request in the Apache combined format to STDOUT
|
269 |
|
270 | ```js
|
271 | var finalhandler = require('finalhandler')
|
272 | var http = require('http')
|
273 | var morgan = require('morgan')
|
274 |
|
275 | // create "middleware"
|
276 | var logger = morgan('combined')
|
277 |
|
278 | http.createServer(function (req, res) {
|
279 | var done = finalhandler(req, res)
|
280 | logger(req, res, function (err) {
|
281 | if (err) return done(err)
|
282 |
|
283 | // respond to request
|
284 | res.setHeader('content-type', 'text/plain')
|
285 | res.end('hello, world!')
|
286 | })
|
287 | })
|
288 | ```
|
289 |
|
290 | ### write logs to a file
|
291 |
|
292 | #### single file
|
293 |
|
294 | Simple app that will log all requests in the Apache combined format to the file
|
295 | `access.log`.
|
296 |
|
297 | ```js
|
298 | var express = require('express')
|
299 | var fs = require('fs')
|
300 | var morgan = require('morgan')
|
301 | var path = require('path')
|
302 |
|
303 | var app = express()
|
304 |
|
305 | // create a write stream (in append mode)
|
306 | var accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.log'), { flags: 'a' })
|
307 |
|
308 | // setup the logger
|
309 | app.use(morgan('combined', { stream: accessLogStream }))
|
310 |
|
311 | app.get('/', function (req, res) {
|
312 | res.send('hello, world!')
|
313 | })
|
314 | ```
|
315 |
|
316 | #### log file rotation
|
317 |
|
318 | Simple app that will log all requests in the Apache combined format to one log
|
319 | file per day in the `log/` directory using the
|
320 | [rotating-file-stream module](https://www.npmjs.com/package/rotating-file-stream).
|
321 |
|
322 | ```js
|
323 | var express = require('express')
|
324 | var morgan = require('morgan')
|
325 | var path = require('path')
|
326 | var rfs = require('rotating-file-stream') // version 2.x
|
327 |
|
328 | var app = express()
|
329 |
|
330 | // create a rotating write stream
|
331 | var accessLogStream = rfs.createStream('access.log', {
|
332 | interval: '1d', // rotate daily
|
333 | path: path.join(__dirname, 'log')
|
334 | })
|
335 |
|
336 | // setup the logger
|
337 | app.use(morgan('combined', { stream: accessLogStream }))
|
338 |
|
339 | app.get('/', function (req, res) {
|
340 | res.send('hello, world!')
|
341 | })
|
342 | ```
|
343 |
|
344 | ### split / dual logging
|
345 |
|
346 | The `morgan` middleware can be used as many times as needed, enabling
|
347 | combinations like:
|
348 |
|
349 | * Log entry on request and one on response
|
350 | * Log all requests to file, but errors to console
|
351 | * ... and more!
|
352 |
|
353 | Sample app that will log all requests to a file using Apache format, but
|
354 | error responses are logged to the console:
|
355 |
|
356 | ```js
|
357 | var express = require('express')
|
358 | var fs = require('fs')
|
359 | var morgan = require('morgan')
|
360 | var path = require('path')
|
361 |
|
362 | var app = express()
|
363 |
|
364 | // log only 4xx and 5xx responses to console
|
365 | app.use(morgan('dev', {
|
366 | skip: function (req, res) { return res.statusCode < 400 }
|
367 | }))
|
368 |
|
369 | // log all requests to access.log
|
370 | app.use(morgan('common', {
|
371 | stream: fs.createWriteStream(path.join(__dirname, 'access.log'), { flags: 'a' })
|
372 | }))
|
373 |
|
374 | app.get('/', function (req, res) {
|
375 | res.send('hello, world!')
|
376 | })
|
377 | ```
|
378 |
|
379 | ### use custom token formats
|
380 |
|
381 | Sample app that will use custom token formats. This adds an ID to all requests and displays it using the `:id` token.
|
382 |
|
383 | ```js
|
384 | var express = require('express')
|
385 | var morgan = require('morgan')
|
386 | var uuid = require('node-uuid')
|
387 |
|
388 | morgan.token('id', function getId (req) {
|
389 | return req.id
|
390 | })
|
391 |
|
392 | var app = express()
|
393 |
|
394 | app.use(assignId)
|
395 | app.use(morgan(':id :method :url :response-time'))
|
396 |
|
397 | app.get('/', function (req, res) {
|
398 | res.send('hello, world!')
|
399 | })
|
400 |
|
401 | function assignId (req, res, next) {
|
402 | req.id = uuid.v4()
|
403 | next()
|
404 | }
|
405 | ```
|
406 |
|
407 | ## License
|
408 |
|
409 | [MIT](LICENSE)
|
410 |
|
411 | [coveralls-image]: https://badgen.net/coveralls/c/github/expressjs/morgan/master
|
412 | [coveralls-url]: https://coveralls.io/r/expressjs/morgan?branch=master
|
413 | [npm-downloads-image]: https://badgen.net/npm/dm/morgan
|
414 | [npm-url]: https://npmjs.org/package/morgan
|
415 | [npm-version-image]: https://badgen.net/npm/v/morgan
|
416 | [travis-image]: https://badgen.net/travis/expressjs/morgan/master
|
417 | [travis-url]: https://travis-ci.org/expressjs/morgan
|