From da59afdaff75000fe2601749832a1fb01ac0f6ff Mon Sep 17 00:00:00 2001 From: YUE CHEN Date: Fri, 15 Mar 2019 14:33:37 +0800 Subject: [PATCH 1/9] update code to connect with RUM and Liberty --- appmetrics-zipkin.js | 24 +++++++++++ probes/http-outbound-probe-zipkin.js | 44 +++++++++++++++++--- probes/http-probe-zipkin.js | 55 +++++++++++++++++++++---- probes/https-outbound-probe-zipkin.js | 47 +++++++++++++++++++--- probes/https-probe-zipkin.js | 58 ++++++++++++++++++++++----- 5 files changed, 199 insertions(+), 29 deletions(-) diff --git a/appmetrics-zipkin.js b/appmetrics-zipkin.js index 54efd22..599a36a 100755 --- a/appmetrics-zipkin.js +++ b/appmetrics-zipkin.js @@ -119,6 +119,30 @@ function start(options) { }); } +module.exports.update = function(options) { + start(options); + // for (var i = 0; i < probes.length; i++) { + // probes[i].updateServiceName(probes[i].serviceName); + // } + probes.forEach(function(probe) { + probe.updateProbes(); + // probe.enableRequests(); + }); +}; + +module.exports.stop = function(){ + probes.forEach(function(probe) { + probe.stop(); + // probe.enableRequests(); + }); +}; + +module.exports.disable = function(){ + probes.forEach(function(probe) { + probe.disable(); + // probe.enableRequests(); + }); +}; /* * Patch the module require function to run the probe attach function * for any matching module. This loads the monitoring probes into the modules diff --git a/probes/http-outbound-probe-zipkin.js b/probes/http-outbound-probe-zipkin.js index ec089a0..bc1a609 100644 --- a/probes/http-outbound-probe-zipkin.js +++ b/probes/http-outbound-probe-zipkin.js @@ -22,6 +22,7 @@ var semver = require('semver'); const zipkin = require('zipkin'); var serviceName; +var tracer; const { Request, @@ -46,8 +47,33 @@ function HttpOutboundProbeZipkin() { } util.inherits(HttpOutboundProbeZipkin, Probe); +HttpOutboundProbeZipkin.prototype.updateProbes = function() { + serviceName = this.serviceName; + tracer = new zipkin.Tracer({ + ctxImpl, + recorder: this.recorder, + sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests + traceId128Bit: true // to generate 128-bit trace IDs. + }); +}; + +function addJaegerHeaders(req, traceId) { + const headers = req.headers || {}; + + var headerKeys = [ + traceId.traceId, + traceId.spanId, + traceId._parentId.value ? traceId._parentId.value : '0', + traceId.sampled.value ? 1 : 0 + ]; + headers['ibm-apm-spancontext'] = headerKeys.join(':'); + console.info('http-outbound ibm-apm-spancontext: ', headers['ibm-apm-spancontext']); + + return Object.assign({}, req, {headers}); +} + HttpOutboundProbeZipkin.prototype.attach = function(name, target) { - const tracer = new zipkin.Tracer({ + tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests @@ -84,13 +110,15 @@ HttpOutboundProbeZipkin.prototype.attach = function(name, target) { } if (!methodArgs[0].headers) methodArgs[0].headers = {}; - let { headers } = Request.addZipkinHeaders(methodArgs[0], tracer.createChildId()); + // let { headers } = Request.addZipkinHeaders(methodArgs[0], tracer.createChildId()); + let { headers } = addJaegerHeaders(methodArgs[0], tracer.createChildId()); Object.assign(methodArgs[0].headers, { headers }); tracer.recordServiceName(serviceName); - tracer.recordRpc(requestMethod); + tracer.recordRpc(requestMethod + ' ' + urlRequested); tracer.recordBinary('http.url', urlRequested); tracer.recordAnnotation(new Annotation.ClientSend()); + console.info('send http-outbound-tracer(before): ', tracer.id); // End metrics aspect.aroundCallback( methodArgs, @@ -98,6 +126,7 @@ HttpOutboundProbeZipkin.prototype.attach = function(name, target) { function(target, args, probeData) { tracer.recordBinary('http.status_code', target.res.statusCode.toString()); tracer.recordAnnotation(new Annotation.ClientRecv()); + console.info('send http-outbound-tracer(aroundCallback): ', tracer.id); }, function(target, args, probeData, ret) { return ret; @@ -131,11 +160,14 @@ function formatURL(httpOptions) { url += httpOptions.host; } else if (httpOptions.hostname) { url += httpOptions.hostname; + if (httpOptions.port) { + url += ':' + httpOptions.port; + } } else { url += 'localhost'; - } - if (httpOptions.port) { - url += ':' + httpOptions.port; + if (httpOptions.port) { + url += ':' + httpOptions.port; + } } if (httpOptions.path) { url += httpOptions.path; diff --git a/probes/http-probe-zipkin.js b/probes/http-probe-zipkin.js index 576eec4..1c81925 100644 --- a/probes/http-probe-zipkin.js +++ b/probes/http-probe-zipkin.js @@ -21,6 +21,7 @@ var util = require('util'); const zipkin = require('zipkin'); var serviceName; +var tracer; const { Request, @@ -41,6 +42,10 @@ function hasZipkinHeader(httpReq) { return headers[(Header.TraceId).toLowerCase()] !== undefined && headers[(Header.SpanId).toLowerCase()] !== undefined; } +function hasJaegerHeader(httpReq) { + const headers = httpReq.headers || {}; + return headers['ibm-apm-spancontext'] !== undefined; +} function HttpProbeZipkin() { Probe.call(this, 'http'); @@ -63,10 +68,20 @@ function stringToIntOption(str) { } } +HttpProbeZipkin.prototype.updateProbes = function() { + serviceName = this.serviceName; + tracer = new zipkin.Tracer({ + ctxImpl, + recorder: this.recorder, + sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests + traceId128Bit: true // to generate 128-bit trace IDs. + }); +}; + HttpProbeZipkin.prototype.attach = function(name, target) { serviceName = this.serviceName; - const tracer = new zipkin.Tracer({ + tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests @@ -90,8 +105,31 @@ HttpProbeZipkin.prototype.attach = function(name, target) { var traceUrl = parse(httpReq.url); // console.log(util.inspect(httpReq)); if (traceUrl !== '') { - const method = httpReq.method; - if (hasZipkinHeader(httpReq)) { + var reqMethod = httpReq.method; + if (reqMethod.toUpperCase() === 'OPTIONS' && httpReq.headers['access-control-request-method']) { + reqMethod = httpReq.headers['access-control-request-method']; + } + if (hasJaegerHeader(httpReq)) { + const headers = httpReq.headers; + var jaegerHeader = headers['ibm-apm-spancontext']; + console.info('http ibm-apm-spancontext:', jaegerHeader); + var headerKeys = jaegerHeader.split(':'); + var jaegerSpanId = headerKeys[1]; + if (jaegerSpanId !== undefined) { + const traceId = new Some(headerKeys[0]); + const parentSpanId = new Some(headerKeys[2]); + const flags = (new Some(headerKeys[3])).flatMap(stringToIntOption).getOrElse(0); + + var id_byJaeger = new TraceId({ + traceId: traceId, + parentId: parentSpanId, + spanId: jaegerSpanId, + flags + }); + tracer.setId(id_byJaeger); + probeData.traceId = tracer.id; + } + } else if (hasZipkinHeader(httpReq)) { const headers = httpReq.headers; var spanId = headers[(Header.SpanId).toLowerCase()]; if (spanId !== undefined) { @@ -116,16 +154,17 @@ HttpProbeZipkin.prototype.attach = function(name, target) { const { headers } = Request.addZipkinHeaders(args[0], tracer.id); Object.assign(args[0].headers, headers); } - - tracer.recordServiceName(serviceName); - tracer.recordRpc(method.toUpperCase()); tracer.recordBinary('http.url', httpReq.headers.host + traceUrl); tracer.recordAnnotation(new Annotation.ServerRecv()); - tracer.recordAnnotation(new Annotation.LocalAddr(0)); - + console.info('http-tracer(before): ', tracer.id); aspect.after(res, 'end', probeData, function(obj, methodName, args, probeData, ret) { + + tracer.recordServiceName(serviceName); + tracer.recordRpc(reqMethod.toUpperCase() + ' ' + traceUrl); + tracer.recordAnnotation(new Annotation.LocalAddr(0)); tracer.recordBinary('http.status_code', res.statusCode.toString()); tracer.recordAnnotation(new Annotation.ServerSend()); + console.info('http-tracer(after): ', tracer.id); }); } }); diff --git a/probes/https-outbound-probe-zipkin.js b/probes/https-outbound-probe-zipkin.js index 09c9352..9cef1ff 100644 --- a/probes/https-outbound-probe-zipkin.js +++ b/probes/https-outbound-probe-zipkin.js @@ -22,6 +22,7 @@ var semver = require('semver'); const zipkin = require('zipkin'); var serviceName; +var tracer; const { Request, @@ -46,8 +47,34 @@ function HttpsOutboundProbeZipkin() { } util.inherits(HttpsOutboundProbeZipkin, Probe); + +HttpsOutboundProbeZipkin.prototype.updateProbes = function() { + serviceName = this.serviceName; + tracer = new zipkin.Tracer({ + ctxImpl, + recorder: this.recorder, + sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests + traceId128Bit: true // to generate 128-bit trace IDs. + }); +}; + +function addJaegerHeaders(req, traceId) { + const headers = req.headers || {}; + + var headerKeys = [ + traceId.traceId, + traceId.spanId, + traceId._parentId.value ? traceId._parentId.value : '0', + traceId.sampled.value ? 1 : 0 + ]; + headers['ibm-apm-spancontext'] = headerKeys.join(':'); + console.info('http-outbound ibm-apm-spancontext: ', headers['ibm-apm-spancontext']); + + return Object.assign({}, req, {headers}); +} + HttpsOutboundProbeZipkin.prototype.attach = function(name, target) { - const tracer = new zipkin.Tracer({ + tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests @@ -79,11 +106,15 @@ HttpsOutboundProbeZipkin.prototype.attach = function(name, target) { } } // Must assign new options back to methodArgs[0] - methodArgs[0] = Request.addZipkinHeaders(methodArgs[0], tracer.createChildId()); + // methodArgs[0] = Request.addZipkinHeaders(methodArgs[0], tracer.createChildId()); + let { headers } = addJaegerHeaders(methodArgs[0], tracer.createChildId()); + Object.assign(methodArgs[0].headers, { headers }); + tracer.recordServiceName(serviceName); - tracer.recordRpc(requestMethod); + tracer.recordRpc(requestMethod + ' ' + urlRequested); tracer.recordBinary('http.url', urlRequested); tracer.recordAnnotation(new Annotation.ClientSend()); + console.info('send https-outbound-tracer(before): ', tracer.id); // End metrics aspect.aroundCallback( methodArgs, @@ -91,6 +122,7 @@ HttpsOutboundProbeZipkin.prototype.attach = function(name, target) { function(target, args, probeData) { tracer.recordBinary('http.status_code', target.res.statusCode.toString()); tracer.recordAnnotation(new Annotation.ClientRecv()); + console.info('send https-outbound-tracer(aroundCallback): ', tracer.id); }, function(target, args, probeData, ret) { return ret; @@ -124,11 +156,14 @@ function formatURL(httpsOptions) { url += httpsOptions.host; } else if (httpsOptions.hostname) { url += httpsOptions.hostname; + if (httpsOptions.port) { + url += ':' + httpsOptions.port; + } } else { url += 'localhost'; - } - if (httpsOptions.port) { - url += ':' + httpsOptions.port; + if (httpsOptions.port) { + url += ':' + httpsOptions.port; + } } if (httpsOptions.path) { url += httpsOptions.path; diff --git a/probes/https-probe-zipkin.js b/probes/https-probe-zipkin.js index 2f6d57b..65cb8b8 100644 --- a/probes/https-probe-zipkin.js +++ b/probes/https-probe-zipkin.js @@ -21,6 +21,7 @@ var util = require('util'); const zipkin = require('zipkin'); var serviceName; +var tracer; const { Request, @@ -41,6 +42,10 @@ function hasZipkinHeader(httpsReq) { return headers[(Header.TraceId).toLowerCase()] !== undefined && headers[(Header.SpanId).toLowerCase()] !== undefined; } +function hasJaegerHeader(httpReq) { + const headers = httpReq.headers || {}; + return headers['ibm-apm-spancontext'] !== undefined; +} function HttpsProbeZipkin() { Probe.call(this, 'https'); @@ -63,10 +68,21 @@ function stringToIntOption(str) { } } +HttpsProbeZipkin.prototype.updateProbes = function() { + serviceName = this.serviceName; + tracer = new zipkin.Tracer({ + ctxImpl, + recorder: this.recorder, + sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests + traceId128Bit: true // to generate 128-bit trace IDs. + }); +}; + + HttpsProbeZipkin.prototype.attach = function(name, target) { serviceName = this.serviceName; - const tracer = new zipkin.Tracer({ + tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests @@ -89,9 +105,31 @@ HttpsProbeZipkin.prototype.attach = function(name, target) { // Filter out urls where filter.to is '' var traceUrl = parse(httpsReq.url); if (traceUrl !== '') { - const method = httpsReq.method; - - if (hasZipkinHeader(httpsReq)) { + var reqMethod = httpsReq.method; + if (reqMethod.toUpperCase() === 'OPTIONS' && httpsReq.headers['access-control-request-method']) { + reqMethod = httpsReq.headers['access-control-request-method']; + } + if (hasJaegerHeader(httpsReq)) { + const headers = httpsReq.headers; + var jaegerHeader = headers['ibm-apm-spancontext']; + console.info('http ibm-apm-spancontext:', jaegerHeader); + var headerKeys = jaegerHeader.split(':'); + var jaegerSpanId = headerKeys[1]; + if (jaegerSpanId !== undefined) { + const traceId = new Some(headerKeys[0]); + const parentSpanId = new Some(headerKeys[2]); + const flags = (new Some(headerKeys[3])).flatMap(stringToIntOption).getOrElse(0); + + var id_byJaeger = new TraceId({ + traceId: traceId, + parentId: parentSpanId, + spanId: jaegerSpanId, + flags + }); + tracer.setId(id_byJaeger); + probeData.traceId = tracer.id; + } + } else if (hasZipkinHeader(httpsReq)) { const headers = httpsReq.headers; var spanId = headers[(Header.SpanId).toLowerCase()]; if (spanId !== undefined) { @@ -116,16 +154,18 @@ HttpsProbeZipkin.prototype.attach = function(name, target) { args[0] = Request.addZipkinHeaders(args[0], tracer.id); } - tracer.recordServiceName(serviceName); - tracer.recordRpc(method.toUpperCase()); - tracer.recordBinary('http.url', httpsReq.headers.host + traceUrl); - tracer.recordAnnotation(new Annotation.ServerRecv()); - tracer.recordAnnotation(new Annotation.LocalAddr(0)); + tracer.recordBinary('http.url', httpReq.headers.host + traceUrl); + tracer.recordAnnotation(new Annotation.ServerRecv()); + console.info('https-tracer(before): ', tracer.id); aspect.after(res, 'end', probeData, function(obj, methodName, args, probeData, ret) { + tracer.recordServiceName(serviceName); + tracer.recordRpc(reqMethod.toUpperCase() + ' ' + traceUrl); + tracer.recordAnnotation(new Annotation.LocalAddr(0)); tracer.recordBinary('http.status_code', res.statusCode.toString()); tracer.recordAnnotation(new Annotation.ServerSend()); + console.info('https-tracer(after): ', tracer.id); }); } }); From 3e71d886ae00253ef82a6400bd77231c282a9f52 Mon Sep 17 00:00:00 2001 From: Yue Chen Date: Wed, 20 Mar 2019 13:06:24 +0800 Subject: [PATCH 2/9] refine some code --- appmetrics-zipkin.js | 14 ++++++++++++ lib/probe.js | 5 +++++ lib/tools.js | 31 +++++++++++++++++++++++++++ probes/http-outbound-probe-zipkin.js | 20 +++++------------ probes/http-probe-zipkin.js | 12 +++++------ probes/https-outbound-probe-zipkin.js | 21 +++++------------- probes/https-probe-zipkin.js | 14 ++++++------ 7 files changed, 71 insertions(+), 46 deletions(-) create mode 100644 lib/tools.js diff --git a/appmetrics-zipkin.js b/appmetrics-zipkin.js index 599a36a..53117a4 100755 --- a/appmetrics-zipkin.js +++ b/appmetrics-zipkin.js @@ -130,6 +130,20 @@ module.exports.update = function(options) { }); }; +module.exports.updateServiceName = function(serviceName){ + probes.forEach(function(probe) { + probe.setServiceName(serviceName); + probe.updateProbes(); + }); +} + +module.exports.updateIbmapmContext = function(context) { + probes.forEach(function(probe) { + probe.setIbmapmContext(context); + probe.updateProbes(); + }); +} + module.exports.stop = function(){ probes.forEach(function(probe) { probe.stop(); diff --git a/lib/probe.js b/lib/probe.js index 9ee3f1c..8c9c7d7 100755 --- a/lib/probe.js +++ b/lib/probe.js @@ -27,6 +27,7 @@ function Probe(name) { this.config = {}; this.recorder = {}; this.serviceName = ''; + this.ibmapmContext = {}; } /* @@ -55,6 +56,10 @@ Probe.prototype.setServiceName = function(name) { this.serviceName = name; }; +Probe.prototype.setIbmapmContext = function(ibmapmContext) { + this.ibmapmContext = ibmapmContext; +}; + /* * Lightweight metrics probes */ diff --git a/lib/tools.js b/lib/tools.js new file mode 100644 index 0000000..0cae13a --- /dev/null +++ b/lib/tools.js @@ -0,0 +1,31 @@ + +'use strict'; + +module.exports.recordIbmapmContext = function(tracer, ibmapmContext){ + if (ibmapmContext && ibmapmContext.podName) { + tracer.recordBinary('podName', ibmapmContext.podName); + tracer.recordBinary('containerId', ibmapmContext.containerId); + tracer.recordBinary('nameSpace', ibmapmContext.nameSpace); + tracer.recordBinary('clusterId', ibmapmContext.clusterId ? ibmapmContext.clusterId : 'unamedcluster'); + } +}; + +module.exports.addJaegerHeaders = function(req, traceId, message) { + const headers = req.headers || {}; + + var headerKeys = [ + traceId.traceId, + traceId.spanId, + traceId._parentId.value ? traceId._parentId.value : '0', + traceId.sampled.value ? 1 : 0 + ]; + headers['ibm-apm-spancontext'] = headerKeys.join(':'); + console.info(message + ' ibm-apm-spancontext: ', headers['ibm-apm-spancontext']); + + return Object.assign({}, req, {headers}); +}; + +module.exports.hasJaegerHeader = function(httpReq) { + const headers = httpReq.headers || {}; + return headers['ibm-apm-spancontext'] !== undefined; +}; diff --git a/probes/http-outbound-probe-zipkin.js b/probes/http-outbound-probe-zipkin.js index bc1a609..603f8cc 100644 --- a/probes/http-outbound-probe-zipkin.js +++ b/probes/http-outbound-probe-zipkin.js @@ -16,12 +16,14 @@ 'use strict'; var Probe = require('../lib/probe.js'); var aspect = require('../lib/aspect.js'); +var tool = require('../lib/tools.js'); var util = require('util'); var url = require('url'); var semver = require('semver'); const zipkin = require('zipkin'); var serviceName; +var ibmapmContext; var tracer; const { @@ -49,6 +51,7 @@ util.inherits(HttpOutboundProbeZipkin, Probe); HttpOutboundProbeZipkin.prototype.updateProbes = function() { serviceName = this.serviceName; + ibmapmContext = this.ibmapmContext; tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, @@ -57,20 +60,6 @@ HttpOutboundProbeZipkin.prototype.updateProbes = function() { }); }; -function addJaegerHeaders(req, traceId) { - const headers = req.headers || {}; - - var headerKeys = [ - traceId.traceId, - traceId.spanId, - traceId._parentId.value ? traceId._parentId.value : '0', - traceId.sampled.value ? 1 : 0 - ]; - headers['ibm-apm-spancontext'] = headerKeys.join(':'); - console.info('http-outbound ibm-apm-spancontext: ', headers['ibm-apm-spancontext']); - - return Object.assign({}, req, {headers}); -} HttpOutboundProbeZipkin.prototype.attach = function(name, target) { tracer = new zipkin.Tracer({ @@ -111,12 +100,13 @@ HttpOutboundProbeZipkin.prototype.attach = function(name, target) { if (!methodArgs[0].headers) methodArgs[0].headers = {}; // let { headers } = Request.addZipkinHeaders(methodArgs[0], tracer.createChildId()); - let { headers } = addJaegerHeaders(methodArgs[0], tracer.createChildId()); + let { headers } = tool.addJaegerHeaders(methodArgs[0], tracer.createChildId(), 'http-outbound'); Object.assign(methodArgs[0].headers, { headers }); tracer.recordServiceName(serviceName); tracer.recordRpc(requestMethod + ' ' + urlRequested); tracer.recordBinary('http.url', urlRequested); + tool.recordIbmapmContext(tracer, ibmapmContext); tracer.recordAnnotation(new Annotation.ClientSend()); console.info('send http-outbound-tracer(before): ', tracer.id); // End metrics diff --git a/probes/http-probe-zipkin.js b/probes/http-probe-zipkin.js index 1c81925..b39bde3 100644 --- a/probes/http-probe-zipkin.js +++ b/probes/http-probe-zipkin.js @@ -17,11 +17,13 @@ var Probe = require('../lib/probe.js'); var aspect = require('../lib/aspect.js'); +var tool = require('../lib/tools.js'); var util = require('util'); const zipkin = require('zipkin'); var serviceName; var tracer; +var ibmapmContext; const { Request, @@ -42,11 +44,6 @@ function hasZipkinHeader(httpReq) { return headers[(Header.TraceId).toLowerCase()] !== undefined && headers[(Header.SpanId).toLowerCase()] !== undefined; } -function hasJaegerHeader(httpReq) { - const headers = httpReq.headers || {}; - return headers['ibm-apm-spancontext'] !== undefined; -} - function HttpProbeZipkin() { Probe.call(this, 'http'); this.config = { @@ -70,6 +67,7 @@ function stringToIntOption(str) { HttpProbeZipkin.prototype.updateProbes = function() { serviceName = this.serviceName; + ibmapmContext = this.ibmapmContext; tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, @@ -109,7 +107,7 @@ HttpProbeZipkin.prototype.attach = function(name, target) { if (reqMethod.toUpperCase() === 'OPTIONS' && httpReq.headers['access-control-request-method']) { reqMethod = httpReq.headers['access-control-request-method']; } - if (hasJaegerHeader(httpReq)) { + if (tool.hasJaegerHeader(httpReq)) { const headers = httpReq.headers; var jaegerHeader = headers['ibm-apm-spancontext']; console.info('http ibm-apm-spancontext:', jaegerHeader); @@ -163,6 +161,7 @@ HttpProbeZipkin.prototype.attach = function(name, target) { tracer.recordRpc(reqMethod.toUpperCase() + ' ' + traceUrl); tracer.recordAnnotation(new Annotation.LocalAddr(0)); tracer.recordBinary('http.status_code', res.statusCode.toString()); + tool.recordIbmapmContext(tracer, ibmapmContext); tracer.recordAnnotation(new Annotation.ServerSend()); console.info('http-tracer(after): ', tracer.id); }); @@ -183,5 +182,4 @@ function parse(url) { return url; }; - module.exports = HttpProbeZipkin; diff --git a/probes/https-outbound-probe-zipkin.js b/probes/https-outbound-probe-zipkin.js index 9cef1ff..b096902 100644 --- a/probes/https-outbound-probe-zipkin.js +++ b/probes/https-outbound-probe-zipkin.js @@ -16,6 +16,7 @@ 'use strict'; var Probe = require('../lib/probe.js'); var aspect = require('../lib/aspect.js'); +var tool = require('../lib/tools.js'); var util = require('util'); var url = require('url'); var semver = require('semver'); @@ -23,6 +24,7 @@ const zipkin = require('zipkin'); var serviceName; var tracer; +var ibmapmContext; const { Request, @@ -50,6 +52,7 @@ util.inherits(HttpsOutboundProbeZipkin, Probe); HttpsOutboundProbeZipkin.prototype.updateProbes = function() { serviceName = this.serviceName; + ibmapmContext = this.ibmapmContext; tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, @@ -58,21 +61,6 @@ HttpsOutboundProbeZipkin.prototype.updateProbes = function() { }); }; -function addJaegerHeaders(req, traceId) { - const headers = req.headers || {}; - - var headerKeys = [ - traceId.traceId, - traceId.spanId, - traceId._parentId.value ? traceId._parentId.value : '0', - traceId.sampled.value ? 1 : 0 - ]; - headers['ibm-apm-spancontext'] = headerKeys.join(':'); - console.info('http-outbound ibm-apm-spancontext: ', headers['ibm-apm-spancontext']); - - return Object.assign({}, req, {headers}); -} - HttpsOutboundProbeZipkin.prototype.attach = function(name, target) { tracer = new zipkin.Tracer({ ctxImpl, @@ -107,12 +95,13 @@ HttpsOutboundProbeZipkin.prototype.attach = function(name, target) { } // Must assign new options back to methodArgs[0] // methodArgs[0] = Request.addZipkinHeaders(methodArgs[0], tracer.createChildId()); - let { headers } = addJaegerHeaders(methodArgs[0], tracer.createChildId()); + let { headers } = tool.addJaegerHeaders(methodArgs[0], tracer.createChildId(), 'https-outbound'); Object.assign(methodArgs[0].headers, { headers }); tracer.recordServiceName(serviceName); tracer.recordRpc(requestMethod + ' ' + urlRequested); tracer.recordBinary('http.url', urlRequested); + tool.recordIbmapmContext(tracer, ibmapmContext); tracer.recordAnnotation(new Annotation.ClientSend()); console.info('send https-outbound-tracer(before): ', tracer.id); // End metrics diff --git a/probes/https-probe-zipkin.js b/probes/https-probe-zipkin.js index 65cb8b8..096397f 100644 --- a/probes/https-probe-zipkin.js +++ b/probes/https-probe-zipkin.js @@ -18,10 +18,12 @@ var Probe = require('../lib/probe.js'); var aspect = require('../lib/aspect.js'); var util = require('util'); +var tool = require('../lib/tools.js'); const zipkin = require('zipkin'); var serviceName; var tracer; +var ibmapmContext; const { Request, @@ -42,11 +44,6 @@ function hasZipkinHeader(httpsReq) { return headers[(Header.TraceId).toLowerCase()] !== undefined && headers[(Header.SpanId).toLowerCase()] !== undefined; } -function hasJaegerHeader(httpReq) { - const headers = httpReq.headers || {}; - return headers['ibm-apm-spancontext'] !== undefined; -} - function HttpsProbeZipkin() { Probe.call(this, 'https'); this.config = { @@ -70,6 +67,7 @@ function stringToIntOption(str) { HttpsProbeZipkin.prototype.updateProbes = function() { serviceName = this.serviceName; + ibmapmContext = this.ibmapmContext; tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, @@ -109,7 +107,7 @@ HttpsProbeZipkin.prototype.attach = function(name, target) { if (reqMethod.toUpperCase() === 'OPTIONS' && httpsReq.headers['access-control-request-method']) { reqMethod = httpsReq.headers['access-control-request-method']; } - if (hasJaegerHeader(httpsReq)) { + if (tool.hasJaegerHeader(httpsReq)) { const headers = httpsReq.headers; var jaegerHeader = headers['ibm-apm-spancontext']; console.info('http ibm-apm-spancontext:', jaegerHeader); @@ -155,7 +153,7 @@ HttpsProbeZipkin.prototype.attach = function(name, target) { } - tracer.recordBinary('http.url', httpReq.headers.host + traceUrl); + tracer.recordBinary('http.url', httpsReq.headers.host + traceUrl); tracer.recordAnnotation(new Annotation.ServerRecv()); console.info('https-tracer(before): ', tracer.id); @@ -164,6 +162,7 @@ HttpsProbeZipkin.prototype.attach = function(name, target) { tracer.recordRpc(reqMethod.toUpperCase() + ' ' + traceUrl); tracer.recordAnnotation(new Annotation.LocalAddr(0)); tracer.recordBinary('http.status_code', res.statusCode.toString()); + tool.recordIbmapmContext(tracer, ibmapmContext); tracer.recordAnnotation(new Annotation.ServerSend()); console.info('https-tracer(after): ', tracer.id); }); @@ -185,5 +184,4 @@ var parse = function(url) { return url; }; - module.exports = HttpsProbeZipkin; From 483e33f5ca200e07168564a5301aa86cd89a7050 Mon Sep 17 00:00:00 2001 From: Yue Chen Date: Wed, 20 Mar 2019 15:42:52 +0800 Subject: [PATCH 3/9] make sure server id is correct --- probes/http-outbound-probe-zipkin.js | 15 +++++---------- probes/http-probe-zipkin.js | 12 +++--------- probes/https-outbound-probe-zipkin.js | 9 +-------- probes/https-probe-zipkin.js | 9 +-------- 4 files changed, 10 insertions(+), 35 deletions(-) diff --git a/probes/http-outbound-probe-zipkin.js b/probes/http-outbound-probe-zipkin.js index 603f8cc..3c8034d 100644 --- a/probes/http-outbound-probe-zipkin.js +++ b/probes/http-outbound-probe-zipkin.js @@ -24,7 +24,6 @@ const zipkin = require('zipkin'); var serviceName; var ibmapmContext; -var tracer; const { Request, @@ -52,17 +51,11 @@ util.inherits(HttpOutboundProbeZipkin, Probe); HttpOutboundProbeZipkin.prototype.updateProbes = function() { serviceName = this.serviceName; ibmapmContext = this.ibmapmContext; - tracer = new zipkin.Tracer({ - ctxImpl, - recorder: this.recorder, - sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests - traceId128Bit: true // to generate 128-bit trace IDs. - }); }; HttpOutboundProbeZipkin.prototype.attach = function(name, target) { - tracer = new zipkin.Tracer({ + const tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests @@ -99,9 +92,11 @@ HttpOutboundProbeZipkin.prototype.attach = function(name, target) { } if (!methodArgs[0].headers) methodArgs[0].headers = {}; - // let { headers } = Request.addZipkinHeaders(methodArgs[0], tracer.createChildId()); - let { headers } = tool.addJaegerHeaders(methodArgs[0], tracer.createChildId(), 'http-outbound'); + var childId = tracer.createChildId(); + // let { headers } = Request.addZipkinHeaders(methodArgs[0], childId); + let { headers } = tool.addJaegerHeaders(methodArgs[0], childId, 'http-outbound'); Object.assign(methodArgs[0].headers, { headers }); + tracer.setId(childId); tracer.recordServiceName(serviceName); tracer.recordRpc(requestMethod + ' ' + urlRequested); diff --git a/probes/http-probe-zipkin.js b/probes/http-probe-zipkin.js index b39bde3..5eabca5 100644 --- a/probes/http-probe-zipkin.js +++ b/probes/http-probe-zipkin.js @@ -22,7 +22,6 @@ var util = require('util'); const zipkin = require('zipkin'); var serviceName; -var tracer; var ibmapmContext; const { @@ -68,18 +67,12 @@ function stringToIntOption(str) { HttpProbeZipkin.prototype.updateProbes = function() { serviceName = this.serviceName; ibmapmContext = this.ibmapmContext; - tracer = new zipkin.Tracer({ - ctxImpl, - recorder: this.recorder, - sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests - traceId128Bit: true // to generate 128-bit trace IDs. - }); }; HttpProbeZipkin.prototype.attach = function(name, target) { serviceName = this.serviceName; - tracer = new zipkin.Tracer({ + const tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests @@ -152,11 +145,12 @@ HttpProbeZipkin.prototype.attach = function(name, target) { const { headers } = Request.addZipkinHeaders(args[0], tracer.id); Object.assign(args[0].headers, headers); } + var serverTracerId = tracer.id; tracer.recordBinary('http.url', httpReq.headers.host + traceUrl); tracer.recordAnnotation(new Annotation.ServerRecv()); console.info('http-tracer(before): ', tracer.id); aspect.after(res, 'end', probeData, function(obj, methodName, args, probeData, ret) { - + tracer.setId(serverTracerId); tracer.recordServiceName(serviceName); tracer.recordRpc(reqMethod.toUpperCase() + ' ' + traceUrl); tracer.recordAnnotation(new Annotation.LocalAddr(0)); diff --git a/probes/https-outbound-probe-zipkin.js b/probes/https-outbound-probe-zipkin.js index b096902..063690d 100644 --- a/probes/https-outbound-probe-zipkin.js +++ b/probes/https-outbound-probe-zipkin.js @@ -23,7 +23,6 @@ var semver = require('semver'); const zipkin = require('zipkin'); var serviceName; -var tracer; var ibmapmContext; const { @@ -53,16 +52,10 @@ util.inherits(HttpsOutboundProbeZipkin, Probe); HttpsOutboundProbeZipkin.prototype.updateProbes = function() { serviceName = this.serviceName; ibmapmContext = this.ibmapmContext; - tracer = new zipkin.Tracer({ - ctxImpl, - recorder: this.recorder, - sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests - traceId128Bit: true // to generate 128-bit trace IDs. - }); }; HttpsOutboundProbeZipkin.prototype.attach = function(name, target) { - tracer = new zipkin.Tracer({ + const tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests diff --git a/probes/https-probe-zipkin.js b/probes/https-probe-zipkin.js index 096397f..e9490dc 100644 --- a/probes/https-probe-zipkin.js +++ b/probes/https-probe-zipkin.js @@ -22,7 +22,6 @@ var tool = require('../lib/tools.js'); const zipkin = require('zipkin'); var serviceName; -var tracer; var ibmapmContext; const { @@ -68,19 +67,13 @@ function stringToIntOption(str) { HttpsProbeZipkin.prototype.updateProbes = function() { serviceName = this.serviceName; ibmapmContext = this.ibmapmContext; - tracer = new zipkin.Tracer({ - ctxImpl, - recorder: this.recorder, - sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests - traceId128Bit: true // to generate 128-bit trace IDs. - }); }; HttpsProbeZipkin.prototype.attach = function(name, target) { serviceName = this.serviceName; - tracer = new zipkin.Tracer({ + const tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests From b5142a9c87da68c0e79782c373a329dc1fd5458f Mon Sep 17 00:00:00 2001 From: Yue Chen Date: Fri, 22 Mar 2019 11:26:06 +0800 Subject: [PATCH 4/9] add filter --- appmetrics-zipkin.js | 22 ++++++++++++++++++++-- lib/probe.js | 12 ++++++++++++ lib/tools.js | 22 ++++++++++++++++++++++ probes/http-outbound-probe-zipkin.js | 10 +++++++++- probes/https-outbound-probe-zipkin.js | 9 +++++++++ 5 files changed, 72 insertions(+), 3 deletions(-) diff --git a/appmetrics-zipkin.js b/appmetrics-zipkin.js index 53117a4..57bc6ae 100755 --- a/appmetrics-zipkin.js +++ b/appmetrics-zipkin.js @@ -135,14 +135,32 @@ module.exports.updateServiceName = function(serviceName){ probe.setServiceName(serviceName); probe.updateProbes(); }); -} +}; + +module.exports.updatePathFilter = function(paths){ + console.info('updatePathFilter', paths); + probes.forEach(function(probe) { + probe.setPathFilter(paths); + probe.updateProbes(); + }); +}; + + +module.exports.updateHeaderFilter = function(headers){ + console.info('updateHeaderFilter', headers); + probes.forEach(function(probe) { + probe.setHeaderFilter(headers); + probe.updateProbes(); + }); +}; + module.exports.updateIbmapmContext = function(context) { probes.forEach(function(probe) { probe.setIbmapmContext(context); probe.updateProbes(); }); -} +}; module.exports.stop = function(){ probes.forEach(function(probe) { diff --git a/lib/probe.js b/lib/probe.js index 8c9c7d7..34b70a6 100755 --- a/lib/probe.js +++ b/lib/probe.js @@ -28,6 +28,8 @@ function Probe(name) { this.recorder = {}; this.serviceName = ''; this.ibmapmContext = {}; + this.pathFilters = []; + this.headerFilters = {}; } /* @@ -55,6 +57,16 @@ Probe.prototype.setRecorder = function(recorder) { Probe.prototype.setServiceName = function(name) { this.serviceName = name; }; +Probe.prototype.setPathFilter = function(paths) { + console.info('setPathFilter'); + this.pathFilters = paths || []; + console.info(this.pathFilters); +}; +Probe.prototype.setHeaderFilter = function(headers) { + console.info('setHeaderFilter'); + this.headerFilters = headers || {}; + console.info(this.headerFilters); +}; Probe.prototype.setIbmapmContext = function(ibmapmContext) { this.ibmapmContext = ibmapmContext; diff --git a/lib/tools.js b/lib/tools.js index 0cae13a..7969dd1 100644 --- a/lib/tools.js +++ b/lib/tools.js @@ -7,6 +7,10 @@ module.exports.recordIbmapmContext = function(tracer, ibmapmContext){ tracer.recordBinary('containerId', ibmapmContext.containerId); tracer.recordBinary('nameSpace', ibmapmContext.nameSpace); tracer.recordBinary('clusterId', ibmapmContext.clusterId ? ibmapmContext.clusterId : 'unamedcluster'); + + } else { + console.info('call recordProcess: onPremise,yes'); + tracer.recordBinary('onPremise', 'yes'); } }; @@ -29,3 +33,21 @@ module.exports.hasJaegerHeader = function(httpReq) { const headers = httpReq.headers || {}; return headers['ibm-apm-spancontext'] !== undefined; }; + +module.exports.isIcamInternalRequest = function(options, headerFilters, pathFilters) { + console.info(options, headerFilters, pathFilters); + if (options.headers) { + for (var key in headerFilters){ + if (Object.keys(options.headers).indexOf(key) >= 0 + || options.headers[key] === headerFilters[key]){ + return true; + } + } + } + for (var i = 0; i < pathFilters.length; i++) { + if (options.path.indexOf(pathFilters[i]) >= 0){ + return true; + } + } + return false; +}; diff --git a/probes/http-outbound-probe-zipkin.js b/probes/http-outbound-probe-zipkin.js index 3c8034d..edff06d 100644 --- a/probes/http-outbound-probe-zipkin.js +++ b/probes/http-outbound-probe-zipkin.js @@ -24,6 +24,8 @@ const zipkin = require('zipkin'); var serviceName; var ibmapmContext; +var headerFilters; +var pathFilters; const { Request, @@ -49,8 +51,11 @@ function HttpOutboundProbeZipkin() { util.inherits(HttpOutboundProbeZipkin, Probe); HttpOutboundProbeZipkin.prototype.updateProbes = function() { + console.info('updateProbes', this.headerFilters, this.pathFilters); serviceName = this.serviceName; ibmapmContext = this.ibmapmContext; + headerFilters = this.headerFilters; + pathFilters = this.pathFilters; }; @@ -75,6 +80,9 @@ HttpOutboundProbeZipkin.prototype.attach = function(name, target) { var requestMethod = 'GET'; var urlRequested = ''; if (typeof options === 'object') { + if (tool.isIcamInternalRequest(options, headerFilters, pathFilters)){ + return; + } urlRequested = formatURL(options); if (options.method) { requestMethod = options.method; @@ -109,6 +117,7 @@ HttpOutboundProbeZipkin.prototype.attach = function(name, target) { methodArgs, probeData, function(target, args, probeData) { + console.info('confirm:', urlRequested); tracer.recordBinary('http.status_code', target.res.statusCode.toString()); tracer.recordAnnotation(new Annotation.ClientRecv()); console.info('send http-outbound-tracer(aroundCallback): ', tracer.id); @@ -161,5 +170,4 @@ function formatURL(httpOptions) { } return url; } - module.exports = HttpOutboundProbeZipkin; diff --git a/probes/https-outbound-probe-zipkin.js b/probes/https-outbound-probe-zipkin.js index 063690d..5302abf 100644 --- a/probes/https-outbound-probe-zipkin.js +++ b/probes/https-outbound-probe-zipkin.js @@ -24,6 +24,8 @@ const zipkin = require('zipkin'); var serviceName; var ibmapmContext; +var headerFilters; +var pathFilters; const { Request, @@ -52,6 +54,8 @@ util.inherits(HttpsOutboundProbeZipkin, Probe); HttpsOutboundProbeZipkin.prototype.updateProbes = function() { serviceName = this.serviceName; ibmapmContext = this.ibmapmContext; + headerFilters = this.headerFilters; + pathFilters = this.pathFilters; }; HttpsOutboundProbeZipkin.prototype.attach = function(name, target) { @@ -75,6 +79,9 @@ HttpsOutboundProbeZipkin.prototype.attach = function(name, target) { var requestMethod = 'GET'; var urlRequested = ''; if (typeof options === 'object') { + if (tool.isIcamInternalRequest(options, headerFilters, pathFilters)){ + return; + } urlRequested = formatURL(options); if (options.method) { requestMethod = options.method; @@ -86,6 +93,7 @@ HttpsOutboundProbeZipkin.prototype.attach = function(name, target) { requestMethod = parsedOptions.method; } } + // Must assign new options back to methodArgs[0] // methodArgs[0] = Request.addZipkinHeaders(methodArgs[0], tracer.createChildId()); let { headers } = tool.addJaegerHeaders(methodArgs[0], tracer.createChildId(), 'https-outbound'); @@ -102,6 +110,7 @@ HttpsOutboundProbeZipkin.prototype.attach = function(name, target) { methodArgs, probeData, function(target, args, probeData) { + console.info('confirm:', urlRequested); tracer.recordBinary('http.status_code', target.res.statusCode.toString()); tracer.recordAnnotation(new Annotation.ClientRecv()); console.info('send https-outbound-tracer(aroundCallback): ', tracer.id); From baec03a83d83047f6aa6f6fe09d42a9d3c5f11ef Mon Sep 17 00:00:00 2001 From: YUE CHEN Date: Mon, 25 Mar 2019 13:00:02 +0800 Subject: [PATCH 5/9] remove jaeger header --- probes/http-outbound-probe-zipkin.js | 3 +-- probes/http-probe-zipkin.js | 22 +--------------------- probes/https-outbound-probe-zipkin.js | 3 +-- probes/https-probe-zipkin.js | 22 +--------------------- 4 files changed, 4 insertions(+), 46 deletions(-) diff --git a/probes/http-outbound-probe-zipkin.js b/probes/http-outbound-probe-zipkin.js index edff06d..c596748 100644 --- a/probes/http-outbound-probe-zipkin.js +++ b/probes/http-outbound-probe-zipkin.js @@ -101,8 +101,7 @@ HttpOutboundProbeZipkin.prototype.attach = function(name, target) { if (!methodArgs[0].headers) methodArgs[0].headers = {}; var childId = tracer.createChildId(); - // let { headers } = Request.addZipkinHeaders(methodArgs[0], childId); - let { headers } = tool.addJaegerHeaders(methodArgs[0], childId, 'http-outbound'); + let { headers } = Request.addZipkinHeaders(methodArgs[0], childId); Object.assign(methodArgs[0].headers, { headers }); tracer.setId(childId); diff --git a/probes/http-probe-zipkin.js b/probes/http-probe-zipkin.js index 5eabca5..90ad15b 100644 --- a/probes/http-probe-zipkin.js +++ b/probes/http-probe-zipkin.js @@ -100,27 +100,7 @@ HttpProbeZipkin.prototype.attach = function(name, target) { if (reqMethod.toUpperCase() === 'OPTIONS' && httpReq.headers['access-control-request-method']) { reqMethod = httpReq.headers['access-control-request-method']; } - if (tool.hasJaegerHeader(httpReq)) { - const headers = httpReq.headers; - var jaegerHeader = headers['ibm-apm-spancontext']; - console.info('http ibm-apm-spancontext:', jaegerHeader); - var headerKeys = jaegerHeader.split(':'); - var jaegerSpanId = headerKeys[1]; - if (jaegerSpanId !== undefined) { - const traceId = new Some(headerKeys[0]); - const parentSpanId = new Some(headerKeys[2]); - const flags = (new Some(headerKeys[3])).flatMap(stringToIntOption).getOrElse(0); - - var id_byJaeger = new TraceId({ - traceId: traceId, - parentId: parentSpanId, - spanId: jaegerSpanId, - flags - }); - tracer.setId(id_byJaeger); - probeData.traceId = tracer.id; - } - } else if (hasZipkinHeader(httpReq)) { + if (hasZipkinHeader(httpReq)) { const headers = httpReq.headers; var spanId = headers[(Header.SpanId).toLowerCase()]; if (spanId !== undefined) { diff --git a/probes/https-outbound-probe-zipkin.js b/probes/https-outbound-probe-zipkin.js index 5302abf..08362b3 100644 --- a/probes/https-outbound-probe-zipkin.js +++ b/probes/https-outbound-probe-zipkin.js @@ -95,8 +95,7 @@ HttpsOutboundProbeZipkin.prototype.attach = function(name, target) { } // Must assign new options back to methodArgs[0] - // methodArgs[0] = Request.addZipkinHeaders(methodArgs[0], tracer.createChildId()); - let { headers } = tool.addJaegerHeaders(methodArgs[0], tracer.createChildId(), 'https-outbound'); + let { headers } = Request.addZipkinHeaders(methodArgs[0], tracer.createChildId()); Object.assign(methodArgs[0].headers, { headers }); tracer.recordServiceName(serviceName); diff --git a/probes/https-probe-zipkin.js b/probes/https-probe-zipkin.js index e9490dc..92b629e 100644 --- a/probes/https-probe-zipkin.js +++ b/probes/https-probe-zipkin.js @@ -100,27 +100,7 @@ HttpsProbeZipkin.prototype.attach = function(name, target) { if (reqMethod.toUpperCase() === 'OPTIONS' && httpsReq.headers['access-control-request-method']) { reqMethod = httpsReq.headers['access-control-request-method']; } - if (tool.hasJaegerHeader(httpsReq)) { - const headers = httpsReq.headers; - var jaegerHeader = headers['ibm-apm-spancontext']; - console.info('http ibm-apm-spancontext:', jaegerHeader); - var headerKeys = jaegerHeader.split(':'); - var jaegerSpanId = headerKeys[1]; - if (jaegerSpanId !== undefined) { - const traceId = new Some(headerKeys[0]); - const parentSpanId = new Some(headerKeys[2]); - const flags = (new Some(headerKeys[3])).flatMap(stringToIntOption).getOrElse(0); - - var id_byJaeger = new TraceId({ - traceId: traceId, - parentId: parentSpanId, - spanId: jaegerSpanId, - flags - }); - tracer.setId(id_byJaeger); - probeData.traceId = tracer.id; - } - } else if (hasZipkinHeader(httpsReq)) { + if (hasZipkinHeader(httpsReq)) { const headers = httpsReq.headers; var spanId = headers[(Header.SpanId).toLowerCase()]; if (spanId !== undefined) { From 6f84a42b2dd76998aff90137ecf7be9ac0ac4af6 Mon Sep 17 00:00:00 2001 From: YUE CHEN Date: Mon, 25 Mar 2019 13:01:11 +0800 Subject: [PATCH 6/9] remove jaeger header --- lib/tools.js | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/lib/tools.js b/lib/tools.js index 7969dd1..d17a22a 100644 --- a/lib/tools.js +++ b/lib/tools.js @@ -14,26 +14,6 @@ module.exports.recordIbmapmContext = function(tracer, ibmapmContext){ } }; -module.exports.addJaegerHeaders = function(req, traceId, message) { - const headers = req.headers || {}; - - var headerKeys = [ - traceId.traceId, - traceId.spanId, - traceId._parentId.value ? traceId._parentId.value : '0', - traceId.sampled.value ? 1 : 0 - ]; - headers['ibm-apm-spancontext'] = headerKeys.join(':'); - console.info(message + ' ibm-apm-spancontext: ', headers['ibm-apm-spancontext']); - - return Object.assign({}, req, {headers}); -}; - -module.exports.hasJaegerHeader = function(httpReq) { - const headers = httpReq.headers || {}; - return headers['ibm-apm-spancontext'] !== undefined; -}; - module.exports.isIcamInternalRequest = function(options, headerFilters, pathFilters) { console.info(options, headerFilters, pathFilters); if (options.headers) { From 88d2843a49db33c003883a5e4eaa3f973ffa3068 Mon Sep 17 00:00:00 2001 From: Yue Chen Date: Tue, 26 Mar 2019 00:38:04 +0800 Subject: [PATCH 7/9] fix in docker problem --- probes/http-outbound-probe-zipkin.js | 13 ++++++++++++- probes/http-probe-zipkin.js | 12 +++++++++++- probes/https-outbound-probe-zipkin.js | 12 +++++++++++- probes/https-probe-zipkin.js | 12 +++++++++++- 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/probes/http-outbound-probe-zipkin.js b/probes/http-outbound-probe-zipkin.js index c596748..fe0eaed 100644 --- a/probes/http-outbound-probe-zipkin.js +++ b/probes/http-outbound-probe-zipkin.js @@ -26,6 +26,7 @@ var serviceName; var ibmapmContext; var headerFilters; var pathFilters; +var tracer; const { Request, @@ -56,11 +57,17 @@ HttpOutboundProbeZipkin.prototype.updateProbes = function() { ibmapmContext = this.ibmapmContext; headerFilters = this.headerFilters; pathFilters = this.pathFilters; + tracer = new zipkin.Tracer({ + ctxImpl, + recorder: this.recorder, + sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests + traceId128Bit: true // to generate 128-bit trace IDs. + }); }; HttpOutboundProbeZipkin.prototype.attach = function(name, target) { - const tracer = new zipkin.Tracer({ + tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests @@ -76,6 +83,9 @@ HttpOutboundProbeZipkin.prototype.attach = function(name, target) { // Before 'http.request' function function(obj, methodName, methodArgs, probeData) { // Get HTTP request method from options + if (process.env.JAEGER_ENDPOINT_NOTREADY === 'true'){ + return; + } var options = methodArgs[0]; var requestMethod = 'GET'; var urlRequested = ''; @@ -116,6 +126,7 @@ HttpOutboundProbeZipkin.prototype.attach = function(name, target) { methodArgs, probeData, function(target, args, probeData) { + tracer.setId(childId); console.info('confirm:', urlRequested); tracer.recordBinary('http.status_code', target.res.statusCode.toString()); tracer.recordAnnotation(new Annotation.ClientRecv()); diff --git a/probes/http-probe-zipkin.js b/probes/http-probe-zipkin.js index 90ad15b..3c2c7d6 100644 --- a/probes/http-probe-zipkin.js +++ b/probes/http-probe-zipkin.js @@ -23,6 +23,7 @@ const zipkin = require('zipkin'); var serviceName; var ibmapmContext; +var tracer; const { Request, @@ -67,12 +68,18 @@ function stringToIntOption(str) { HttpProbeZipkin.prototype.updateProbes = function() { serviceName = this.serviceName; ibmapmContext = this.ibmapmContext; + tracer = new zipkin.Tracer({ + ctxImpl, + recorder: this.recorder, + sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests + traceId128Bit: true // to generate 128-bit trace IDs. + }); }; HttpProbeZipkin.prototype.attach = function(name, target) { serviceName = this.serviceName; - const tracer = new zipkin.Tracer({ + tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests @@ -90,6 +97,9 @@ HttpProbeZipkin.prototype.attach = function(name, target) { if (obj.__zipkinhttpProbe__) return; obj.__zipkinhttpProbe__ = true; aspect.aroundCallback(args, probeData, function(obj, args, probeData) { + if (process.env.JAEGER_ENDPOINT_NOTREADY === 'true'){ + return; + } var httpReq = args[0]; var res = args[1]; // Filter out urls where filter.to is '' diff --git a/probes/https-outbound-probe-zipkin.js b/probes/https-outbound-probe-zipkin.js index 08362b3..9189831 100644 --- a/probes/https-outbound-probe-zipkin.js +++ b/probes/https-outbound-probe-zipkin.js @@ -26,6 +26,7 @@ var serviceName; var ibmapmContext; var headerFilters; var pathFilters; +var tracer; const { Request, @@ -56,10 +57,16 @@ HttpsOutboundProbeZipkin.prototype.updateProbes = function() { ibmapmContext = this.ibmapmContext; headerFilters = this.headerFilters; pathFilters = this.pathFilters; + tracer = new zipkin.Tracer({ + ctxImpl, + recorder: this.recorder, + sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests + traceId128Bit: true // to generate 128-bit trace IDs. + }); }; HttpsOutboundProbeZipkin.prototype.attach = function(name, target) { - const tracer = new zipkin.Tracer({ + tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests @@ -75,6 +82,9 @@ HttpsOutboundProbeZipkin.prototype.attach = function(name, target) { // Before 'http.request' function function(obj, methodName, methodArgs, probeData) { // Get HTTP request method from options + if (process.env.JAEGER_ENDPOINT_NOTREADY === 'true'){ + return; + } var options = methodArgs[0]; var requestMethod = 'GET'; var urlRequested = ''; diff --git a/probes/https-probe-zipkin.js b/probes/https-probe-zipkin.js index 92b629e..e95cc2e 100644 --- a/probes/https-probe-zipkin.js +++ b/probes/https-probe-zipkin.js @@ -23,6 +23,7 @@ const zipkin = require('zipkin'); var serviceName; var ibmapmContext; +var tracer; const { Request, @@ -67,13 +68,19 @@ function stringToIntOption(str) { HttpsProbeZipkin.prototype.updateProbes = function() { serviceName = this.serviceName; ibmapmContext = this.ibmapmContext; + tracer = new zipkin.Tracer({ + ctxImpl, + recorder: this.recorder, + sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests + traceId128Bit: true // to generate 128-bit trace IDs. + }); }; HttpsProbeZipkin.prototype.attach = function(name, target) { serviceName = this.serviceName; - const tracer = new zipkin.Tracer({ + tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests @@ -91,6 +98,9 @@ HttpsProbeZipkin.prototype.attach = function(name, target) { if (obj.__zipkinhttpsProbe__) return; obj.__zipkinhttpsProbe__ = true; aspect.aroundCallback(args, probeData, function(obj, args, probeData) { + if (process.env.JAEGER_ENDPOINT_NOTREADY === 'true'){ + return; + } var httpsReq = args[0]; var res = args[1]; // Filter out urls where filter.to is '' From eaea6a4042f80c41de556916b01d5c44f6ef6dfd Mon Sep 17 00:00:00 2001 From: Yue Chen Date: Tue, 26 Mar 2019 16:56:29 +0800 Subject: [PATCH 8/9] create childid --- probes/http-probe-zipkin.js | 7 +++++-- probes/https-probe-zipkin.js | 4 ++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/probes/http-probe-zipkin.js b/probes/http-probe-zipkin.js index 3c2c7d6..e49ff19 100644 --- a/probes/http-probe-zipkin.js +++ b/probes/http-probe-zipkin.js @@ -102,6 +102,7 @@ HttpProbeZipkin.prototype.attach = function(name, target) { } var httpReq = args[0]; var res = args[1]; + var childId; // Filter out urls where filter.to is '' var traceUrl = parse(httpReq.url); // console.log(util.inspect(httpReq)); @@ -126,6 +127,8 @@ HttpProbeZipkin.prototype.attach = function(name, target) { flags }); tracer.setId(id); + childId = tracer.createChildId(); + tracer.setId(childId); probeData.traceId = tracer.id; }; } else { @@ -135,12 +138,12 @@ HttpProbeZipkin.prototype.attach = function(name, target) { const { headers } = Request.addZipkinHeaders(args[0], tracer.id); Object.assign(args[0].headers, headers); } - var serverTracerId = tracer.id; + // var serverTracerId = tracer.id; tracer.recordBinary('http.url', httpReq.headers.host + traceUrl); tracer.recordAnnotation(new Annotation.ServerRecv()); console.info('http-tracer(before): ', tracer.id); aspect.after(res, 'end', probeData, function(obj, methodName, args, probeData, ret) { - tracer.setId(serverTracerId); + tracer.setId(probeData.traceId); tracer.recordServiceName(serviceName); tracer.recordRpc(reqMethod.toUpperCase() + ' ' + traceUrl); tracer.recordAnnotation(new Annotation.LocalAddr(0)); diff --git a/probes/https-probe-zipkin.js b/probes/https-probe-zipkin.js index e95cc2e..7b7dadd 100644 --- a/probes/https-probe-zipkin.js +++ b/probes/https-probe-zipkin.js @@ -103,6 +103,7 @@ HttpsProbeZipkin.prototype.attach = function(name, target) { } var httpsReq = args[0]; var res = args[1]; + var childId; // Filter out urls where filter.to is '' var traceUrl = parse(httpsReq.url); if (traceUrl !== '') { @@ -126,6 +127,8 @@ HttpsProbeZipkin.prototype.attach = function(name, target) { flags }); tracer.setId(id); + childId = tracer.createChildId(); + tracer.setId(childId); probeData.traceId = tracer.id; }; } else { @@ -141,6 +144,7 @@ HttpsProbeZipkin.prototype.attach = function(name, target) { console.info('https-tracer(before): ', tracer.id); aspect.after(res, 'end', probeData, function(obj, methodName, args, probeData, ret) { + tracer.setId(probeData.traceId); tracer.recordServiceName(serviceName); tracer.recordRpc(reqMethod.toUpperCase() + ' ' + traceUrl); tracer.recordAnnotation(new Annotation.LocalAddr(0)); From fd404de0cf35a98ac3dcfd6ccd90da9bbc0a693a Mon Sep 17 00:00:00 2001 From: YUE CHEN Date: Tue, 30 Apr 2019 09:35:07 +0800 Subject: [PATCH 9/9] sync with icam2019.2.0 release --- appmetrics-zipkin.js | 53 +++++++++---- lib/aspect.js | 2 +- lib/probe.js | 4 - lib/timer.js | 2 +- lib/tools.js | 26 +++++-- lib/zipkin-transport-https.js | 103 ++++++++++++++++++++++++++ probes/http-outbound-probe-zipkin.js | 32 ++++++-- probes/http-probe-zipkin.js | 50 ++++++++++--- probes/https-outbound-probe-zipkin.js | 42 ++++++++--- probes/https-probe-zipkin.js | 62 ++++++++++++---- test/unit/aspect.test.js | 2 +- 11 files changed, 305 insertions(+), 73 deletions(-) create mode 100644 lib/zipkin-transport-https.js diff --git a/appmetrics-zipkin.js b/appmetrics-zipkin.js index 57bc6ae..4a29db3 100755 --- a/appmetrics-zipkin.js +++ b/appmetrics-zipkin.js @@ -21,7 +21,11 @@ var aspect = require('./lib/aspect.js'); var fs = require('fs'); var PropertyReader = require('properties-reader'); var properties = PropertyReader(__dirname + '/appmetrics-zipkin.properties'); -var tcpp = require('tcp-ping'); +var {Endpoint} = require('zipkin/lib/model'); +Endpoint.prototype.setServiceName = function setServiceName(serviceName) { + // In zipkin, names are lowercase. This eagerly converts to alert users early. + this.serviceName = serviceName || undefined; +}; const { BatchRecorder @@ -29,6 +33,7 @@ const { const { HttpLogger } = require('zipkin-transport-http'); +const HttpsLogger = require('./lib/zipkin-transport-https'); // Load module probes into probes array by searching the probes directory. var probes = []; @@ -54,10 +59,22 @@ module.exports = function(options) { function start(options) { // Set up the zipkin var host, port, serviceName, sampleRate; + var zipkin_endpoint, pfx, passphase; + + global.KNJ_TT_MAX_LENGTH = global.KNJ_TT_MAX_LENGTH || 128; if (options) { host = options['host']; port = options['port']; + if (options.zipkinEndpoint){ + zipkin_endpoint = options.zipkinEndpoint; + } + if (options.pfx){ + pfx = options.pfx; + } + if (options.passphase){ + passphase = options.passphase; + } serviceName = options['serviceName']; sampleRate = options['sampleRate']; } @@ -92,20 +109,28 @@ function start(options) { } // Test if the host & port are valid - tcpp.probe(host, port, function(err, available) { - if (err) { - console.log('Unable to contact Zipkin at ' + host + ':' + port); - return; - } - if (!available) { - console.log('Unable to contact Zipkin at ' + host + ':' + port); - } - }); + // if (host && port) { + // tcpp.probe(host, port, function(err, available) { + // if (err) { + // console.log('Unable to contact Zipkin at ' + host + ':' + port); + // return; + // } + // if (!available) { + // console.log('Unable to contact Zipkin at ' + host + ':' + port); + // } + // }); + // } - const zipkinUrl = `http://${host}:${port}`; + const zipkinUrl = zipkin_endpoint || `http://${host}:${port}/api/v1/spans`; const recorder = new BatchRecorder({ - logger: new HttpLogger({ - endpoint: `${zipkinUrl}/api/v1/spans` + logger: zipkinUrl.startsWith('https:') ? + new HttpsLogger({ + endpoint: zipkinUrl, + pfx: pfx, + passphase: passphase + }) : + new HttpLogger({ + endpoint: zipkinUrl }) }); @@ -138,7 +163,6 @@ module.exports.updateServiceName = function(serviceName){ }; module.exports.updatePathFilter = function(paths){ - console.info('updatePathFilter', paths); probes.forEach(function(probe) { probe.setPathFilter(paths); probe.updateProbes(); @@ -147,7 +171,6 @@ module.exports.updatePathFilter = function(paths){ module.exports.updateHeaderFilter = function(headers){ - console.info('updateHeaderFilter', headers); probes.forEach(function(probe) { probe.setHeaderFilter(headers); probe.updateProbes(); diff --git a/lib/aspect.js b/lib/aspect.js index 3ea5a0a..edcb8bc 100755 --- a/lib/aspect.js +++ b/lib/aspect.js @@ -17,7 +17,7 @@ exports.aroundCallback = function(args, context, hookBefore, hookAfter) { var position = this.findCallbackArg(args); - if (position == undefined) return; + if (position === undefined) return; var orig = args[position]; diff --git a/lib/probe.js b/lib/probe.js index 34b70a6..13daf33 100755 --- a/lib/probe.js +++ b/lib/probe.js @@ -58,14 +58,10 @@ Probe.prototype.setServiceName = function(name) { this.serviceName = name; }; Probe.prototype.setPathFilter = function(paths) { - console.info('setPathFilter'); this.pathFilters = paths || []; - console.info(this.pathFilters); }; Probe.prototype.setHeaderFilter = function(headers) { - console.info('setHeaderFilter'); this.headerFilters = headers || {}; - console.info(this.headerFilters); }; Probe.prototype.setIbmapmContext = function(ibmapmContext) { diff --git a/lib/timer.js b/lib/timer.js index ed685cd..701540b 100755 --- a/lib/timer.js +++ b/lib/timer.js @@ -24,7 +24,7 @@ function Timer() { Timer.prototype.stop = function() { // Prevent the timer being stopped twice. - if (this.timeDelta == -1) { + if (this.timeDelta === -1) { var dur = process.hrtime(this.startTime); this.timeDelta = (dur[0] * 1000) + (dur[1] / 1000000); } diff --git a/lib/tools.js b/lib/tools.js index d17a22a..f57989f 100644 --- a/lib/tools.js +++ b/lib/tools.js @@ -3,19 +3,29 @@ module.exports.recordIbmapmContext = function(tracer, ibmapmContext){ if (ibmapmContext && ibmapmContext.podName) { - tracer.recordBinary('podName', ibmapmContext.podName); - tracer.recordBinary('containerId', ibmapmContext.containerId); - tracer.recordBinary('nameSpace', ibmapmContext.nameSpace); - tracer.recordBinary('clusterId', ibmapmContext.clusterId ? ibmapmContext.clusterId : 'unamedcluster'); + tracer.recordBinary('pod.name', ibmapmContext.podName); + tracer.recordBinary('container.id', ibmapmContext.containerId); + tracer.recordBinary('namespace', ibmapmContext.nameSpace); + tracer.recordBinary('cluster.id', ibmapmContext.clusterID || 'unamedcluster'); + tracer.recordBinary('node.name', ibmapmContext.nodeName); + tracer.recordBinary('service.name', ibmapmContext.serviceName); - } else { - console.info('call recordProcess: onPremise,yes'); - tracer.recordBinary('onPremise', 'yes'); + } + if (ibmapmContext && ibmapmContext.applicationName) { + tracer.recordBinary('application.name', ibmapmContext.applicationName); + } + if (ibmapmContext && ibmapmContext['resource.id']) { + tracer.recordBinary('resource.id', ibmapmContext['resource.id']); + } + if (ibmapmContext && ibmapmContext.tenantId) { + tracer.recordBinary('tenant.id', ibmapmContext.tenantId); + } + if (ibmapmContext && ibmapmContext.ip) { + tracer.recordBinary('ip', ibmapmContext.ip); } }; module.exports.isIcamInternalRequest = function(options, headerFilters, pathFilters) { - console.info(options, headerFilters, pathFilters); if (options.headers) { for (var key in headerFilters){ if (Object.keys(options.headers).indexOf(key) >= 0 diff --git a/lib/zipkin-transport-https.js b/lib/zipkin-transport-https.js new file mode 100644 index 0000000..c9c0308 --- /dev/null +++ b/lib/zipkin-transport-https.js @@ -0,0 +1,103 @@ +'use strict'; +var uuid = require('uuid'); +var https = require('https'); +var url = require('url'); +var commonTools = require('../../lib/tool/common.js'); + +var log4js = require('log4js'); +var logger = log4js.getLogger('knj_log'); +var _createClass = function() { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function(Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +var _require = require('zipkin'); +var JSON_V1 = _require.jsonEncoder.JSON_V1; + +var HttpsLogger = function() { + function HttpsLogger(_ref) { + var _this = this; + + var endpoint = _ref.endpoint; + var _ref$httpInterval = _ref.httpInterval; + var httpInterval = _ref$httpInterval === undefined ? 1000 : _ref$httpInterval; + var _ref$jsonEncoder = _ref.jsonEncoder; + var jsonEncoder = _ref$jsonEncoder === undefined ? JSON_V1 : _ref$jsonEncoder; + + _classCallCheck(this, HttpsLogger); + + this.endpoint = endpoint; + this.pfx = _ref.pfx; + this.passphase = _ref.passphase; + this.queue = []; + this.jsonEncoder = jsonEncoder; + + var timer = setInterval(function() { + _this.processQueue(); + }, httpInterval); + if (timer.unref) { + // unref might not be available in browsers + timer.unref(); // Allows Node to terminate instead of blocking on timer + } + } + + _createClass(HttpsLogger, [{ + key: 'logSpan', + value: function logSpan(span) { + this.queue.push(this.jsonEncoder.encode(span)); + } + }, { + key: 'processQueue', + value: function processQueue() { + if (this.queue.length > 0) { + var postBody = '[' + this.queue.join(',') + ']'; + var options = url.parse(this.endpoint); + var header = { + Accept: 'application/json', + 'Content-Type': 'application/json', + 'X-TransactionID': uuid.v1(), + 'User-Agent': 'NodeDC' + }; + if (process.env.APM_TENANT_ID) { + header['X-TenantId'] = process.env.APM_TENANT_ID; + } + var finalOptions = { + hostname: options.hostname, + host: options.host, + port: options.port, + path: options.path, + protocol: options.protocol, + pfx: this.pfx, + passphrase: this.passphase, + ca: this.pfx, + requestCert: true, + rejectUnauthorized: false, + method: 'POST', + headers: header + }; + commonTools.tlsFix8(finalOptions); + try { + var req = https.request(finalOptions, function(res){ + if (res.statusCode === 202) + logger.debug('Send to Jaeger server successfully: ', postBody); + else + logger.warn('Failed to sent to Jaeger server. statusCode=', res.statusCode, 'options=', finalOptions); + }); + req.on('error', function(err){ + logger.error('Failed to sent to Jaeger server'); + logger.error(err); + }); + req.write(postBody); + req.end(); + } catch (e) { + logger.error('Failed to sent to Jaeger server'); + logger.error(e); + } + this.queue.length = 0; + } + } + }]); + + return HttpsLogger; +}(); + +module.exports = HttpsLogger; diff --git a/probes/http-outbound-probe-zipkin.js b/probes/http-outbound-probe-zipkin.js index fe0eaed..7af5950 100644 --- a/probes/http-outbound-probe-zipkin.js +++ b/probes/http-outbound-probe-zipkin.js @@ -21,6 +21,8 @@ var util = require('util'); var url = require('url'); var semver = require('semver'); const zipkin = require('zipkin'); +var log4js = require('log4js'); +var logger = log4js.getLogger('knj_log'); var serviceName; var ibmapmContext; @@ -52,7 +54,6 @@ function HttpOutboundProbeZipkin() { util.inherits(HttpOutboundProbeZipkin, Probe); HttpOutboundProbeZipkin.prototype.updateProbes = function() { - console.info('updateProbes', this.headerFilters, this.pathFilters); serviceName = this.serviceName; ibmapmContext = this.ibmapmContext; headerFilters = this.headerFilters; @@ -60,7 +61,8 @@ HttpOutboundProbeZipkin.prototype.updateProbes = function() { tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, - sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests + sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), + // sample rate 0.01 will sample 1 % of all incoming requests traceId128Bit: true // to generate 128-bit trace IDs. }); }; @@ -70,7 +72,8 @@ HttpOutboundProbeZipkin.prototype.attach = function(name, target) { tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, - sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests + sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), + // sample rate 0.01 will sample 1 % of all incoming requests traceId128Bit: true // to generate 128-bit trace IDs. }); serviceName = this.serviceName; @@ -115,22 +118,35 @@ HttpOutboundProbeZipkin.prototype.attach = function(name, target) { Object.assign(methodArgs[0].headers, { headers }); tracer.setId(childId); + if (urlRequested.length > global.KNJ_TT_MAX_LENGTH) { + urlRequested = urlRequested.substr(0, global.KNJ_TT_MAX_LENGTH); + } tracer.recordServiceName(serviceName); - tracer.recordRpc(requestMethod + ' ' + urlRequested); + tracer.recordRpc(urlRequested); tracer.recordBinary('http.url', urlRequested); + tracer.recordBinary('http.method', requestMethod.toUpperCase()); + if (process.env.APM_TENANT_ID){ + tracer.recordBinary('tenant.id', process.env.APM_TENANT_ID); + } + tracer.recordBinary('edge.request', 'false'); + tracer.recordBinary('request.type', 'http'); tool.recordIbmapmContext(tracer, ibmapmContext); tracer.recordAnnotation(new Annotation.ClientSend()); - console.info('send http-outbound-tracer(before): ', tracer.id); + logger.debug('send http-outbound-tracer(before): ', tracer.id); // End metrics aspect.aroundCallback( methodArgs, probeData, function(target, args, probeData) { tracer.setId(childId); - console.info('confirm:', urlRequested); - tracer.recordBinary('http.status_code', target.res.statusCode.toString()); + logger.debug('confirm:', urlRequested); + var status_code = target.res.statusCode.toString(); + tracer.recordBinary('http.status_code', status_code); + if (status_code >= 400) { + tracer.recordBinary('error', 'true'); + } tracer.recordAnnotation(new Annotation.ClientRecv()); - console.info('send http-outbound-tracer(aroundCallback): ', tracer.id); + logger.debug('send http-outbound-tracer(aroundCallback): ', tracer.id); }, function(target, args, probeData, ret) { return ret; diff --git a/probes/http-probe-zipkin.js b/probes/http-probe-zipkin.js index e49ff19..464e9d2 100644 --- a/probes/http-probe-zipkin.js +++ b/probes/http-probe-zipkin.js @@ -20,6 +20,8 @@ var aspect = require('../lib/aspect.js'); var tool = require('../lib/tools.js'); var util = require('util'); const zipkin = require('zipkin'); +var log4js = require('log4js'); +var logger = log4js.getLogger('knj_log'); var serviceName; var ibmapmContext; @@ -47,7 +49,7 @@ function hasZipkinHeader(httpReq) { function HttpProbeZipkin() { Probe.call(this, 'http'); this.config = { - filters: [], + filters: [] }; } util.inherits(HttpProbeZipkin, Probe); @@ -59,6 +61,7 @@ function stringToBoolean(str) { function stringToIntOption(str) { try { + // eslint-disable-next-line radix return new Some(parseInt(str, 10)); } catch (err) { return None; @@ -71,7 +74,8 @@ HttpProbeZipkin.prototype.updateProbes = function() { tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, - sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests + sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), + // sample rate 0.01 will sample 1 % of all incoming requests traceId128Bit: true // to generate 128-bit trace IDs. }); }; @@ -82,11 +86,12 @@ HttpProbeZipkin.prototype.attach = function(name, target) { tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, - sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests + sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), + // sample rate 0.01 will sample 1 % of all incoming requests traceId128Bit: true // to generate 128-bit trace IDs. }); - if (name == 'http') { + if (name === 'http') { if (target.__zipkinProbeAttached__) return target; target.__zipkinProbeAttached__ = true; var methods = ['on', 'addListener']; @@ -105,9 +110,9 @@ HttpProbeZipkin.prototype.attach = function(name, target) { var childId; // Filter out urls where filter.to is '' var traceUrl = parse(httpReq.url); - // console.log(util.inspect(httpReq)); if (traceUrl !== '') { var reqMethod = httpReq.method; + var edgeRequest = false; if (reqMethod.toUpperCase() === 'OPTIONS' && httpReq.headers['access-control-request-method']) { reqMethod = httpReq.headers['access-control-request-method']; } @@ -132,25 +137,48 @@ HttpProbeZipkin.prototype.attach = function(name, target) { probeData.traceId = tracer.id; }; } else { + edgeRequest = true; tracer.setId(tracer.createRootId()); probeData.traceId = tracer.id; // Must assign new options back to args[0] const { headers } = Request.addZipkinHeaders(args[0], tracer.id); Object.assign(args[0].headers, headers); } - // var serverTracerId = tracer.id; - tracer.recordBinary('http.url', httpReq.headers.host + traceUrl); + + var urlPrefix = 'http://' + httpReq.headers.host; + var maxUrlLength = global.KNJ_TT_MAX_LENGTH; + if (urlPrefix.length < global.KNJ_TT_MAX_LENGTH) { + maxUrlLength = global.KNJ_TT_MAX_LENGTH - urlPrefix.length; + } else { + maxUrlLength = 1; + } + if (traceUrl.length > maxUrlLength) { + traceUrl = traceUrl.substr(0, maxUrlLength); + } + + tracer.recordBinary('http.url', urlPrefix + traceUrl); tracer.recordAnnotation(new Annotation.ServerRecv()); - console.info('http-tracer(before): ', tracer.id); + logger.debug('http-tracer(before): ', tracer.id); aspect.after(res, 'end', probeData, function(obj, methodName, args, probeData, ret) { tracer.setId(probeData.traceId); tracer.recordServiceName(serviceName); - tracer.recordRpc(reqMethod.toUpperCase() + ' ' + traceUrl); + tracer.recordBinary('service.name', serviceName); + tracer.recordRpc(traceUrl); tracer.recordAnnotation(new Annotation.LocalAddr(0)); - tracer.recordBinary('http.status_code', res.statusCode.toString()); + var status_code = res.statusCode.toString(); + tracer.recordBinary('http.status_code', status_code); + if (status_code >= 400) { + tracer.recordBinary('error', 'true'); + } + tracer.recordBinary('http.method', reqMethod.toUpperCase()); + if (process.env.APM_TENANT_ID){ + tracer.recordBinary('tenant.id', process.env.APM_TENANT_ID); + } + tracer.recordBinary('edge.request', '' + edgeRequest); + tracer.recordBinary('request.type', 'http'); tool.recordIbmapmContext(tracer, ibmapmContext); tracer.recordAnnotation(new Annotation.ServerSend()); - console.info('http-tracer(after): ', tracer.id); + logger.debug('http-tracer(after): ', tracer.id); }); } }); diff --git a/probes/https-outbound-probe-zipkin.js b/probes/https-outbound-probe-zipkin.js index 9189831..290f8c3 100644 --- a/probes/https-outbound-probe-zipkin.js +++ b/probes/https-outbound-probe-zipkin.js @@ -21,6 +21,8 @@ var util = require('util'); var url = require('url'); var semver = require('semver'); const zipkin = require('zipkin'); +var log4js = require('log4js'); +var logger = log4js.getLogger('knj_log'); var serviceName; var ibmapmContext; @@ -60,7 +62,8 @@ HttpsOutboundProbeZipkin.prototype.updateProbes = function() { tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, - sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests + sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), + // sample rate 0.01 will sample 1 % of all incoming requests traceId128Bit: true // to generate 128-bit trace IDs. }); }; @@ -69,7 +72,8 @@ HttpsOutboundProbeZipkin.prototype.attach = function(name, target) { tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, - sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests + sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), + // sample rate 0.01 will sample 1 % of all incoming requests traceId128Bit: true // to generate 128-bit trace IDs. }); serviceName = this.serviceName; @@ -102,27 +106,47 @@ HttpsOutboundProbeZipkin.prototype.attach = function(name, target) { if (parsedOptions.method) { requestMethod = parsedOptions.method; } + + // This converts the outgoing request's options to an object + // so that we can add headers onto it + methodArgs[0] = Object.assign({}, parsedOptions); } - // Must assign new options back to methodArgs[0] - let { headers } = Request.addZipkinHeaders(methodArgs[0], tracer.createChildId()); + if (!methodArgs[0].headers) methodArgs[0].headers = {}; + var childId = tracer.createChildId(); + let { headers } = Request.addZipkinHeaders(methodArgs[0], childId); Object.assign(methodArgs[0].headers, { headers }); + tracer.setId(childId); + if (urlRequested.length > global.KNJ_TT_MAX_LENGTH) { + urlRequested = urlRequested.substr(0, global.KNJ_TT_MAX_LENGTH); + } tracer.recordServiceName(serviceName); - tracer.recordRpc(requestMethod + ' ' + urlRequested); + tracer.recordRpc(urlRequested); tracer.recordBinary('http.url', urlRequested); + tracer.recordBinary('http.method', requestMethod.toUpperCase()); + if (process.env.APM_TENANT_ID){ + tracer.recordBinary('tenant.id', process.env.APM_TENANT_ID); + } + tracer.recordBinary('edge.request', 'false'); + tracer.recordBinary('request.type', 'https'); tool.recordIbmapmContext(tracer, ibmapmContext); tracer.recordAnnotation(new Annotation.ClientSend()); - console.info('send https-outbound-tracer(before): ', tracer.id); + logger.debug('send https-outbound-tracer(before): ', tracer.id); // End metrics aspect.aroundCallback( methodArgs, probeData, function(target, args, probeData) { - console.info('confirm:', urlRequested); - tracer.recordBinary('http.status_code', target.res.statusCode.toString()); + tracer.setId(childId); + logger.debug('confirm:', urlRequested); + var status_code = target.res.statusCode.toString(); + tracer.recordBinary('http.status_code', status_code); + if (status_code >= 400) { + tracer.recordBinary('error', 'true'); + } tracer.recordAnnotation(new Annotation.ClientRecv()); - console.info('send https-outbound-tracer(aroundCallback): ', tracer.id); + logger.debug('send https-outbound-tracer(aroundCallback): ', tracer.id); }, function(target, args, probeData, ret) { return ret; diff --git a/probes/https-probe-zipkin.js b/probes/https-probe-zipkin.js index 7b7dadd..06f5679 100644 --- a/probes/https-probe-zipkin.js +++ b/probes/https-probe-zipkin.js @@ -17,9 +17,11 @@ var Probe = require('../lib/probe.js'); var aspect = require('../lib/aspect.js'); -var util = require('util'); var tool = require('../lib/tools.js'); +var util = require('util'); const zipkin = require('zipkin'); +var log4js = require('log4js'); +var logger = log4js.getLogger('knj_log'); var serviceName; var ibmapmContext; @@ -41,13 +43,14 @@ const ctxImpl = new CLSContext(); function hasZipkinHeader(httpsReq) { const headers = httpsReq.headers || {}; - return headers[(Header.TraceId).toLowerCase()] !== undefined && headers[(Header.SpanId).toLowerCase()] !== undefined; + return headers[(Header.TraceId).toLowerCase()] !== undefined + && headers[(Header.SpanId).toLowerCase()] !== undefined; } function HttpsProbeZipkin() { Probe.call(this, 'https'); this.config = { - filters: [], + filters: [] }; } util.inherits(HttpsProbeZipkin, Probe); @@ -59,6 +62,7 @@ function stringToBoolean(str) { function stringToIntOption(str) { try { + // eslint-disable-next-line radix return new Some(parseInt(str, 10)); } catch (err) { return None; @@ -71,7 +75,8 @@ HttpsProbeZipkin.prototype.updateProbes = function() { tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, - sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests + sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), + // sample rate 0.01 will sample 1 % of all incoming requests traceId128Bit: true // to generate 128-bit trace IDs. }); }; @@ -83,11 +88,12 @@ HttpsProbeZipkin.prototype.attach = function(name, target) { tracer = new zipkin.Tracer({ ctxImpl, recorder: this.recorder, - sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), // sample rate 0.01 will sample 1 % of all incoming requests + sampler: new zipkin.sampler.CountingSampler(this.config.sampleRate), + // sample rate 0.01 will sample 1 % of all incoming requests traceId128Bit: true // to generate 128-bit trace IDs. }); - if (name == 'https') { + if (name === 'https') { if (target.__zipkinProbeAttached__) return target; target.__zipkinProbeAttached__ = true; var methods = ['on', 'addListener']; @@ -108,7 +114,9 @@ HttpsProbeZipkin.prototype.attach = function(name, target) { var traceUrl = parse(httpsReq.url); if (traceUrl !== '') { var reqMethod = httpsReq.method; - if (reqMethod.toUpperCase() === 'OPTIONS' && httpsReq.headers['access-control-request-method']) { + var edgeRequest = false; + if (reqMethod.toUpperCase() === 'OPTIONS' + && httpsReq.headers['access-control-request-method']) { reqMethod = httpsReq.headers['access-control-request-method']; } if (hasZipkinHeader(httpsReq)) { @@ -118,7 +126,8 @@ HttpsProbeZipkin.prototype.attach = function(name, target) { const traceId = new Some(headers[(Header.TraceId).toLowerCase()]); const parentSpanId = new Some(headers[(Header.ParentSpanId).toLowerCase()]); const sampled = new Some(headers[(Header.Sampled).toLowerCase()]); - const flags = (new Some(headers[(Header.Flags).toLowerCase()])).flatMap(stringToIntOption).getOrElse(0); + const flags = (new Some(headers[(Header.Flags).toLowerCase()])) + .flatMap(stringToIntOption).getOrElse(0); var id = new TraceId({ traceId: traceId, parentId: parentSpanId, @@ -132,26 +141,49 @@ HttpsProbeZipkin.prototype.attach = function(name, target) { probeData.traceId = tracer.id; }; } else { + edgeRequest = true; tracer.setId(tracer.createRootId()); probeData.traceId = tracer.id; // Must assign new options back to args[0] - args[0] = Request.addZipkinHeaders(args[0], tracer.id); + const { headers } = Request.addZipkinHeaders(args[0], tracer.id); + Object.assign(args[0].headers, headers); } + var urlPrefix = 'https://' + httpsReq.headers.host; + var maxUrlLength = global.KNJ_TT_MAX_LENGTH; + if (urlPrefix.length < global.KNJ_TT_MAX_LENGTH) { + maxUrlLength = global.KNJ_TT_MAX_LENGTH - urlPrefix.length; + } else { + maxUrlLength = 1; + } + if (traceUrl.length > maxUrlLength) { + traceUrl = traceUrl.substr(0, maxUrlLength); + } - tracer.recordBinary('http.url', httpsReq.headers.host + traceUrl); + tracer.recordBinary('http.url', urlPrefix + traceUrl); tracer.recordAnnotation(new Annotation.ServerRecv()); - console.info('https-tracer(before): ', tracer.id); + logger.debug('https-tracer(before): ', tracer.id); aspect.after(res, 'end', probeData, function(obj, methodName, args, probeData, ret) { tracer.setId(probeData.traceId); tracer.recordServiceName(serviceName); - tracer.recordRpc(reqMethod.toUpperCase() + ' ' + traceUrl); + tracer.recordBinary('service.name', serviceName); + tracer.recordRpc(traceUrl); tracer.recordAnnotation(new Annotation.LocalAddr(0)); - tracer.recordBinary('http.status_code', res.statusCode.toString()); + var status_code = res.statusCode.toString(); + tracer.recordBinary('http.status_code', status_code); + if (status_code >= 400) { + tracer.recordBinary('error', 'true'); + } + tracer.recordBinary('http.method', reqMethod.toUpperCase()); + if (process.env.APM_TENANT_ID){ + tracer.recordBinary('tenant.id', process.env.APM_TENANT_ID); + } + tracer.recordBinary('edge.request', '' + edgeRequest); + tracer.recordBinary('request.type', 'https'); tool.recordIbmapmContext(tracer, ibmapmContext); tracer.recordAnnotation(new Annotation.ServerSend()); - console.info('https-tracer(after): ', tracer.id); + logger.debug('https-tracer(after): ', tracer.id); }); } }); @@ -163,7 +195,7 @@ HttpsProbeZipkin.prototype.attach = function(name, target) { /* * Custom req.url parser that strips out any trailing query */ -var parse = function(url) { +function parse(url) { ['?', '#'].forEach(function(separator) { var index = url.indexOf(separator); if (index !== -1) url = url.substring(0, index); diff --git a/test/unit/aspect.test.js b/test/unit/aspect.test.js index e75ebc4..d8896a6 100644 --- a/test/unit/aspect.test.js +++ b/test/unit/aspect.test.js @@ -40,7 +40,7 @@ describe('aspect', () => { }); it('should not find a callback among parameters with no callback', () => { const args = ['a', {}, 123]; - expect(findCallbackArg(args) == undefined).to.be.ok; + expect(findCallbackArg(args) === undefined).to.be.ok; }); }); describe('aroundCallBack', () => {