From 05d4d1c624e31d96dc46c0872fc0eaabfe6051bb Mon Sep 17 00:00:00 2001 From: Bradley Farias Date: Thu, 6 Oct 2016 11:25:25 -0500 Subject: [PATCH 1/4] Document custom function for tokens/format --- README.md | 63 +++++++++++++++++++++++++++++++++++++++++++ test/morgan.js | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+) diff --git a/README.md b/README.md index d63f848..e70c530 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ Create a new morgan logger middleware function using the given `format` and `opt The `format` argument may be a string of a predefined name (see below for the names), a string of a format string, or a function that will produce a log entry. +For the syntax of strings and functions see [morgan.compile](#morgancompileformat). + #### Options Morgan accepts these properties in the options object. @@ -103,6 +105,14 @@ To define a token, simply invoke `morgan.token()` with the name and a callback f morgan.token('type', function (req, res) { return req.headers['content-type'] }) ``` +Tokens can accept a string argument passed in from `[]` brackets by specifying +a third argument `arg`: +```js +morgan.token('type', function (req, res, arg) { return arg }) +``` + +Falsey values returned from this function will be replaced with `-`. + Calling `morgan.token()` using the same name as an existing token will overwrite that token definition. ##### :date[format] @@ -178,6 +188,11 @@ be passed using `[]`, for example: `:token-name[pretty]` would pass the string Normally formats are defined using `morgan.format(name, format)`, but for certain advanced uses, this compile function is directly available. +The function returned takes arguments `tokens` , `req`, and `res` where `tokens` +refers to `morgan` itself. If a log should be skipped the function will return +`null`. The function returned or a custom function can be passed directly to +morgan using `morgan(myFn)`. + ## Examples ### express/connect @@ -310,6 +325,54 @@ function assignId (req, res, next) { } ``` +#### arguments to custom token formats + +Example of a custom token format that uses an argument. It will echo the +argument passed to the token. + +```js +var express = require('express') +var morgan = require('morgan') + +morgan.token('echo', function getId (req, res, arg) { + return arg +}) + +var app = express() + +app.use(morgan(':echo[hello world!] :response-time')) + +app.get('/', function (req, res) { + res.send('hello, world!') +}) +``` + +### use custom format function + +Sample app that will use a custom formatting function. This will print JSON +instead of a simple string. + +```js +var express = require('express') +var morgan = require('morgan') + +var combined = morgan.compile('[:date[clf]] :method :url :res[content-length]') +var JSONOutput = function (morgan, req, res) { + return JSON.stringify({ + status: morgan.status(req,res), + default: combined(morgan, req, res), + }) +} + +var app = express() + +app.use(morgan(JSONOutput)) + +app.get('/', function (req, res) { + res.send('hello, world!') +}) +``` + ## License [MIT](LICENSE) diff --git a/test/morgan.js b/test/morgan.js index 786cda1..0f1f328 100644 --- a/test/morgan.js +++ b/test/morgan.js @@ -822,6 +822,79 @@ describe('morgan()', function () { test.write('0') }) }) + + describe('a custom', function () { + function token (req, res, arg) { + return arg + } + var url + beforeEach(function () { + url = morgan.url + morgan.token('url', token) + }) + afterEach(function () { + morgan.url = url + }) + + it('should overwrite existing', function (done) { + assert.equal(morgan.url, token) + done() + }) + + it('should use - if result is falsey', function (done) { + var cb = after(2, function (err, res, line) { + if (err) return done(err) + assert.equal(line, '-') + done() + }) + + var stream = createLineStream(function (line) { + cb(null, null, line) + }) + + var server = createServer(':url', { stream: stream }, function (req, res, next) { + next() + }) + + request(server) + .get('/') + .expect(200, cb) + }) + + it('should not see empty brackets', function (done) { + var cb = after(2, function (err, res, line) { + if (err) return done(err) + assert.equal(line, '-[]') + done() + }) + + var stream = createLineStream(function (line) { + cb(null, null, line) + }) + + var server = createServer(':url[]', { stream: stream }, function (req, res, next) { + next() + }) + + request(server) + .get('/') + .expect(200, cb) + }) + + it('should use the result', function (done) { + var stream = createLineStream(function (line) { + assert.equal(line, 'HIDDEN') + server.close(done) + }) + + var server = createServer(':url[HIDDEN]', { stream: stream }, function () { + test.abort() + }) + + var test = request(server).post('/') + test.write('0') + }) + }) }) describe('formats', function () { From c912b904017831bed72a4f8ada07ee11dd78bc81 Mon Sep 17 00:00:00 2001 From: Bradley Farias Date: Thu, 6 Oct 2016 20:14:17 -0500 Subject: [PATCH 2/4] fixup --- README.md | 10 +++++----- test/morgan.js | 38 +++++++++++++++++++++++--------------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index e70c530..a5d7cbe 100644 --- a/README.md +++ b/README.md @@ -327,20 +327,20 @@ function assignId (req, res, next) { #### arguments to custom token formats -Example of a custom token format that uses an argument. It will echo the -argument passed to the token. +Example of a custom token format that uses an argument. It will output the +header related to the argument passed to the token. ```js var express = require('express') var morgan = require('morgan') -morgan.token('echo', function getId (req, res, arg) { - return arg +morgan.token('header', function getId (req, res, arg) { + return String(req.headers[arg]) }) var app = express() -app.use(morgan(':echo[hello world!] :response-time')) +app.use(morgan(':header[host] :response-time')) app.get('/', function (req, res) { res.send('hello, world!') diff --git a/test/morgan.js b/test/morgan.js index 0f1f328..e57ee75 100644 --- a/test/morgan.js +++ b/test/morgan.js @@ -7,6 +7,7 @@ var join = require('path').join var morgan = require('..') var request = require('supertest') var split = require('split') +var url = require('url') describe('morgan()', function () { describe('arguments', function () { @@ -823,17 +824,19 @@ describe('morgan()', function () { }) }) - describe('a custom', function () { + describe('a custom token function provided to .token(name,fn)', function () { function token (req, res, arg) { - return arg + return arg && url.parse(req.url)[arg] } - var url - beforeEach(function () { - url = morgan.url + var urlToken = morgan.url + beforeEach(function (done) { + // test clobbering morgan.token('url', token) + done(); }) - afterEach(function () { - morgan.url = url + afterEach(function (done) { + morgan.token('url', urlToken) + done() }) it('should overwrite existing', function (done) { @@ -841,7 +844,7 @@ describe('morgan()', function () { done() }) - it('should use - if result is falsey', function (done) { + it('should use the string `-` if return value of the token function is falsey', function (done) { var cb = after(2, function (err, res, line) { if (err) return done(err) assert.equal(line, '-') @@ -861,7 +864,7 @@ describe('morgan()', function () { .expect(200, cb) }) - it('should not see empty brackets', function (done) { + it('should not see empty brackets as an argument value', function (done) { var cb = after(2, function (err, res, line) { if (err) return done(err) assert.equal(line, '-[]') @@ -882,17 +885,22 @@ describe('morgan()', function () { }) it('should use the result', function (done) { + var cb = after(2, function (err, res, line) { + if (err) return done(err) + assert.equal(line, 'foo=bar') + done() + }) + + var stream = createLineStream(function (line) { - assert.equal(line, 'HIDDEN') - server.close(done) + cb(null, null, line) }) - var server = createServer(':url[HIDDEN]', { stream: stream }, function () { - test.abort() + var server = createServer(':url[query]', { stream: stream }, function (req, res, next) { + next() }) - var test = request(server).post('/') - test.write('0') + var test = request(server).post('/test').query('foo=bar').expect(200, cb) }) }) }) From ad51d1c05486165d9c74ad06daa526d1e18d08f7 Mon Sep 17 00:00:00 2001 From: Bradley Farias Date: Thu, 6 Oct 2016 20:32:17 -0500 Subject: [PATCH 3/4] more fixup --- README.md | 4 +-- test/morgan.js | 82 ++++++++++++++++++++++++++++++-------------------- 2 files changed, 51 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index a5d7cbe..109c1d8 100644 --- a/README.md +++ b/README.md @@ -356,11 +356,11 @@ instead of a simple string. var express = require('express') var morgan = require('morgan') -var combined = morgan.compile('[:date[clf]] :method :url :res[content-length]') +var formatter = morgan.compile('[:date[clf]] :method :url :res[content-length]') var JSONOutput = function (morgan, req, res) { return JSON.stringify({ status: morgan.status(req,res), - default: combined(morgan, req, res), + default: formatter(morgan, req, res), }) } diff --git a/test/morgan.js b/test/morgan.js index e57ee75..e67d5c7 100644 --- a/test/morgan.js +++ b/test/morgan.js @@ -825,47 +825,61 @@ describe('morgan()', function () { }) describe('a custom token function provided to .token(name,fn)', function () { - function token (req, res, arg) { - return arg && url.parse(req.url)[arg] - } - var urlToken = morgan.url - beforeEach(function (done) { - // test clobbering + it('should overwrite existing', function (done) { + function token (req, res, arg) { + return arg && url.parse(req.url)[arg] + } + var urlToken = morgan.url morgan.token('url', token) - done(); - }) - afterEach(function (done) { + assert.equal(morgan.url, token) morgan.token('url', urlToken) done() }) - it('should overwrite existing', function (done) { - assert.equal(morgan.url, token) - done() - }) + describe('should use the string `-` if return value of the token function is falsey', function () { + function test (v, done) { + morgan.token('ret', function ret (req, res, arg) { + return arg + }) + var cb = after(2, function (err, res, line) { + if (err) return done(err) + assert.equal(line, '-') + done() + }) - it('should use the string `-` if return value of the token function is falsey', function (done) { - var cb = after(2, function (err, res, line) { - if (err) return done(err) - assert.equal(line, '-') - done() - }) + var stream = createLineStream(function (line) { + cb(null, null, line) + }) - var stream = createLineStream(function (line) { - cb(null, null, line) - }) + var server = createServer(':ret', { stream: stream }, function (req, res, next) { + next() + }) - var server = createServer(':url', { stream: stream }, function (req, res, next) { - next() + request(server) + .get('/') + .expect(200, cb) + } + [ + 0, + NaN, + false, + '', + null, + undefined + ].forEach(function (v) { + it('for ' + (String(v) || JSON.stringify(v)), function (done) { + test(v, done) + }) }) - - request(server) - .get('/') - .expect(200, cb) }) it('should not see empty brackets as an argument value', function (done) { - var cb = after(2, function (err, res, line) { + morgan.token('checkempty', function ret (req, res, arg) { + assert.equal(arg, undefined) + assert.equal(arguments.length, 2) + cb(null) + }) + var cb = after(3, function (err, res, line) { if (err) return done(err) assert.equal(line, '-[]') done() @@ -875,7 +889,7 @@ describe('morgan()', function () { cb(null, null, line) }) - var server = createServer(':url[]', { stream: stream }, function (req, res, next) { + var server = createServer(':checkempty[]', { stream: stream }, function (req, res, next) { next() }) @@ -885,22 +899,24 @@ describe('morgan()', function () { }) it('should use the result', function (done) { + morgan.token('urlpart', function ret (req, res, arg) { + return url.parse(req.url)[arg] + }) var cb = after(2, function (err, res, line) { if (err) return done(err) assert.equal(line, 'foo=bar') done() }) - var stream = createLineStream(function (line) { cb(null, null, line) }) - var server = createServer(':url[query]', { stream: stream }, function (req, res, next) { + var server = createServer(':urlpart[query]', { stream: stream }, function (req, res, next) { next() }) - var test = request(server).post('/test').query('foo=bar').expect(200, cb) + request(server).post('/test').query('foo=bar').expect(200, cb) }) }) }) From 12230b264a41b04255e0d567ace2110276b5e62d Mon Sep 17 00:00:00 2001 From: Bradley Farias Date: Thu, 6 Oct 2016 20:38:22 -0500 Subject: [PATCH 4/4] move some of the token tests to top level describe --- test/morgan.js | 192 ++++++++++++++++++++++++------------------------- 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/test/morgan.js b/test/morgan.js index e67d5c7..7cc89ba 100644 --- a/test/morgan.js +++ b/test/morgan.js @@ -823,102 +823,6 @@ describe('morgan()', function () { test.write('0') }) }) - - describe('a custom token function provided to .token(name,fn)', function () { - it('should overwrite existing', function (done) { - function token (req, res, arg) { - return arg && url.parse(req.url)[arg] - } - var urlToken = morgan.url - morgan.token('url', token) - assert.equal(morgan.url, token) - morgan.token('url', urlToken) - done() - }) - - describe('should use the string `-` if return value of the token function is falsey', function () { - function test (v, done) { - morgan.token('ret', function ret (req, res, arg) { - return arg - }) - var cb = after(2, function (err, res, line) { - if (err) return done(err) - assert.equal(line, '-') - done() - }) - - var stream = createLineStream(function (line) { - cb(null, null, line) - }) - - var server = createServer(':ret', { stream: stream }, function (req, res, next) { - next() - }) - - request(server) - .get('/') - .expect(200, cb) - } - [ - 0, - NaN, - false, - '', - null, - undefined - ].forEach(function (v) { - it('for ' + (String(v) || JSON.stringify(v)), function (done) { - test(v, done) - }) - }) - }) - - it('should not see empty brackets as an argument value', function (done) { - morgan.token('checkempty', function ret (req, res, arg) { - assert.equal(arg, undefined) - assert.equal(arguments.length, 2) - cb(null) - }) - var cb = after(3, function (err, res, line) { - if (err) return done(err) - assert.equal(line, '-[]') - done() - }) - - var stream = createLineStream(function (line) { - cb(null, null, line) - }) - - var server = createServer(':checkempty[]', { stream: stream }, function (req, res, next) { - next() - }) - - request(server) - .get('/') - .expect(200, cb) - }) - - it('should use the result', function (done) { - morgan.token('urlpart', function ret (req, res, arg) { - return url.parse(req.url)[arg] - }) - var cb = after(2, function (err, res, line) { - if (err) return done(err) - assert.equal(line, 'foo=bar') - done() - }) - - var stream = createLineStream(function (line) { - cb(null, null, line) - }) - - var server = createServer(':urlpart[query]', { stream: stream }, function (req, res, next) { - next() - }) - - request(server).post('/test').query('foo=bar').expect(200, cb) - }) - }) }) describe('formats', function () { @@ -1413,6 +1317,102 @@ describe('morgan.compile(format)', function () { }) }) +describe('morgan.token(name, function)', function () { + it('should overwrite existing functions if called multiple times', function (done) { + function token (req, res, arg) { + return arg && url.parse(req.url)[arg] + } + var urlToken = morgan.url + morgan.token('url', token) + assert.equal(morgan.url, token) + morgan.token('url', urlToken) + done() + }) + + describe('should use the string `-` if return value of the token function is falsey', function () { + function test (v, done) { + morgan.token('ret', function ret (req, res, arg) { + return arg + }) + var cb = after(2, function (err, res, line) { + if (err) return done(err) + assert.equal(line, '-') + done() + }) + + var stream = createLineStream(function (line) { + cb(null, null, line) + }) + + var server = createServer(':ret', { stream: stream }, function (req, res, next) { + next() + }) + + request(server) + .get('/') + .expect(200, cb) + } + [ + 0, + NaN, + false, + '', + null, + undefined + ].forEach(function (v) { + it('for ' + (String(v) || JSON.stringify(v)), function (done) { + test(v, done) + }) + }) + }) + + it('should not see empty brackets as an argument value', function (done) { + morgan.token('checkempty', function ret (req, res, arg) { + assert.equal(arg, undefined) + assert.equal(arguments.length, 2) + cb(null) + }) + var cb = after(3, function (err, res, line) { + if (err) return done(err) + assert.equal(line, '-[]') + done() + }) + + var stream = createLineStream(function (line) { + cb(null, null, line) + }) + + var server = createServer(':checkempty[]', { stream: stream }, function (req, res, next) { + next() + }) + + request(server) + .get('/') + .expect(200, cb) + }) + + it('should use the result', function (done) { + morgan.token('urlpart', function ret (req, res, arg) { + return url.parse(req.url)[arg] + }) + var cb = after(2, function (err, res, line) { + if (err) return done(err) + assert.equal(line, 'foo=bar') + done() + }) + + var stream = createLineStream(function (line) { + cb(null, null, line) + }) + + var server = createServer(':urlpart[query]', { stream: stream }, function (req, res, next) { + next() + }) + + request(server).post('/test').query('foo=bar').expect(200, cb) + }) +}) + function after (count, callback) { var args = new Array(3) var i = 0