-
Notifications
You must be signed in to change notification settings - Fork 172
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds zipkin-instrumentation-redis support (#50)
- Loading branch information
1 parent
7f3efe8
commit 3ff7b2d
Showing
8 changed files
with
189 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ script: | |
|
||
services: | ||
- memcached | ||
- redis | ||
|
||
compiler: clang-3.6 | ||
env: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# zipkin-instrumentation-redis | ||
|
||
This library will wrap the [redis client](https://www.npmjs.com/package/redis). | ||
|
||
## Usage | ||
|
||
```javascript | ||
const {Tracer} = require('zipkin'); | ||
const Redis = require('redis'); | ||
const zipkinClient = require('zipkin-instrumentation-redis'); | ||
const tracer = new Tracer({ctxImpl, recorder}); // configure your tracer properly here | ||
const redisConnectionOptions = { | ||
host: 'localhost', | ||
port: '6379' | ||
}; | ||
const redis = zipkinClient(tracer, Redis, redisConnectionOptions); | ||
|
||
// Your application code here | ||
redis.get('foo', (err, data) => { | ||
console.log('got', data.foo); | ||
}); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"name": "zipkin-instrumentation-redis", | ||
"version": "0.2.6", | ||
"description": "Interceptor for redis clients", | ||
"main": "src/zipkinClient.js", | ||
"scripts": { | ||
"test": "node ../../node_modules/mocha/bin/mocha --require ../../test/helper.js" | ||
}, | ||
"author": "OpenZipkin <[email protected]>", | ||
"license": "Apache-2.0", | ||
"repository": "https://github.com/openzipkin/zipkin-js", | ||
"devDependencies": { | ||
"redis": "^2.6.2", | ||
"zipkin": "^0.2.6" | ||
}, | ||
"dependencies": { | ||
"redis-commands": "^1.2.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
const {Annotation} = require('zipkin'); | ||
const redisCommands = require('redis-commands'); | ||
module.exports = function zipkinClient(tracer, redis, options, serviceName = 'redis') { | ||
function mkZipkinCallback(callback, id) { | ||
return function zipkinCallback(...args) { | ||
tracer.scoped(() => { | ||
tracer.setId(id); | ||
tracer.recordAnnotation(new Annotation.ClientRecv()); | ||
}); | ||
callback.apply(this, args); | ||
}; | ||
} | ||
function commonAnnotations(rpc) { | ||
tracer.recordAnnotation(new Annotation.ClientSend()); | ||
tracer.recordServiceName(serviceName); | ||
tracer.recordRpc(rpc); | ||
} | ||
|
||
|
||
const redisClient = redis.createClient(options); | ||
const methodsToWrap = redisCommands.list; | ||
const restrictedCommands = [ | ||
'ping', | ||
'flushall', | ||
'flushdb', | ||
'select', | ||
'auth', | ||
'info', | ||
'quit', | ||
'slaveof', | ||
'config', | ||
'sentinel']; | ||
methodsToWrap.forEach((method) => { | ||
if (restrictedCommands.indexOf(method) > -1) { | ||
return; | ||
} | ||
const actualFn = redisClient[method]; | ||
redisClient[method] = function(...args) { | ||
const callback = args.pop(); | ||
let id; | ||
tracer.scoped(() => { | ||
id = tracer.createChildId(); | ||
tracer.setId(id); | ||
commonAnnotations(method); | ||
}); | ||
const wrapper = mkZipkinCallback(callback, id); | ||
const newArgs = [...args, wrapper]; | ||
actualFn.apply(this, newArgs); | ||
}; | ||
}); | ||
|
||
return redisClient; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"env": { | ||
"mocha": true | ||
}, | ||
"globals": { | ||
"expect": true | ||
} | ||
} |
84 changes: 84 additions & 0 deletions
84
packages/zipkin-instrumentation-redis/test/integrationTest.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
const sinon = require('sinon'); | ||
const {Tracer, ExplicitContext} = require('zipkin'); | ||
const zipkinClient = require('../src/zipkinClient'); | ||
|
||
const redisConnectionOptions = { | ||
host: 'localhost', | ||
port: '6379' | ||
}; | ||
|
||
const Redis = require('redis'); | ||
|
||
function getRedis(tracer) { | ||
return zipkinClient(tracer, Redis, redisConnectionOptions); | ||
} | ||
|
||
describe('redis interceptor', () => { | ||
it('should add zipkin annotations', (done) => { | ||
const ctxImpl = new ExplicitContext(); | ||
const recorder = {record: sinon.spy()}; | ||
// const recorder = new ConsoleRecorder(); | ||
const tracer = new Tracer({ctxImpl, recorder}); | ||
|
||
const redis = getRedis(tracer); | ||
redis.on('error', done); | ||
tracer.setId(tracer.createRootId()); | ||
const ctx = ctxImpl.getContext(); | ||
redis.set('ping', 'pong', 10, () => { | ||
ctxImpl.letContext(ctx, () => { | ||
redis.get('ping', () => { | ||
const annotations = recorder.record.args.map(args => args[0]); | ||
const firstAnn = annotations[0]; | ||
expect(annotations).to.have.length(8); | ||
|
||
function runTest(start, stop) { | ||
let lastSpanId; | ||
annotations.slice(start, stop).forEach((ann) => { | ||
if (!lastSpanId) { | ||
lastSpanId = ann.traceId.spanId; | ||
} | ||
expect(ann.traceId.spanId).to.equal(lastSpanId); | ||
}); | ||
} | ||
|
||
runTest(0, 4); | ||
runTest(4, 8); | ||
|
||
expect( | ||
annotations[0].traceId.spanId | ||
).not.to.equal(annotations[4].traceId.spanId); | ||
|
||
annotations.forEach(ann => { | ||
expect(ann.traceId.parentId).to.equal(firstAnn.traceId.traceId); | ||
expect(ann.traceId.spanId).not.to.equal(firstAnn.traceId.traceId); | ||
expect(ann.traceId.traceId).to.equal(firstAnn.traceId.traceId); | ||
}); | ||
|
||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
|
||
it('should run redis calls', done => { | ||
const ctxImpl = new ExplicitContext(); | ||
const recorder = {record: () => { }}; | ||
const tracer = new Tracer({ctxImpl, recorder}); | ||
const redis = getRedis(tracer); | ||
redis.on('error', done); | ||
redis.set('foo', 'bar', err => { | ||
if (err) { | ||
done(err); | ||
} else { | ||
redis.get('foo', (err2, data) => { | ||
if (err2) { | ||
done(err2); | ||
} else { | ||
expect(data).to.deep.equal('bar'); | ||
done(); | ||
} | ||
}); | ||
} | ||
}); | ||
}); | ||
}); |