Skip to content

Commit 9f41a02

Browse files
committed
Merge pull request #15 from marcellodesales/feature/issue14-Auditor-Support
Adding support to Req/Res Auditor similar to Server.
2 parents 314e2d8 + d14d5eb commit 9f41a02

File tree

3 files changed

+109
-0
lines changed

3 files changed

+109
-0
lines changed

lib/HttpClient.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ var once = require('once');
1919
var tunnelAgent = require('tunnel-agent');
2020

2121
var dtrace = require('./helpers/dtrace');
22+
var auditor = require('./helpers/auditor');
2223
var errors = require('restify-errors');
2324
var serializers = require('./helpers/bunyan').serializers;
2425

@@ -152,9 +153,22 @@ function rawRequest(opts, cb) {
152153

153154
var emitResult = once(function _emitResult(_err, _req, _res) {
154155
_req.emit('result', _err, _res);
156+
157+
// Use the default auditor with the switch "opts.audit: true | false"
158+
if (opts.audit.defaultEnabled) {
159+
auditor(_err, _req, _res);
160+
161+
} else if (opts.audit.func && typeof opts.audit.func === 'function') {
162+
// Use the function provided by the user through "opts.auditor"
163+
opts.audit.func(_err, _req, _res);
164+
}
155165
});
156166

167+
var requestTime = new Date().getTime();
157168
req = proto.request(opts, function onResponse(res) {
169+
var latency = Date.now() - requestTime;
170+
res.headers['x-request-received'] = requestTime;
171+
res.headers['x-request-processing-time'] = latency;
158172
clearTimeout(connectionTimer);
159173
clearTimeout(requestTimer);
160174

@@ -343,6 +357,11 @@ function HttpClient(options) {
343357
this.requestTimeout = options.requestTimeout || false;
344358
this.headers = options.headers || {};
345359
this.log = options.log;
360+
this.audit = {
361+
func: options.auditor || null,
362+
defaultEnabled: options.audit || false
363+
};
364+
346365

347366
if (!this.log.serializers) {
348367
// Ensure logger has a reasonable serializer for `client_res`
@@ -570,6 +589,8 @@ HttpClient.prototype.request = function request(opts, cb) {
570589
cb = once(cb);
571590
/* eslint-enable no-param-reassign */
572591

592+
opts.audit = this.audit;
593+
573594
if (opts.retry === false) {
574595
rawRequest(opts, cb);
575596
return;

lib/helpers/auditor.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
'use strict';
2+
3+
module.exports = audit;
4+
5+
/**
6+
* Audits the req/res for the client. The audit will use bunyan's
7+
* formatters. See bunyan-format for the user-friendly output.
8+
*
9+
* @param {Object} err The http error object.
10+
* @param {Object} req The http request object.
11+
* @param {Object} res The http response object.
12+
*
13+
* @returns {undefined} Does not return anything.
14+
*/
15+
function audit(err, req, res) {
16+
req.headers = req._headers;
17+
req.url = req.path;
18+
var log = req.log;
19+
20+
var obj = {
21+
remoteAddress: req.connection.remoteAddress,
22+
remotePort: req.connection.remotePort,
23+
req: req,
24+
res: res,
25+
err: err,
26+
secure: req.secure
27+
};
28+
29+
log.info(obj);
30+
}

test/index.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ var uuid = require('node-uuid');
1313

1414
var restify = require('restify');
1515
var clients = require('../lib');
16+
var auditor = require('../lib/helpers/auditor');
17+
var pkgJson = require('../package');
1618

1719
///--- Globals
1820

@@ -899,6 +901,62 @@ describe('restify-client tests', function () {
899901
});
900902
});
901903

904+
it('create JSON client with auditor on', function (done) {
905+
906+
// Bunyan stream to capture the logs.
907+
function CapturingStream(recs) {
908+
909+
this.entries = recs;
910+
}
911+
912+
// Capture the bunyan logs as of
913+
// https://github.com/trentm/node-bunyan/blob/master/test/raw-stream.test.js#L19-L24
914+
CapturingStream.prototype.checkEntriesTest = function checkEntriesTest() {
915+
916+
assert.equal(this.entries.length, 1);
917+
};
918+
919+
// The write method to add log entries
920+
CapturingStream.prototype.write = function write(rec) {
921+
922+
this.entries.push(rec);
923+
};
924+
925+
// Instances of the log entries and the capturing stream
926+
var logEntries = [];
927+
var streamConfig = {
928+
name: 'capturingStream',
929+
level: 'info',
930+
stream: new CapturingStream(logEntries),
931+
type: 'raw',
932+
};
933+
934+
// the logger instance
935+
var logger = bunyan.createLogger({
936+
url: 'http://127.0.0.1:' + PORT,
937+
name: 'http-json-client',
938+
streams: [streamConfig]
939+
});
940+
941+
var httpClientOpts = {
942+
userAgent: pkgJson.name + "/" + pkgJson.version,
943+
auditor: auditor,
944+
log: logger,
945+
retry: false
946+
};
947+
948+
var client = clients.createJsonClient(httpClientOpts);
949+
client.agent = false;
950+
951+
client.get('/json/mcavage', function (err, req, res, obj) {
952+
err
953+
//assert.ok(req);
954+
//assert.ok(res);
955+
956+
// The verification is done in the CapturingStream.checkEntriesTest()
957+
done();
958+
});
959+
});
902960

903961
it('create string client with url instead of opts', function (done) {
904962
var client = clients.createStringClient('http://127.0.0.1:' + PORT);

0 commit comments

Comments
 (0)