Skip to content

Commit

Permalink
Merge pull request #1 from voldern/intial-version
Browse files Browse the repository at this point in the history
Initial version
  • Loading branch information
voldern authored Nov 14, 2017
2 parents 70123bb + 7c3c4a5 commit bc46b43
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
lib
8 changes: 8 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
language: node_js
node_js:
- 8
- 6
- 4
script:
- npm run lint
- npm test
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,24 @@
"description": "Interceptor for got clients",
"main": "lib/zipkinClient.js",
"scripts": {
"test": "mocha"
"build": "babel src -d lib",
"lint": "eslint .",
"test": "mocha --require babel-register",
"prepublish": "npm run build"
},
"author": "Espen Volden <[email protected]>",
"license": "Apache-2.0",
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-preset-es2015": "^6.24.1",
"babel-register": "^6.26.0",
"chai": "^3.5.0",
"eslint": "^2.10.0",
"eslint-config-airbnb": "^9.0.0",
"eslint-plugin-import": "^1.6.0",
"eslint-plugin-jsx-a11y": "^1.0.2",
"eslint-plugin-react": "^5.0.1",
"express": "^4.16.2",
"got": "^7.1.0",
"mocha": "^3.2.0",
"sinon": "^1.17.6",
Expand Down
72 changes: 72 additions & 0 deletions src/zipkinClient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
const {Instrumentation} = require('zipkin');

module.exports = function zipkinClient(got, {tracer, serviceName = 'unknown', remoteServiceName}) {
const instrumentation = new Instrumentation.HttpClient({tracer, serviceName, remoteServiceName});

function zipkinGot(url, opts) {
opts = opts || {}; // eslint-disable-line no-param-reassign

return new Promise((resolve, reject) => {
tracer.scoped(() => {
const method = opts.method || 'GET';
const zipkinOpts = instrumentation.recordRequest(opts, url, method);
const traceId = tracer.id;

got(url, zipkinOpts).then(res => {
tracer.scoped(() => {
instrumentation.recordResponse(traceId, res.statusCode);
});
resolve(res);
}).catch(err => {
tracer.scoped(() => {
instrumentation.recordError(traceId, err);
});
reject(err);
});
});
});
}

zipkinGot.stream = function zipkinGotStream(url, opts) {
opts = opts || {}; // eslint-disable-line no-param-reassign

let traceId;
let zipkinOpts;
tracer.scoped(() => {
const method = opts.method || 'GET';
zipkinOpts = instrumentation.recordRequest(opts, url, method);
traceId = tracer.id;
});

const stream = got.stream(url, zipkinOpts);
stream.on('response', (res) => {
tracer.scoped(() => {
instrumentation.recordResponse(traceId, res.statusCode);
});
});
stream.on('error', (err) => {
tracer.scoped(() => {
instrumentation.recordError(traceId, err);
});
});

return stream;
};

const methods = [
'get',
'post',
'put',
'patch',
'head',
'delete'
];

for (const method of methods) {
zipkinGot[method] = (url, opts) => zipkinGot(url, Object.assign({}, opts, {method}));
zipkinGot.stream[method] = (url, opts) =>
zipkinGot.stream(url, Object.assign({}, opts, {method}));
}

return zipkinGot;
};
11 changes: 11 additions & 0 deletions test/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"env": {
"mocha": true
},
"globals": {
"expect": true
},
"rules": {
"no-console": "off"
}
}
98 changes: 98 additions & 0 deletions test/integrationTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
const sinon = require('sinon');
const express = require('express');
const got = require('got');
const {Tracer, ExplicitContext, BatchRecorder} = require('zipkin');
const {expect} = require('chai');
const zipkinClient = require('../src/zipkinClient');

function expectCorrectSpanData(span, path) {
expect(span.remoteEndpoint.serviceName).to.equal('test');
expect(span.tags['http.url']).to.equal(path);
expect(span.tags['http.status_code']).to.equal('202');
}

describe('got interceptor', () => {
before(function(done) {
const app = express();
app.post('/user', (req, res) => res.status(202).json({
traceId: req.header('X-B3-TraceId') || '?',
spanId: req.header('X-B3-SpanId') || '?'
}));
app.get('/user', (req, res) => res.status(202).json({}));
this.server = app.listen(0, () => {
this.port = this.server.address().port;
done();
});
});

after(function(done) {
this.server.close(done);
});

it('should instrument "got"', function(done) {
const logSpan = sinon.spy();

const ctxImpl = new ExplicitContext();
const recorder = new BatchRecorder({logger: {logSpan}});
const tracer = new Tracer({ctxImpl, recorder});
tracer.setId(tracer.createRootId());

const zipkinGot = zipkinClient(got, {tracer, remoteServiceName: 'test'});
const path = `http://127.0.0.1:${this.port}/user`;
zipkinGot(path).then(() => {
zipkinGot.post(path, {json: true}).then((postRes) => {
zipkinGot.stream(path).on('response', () => {
const postStream = zipkinGot.stream.post(path);
postStream.end();

postStream.on('data', (streamPostRes) => {
const span = logSpan.args[3][0];

expect(span.traceId).to.equal(JSON.parse(streamPostRes.body).traceId);
expect(span.id).to.equal(JSON.parse(streamPostRes.body).spanId);
});

postStream.on('response', () => {
const spans = logSpan.args.map(arg => arg[0]);
expect(spans).to.have.length(4);

spans.forEach(span => expectCorrectSpanData(span, path));

expect(spans[0].name).to.equal('get');
expect(spans[1].name).to.equal('post');
expect(spans[2].name).to.equal('get');
expect(spans[3].name).to.equal('post');

expect(spans[1].traceId).to.equal(postRes.body.traceId);
expect(spans[1].id).to.equal(postRes.body.spanId);

done();
});
});
}).catch(done);
}).catch(done);
});

it('should record errors', function(done) {
const logSpan = sinon.spy();

const ctxImpl = new ExplicitContext();
const recorder = new BatchRecorder({logger: {logSpan}});
const tracer = new Tracer({ctxImpl, recorder});
tracer.setId(tracer.createRootId());

const zipkinGot = zipkinClient(got, {tracer});
const path = `http://127.0.0.1:${this.port}/missing`;
zipkinGot(path).catch((err) => {
zipkinGot.stream(path).on('error', (streamErr) => {
const spans = logSpan.args.map(arg => arg[0]);
expect(spans).to.have.length(2);

expect(spans[0].tags.error).to.equal(err.toString());
expect(spans[1].tags.error).to.equal(streamErr.toString());

done();
});
});
});
});

0 comments on commit bc46b43

Please sign in to comment.