From 5fa6f3887756ba59445e60ba7af9a4370d10edd6 Mon Sep 17 00:00:00 2001 From: asanluis Date: Wed, 15 Jul 2020 23:47:15 +0200 Subject: [PATCH 1/8] start propagation interface --- packages/zipkin/index.d.ts | 33 ++++++++---- packages/zipkin/src/httpHeaders.js | 7 --- .../zipkin/src/instrumentation/httpServer.js | 36 +++---------- .../zipkin/src/propagation/b3propagation.js | 51 +++++++++++++++++++ packages/zipkin/src/propagation/index.js | 5 ++ 5 files changed, 85 insertions(+), 47 deletions(-) delete mode 100644 packages/zipkin/src/httpHeaders.js create mode 100644 packages/zipkin/src/propagation/b3propagation.js create mode 100644 packages/zipkin/src/propagation/index.js diff --git a/packages/zipkin/index.d.ts b/packages/zipkin/index.d.ts index e0e45665..1f734c5a 100644 --- a/packages/zipkin/index.d.ts +++ b/packages/zipkin/index.d.ts @@ -271,14 +271,6 @@ declare namespace zipkin { toInt(): number; } - namespace HttpHeaders { - const TraceId: string; - const SpanId: string; - const ParentSpanId: string; - const Sampled: string; - const Flags: string; - } - interface Record { traceId: TraceId; timestamp: number; @@ -339,13 +331,15 @@ declare namespace zipkin { } namespace Instrumentation { + class HttpServer { constructor(args: { tracer: Tracer, port: number, serviceName?: string, host?: string, - serverTags?: {[key: string]: string} + serverTags?: {[key: string]: string}, + propagation?: propagation.Propagation }); recordRequest( @@ -357,7 +351,7 @@ declare namespace zipkin { } class HttpClient { - constructor(args: { tracer: Tracer, serviceName?: string, remoteServiceName?: string }); + constructor(args: { tracer: Tracer, serviceName?: string, remoteServiceName?: string, propagation?: propagation.Propagation }); recordRequest( request: T, @@ -368,6 +362,25 @@ declare namespace zipkin { recordError(traceId: TraceId, error: Error): void; } } + namespace propagation { + class Headers { + TraceId: string; + SpanId: string; + ParentSpanId: string; + Sampled: string; + Flags: string; + } + interface Propagation { + headers: Headers; + extractor(readHeader: (header: string) => option.IOption): TraceId; + injector(req: T & { headers?: any }, traceId: TraceId): RequestZipkinHeaders; + } + class B3Propagation implements Propagation { + headers: Headers; + extractor(readHeader: (header: string) => option.IOption): TraceId; + injector(req: T & { headers?: any }, traceId: TraceId): RequestZipkinHeaders; + } + } } export = zipkin; diff --git a/packages/zipkin/src/httpHeaders.js b/packages/zipkin/src/httpHeaders.js deleted file mode 100644 index 5f84f2c6..00000000 --- a/packages/zipkin/src/httpHeaders.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - TraceId: 'X-B3-TraceId', - SpanId: 'X-B3-SpanId', - ParentSpanId: 'X-B3-ParentSpanId', - Sampled: 'X-B3-Sampled', - Flags: 'X-B3-Flags' -}; diff --git a/packages/zipkin/src/instrumentation/httpServer.js b/packages/zipkin/src/instrumentation/httpServer.js index bcf4da26..c549bc50 100644 --- a/packages/zipkin/src/instrumentation/httpServer.js +++ b/packages/zipkin/src/instrumentation/httpServer.js @@ -1,3 +1,5 @@ +import B3Propagation from '../propagation/b3propagation'; + const Annotation = require('../annotation'); const Header = require('../httpHeaders'); const InetAddress = require('../InetAddress'); @@ -30,40 +32,14 @@ class HttpServerInstrumentation { tracer = requiredArg('tracer'), serviceName = tracer.localEndpoint.serviceName, host, - port = requiredArg('port') + port = requiredArg('port'), + propagation = B3Propagation.DEFAULT }) { this.tracer = tracer; this.serviceName = serviceName; this.host = host && new InetAddress(host); this.port = port; - } - - _createIdFromHeaders(readHeader) { - if (containsRequiredHeaders(readHeader)) { - const spanId = readHeader(Header.SpanId); - const parentId = spanId.map((sid) => { - const traceId = readHeader(Header.TraceId); - const parentSpanId = readHeader(Header.ParentSpanId); - const sampled = readHeader(Header.Sampled); - const flags = readHeader(Header.Flags).flatMap(stringToIntOption).getOrElse(0); - return new TraceId({ - traceId: traceId.getOrElse(), - parentId: parentSpanId, - spanId: sid, - debug: flags === 1, - sampled: sampled.map(stringToBoolean), - }); - }); - - return new Some(this.tracer.join(parentId.getOrElse())); - } else if (readHeader(Header.Flags) !== None || readHeader(Header.Sampled) !== None) { - const sampled = readHeader(Header.Sampled) === None - ? None : readHeader(Header.Sampled).map(stringToBoolean); - const flags = readHeader(Header.Flags).flatMap(stringToIntOption).getOrElse(0); - return new Some(this.tracer.createRootId(sampled, flags === 1)); - } else { - return new Some(this.tracer.createRootId()); - } + this.propagation = propagation; } spanNameFromRoute(method, route, code) { // eslint-disable-line class-methods-use-this @@ -74,7 +50,7 @@ class HttpServerInstrumentation { } recordRequest(method, requestUrl, readHeader) { - this._createIdFromHeaders(readHeader).ifPresent(id => this.tracer.setId(id)); + this.propagation.extractor(readHeader).ifPresent(id => this.tracer.setId(id)); const {id} = this.tracer; const {path} = parseRequestUrl(requestUrl); diff --git a/packages/zipkin/src/propagation/b3propagation.js b/packages/zipkin/src/propagation/b3propagation.js new file mode 100644 index 00000000..1d9c47ae --- /dev/null +++ b/packages/zipkin/src/propagation/b3propagation.js @@ -0,0 +1,51 @@ +class B3Propagation { + static DEFAULT = new B3Propagation(); + + headers = { + TraceId: 'X-B3-TraceId', + SpanId: 'X-B3-SpanId', + ParentSpanId: 'X-B3-ParentSpanId', + Sampled: 'X-B3-Sampled', + Flags: 'X-B3-Flags' + }; + + extractor(readHeader) { + if (this.containsRequiredHeaders(readHeader)) { + const SpanId = readHeader(this.headers.SpanId); + const parentId = SpanId.map((sid) => { + const TraceId = readHeader(this.headers.TraceId); + const ParentSpanId = readHeader(this.headers.ParentSpanId); + const Sampled = readHeader(this.headers.Sampled); + const Flags = readHeader(this.headers.Flags) + .flatMap(stringToIntOption) + .getOrElse(0); + return new TraceId({ + TraceId: TraceId.getOrElse(), + parentId: ParentSpanId, + SpanId: sid, + debug: Flags === 1, + Sampled: Sampled.map(stringToBoolean), + }); + }); + + return new Some(this.tracer.join(parentId.getOrElse())); + } else if (readHeader(this.headers.Flags) !== None || readHeader(this.headers.Sampled) !== None) { + const Sampled = readHeader(this.headers.Sampled) === None + ? None : readHeader(this.headers.Sampled) + .map(stringToBoolean); + const Flags = readHeader(this.headers.Flags) + .flatMap(stringToIntOption) + .getOrElse(0); + return new Some(this.tracer.createRootId(Sampled, Flags === 1)); + } else { + return new Some(this.tracer.createRootId()); + } + } + + #containsRequiredHeaders(readHeader) { + return readHeader(this.headers.TraceId) !== None && readHeader(this.headers.SpanId) !== None; + } + +} + +module.exports = B3Propagation; diff --git a/packages/zipkin/src/propagation/index.js b/packages/zipkin/src/propagation/index.js new file mode 100644 index 00000000..0597506b --- /dev/null +++ b/packages/zipkin/src/propagation/index.js @@ -0,0 +1,5 @@ +const B3Propagation = require('./b3propagation'); + +module.exports = { + B3Propagation +}; From 7e851537500bf70bd613f2fef72cd8984bc0fdb3 Mon Sep 17 00:00:00 2001 From: asanluis Date: Tue, 28 Jul 2020 00:47:55 +0200 Subject: [PATCH 2/8] start propagation interface --- packages/zipkin/index.d.ts | 28 +++--- packages/zipkin/src/index.ts | 3 +- .../zipkin/src/instrumentation/httpClient.js | 5 +- .../zipkin/src/instrumentation/httpServer.js | 27 +----- .../zipkin/src/propagation/b3propagation.js | 97 ++++++++++++------- packages/zipkin/src/request.js | 29 ------ packages/zipkin/src/tracer/index.js | 14 ++- packages/zipkin/test/request.test.js | 41 -------- 8 files changed, 91 insertions(+), 153 deletions(-) delete mode 100644 packages/zipkin/src/request.js delete mode 100644 packages/zipkin/test/request.test.js diff --git a/packages/zipkin/index.d.ts b/packages/zipkin/index.d.ts index 1f734c5a..8d70276a 100644 --- a/packages/zipkin/index.d.ts +++ b/packages/zipkin/index.d.ts @@ -39,7 +39,8 @@ declare namespace zipkin { localServiceName?: string, localEndpoint?: model.Endpoint, log?: Console, - defaultTags?: {} + defaultTags?: {}, + propagation?: propagation.Propagation }); /** Returns the current trace ID or a sentinel value indicating its absence. */ @@ -61,6 +62,11 @@ declare namespace zipkin { recordLocalAddr(inetAddress: InetAddress): void; recordBinary(key: string, value: boolean | string | number): void; writeIdToConsole(message: any): void; + /** Extract propagation ctx from request */ + extractId(readHeader: (header: string) => option.IOption): void; + /** Injector propagation ctx from request */ + injector(request: any): object; + } class TraceId { @@ -338,8 +344,7 @@ declare namespace zipkin { port: number, serviceName?: string, host?: string, - serverTags?: {[key: string]: string}, - propagation?: propagation.Propagation + serverTags?: {[key: string]: string} }); recordRequest( @@ -363,22 +368,13 @@ declare namespace zipkin { } } namespace propagation { - class Headers { - TraceId: string; - SpanId: string; - ParentSpanId: string; - Sampled: string; - Flags: string; - } interface Propagation { - headers: Headers; - extractor(readHeader: (header: string) => option.IOption): TraceId; - injector(req: T & { headers?: any }, traceId: TraceId): RequestZipkinHeaders; + extractor(tracer: Tracer, readHeader: (header: string) => option.IOption): TraceId; + injector(req: T & { headers?: any }, traceId: TraceId): object; } class B3Propagation implements Propagation { - headers: Headers; - extractor(readHeader: (header: string) => option.IOption): TraceId; - injector(req: T & { headers?: any }, traceId: TraceId): RequestZipkinHeaders; + extractor(tracer: Tracer, readHeader: (header: string) => option.IOption): TraceId; + injector(req: T & { headers?: any }, traceId: TraceId): object; } } } diff --git a/packages/zipkin/src/index.ts b/packages/zipkin/src/index.ts index 77bb38b6..8f546da8 100644 --- a/packages/zipkin/src/index.ts +++ b/packages/zipkin/src/index.ts @@ -7,7 +7,6 @@ export { default as randomTraceId } from './tracer/randomTraceId'; export { default as sampler } from './tracer/sampler'; export { default as TraceId } from './tracer/TraceId'; -export { default as HttpHeaders } from './httpHeaders'; export { default as InetAddress } from './InetAddress'; export { default as BatchRecorder } from './batch-recorder'; @@ -16,7 +15,7 @@ export { default as ConsoleRecorder } from './console-recorder'; export { default as ExplicitContext } from './explicit-context'; export { default as Instrumentation } from './instrumentation'; -export { default as Request } from './request'; +export { default as B3Propagation } from './propagation/b3propagation'; export { default as jsonEncoder } from './jsonEncoder'; export { default as model } from './model'; diff --git a/packages/zipkin/src/instrumentation/httpClient.js b/packages/zipkin/src/instrumentation/httpClient.js index eb64fa1d..caf52eea 100644 --- a/packages/zipkin/src/instrumentation/httpClient.js +++ b/packages/zipkin/src/instrumentation/httpClient.js @@ -1,5 +1,4 @@ const Annotation = require('../annotation'); -const Request = require('../request'); const parseRequestUrl = require('../parseUrl'); function requiredArg(name) { @@ -33,8 +32,8 @@ class HttpClientInstrumentation { serviceName: this.remoteServiceName })); } - - return Request.addZipkinHeaders(request, traceId); + const headers = this.tracer.injector(request); + return Object.assign({}, request, {headers}) } recordResponse(traceId, statusCode) { diff --git a/packages/zipkin/src/instrumentation/httpServer.js b/packages/zipkin/src/instrumentation/httpServer.js index c549bc50..11492526 100644 --- a/packages/zipkin/src/instrumentation/httpServer.js +++ b/packages/zipkin/src/instrumentation/httpServer.js @@ -1,27 +1,6 @@ -import B3Propagation from '../propagation/b3propagation'; - const Annotation = require('../annotation'); -const Header = require('../httpHeaders'); const InetAddress = require('../InetAddress'); -const TraceId = require('../tracer/TraceId'); const parseRequestUrl = require('../parseUrl'); -const {Some, None} = require('../option'); - -function stringToBoolean(str) { - return str === '1' || str === 'true'; -} - -function stringToIntOption(str) { - try { - return new Some(parseInt(str)); - } catch (err) { - return None; - } -} - -function containsRequiredHeaders(readHeader) { - return readHeader(Header.TraceId) !== None && readHeader(Header.SpanId) !== None; -} function requiredArg(name) { throw new Error(`HttpServerInstrumentation: Missing required argument ${name}.`); @@ -32,14 +11,12 @@ class HttpServerInstrumentation { tracer = requiredArg('tracer'), serviceName = tracer.localEndpoint.serviceName, host, - port = requiredArg('port'), - propagation = B3Propagation.DEFAULT + port = requiredArg('port') }) { this.tracer = tracer; this.serviceName = serviceName; this.host = host && new InetAddress(host); this.port = port; - this.propagation = propagation; } spanNameFromRoute(method, route, code) { // eslint-disable-line class-methods-use-this @@ -50,7 +27,7 @@ class HttpServerInstrumentation { } recordRequest(method, requestUrl, readHeader) { - this.propagation.extractor(readHeader).ifPresent(id => this.tracer.setId(id)); + this.tracer.extractId(readHeader); const {id} = this.tracer; const {path} = parseRequestUrl(requestUrl); diff --git a/packages/zipkin/src/propagation/b3propagation.js b/packages/zipkin/src/propagation/b3propagation.js index 1d9c47ae..3ee5d4d0 100644 --- a/packages/zipkin/src/propagation/b3propagation.js +++ b/packages/zipkin/src/propagation/b3propagation.js @@ -1,49 +1,74 @@ +const {Some, None} = require('../option'); +const TraceId = require('../tracer/TraceId'); + +function stringToBoolean(str) { + return str === '1' || str === 'true'; +} + +function stringToIntOption(str) { + try { + return new Some(parseInt(str)); + } catch (err) { + return None; + } +} + class B3Propagation { - static DEFAULT = new B3Propagation(); - - headers = { - TraceId: 'X-B3-TraceId', - SpanId: 'X-B3-SpanId', - ParentSpanId: 'X-B3-ParentSpanId', - Sampled: 'X-B3-Sampled', - Flags: 'X-B3-Flags' - }; - - extractor(readHeader) { - if (this.containsRequiredHeaders(readHeader)) { - const SpanId = readHeader(this.headers.SpanId); - const parentId = SpanId.map((sid) => { - const TraceId = readHeader(this.headers.TraceId); - const ParentSpanId = readHeader(this.headers.ParentSpanId); - const Sampled = readHeader(this.headers.Sampled); - const Flags = readHeader(this.headers.Flags) - .flatMap(stringToIntOption) - .getOrElse(0); + + constructor() { + this.headers = { + TraceId: 'X-B3-TraceId', + SpanId: 'X-B3-SpanId', + ParentSpanId: 'X-B3-ParentSpanId', + Sampled: 'X-B3-Sampled', + Flags: 'X-B3-Flags' + }; + } + + extractor(tracer, readHeader) { + if (readHeader(this.headers.TraceId) !== None && readHeader(this.headers.SpanId) !== None) { + const spanId = readHeader(this.headers.SpanId); + const parentId = spanId.map((sid) => { + const traceId = readHeader(this.headers.TraceId); + const parentSpanId = readHeader(this.headers.ParentSpanId); + const sampled = readHeader(this.headers.Sampled); + const flags = readHeader(this.headers.Flags).flatMap(stringToIntOption).getOrElse(0); return new TraceId({ - TraceId: TraceId.getOrElse(), - parentId: ParentSpanId, - SpanId: sid, - debug: Flags === 1, - Sampled: Sampled.map(stringToBoolean), + traceId: traceId.getOrElse(), + parentId: parentSpanId, + spanId: sid, + debug: flags === 1, + sampled: sampled.map(stringToBoolean), }); }); - return new Some(this.tracer.join(parentId.getOrElse())); + return new Some(tracer.join(parentId.getOrElse())); } else if (readHeader(this.headers.Flags) !== None || readHeader(this.headers.Sampled) !== None) { - const Sampled = readHeader(this.headers.Sampled) === None - ? None : readHeader(this.headers.Sampled) - .map(stringToBoolean); - const Flags = readHeader(this.headers.Flags) - .flatMap(stringToIntOption) - .getOrElse(0); - return new Some(this.tracer.createRootId(Sampled, Flags === 1)); + const sampled = readHeader(this.headers.Sampled) === None + ? None : readHeader(this.headers.Sampled).map(stringToBoolean); + const flags = readHeader(this.headers.Flags).flatMap(stringToIntOption).getOrElse(0); + return new Some(tracer.createRootId(sampled, flags === 1)); } else { - return new Some(this.tracer.createRootId()); + return new Some(tracer.createRootId()); } } - #containsRequiredHeaders(readHeader) { - return readHeader(this.headers.TraceId) !== None && readHeader(this.headers.SpanId) !== None; + injector(request, traceId) { + const headers = request.headers || {}; + headers[this.headers.TraceId] = traceId.traceId; + headers[this.headers.SpanId] = traceId.spanId; + + traceId.parentSpanId.ifPresent((psid) => { + headers[this.headers.ParentSpanId] = psid; + }); + traceId.sampled.ifPresent((sampled) => { + headers[this.headers.Sampled] = sampled ? '1' : '0'; + }); + + if (traceId.isDebug()) { + headers[this.headers.Flags] = '1'; + } + return headers; } } diff --git a/packages/zipkin/src/request.js b/packages/zipkin/src/request.js deleted file mode 100644 index c611ddde..00000000 --- a/packages/zipkin/src/request.js +++ /dev/null @@ -1,29 +0,0 @@ -const HttpHeaders = require('./httpHeaders'); - -function appendZipkinHeaders(req, traceId) { - const headers = req.headers || {}; - headers[HttpHeaders.TraceId] = traceId.traceId; - headers[HttpHeaders.SpanId] = traceId.spanId; - - traceId.parentSpanId.ifPresent((psid) => { - headers[HttpHeaders.ParentSpanId] = psid; - }); - traceId.sampled.ifPresent((sampled) => { - headers[HttpHeaders.Sampled] = sampled ? '1' : '0'; - }); - - if (traceId.isDebug()) { - headers[HttpHeaders.Flags] = '1'; - } - - return headers; -} - -function addZipkinHeaders(req, traceId) { - const headers = appendZipkinHeaders(req, traceId); - return Object.assign({}, req, {headers}); -} - -module.exports = { - addZipkinHeaders -}; diff --git a/packages/zipkin/src/tracer/index.js b/packages/zipkin/src/tracer/index.js index de4ca823..7694d751 100644 --- a/packages/zipkin/src/tracer/index.js +++ b/packages/zipkin/src/tracer/index.js @@ -1,3 +1,4 @@ + const isPromise = require('is-promise'); const {None, Some} = require('../option'); const {Sampler, alwaysSample} = require('./sampler'); @@ -8,6 +9,7 @@ const TraceId = require('./TraceId'); const randomTraceId = require('./randomTraceId'); const {now, hrtime} = require('../time'); const {Endpoint} = require('../model'); +const {B3Propagation} = require('../propagation'); function requiredArg(name) { @@ -37,13 +39,15 @@ class Tracer { localEndpoint, /* eslint-disable no-console */ log = console, - defaultTags + defaultTags, + propagation = new B3Propagation() }) { this.log = log; this.recorder = recorder; this.sampler = sampler; this.traceId128Bit = traceId128Bit; this.supportsJoin = supportsJoin; + this._propagation = propagation; if (localEndpoint) { this._localEndpoint = localEndpoint; } else { @@ -265,6 +269,14 @@ class Tracer { } } } + + extractId(readHeader) { + this._propagation.extractor(this, readHeader).ifPresent(id => this.setId(id)); + } + + injector(request) { + return this._propagation.injector(request, this.id); + } } module.exports = Tracer; diff --git a/packages/zipkin/test/request.test.js b/packages/zipkin/test/request.test.js deleted file mode 100644 index c0586f68..00000000 --- a/packages/zipkin/test/request.test.js +++ /dev/null @@ -1,41 +0,0 @@ -const Request = require('../src/request.js'); -const HttpHeaders = require('../src/httpHeaders'); -const {Some} = require('../src/option'); -const TraceId = require('../src/tracer/TraceId'); - -describe('Request', () => { - it('should add trace/span and ignore parent span/sampled headers if they do not exist', () => { - const traceId = new TraceId({ - spanId: '48485a3953bb6124' - }); - const req = Request.addZipkinHeaders({}, traceId); - - expect(req.headers[HttpHeaders.TraceId]).to.equal('48485a3953bb6124'); - expect(req.headers[HttpHeaders.SpanId]).to.equal('48485a3953bb6124'); - }); - - it('should add trace, span, parent span, and sampled headers', () => { - const traceId = new TraceId({ - traceId: '48485a3953bb6124', - spanId: '48485a3953bb6124', - parentId: new Some('d56852c923dc9325'), - sampled: new Some(true) - }); - const req = Request.addZipkinHeaders({}, traceId); - - expect(req.headers[HttpHeaders.TraceId]).to.equal('48485a3953bb6124'); - expect(req.headers[HttpHeaders.SpanId]).to.equal('48485a3953bb6124'); - expect(req.headers[HttpHeaders.ParentSpanId]).to.equal('d56852c923dc9325'); - }); - - it('should add flags headers if debug is on', () => { - const traceId = new TraceId({ - spanId: '48485a3953bb6124', - flags: 1 - }); - const req = Request.addZipkinHeaders({}, traceId); - - expect(req.headers[HttpHeaders.Flags]).to.equal('1'); - expect(req.headers[HttpHeaders.SpanId]).to.equal('48485a3953bb6124'); - }); -}); From b5472eb7e0ff0ef8ec226855f28718b99ad4999a Mon Sep 17 00:00:00 2001 From: asanluis Date: Wed, 5 Aug 2020 17:51:58 +0200 Subject: [PATCH 3/8] clean propagation // TODO if is the correct approach - Delete RequestZipkinHeader - Refactor kafkajs and expressjs instrumentation - Update README, add example usage of a custom propagation - Add AWS propagation module --- packages/zipkin/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/zipkin/index.d.ts b/packages/zipkin/index.d.ts index 8d70276a..1837d7a8 100644 --- a/packages/zipkin/index.d.ts +++ b/packages/zipkin/index.d.ts @@ -356,7 +356,7 @@ declare namespace zipkin { } class HttpClient { - constructor(args: { tracer: Tracer, serviceName?: string, remoteServiceName?: string, propagation?: propagation.Propagation }); + constructor(args: { tracer: Tracer, serviceName?: string, remoteServiceName?: string}); recordRequest( request: T, From 4ce69424700243d5fd4c1f6840005b2304855f70 Mon Sep 17 00:00:00 2001 From: asanluis Date: Wed, 5 Aug 2020 18:59:03 +0200 Subject: [PATCH 4/8] start adapting instrumentations // TODO if is the correct approach - Delete RequestZipkinHeader - Refactor kafkajs and expressjs instrumentation - Update README, add example usage of a custom propagation - Add AWS propagation module --- .../src/wrapExpressHttpProxy.js | 2 +- .../src/zipkin-instrumentation-kafkajs.js | 2 +- packages/zipkin/src/instrumentation/httpClient.js | 4 +--- packages/zipkin/src/tracer/index.js | 3 ++- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/zipkin-instrumentation-express/src/wrapExpressHttpProxy.js b/packages/zipkin-instrumentation-express/src/wrapExpressHttpProxy.js index c49d336e..5c193e6d 100644 --- a/packages/zipkin-instrumentation-express/src/wrapExpressHttpProxy.js +++ b/packages/zipkin-instrumentation-express/src/wrapExpressHttpProxy.js @@ -18,7 +18,7 @@ class ExpressHttpProxyInstrumentation { const clientTraceId = this.tracer.createChildId(); this.tracer.setId(clientTraceId); - const proxyReqWithZipkinHeaders = Request.addZipkinHeaders(proxyReq, clientTraceId); + const proxyReqWithZipkinHeaders = this.tracer.injector(proxyReq); Object.defineProperty(serverReq, '_trace_id_proxy', {configurable: false, get: () => clientTraceId}); diff --git a/packages/zipkin-instrumentation-kafkajs/src/zipkin-instrumentation-kafkajs.js b/packages/zipkin-instrumentation-kafkajs/src/zipkin-instrumentation-kafkajs.js index b9793a93..50cfd5e1 100644 --- a/packages/zipkin-instrumentation-kafkajs/src/zipkin-instrumentation-kafkajs.js +++ b/packages/zipkin-instrumentation-kafkajs/src/zipkin-instrumentation-kafkajs.js @@ -49,7 +49,7 @@ const instrumentKafkaJs = (kafkaJs, {tracer, remoteServiceName}) => { id = recordProducerStart(tracer, 'send', remoteServiceName, {topic: params.topic}); const withTraceHeaders = Object.assign({}, params, { - messages: params.messages.map(msg => Request.addZipkinHeaders(msg, id)) + messages: params.messages.map(msg => tracer.injector(msg)) }); promise = obj[prop](withTraceHeaders); diff --git a/packages/zipkin/src/instrumentation/httpClient.js b/packages/zipkin/src/instrumentation/httpClient.js index caf52eea..3e2f0d4b 100644 --- a/packages/zipkin/src/instrumentation/httpClient.js +++ b/packages/zipkin/src/instrumentation/httpClient.js @@ -18,7 +18,6 @@ class HttpClientInstrumentation { recordRequest(request, url, method) { this.tracer.setId(this.tracer.createChildId()); - const traceId = this.tracer.id; const {path} = parseRequestUrl(url); this.tracer.recordServiceName(this.serviceName); @@ -32,8 +31,7 @@ class HttpClientInstrumentation { serviceName: this.remoteServiceName })); } - const headers = this.tracer.injector(request); - return Object.assign({}, request, {headers}) + return this.tracer.injector(request); } recordResponse(traceId, statusCode) { diff --git a/packages/zipkin/src/tracer/index.js b/packages/zipkin/src/tracer/index.js index 7694d751..43361e78 100644 --- a/packages/zipkin/src/tracer/index.js +++ b/packages/zipkin/src/tracer/index.js @@ -275,7 +275,8 @@ class Tracer { } injector(request) { - return this._propagation.injector(request, this.id); + const headers = this._propagation.injector(request, this.id); + return Object.assign({}, request, {headers}); } } From a9f4c834a4002744eab3e7861a285ba38e85badf Mon Sep 17 00:00:00 2001 From: asanluis Date: Wed, 5 Aug 2020 19:03:31 +0200 Subject: [PATCH 5/8] fix eslint rules // TODO if is the correct approach - Delete RequestZipkinHeader - Refactor kafkajs and expressjs instrumentation - Update README, add example usage of a custom propagation - Add AWS propagation module --- .../src/wrapExpressHttpProxy.js | 2 +- .../src/zipkin-instrumentation-kafkajs.js | 1 - packages/zipkin/src/propagation/b3propagation.js | 5 ++--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/zipkin-instrumentation-express/src/wrapExpressHttpProxy.js b/packages/zipkin-instrumentation-express/src/wrapExpressHttpProxy.js index 5c193e6d..03981b3a 100644 --- a/packages/zipkin-instrumentation-express/src/wrapExpressHttpProxy.js +++ b/packages/zipkin-instrumentation-express/src/wrapExpressHttpProxy.js @@ -1,4 +1,4 @@ -const {Request, Annotation} = require('zipkin'); +const {Annotation} = require('zipkin'); const url = require('url'); function getPathnameFromPath(path) { diff --git a/packages/zipkin-instrumentation-kafkajs/src/zipkin-instrumentation-kafkajs.js b/packages/zipkin-instrumentation-kafkajs/src/zipkin-instrumentation-kafkajs.js index 50cfd5e1..afa01c38 100644 --- a/packages/zipkin-instrumentation-kafkajs/src/zipkin-instrumentation-kafkajs.js +++ b/packages/zipkin-instrumentation-kafkajs/src/zipkin-instrumentation-kafkajs.js @@ -1,4 +1,3 @@ -const {Request} = require('zipkin'); const { recordConsumeStop, recordConsumeStart, recordProducerStart, recordProducerStop diff --git a/packages/zipkin/src/propagation/b3propagation.js b/packages/zipkin/src/propagation/b3propagation.js index 3ee5d4d0..434f0d09 100644 --- a/packages/zipkin/src/propagation/b3propagation.js +++ b/packages/zipkin/src/propagation/b3propagation.js @@ -14,7 +14,6 @@ function stringToIntOption(str) { } class B3Propagation { - constructor() { this.headers = { TraceId: 'X-B3-TraceId', @@ -43,7 +42,8 @@ class B3Propagation { }); return new Some(tracer.join(parentId.getOrElse())); - } else if (readHeader(this.headers.Flags) !== None || readHeader(this.headers.Sampled) !== None) { + } else if (readHeader(this.headers.Flags) !== None + || readHeader(this.headers.Sampled) !== None) { const sampled = readHeader(this.headers.Sampled) === None ? None : readHeader(this.headers.Sampled).map(stringToBoolean); const flags = readHeader(this.headers.Flags).flatMap(stringToIntOption).getOrElse(0); @@ -70,7 +70,6 @@ class B3Propagation { } return headers; } - } module.exports = B3Propagation; From 5349ef71878e1ba63f3b46903e21572603ac15d5 Mon Sep 17 00:00:00 2001 From: asanluis Date: Mon, 21 Sep 2020 19:27:49 +0200 Subject: [PATCH 6/8] add Getter and Setter interface to extract traceId and set trace context --- packages/zipkin/index.d.ts | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/zipkin/index.d.ts b/packages/zipkin/index.d.ts index 1837d7a8..fdd056da 100644 --- a/packages/zipkin/index.d.ts +++ b/packages/zipkin/index.d.ts @@ -368,13 +368,21 @@ declare namespace zipkin { } } namespace propagation { - interface Propagation { - extractor(tracer: Tracer, readHeader: (header: string) => option.IOption): TraceId; - injector(req: T & { headers?: any }, traceId: TraceId): object; - } - class B3Propagation implements Propagation { - extractor(tracer: Tracer, readHeader: (header: string) => option.IOption): TraceId; - injector(req: T & { headers?: any }, traceId: TraceId): object; + interface Setter { + put(request: R, key: K, value: string): void; + } + interface Getter { + get(request: R, key: K): string; + } + interface Propagation { + keys(): []; + extractor(getter: Getter): TraceId; + injector(setter: Setter): object; + } + class B3Propagation implements Propagation { + keys(): []; + extractor(getter: Getter): TraceId; + injector(setter: Setter): object; } } } From fcf3d23b36af178ed83655644d81ced543470f30 Mon Sep 17 00:00:00 2001 From: asanluis Date: Mon, 21 Sep 2020 21:00:06 +0200 Subject: [PATCH 7/8] add Extractor and Injector interface --- packages/zipkin/index.d.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/zipkin/index.d.ts b/packages/zipkin/index.d.ts index fdd056da..15378a1f 100644 --- a/packages/zipkin/index.d.ts +++ b/packages/zipkin/index.d.ts @@ -29,6 +29,14 @@ declare namespace zipkin { const alwaysSample: (traceId: TraceId) => boolean; } + interface Injector { + inject(context: Context, request: R): void; + } + + interface Extractor { + extract(request: R): TraceId; + } + class Tracer { constructor(args: { ctxImpl: Context, @@ -376,13 +384,13 @@ declare namespace zipkin { } interface Propagation { keys(): []; - extractor(getter: Getter): TraceId; - injector(setter: Setter): object; + extractor(getter: Getter): Extractor; + injector(setter: Setter): Injector; } class B3Propagation implements Propagation { keys(): []; - extractor(getter: Getter): TraceId; - injector(setter: Setter): object; + extractor(getter: Getter): Extractor; + injector(setter: Setter): Injector; } } } From d34a721373ed793b0c7464f682e5d7fb4586791a Mon Sep 17 00:00:00 2001 From: asanluis Date: Wed, 2 Dec 2020 18:57:01 +0100 Subject: [PATCH 8/8] add Extractor and Injector implementation --- .../zipkin/src/propagation/b3propagation.js | 114 ++++++++++-------- 1 file changed, 67 insertions(+), 47 deletions(-) diff --git a/packages/zipkin/src/propagation/b3propagation.js b/packages/zipkin/src/propagation/b3propagation.js index 434f0d09..2f80b7f7 100644 --- a/packages/zipkin/src/propagation/b3propagation.js +++ b/packages/zipkin/src/propagation/b3propagation.js @@ -1,5 +1,6 @@ const {Some, None} = require('../option'); const TraceId = require('../tracer/TraceId'); +const Tracer = require('../tracer'); function stringToBoolean(str) { return str === '1' || str === 'true'; @@ -13,62 +14,81 @@ function stringToIntOption(str) { } } -class B3Propagation { - constructor() { - this.headers = { - TraceId: 'X-B3-TraceId', - SpanId: 'X-B3-SpanId', - ParentSpanId: 'X-B3-ParentSpanId', - Sampled: 'X-B3-Sampled', - Flags: 'X-B3-Flags' - }; +class B3Extractor { + + constructor(b3Propagation, getter) { + this._propagation = b3Propagation + this._getter = getter } - extractor(tracer, readHeader) { - if (readHeader(this.headers.TraceId) !== None && readHeader(this.headers.SpanId) !== None) { - const spanId = readHeader(this.headers.SpanId); - const parentId = spanId.map((sid) => { - const traceId = readHeader(this.headers.TraceId); - const parentSpanId = readHeader(this.headers.ParentSpanId); - const sampled = readHeader(this.headers.Sampled); - const flags = readHeader(this.headers.Flags).flatMap(stringToIntOption).getOrElse(0); - return new TraceId({ - traceId: traceId.getOrElse(), - parentId: parentSpanId, - spanId: sid, - debug: flags === 1, - sampled: sampled.map(stringToBoolean), + extract(request) { + const traceId = this._getter.get(request, this._propagation._TRACE_ID); + const spanId = this._getter.get(request, this._propagation._SPAN_ID); + const flags = this._getter.get(request, this._propagation._FLAGS); + const sampled = this._getter.get(request, this._propagation._SAMPLED); + if(traceId !== None && spanId !== None){ + return spanId.map((sid) => { + const parentSpanId = this._getter.get(request, this._propagation._PARENT_SPAN_ID); + return new TraceId({ + traceId: traceId.getOrElse(), + parentId: parentSpanId, + spanId: sid, + debug: flags.flatMap(stringToIntOption).getOrElse(0) === 1, + sampled: sampled.map(stringToBoolean), + }); }); - }); - - return new Some(tracer.join(parentId.getOrElse())); - } else if (readHeader(this.headers.Flags) !== None - || readHeader(this.headers.Sampled) !== None) { - const sampled = readHeader(this.headers.Sampled) === None - ? None : readHeader(this.headers.Sampled).map(stringToBoolean); - const flags = readHeader(this.headers.Flags).flatMap(stringToIntOption).getOrElse(0); - return new Some(tracer.createRootId(sampled, flags === 1)); - } else { - return new Some(tracer.createRootId()); + } else if(flags !== None || sampled !== None){ + // TODO Change ?? + return Tracer.createRootId(sampled === None ? None : sampled.map(stringToBoolean), + flags.flatMap(stringToIntOption).getOrElse(0) === 1) } + return Tracer.createRootId(); } +} - injector(request, traceId) { - const headers = request.headers || {}; - headers[this.headers.TraceId] = traceId.traceId; - headers[this.headers.SpanId] = traceId.spanId; +class B3Injector { - traceId.parentSpanId.ifPresent((psid) => { - headers[this.headers.ParentSpanId] = psid; - }); - traceId.sampled.ifPresent((sampled) => { - headers[this.headers.Sampled] = sampled ? '1' : '0'; - }); + constructor(b3Propagation, setter) { + this._propagation = b3Propagation + this._setter = setter + } - if (traceId.isDebug()) { - headers[this.headers.Flags] = '1'; + inject(context, request) { + this._setter.put(request, this._propagation._TRACE_ID, context.traceId); + this._setter.put(request, this._propagation._SPAN_ID, context.spanId); + context.sampled.ifPresent((psid) => { this._setter.put(request, this._propagation._PARENT_SPAN_ID, psid) }); + context.sampled.ifPresent((sampled) => { this._setter.put(request, this._propagation._SAMPLED, sampled? '1' : '0') }); + if(context.isDebug()){ + this._setter.put(request, this._propagation._FLAGS, '1'); } - return headers; + } + +} + +class B3Propagation { + + _TRACE_ID = 'X-B3-TraceId' + _SPAN_ID = 'X-B3-SpanId' + _PARENT_SPAN_ID = 'X-B3-ParentSpanId' + _SAMPLED = 'X-B3-Sampled' + _FLAGS = 'X-B3-Flags' + + get keys() { + return [ + this._TRACE_ID, + this._SPAN_ID, + this._PARENT_SPAN_ID, + this._SAMPLED, + this._FLAGS + ]; + } + + extractor(getter) { + return new B3Extractor(this, getter); + } + + injector(setter) { + return new B3Injector(this, setter); } }