Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
eirslett committed May 11, 2016
0 parents commit 73fc0e9
Show file tree
Hide file tree
Showing 57 changed files with 2,651 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .editorconfig
@@ -0,0 +1,6 @@
[*.js]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
2 changes: 2 additions & 0 deletions .eslintignore
@@ -0,0 +1,2 @@
node_modules
gen-nodejs
19 changes: 19 additions & 0 deletions .eslintrc
@@ -0,0 +1,19 @@
{
"extends": "airbnb",
"rules": {
"comma-dangle": "off",
"func-names": "off",
"object-curly-spacing": [2, "never"],
"space-before-function-paren": [2, "never"],
"eqeqeq": [2, "allow-null"],
"no-else-return": "off",
"prefer-arrow-callback": ["error", { "allowNamedFunctions": true }],
"no-underscore-dangle": "off",
"import/no-unresolved": [2, {
"ignore": ["url"] }
]
},
"env": {
"node": true
}
}
2 changes: 2 additions & 0 deletions .gitignore
@@ -0,0 +1,2 @@
node_modules
**/node_modules
7 changes: 7 additions & 0 deletions .travis.yml
@@ -0,0 +1,7 @@
language: node_js
install:
- npm install
- npm run lerna-bootstrap
script:
- npm run lint
- npm test
65 changes: 65 additions & 0 deletions README.md
@@ -0,0 +1,65 @@
# Zipkin.js

This is a library for instrumenting Node.js applications. It uses a lot of
new JavaScript features and syntax, so Node.js version 6 or newer is required.


## Installation:

npm install zipkin --save

## Usage:

```javascript
const {tracer, consoleTracer} = require('zipkin');

tracer.pushTracer(consoleTracer);
```

## Instrumentations

Various Node.js libraries have been instrumented with Zipkin support.
In this project:

- express
- cujojs/rest

## Transports

You can choose between multiple transports; for now,
scribe and kafka transports are implemented. They can
be used like this:

Scribe:

```javascript
const ScribeTracer = require('zipkin-transport-scribe');
tracer.pushTracer(new ScribeTracer({
host: 'localhost',
port: 9410
});
```
Kafka
```javascript
const KafkaTracer = require('zipkin-transport-kafka');
tracer.pushTracer(new KafkaTracer({
clientOpts: {connectionString: 'localhost:2181'}
});
```
## Developing
The code base is a monorepo. We use [Lerna](https://github.com/kittens/lerna) for managing inter-module
dependencies, which makes it easier to develop coordinated changes.
To setup, run:
npm install
npm run lerna-bootstrap
Running tests: npm test
Running code style linting: npm run lint
1 change: 1 addition & 0 deletions index.js
@@ -0,0 +1 @@
module.exports.Zipkin = require('src/zipkin/zipkin');
4 changes: 4 additions & 0 deletions lerna.json
@@ -0,0 +1,4 @@
{
"lerna": "2.0.0-beta.6",
"version": "0.1.0"
}
24 changes: 24 additions & 0 deletions package.json
@@ -0,0 +1,24 @@
{
"name": "zipkin-js",
"private": true,
"license": "Apache-2.0",
"dependencies": {
"lerna": "2.0.0-beta.6"
},
"scripts": {
"lint": "node node_modules/eslint/bin/eslint.js packages",
"test": "node node_modules/mocha/bin/mocha",
"lerna-bootstrap": "node node_modules/lerna/bin/lerna.js bootstrap"
},
"devDependencies": {
"chai": "^3.5.0",
"eslint": "^2.8.0",
"eslint-config-airbnb": "^8.0.0",
"eslint-plugin-import": "^1.6.0",
"eslint-plugin-jsx-a11y": "^1.0.2",
"eslint-plugin-react": "^5.0.1",
"lerna": "^2.0.0-beta.6",
"mocha": "^2.4.5",
"sinon": "^1.17.4"
}
}
1 change: 1 addition & 0 deletions packages/zipkin-instrumentation-cujojs-rest/index.js
@@ -0,0 +1 @@
module.exports.restInterceptor = require('./src/restInterceptor');
17 changes: 17 additions & 0 deletions packages/zipkin-instrumentation-cujojs-rest/package.json
@@ -0,0 +1,17 @@
{
"name": "zipkin-instrumentation-cujojs-rest",
"version": "0.1.0",
"description": "Interceptor for instrumenting HTTP calls from the cujoJS rest library",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "OpenZipkin",
"license": "Apache-2.0",
"devDependencies": {
"rest": "^1.3.2"
},
"peerDependencies": {
"zipkin": "~0.1.0"
}
}
69 changes: 69 additions & 0 deletions packages/zipkin-instrumentation-cujojs-rest/src/restInterceptor.js
@@ -0,0 +1,69 @@
/* eslint-disable no-param-reassign */
const interceptor = require('rest/interceptor');
const {
trace,
HttpHeaders: Header,
Annotation
} = require('zipkin');

function getRequestMethod(req) {
let method = 'get';
if (req.entity) {
method = 'post';
}
if (req.method) {
method = req.method;
}
return method;
}

function request(req, {serviceName}) {
function recordTraceData(name) {
const method = getRequestMethod(req);
trace.recordServiceName(name);
trace.recordRpc(method.toUpperCase());
trace.recordBinary('http.url', req.path);
trace.recordAnnotation(new Annotation.ClientSend());
}

trace.withContext(() => {
trace.setId(trace.nextId());
const traceId = trace.id();
this.traceId = traceId;

req.headers = req.headers || {};
req.headers[Header.TraceId] = traceId.traceId;
req.headers[Header.SpanId] = traceId.spanId;
traceId._parentId.ifPresent(psid => {
req.headers[Header.ParentSpanId] = psid;
});
traceId.sampled.ifPresent(sampled => {
req.headers[Header.Sampled] = sampled ? 'true' : 'false';
});

if (trace.isActivelyTracing()) {
if (serviceName instanceof Function) {
serviceName(req, recordTraceData);
} else {
recordTraceData(serviceName);
}
}
});

return req;
}

function response(res) {
trace.withContext(() => {
trace.setId(this.traceId);
trace.recordBinary('http.status_code', res.status.code.toString());
trace.recordAnnotation(new Annotation.ClientRecv());
});
return res;
}

module.exports = interceptor({

request,
response
});
8 changes: 8 additions & 0 deletions packages/zipkin-instrumentation-cujojs-rest/test/.eslintrc
@@ -0,0 +1,8 @@
{
"env": {
"mocha": true
},
"globals": {
"expect": true
}
}
@@ -0,0 +1,73 @@
const {trace} = require('zipkin');
const express = require('express');
const sinon = require('sinon');
const rest = require('rest');
const restInterceptor = require('../src/restInterceptor');

describe('cujojs rest interceptor - integration test', () => {
it('should add headers to requests', done => {
const app = express();
app.get('/abc', (req, res) => {
res.status(202).json({
traceId: req.header('X-B3-TraceId'),
spanId: req.header('X-B3-SpanId')
});
});

const server = app.listen(0, () => {
const record = sinon.spy();
const tracer = {record};

trace.letTracer(tracer, () => {
const client = rest.wrap(restInterceptor, {serviceName: 'service-a'});
const port = server.address().port;
const path = `http://127.0.0.1:${port}/abc`;
client(path).then(successResponse => {
const responseData = JSON.parse(successResponse.entity);
server.close();

const annotations = record.args.map(args => args[0]);

// All annotations should have the same trace id and span id
const traceId = annotations[0].traceId.traceId;
const spanId = annotations[0].traceId.spanId;
annotations.forEach(ann => expect(ann.traceId.traceId).to.equal(traceId));
annotations.forEach(ann => expect(ann.traceId.spanId).to.equal(spanId));

expect(annotations[0].annotation.annotationType).to.equal('ServiceName');
expect(annotations[0].annotation.serviceName).to.equal('service-a');

expect(annotations[1].annotation.annotationType).to.equal('Rpc');
expect(annotations[1].annotation.name).to.equal('GET');

expect(annotations[2].annotation.annotationType).to.equal('BinaryAnnotation');
expect(annotations[2].annotation.key).to.equal('http.url');
expect(annotations[2].annotation.value).to.equal(path);

expect(annotations[3].annotation.annotationType).to.equal('ClientSend');

expect(annotations[4].annotation.annotationType).to.equal('BinaryAnnotation');
expect(annotations[4].annotation.key).to.equal('http.status_code');
expect(annotations[4].annotation.value).to.equal('202');

expect(annotations[5].annotation.annotationType).to.equal('ClientRecv');

const traceIdOnServer = responseData.traceId;
expect(traceIdOnServer).to.equal(traceId);

const spanIdOnServer = responseData.spanId;
expect(spanIdOnServer).to.equal(spanId);

done();
}, errorResponse => {
if (errorResponse instanceof Error) {
done(errorResponse);
} else {
server.close();
done(new Error(`The request failed: ${errorResponse.error.toString()}`));
}
});
});
});
});
});
18 changes: 18 additions & 0 deletions packages/zipkin-instrumentation-express/README.md
@@ -0,0 +1,18 @@
# zipkin-instrumentation-express

An express middleware that adds Zipkin tracing to the application.

## Usage

```javascript
const express = require('express');
const {trace} = require('zipkin');
const zipkinMiddleware = require('zipkin-instrumentation-express');

trace.pushTracer(ConsoleTracer);
const app = express();
app.use(zipkinMiddleware({
serviceName: 'service-a', // name of this application
port: 8080 // port this application is listening on
}));
```
1 change: 1 addition & 0 deletions packages/zipkin-instrumentation-express/index.js
@@ -0,0 +1 @@
module.exports.expressMiddleware = require('./src/expressMiddleware');
18 changes: 18 additions & 0 deletions packages/zipkin-instrumentation-express/package.json
@@ -0,0 +1,18 @@
{
"name": "zipkin-instrumentation-express",
"version": "0.1.0",
"description": "Express middleware for instrumentation with Zipkin.js",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "OpenZipkin",
"license": "Apache-2.0",
"peerDependencies": {
"zipkin": "~0.1.0"
},
"devDependencies": {
"express": "^4.13.4",
"node-fetch": "^1.5.1"
}
}

0 comments on commit 73fc0e9

Please sign in to comment.