Skip to content

Commit aa718d7

Browse files
committed
Add :total-time token
closes #165
1 parent ce15462 commit aa718d7

File tree

4 files changed

+210
-5
lines changed

4 files changed

+210
-5
lines changed

HISTORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
unreleased
22
==========
33

4+
* Add `:total-time` token
45
* Fix trailing space in colored status code for `dev` format
56
* deps: basic-auth@~2.0.1
67

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,14 @@ If the request/response cycle completes before a response was sent to the
212212
client (for example, the TCP socket closed prematurely by a client aborting
213213
the request), then the status will be empty (displayed as `"-"` in the log).
214214

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+
215223
##### :url
216224

217225
The URL of the request. This will use `req.originalUrl` if exists, otherwise `req.url`.

index.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,26 @@ morgan.token('response-time', function getResponseTimeToken (req, res, digits) {
239239
return ms.toFixed(digits === undefined ? 3 : digits)
240240
})
241241

242+
/**
243+
* total time in milliseconds
244+
*/
245+
246+
morgan.token('total-time', function getTotalTimeToken (req, res, digits) {
247+
if (!req._startAt || !res._startAt) {
248+
// missing request and/or response start time
249+
return
250+
}
251+
252+
// time elapsed from request start
253+
var elapsed = process.hrtime(req._startAt)
254+
255+
// cover to milliseconds
256+
var ms = (elapsed[0] * 1e3) + (elapsed[1] * 1e-6)
257+
258+
// return truncated value
259+
return ms.toFixed(digits === undefined ? 3 : digits)
260+
})
261+
242262
/**
243263
* current date
244264
*/

test/morgan.js

Lines changed: 181 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -641,12 +641,14 @@ describe('morgan()', function () {
641641
.expect(200, cb)
642642
})
643643

644-
it('should not include response latency', function (done) {
644+
it('should not include response write time', function (done) {
645645
var cb = after(2, function (err, res, line) {
646646
if (err) return done(err)
647+
var end = Date.now()
647648
var ms = parseFloat(line)
648-
assert.ok(ms > 0, 'positive milliseconds')
649-
assert.ok(ms < end - start + 1, 'response time expected to be < ' + (end - start + 1) + ', but was ' + ms)
649+
assert(ms > 0)
650+
assert(ms < end - start + 1)
651+
assert(ms < write - start + 1)
650652
done()
651653
})
652654

@@ -656,15 +658,15 @@ describe('morgan()', function () {
656658

657659
var server = createServer(':response-time', { stream: stream }, function (req, res) {
658660
res.write('hello, ')
659-
end = Date.now()
661+
write = Date.now()
660662

661663
setTimeout(function () {
662664
res.end('world!')
663665
}, 50)
664666
})
665667

666-
var end
667668
var start = Date.now()
669+
var write = null
668670

669671
request(server)
670672
.get('/')
@@ -796,6 +798,180 @@ describe('morgan()', function () {
796798
})
797799
})
798800

801+
describe(':total-time', function () {
802+
it('should be in milliseconds', function (done) {
803+
var cb = after(2, function (err, res, line) {
804+
if (err) return done(err)
805+
var end = Date.now()
806+
var ms = parseFloat(line)
807+
assert(ms > 0)
808+
assert(ms < end - start + 1)
809+
done()
810+
})
811+
812+
var stream = createLineStream(function (line) {
813+
cb(null, null, line)
814+
})
815+
816+
var start = Date.now()
817+
818+
request(createServer(':total-time', { stream: stream }))
819+
.get('/')
820+
.expect(200, cb)
821+
})
822+
823+
it('should have three digits by default', function (done) {
824+
var cb = after(2, function (err, res, line) {
825+
if (err) return done(err)
826+
assert.ok(/^[0-9]+\.[0-9]{3}$/.test(line))
827+
done()
828+
})
829+
830+
var stream = createLineStream(function (line) {
831+
cb(null, null, line)
832+
})
833+
834+
request(createServer(':total-time', { stream: stream }))
835+
.get('/')
836+
.expect(200, cb)
837+
})
838+
839+
it('should have five digits with argument "5"', function (done) {
840+
var cb = after(2, function (err, res, line) {
841+
if (err) return done(err)
842+
assert.ok(/^[0-9]+\.[0-9]{5}$/.test(line))
843+
done()
844+
})
845+
846+
var stream = createLineStream(function (line) {
847+
cb(null, null, line)
848+
})
849+
850+
request(createServer(':total-time[5]', { stream: stream }))
851+
.get('/')
852+
.expect(200, cb)
853+
})
854+
855+
it('should have no digits with argument "0"', function (done) {
856+
var cb = after(2, function (err, res, line) {
857+
if (err) return done(err)
858+
assert.ok(/^[0-9]+$/.test(line))
859+
done()
860+
})
861+
862+
var stream = createLineStream(function (line) {
863+
cb(null, null, line)
864+
})
865+
866+
request(createServer(':total-time[0]', { stream: stream }))
867+
.get('/')
868+
.expect(200, cb)
869+
})
870+
871+
it('should include response write time', function (done) {
872+
var cb = after(2, function (err, res, line) {
873+
if (err) return done(err)
874+
var end = Date.now()
875+
var ms = parseFloat(line)
876+
assert(ms > 0)
877+
assert(ms > write - start - 1)
878+
assert(ms < end - start + 1)
879+
done()
880+
})
881+
882+
var stream = createLineStream(function (line) {
883+
cb(null, null, line)
884+
})
885+
886+
var server = createServer(':total-time', { stream: stream }, function (req, res) {
887+
res.write('hello, ')
888+
write = Date.now()
889+
890+
setTimeout(function () {
891+
res.end('world!')
892+
}, 50)
893+
})
894+
895+
var start = Date.now()
896+
var write = null
897+
898+
request(server)
899+
.get('/')
900+
.expect(200, cb)
901+
})
902+
903+
it('should be empty without hidden property', function (done) {
904+
var cb = after(2, function (err, res, line) {
905+
if (err) return done(err)
906+
assert.strictEqual(line, '-')
907+
done()
908+
})
909+
910+
var stream = createLineStream(function (line) {
911+
cb(null, null, line)
912+
})
913+
914+
var server = createServer(':total-time', { stream: stream }, function (req, res, next) {
915+
delete req._startAt
916+
next()
917+
})
918+
919+
request(server)
920+
.get('/')
921+
.expect(200, cb)
922+
})
923+
924+
it('should be empty before response', function (done) {
925+
var cb = after(2, function (err, res, line) {
926+
if (err) return done(err)
927+
assert.strictEqual(line, '-')
928+
done()
929+
})
930+
931+
var stream = createLineStream(function (line) {
932+
cb(null, null, line)
933+
})
934+
935+
var server = createServer(':total-time', {
936+
immediate: true,
937+
stream: stream
938+
})
939+
940+
request(server)
941+
.get('/')
942+
.expect(200, cb)
943+
})
944+
945+
it('should be empty if morgan invoked after response sent', function (done) {
946+
var cb = after(3, function (err, res, line) {
947+
if (err) return done(err)
948+
assert.strictEqual(line, '-')
949+
done()
950+
})
951+
952+
var stream = createLineStream(function (line) {
953+
cb(null, null, line)
954+
})
955+
956+
var logger = morgan(':total-time', {
957+
immediate: true,
958+
stream: stream
959+
})
960+
961+
var server = http.createServer(function (req, res) {
962+
setTimeout(function () {
963+
logger(req, res, cb)
964+
}, 10)
965+
966+
res.end()
967+
})
968+
969+
request(server)
970+
.get('/')
971+
.expect(200, cb)
972+
})
973+
})
974+
799975
describe(':url', function () {
800976
it('should get request URL', function (done) {
801977
var cb = after(2, function (err, res, line) {

0 commit comments

Comments
 (0)