Created
October 30, 2015 15:39
-
-
Save peterholditch/c0eb5ab3d8a7f35cee10 to your computer and use it in GitHub Desktop.
example for custom correlation with AppDynamics in Node.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
var argv = process.argv.slice(2); | |
var appd = require('appdynamics'); | |
if (!(argv[0] === '-entry' || argv[0] === '-service')) { | |
console.error('Please specify an -entry or -service role, e.g. `node example -entry`') | |
process.exit(1); | |
} | |
/* Initialize App Dynamics */ | |
appd.profile({ | |
debug: false, | |
controllerHostName: 'localhost', | |
controllerPort: 8090, | |
applicationName: 'microservices', | |
tierName: 'tier' + argv[0], | |
nodeName: 'node' + argv[0], // Node names must be unique. | |
controllerSslEnabled: false // Optional - use if connecting to controller via SSL | |
}); | |
var EventEmitter = require('events').EventEmitter; | |
var redis = require('redis'); | |
var publisherClient; | |
var subscriberClient; | |
function publish(channel, message, cb) { | |
var client = publisherClient || (publisherClient = redis.createClient()); | |
client.publish(channel, JSON.stringify(message), cb); | |
} | |
function subscribe(channel) { | |
var client = subscriberClient || (subscriberClient = redis.createClient()); | |
var emitter = new EventEmitter(); | |
client.on('message', function(messageChannel, message) { | |
if (channel !== messageChannel) return; | |
emitter.emit('message', JSON.parse(message)); | |
}); | |
client.subscribe(channel); | |
return emitter; | |
} | |
function createEntry() { | |
var publisherTopic = 'entry'; | |
var subscriberTopic = 'entry:response'; | |
var subscriber = subscribe(subscriberTopic); | |
require('http').createServer(function(req, res) { | |
/* Take next message */ | |
subscriber.once('message', function(message) { | |
res.writeHead(message.statusCode); | |
res.end(JSON.stringify(message)); | |
}); | |
var request = { | |
at: new Date() | |
}; | |
publish(publisherTopic, request, function(err) { | |
if (err) console.error(err); | |
console.log('requested'); | |
}); | |
}).listen(8080, function() { | |
console.log('example listening on 8080'); | |
}); | |
} | |
function createService() { | |
var publisherTopic = 'entry:response'; | |
var subscriberTopic = 'entry'; | |
var subscriber = subscribe(subscriberTopic); | |
subscriber.on('message', function(message) { | |
console.log('received', message); | |
var response = { | |
statusCode: 200, | |
dates: [message.at, new Date()] | |
}; | |
publish(publisherTopic, response, function(err) { | |
if (err) console.error(err); | |
console.log('responded'); | |
}); | |
}); | |
} | |
if (argv[0] === '-entry') createEntry(); | |
else if (argv[0] === '-service') createService(); | |
function noop(){} |
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
var argv = process.argv.slice(2); | |
var appd = require('appdynamics'); | |
if (!(argv[0] === '-entry' || argv[0] === '-service')) { | |
console.error('Please specify an -entry or -service role, e.g. `node example -entry`') | |
process.exit(1); | |
} | |
/* Initialize App Dynamics */ | |
appd.profile({ | |
debug: false, | |
controllerHostName: 'localhost', | |
controllerPort: 8090, | |
applicationName: 'microservices', | |
tierName: 'tier' + argv[0], | |
nodeName: 'node' + argv[0], // Node names must be unique. | |
controllerSslEnabled: false // Optional - use if connecting to controller via SSL | |
}); | |
var EventEmitter = require('events').EventEmitter; | |
var redis = require('redis'); | |
var publisherClient; | |
var subscriberClient; | |
function publish(channel, message, cb) { | |
var client = publisherClient || (publisherClient = redis.createClient()); | |
client.publish(channel, JSON.stringify(message), cb); | |
} | |
function subscribe(channel) { | |
var client = subscriberClient || (subscriberClient = redis.createClient()); | |
var emitter = new EventEmitter(); | |
client.on('message', function(messageChannel, message) { | |
if (channel !== messageChannel) return; | |
emitter.emit('message', JSON.parse(message)); | |
}); | |
client.subscribe(channel); | |
return emitter; | |
} | |
function createEntry() { | |
var publisherTopic = 'entry'; | |
var subscriberTopic = 'entry:response'; | |
var subscriber = subscribe(subscriberTopic); | |
require('http').createServer(function(req, res) { | |
var trx = appd.startTransaction(req); | |
trx.beforeExitCall = function getExitInfo(exitCall) { //Suppress default Redis exit handling | |
if (exitCall.backendName == 'Redis') | |
return; | |
else | |
return exitCall; | |
} | |
/* Take next message */ | |
subscriber.once('message', function(message) { | |
if (message.ci) { | |
var nci = appd.parseCorrelationInfo(message.ci); | |
var trx = appd.startTransaction(nci); | |
} | |
res.writeHead(message.statusCode); | |
res.end(JSON.stringify(message)); | |
if (message.ci) trx.end(); | |
}); | |
var exit = trx.startExitCall({ // Inform AppD of upcoming exit call | |
exitType: 'EXIT_CACHE', | |
label: 'Event Bus - ' + publisherTopic, | |
identifyingProperties: { // together, properties must uniquely identify the message destination | |
bus: "local_redis", | |
topic: publisherTopic | |
} | |
}); | |
var request = { | |
ci: trx.createCorrelationInfo(exit), // put the AppD correlation header into the message payload | |
at: new Date() | |
}; | |
publish(publisherTopic, request, function(err) { | |
if (err) console.error(err); | |
console.log('requested'); | |
trx.endExitCall(exit); // Inform AppD that exit call has completed | |
trx.end(); | |
}); | |
}).listen(8080, function() { | |
console.log('example listening on 8080'); | |
}); | |
} | |
function createService() { | |
var publisherTopic = 'entry:response'; | |
var subscriberTopic = 'entry'; | |
var subscriber = subscribe(subscriberTopic); | |
subscriber.on('message', function(message) { | |
console.log('received', message); | |
if (!message.ci) return publish(publisherTopic, { statusCode: 400, info: 'CorrelationInfo is empty.' }, noop); | |
var nci = appd.parseCorrelationInfo(message.ci); | |
var trx = appd.startTransaction(nci); // Associate transaction as downstream component of txn defined in ci field (upstream correlato header) | |
trx.beforeExitCall = function getExitInfo(exitCall) { // Supress default Redis exit handling | |
if (exitCall.backendName == 'Redis') | |
return; | |
else | |
return exitCall; | |
} | |
var exit = trx.startExitCall({ | |
exitType: 'EXIT_CACHE', | |
label: 'Event Bus - ' + publisherTopic, | |
identifyingProperties: { // together, properties must identify the message destination | |
bus: "local_redis", | |
topic: publisherTopic | |
} | |
}); | |
var response = { | |
ci: trx.createCorrelationInfo(exit), // ci is correlation header for reply message | |
statusCode: 200, | |
dates: [message.at, new Date()] | |
}; | |
publish(publisherTopic, response, function(err) { | |
if (err) console.error(err); | |
console.log('responded'); | |
trx.endExitCall(exit); // Inform AppD that exit call is over | |
trx.end(); | |
}); | |
}); | |
} | |
if (argv[0] === '-entry') createEntry(); | |
else if (argv[0] === '-service') createService(); | |
function noop(){} |
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
The 2 other files in this gist show a Redis request/response example (example-original.js) | |
and the same file modified for instrumentation with AppDynamics (example.js) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment