lightstep-tracer
Version:
> ❗ **This instrumentation is no longer recommended**. Please review [documentation on setting up and configuring the OpenTelemetry Node.js Launcher](https://github.com/lightstep/otel-launcher-node) or [OpenTelemetry JS (Browser)](https://github.com/open-
240 lines (215 loc) • 7.29 kB
JavaScript
//
// node index.js [username]
//
// Makes a series of GitHub API calls to return information about the user.
// Creates a trace with spans for the overall query as well as the individual
// API requests.
//
;
//
// Dependencies
//
// Note: the LightStep package is included directly. Normally this require()
// would simply be:
//
// var lightstep = require('lightstep');
//
var lightstep = require('../..');
var http = require('http');
var url = require('url');
var opentracing = require('opentracing');
// Proxy the requests through a LightStep server
var PROXY_HOST = process.env.LIGHTSTEP_PROXY_HOST || 'example-proxy.lightstep.com';
var PROXY_PORT = process.env.LIGHTSTEP_PROXY_PORT || 80;
//
// The first argument to the script is the GitHub user name
//
var username = process.argv[2] || 'lightstep';
// Initialize the OpenTracing APIs to use the LightStep bindings
//
// NOTE: the access token will need to be replaced with your project's access
// token. The component_name can be an identifier you wish to use to identify the
// service or process.
//
opentracing.initGlobalTracer(new lightstep.Tracer({
access_token : '{your_access_token}',
component_name : 'lightstep-tracer/examples/node',
}));
// Do the work.
printUserInfo(username);
//
// Worker functions
//
function printUserInfo(username) {
// Start the outer operation span
var span = opentracing.globalTracer().startSpan('printUserInfo');
span.log({ event : 'query_started' });
queryUserInfo(span, username, function(err, user) {
if (err) {
span.setTag('error', true);
span.log({
event : 'error',
'error.object' : err,
});
span.finish();
return;
}
span.log({
event : 'query_finished',
user : user,
});
console.log('User: ' + user.login);
console.log('Type: ' + user.type);
console.log('Public repositories: ' + user.repoNames.length);
for (var i = 0; i < user.repoNames.length; i++) {
console.log(' ' + user.repoNames[i]);
}
console.log('Recent events: ' + user.recentEvents);
for (var key in user.eventCounts) {
console.log(' ' + key + ': ' + user.eventCounts[key]);
}
// Lastly, log the remaining rate limit data to see how many more times
// the public GitHub APIs can be queried!
httpGet(span, 'http://api.github.com/rate_limit', function (err, json) {
if (err) {
span.setTag('error', true);
span.log({
event : 'error',
'error.object' : err,
});
}
span.log({
event : 'rate_limit',
json : json,
});
span.finish();
// Generate a LightStep-specific URL
var url = span.generateTraceURL();
console.log('');
console.log('View the trace at: ' + url);
});
});
}
/**
* Make a series GitHub calls and aggregate the data into the `user` object
* defined below.
*/
function queryUserInfo(parentSpan, username, callback) {
// Aggregated user information across multiple API calls
var user = {
login : null,
type : null,
repoNames : [],
recentEvents : 0,
eventCounts : {},
};
// Call the callback only when all three API requests finish or on the
// first error.
var remainingCalls = 3;
var next = function (err) {
// Early terminate on any error
remainingCalls -= err ? Math.max(remainingCalls, 1) : 1;
if (remainingCalls === 0) {
callback(err, err ? null : user);
}
};
// First query the user info for the given username
httpGet(parentSpan, 'http://api.github.com/users/' + username, function (err, json) {
if (err) {
return next(err);
}
user.login = json.login;
user.type = json.type;
// Use the user info to query names of all the user's public repositories
httpGet(parentSpan, json.repos_url, function (err, json) {
if (err) {
return next(err);
}
for (var i = 0; i < json.length; i++) {
user.repoNames.push(json[i].name);
}
next(null);
});
// In parallel, query the recent events activity for the user
httpGet(parentSpan, json.received_events_url, function (err, json) {
if (err) {
return next(err);
}
user.recentEvents = json.length;
for (var i = 0; i < json.length; i++) {
var eventType = json[i].type;
user.eventCounts[eventType] = user.eventCounts[eventType] || 0;
user.eventCounts[eventType]++;
}
next(null);
});
next(null);
});
}
/**
* Helper function to make a GET request and return parsed JSON data.
*/
function httpGet(parentSpan, urlString, callback) {
var span = opentracing.globalTracer().startSpan('http.get', { childOf : parentSpan });
var callbackWrapper = function (err, data) {
span.finish();
callback(err, data);
};
try {
var carrier = {};
opentracing.globalTracer().inject(span, opentracing.FORMAT_TEXT_MAP, carrier);
var dest = url.parse(urlString);
var options = {
host : PROXY_HOST,
path : dest.path,
port : PROXY_PORT,
headers: {
// User-Agent is required by the GitHub APIs
'User-Agent': 'LightStep Example',
}
};
for (var key in carrier) {
options.headers[key] = carrier[key];
}
// Create a span representing the https request
span.setTag('url', urlString);
span.log({
event : 'options',
'options': options,
});
return http.get(options, function(response) {
var bodyBuffer = '';
response.on('data', function(chunk) {
bodyBuffer += chunk;
});
response.on('end', function() {
span.log({
body : bodyBuffer,
length : bodyBuffer.length,
});
var parsedJSON, err;
try {
parsedJSON = JSON.parse(bodyBuffer);
} catch (exception) {
err = {
buffer : bodyBuffer,
exception : exception,
};
span.setTag('error', true);
span.log({
event : 'error',
'error.object': err,
});
}
callbackWrapper(err, parsedJSON);
});
});
} catch (exception) {
span.setTag('error', true);
span.log({
event : 'error',
'error.object': exception,
});
callbackWrapper(exception, null);
}
}