From 78649afce7fde9409f31cdfd1b4315fe9c8d2e77 Mon Sep 17 00:00:00 2001 From: Ashish Aggarwal Date: Thu, 2 Aug 2018 11:56:10 +0530 Subject: [PATCH 1/2] upgrading 0.14 opentracing --- .gitignore | 1 + examples/index.js | 1 + package.json | 2 +- src/dispatchers/remote.ts | 25 +++++--- src/log_data.ts | 25 ++++++++ src/span.ts | 125 ++++++++++++++++++++++++-------------- src/span_context.ts | 4 +- src/start_span_fields.ts | 2 +- src/tracer.ts | 31 +++++++--- tests/tracer.spec.ts | 7 +-- 10 files changed, 154 insertions(+), 69 deletions(-) create mode 100644 src/log_data.ts diff --git a/.gitignore b/.gitignore index 6aa2bed..83b04bd 100644 --- a/.gitignore +++ b/.gitignore @@ -64,3 +64,4 @@ src/proto_idl_codegen/ .idea/ dist/ .idea/typescript-compiler.xml +*.iml diff --git a/examples/index.js b/examples/index.js index a0015fc..9afae4e 100644 --- a/examples/index.js +++ b/examples/index.js @@ -91,6 +91,7 @@ const clientChildSpan = tracer.startSpan('downstream-service-call', { /// add more tags or logs to your spans clientChildSpan.setTag(opentracing.Tags.ERROR, true); clientChildSpan.setTag(opentracing.Tags.HTTP_STATUS_CODE, 503); +clientChildSpan.addTags({'child-custom-tag-1': 1, 'child-custom-tag-2': 'someval'}); serverSpan.setTag(opentracing.Tags.ERROR, true); serverSpan.setTag('my-custom-tag', 10.5); diff --git a/package.json b/package.json index b0d6c7c..a321884 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "dependencies": { "google-protobuf": "^3.0.0", "grpc": "^1.9.0", - "opentracing": "^0.13.0", + "opentracing": "^0.14.0", "uuid": "^3.2.1" }, "devDependencies": { diff --git a/src/dispatchers/remote.ts b/src/dispatchers/remote.ts index 77a9782..08660b1 100644 --- a/src/dispatchers/remote.ts +++ b/src/dispatchers/remote.ts @@ -70,9 +70,13 @@ export default class RemoteDispatcher implements Dispatcher { protoSpan.setDuration(span.duration()); const protoSpanTags = []; - span.tags().forEach(tag => { - protoSpanTags.push(this._createProtoTag(tag)); - }); + + const tags = span.tags(); + for (const k in tags) { + if (tags.hasOwnProperty(k)) { + protoSpanTags.push(RemoteDispatcher._createProtoTag(k, tags[k])); + } + } protoSpan.setTagsList(protoSpanTags); @@ -80,9 +84,12 @@ export default class RemoteDispatcher implements Dispatcher { span.logs().forEach(log => { const protoLog = new messages.Log(); const protoLogTags = []; - log.tags.forEach(tag => { - protoLogTags.push(this._createProtoTag(tag)); - }); + const kvPairs = log.keyValuePairs; + for (const k in kvPairs) { + if (kvPairs.hasOwnProperty(k)) { + protoLogTags.push(RemoteDispatcher._createProtoTag(k, kvPairs[k])); + } + } protoLog.setTimestamp(log.timestamp); protoLog.setFieldsList(protoLogTags); protoSpanLogs.push(protoLog); @@ -92,11 +99,11 @@ export default class RemoteDispatcher implements Dispatcher { return protoSpan; } - private _createProtoTag(tag: any): any { + private static _createProtoTag(key: string, value: any): any { const protoTag = new messages.Tag(); - protoTag.setKey(tag.key); + protoTag.setKey(key); - const tagValue = tag.value; + const tagValue = value; if (typeof tagValue === 'number') { if (Utils.isFloatType(tagValue)) { protoTag.setVdouble(tagValue); diff --git a/src/log_data.ts b/src/log_data.ts new file mode 100644 index 0000000..810ff6e --- /dev/null +++ b/src/log_data.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2018 Expedia, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export default class LogData { + keyValuePairs: { [key: string]: any }; + timestamp: number; + + constructor(keyValuePairs: { [key: string]: any }, timestamp: number) { + this.keyValuePairs = keyValuePairs; + this.timestamp = timestamp; + } +} diff --git a/src/span.ts b/src/span.ts index ed38a59..ba87a31 100644 --- a/src/span.ts +++ b/src/span.ts @@ -19,16 +19,17 @@ import Tracer from './tracer'; import Utils from './utils'; import * as opentracing from 'opentracing'; +import LogData from './log_data'; -export default class Span { - _tracer: Tracer; +export default class Span extends opentracing.Span { + _tracerImpl: Tracer; _operationName: string; _spanContext: SpanContext; _startTime: number; _duration: number; _references: opentracing.Reference[]; - _logs: opentracing.LogData[]; - _tags: opentracing.Tag[]; + _logs: LogData[]; + _tags: { [key: string]: any }; _isFinished: boolean; constructor(tracer: Tracer, @@ -36,13 +37,14 @@ export default class Span { spanContext: SpanContext, startTime: number, references: opentracing.Reference[]) { - this._tracer = tracer; + super(); + this._tracerImpl = tracer; this._operationName = operationName; this._spanContext = spanContext; this._startTime = startTime; this._references = references; this._logs = []; - this._tags = []; + this._tags = {}; this._isFinished = false; } @@ -51,18 +53,18 @@ export default class Span { } serviceName(): string { - return this._tracer._serviceName; + return this._tracerImpl._serviceName; } context(): SpanContext { return this._spanContext; } - tags(): opentracing.Tag[] { + tags(): { [key: string]: any } { return this._tags; } - logs(): opentracing.LogData[] { + logs(): LogData[] { return this._logs; } @@ -74,68 +76,68 @@ export default class Span { return this._duration; } - tracer(): Tracer { - return this._tracer; + tracer(): opentracing.Tracer { + return this._tracer(); } - setOperationName(name): Span { - this._operationName = name; + setOperationName(name): this { + this._setOperationName(name); return this; } isFinished(): boolean { return this._isFinished; } - addTags(keyValues: any): Span { - for (const k in keyValues) { - if (keyValues.hasOwnProperty(k)) { - this.setTag(k, keyValues[k]); - } - } + + addTags(keyValueMap: { [key: string]: any; }): this { + this._addTags(keyValueMap); return this; } - setTag(k: string, v: any): Span { - this._tags.push({ key: k, value: v }); + setTag(k: string, v: any): this { + this._tags[k] = v; return this; } - setBaggageItem(key: string, value: string): Span { + setBaggageItem(key: string, value: string): this { const prevBaggageValue = this._spanContext.baggage[key]; this._logFields(key, value, prevBaggageValue); - this._spanContext.addBaggageItem(key, value); + this._spanContext = this._spanContext.addBaggageItem(key, value); return this; } - log(keyValuePairs: any, timestamp?: number): void { - const _tags = []; - for (const k in keyValuePairs) { - if (keyValuePairs.hasOwnProperty(k)) { - _tags.push({key: k, value: keyValuePairs[k]}); - } - } - this._logs.push({ - timestamp: timestamp || Utils.now(), - tags: _tags - }); + log(keyValuePairs: { [p: string]: any }, timestamp?: number): this { + this._log(keyValuePairs, timestamp); + return this; } - logEvent(eventName: string, payLoad: any): void { - return this.log({ + logEvent(eventName: string, data: any): void { + this.log({ event: eventName, - payload: payLoad + payload: data }); } finish(finishTime?: number, callback?: (error) => void): void { - if (this._isFinished) { - const spanInfo = `operation=${this.operationName},context=${this.context().toString()}`; - throw new Error(`cant finish the same span twice - ${spanInfo}`); + this._finish(finishTime, callback); + } + + getBaggageItem(key: string): string | any { + return this._getBaggageItem(key); + } + + protected _tracer(): opentracing.Tracer { + return this._tracerImpl; + } + + protected _log(keyValuePairs: { [p: string]: any }, timestamp?: number): void { + const kvPairs = {}; + for (const k in keyValuePairs) { + if (keyValuePairs.hasOwnProperty(k)) { + kvPairs[k] = keyValuePairs[k]; + } } - const endTime = finishTime || Utils.now(); - this._duration = endTime - this._startTime; - this._tracer.dispatcher().dispatch(this, callback); - this._isFinished = true; + this._logs.push(new LogData(kvPairs, timestamp || Utils.now())); } private _logFields(k: string, v: string, prevBaggageValue: string): void { @@ -150,6 +152,41 @@ export default class Span { this.log(fields); } + protected _addTags(keyValuePairs: { [p: string]: any }): void { + for (const k in keyValuePairs) { + if (keyValuePairs.hasOwnProperty(k)) { + this.setTag(k, keyValuePairs[k]); + } + } + } + + protected _setOperationName(name: string): void { + this._operationName = name; + } + + protected _setBaggageItem(key: string, value: string): void { + this._spanContext = this._spanContext.addBaggageItem(key, value); + } + + protected _getBaggageItem(key: string): string | any { + return this._spanContext.baggage()[key]; + } + + protected _context(): SpanContext { + return this._spanContext; + } + + protected _finish(finishTime?: number, callback?: (error) => void): void { + if (this._isFinished) { + const spanInfo = `operation=${this.operationName},context=${this.context().toString()}`; + throw new Error(`cant finish the same span twice - ${spanInfo}`); + } + const endTime = finishTime || Utils.now(); + this._duration = endTime - this._startTime; + this._tracerImpl.dispatcher().dispatch(this, callback); + this._isFinished = true; + } + toString(): string { return JSON.stringify( Utils.merge(this._spanContext, { diff --git a/src/span_context.ts b/src/span_context.ts index 31e372b..94b1906 100644 --- a/src/span_context.ts +++ b/src/span_context.ts @@ -15,8 +15,9 @@ */ import Utils from './utils'; +import * as opentracing from 'opentracing'; -export default class SpanContext { +export default class SpanContext extends opentracing.SpanContext { _traceId: string; _spanId: string; _parentSpanId: string; @@ -27,6 +28,7 @@ export default class SpanContext { spanId, parentSpanId, baggage = {}) { + super(); this._traceId = traceId; this._spanId = spanId; this._parentSpanId = parentSpanId; diff --git a/src/start_span_fields.ts b/src/start_span_fields.ts index 35a2b8f..b13d9c3 100644 --- a/src/start_span_fields.ts +++ b/src/start_span_fields.ts @@ -18,7 +18,7 @@ import SpanContext from './span_context'; import * as opentracing from 'opentracing'; -export default class StartSpanFields { +export default class StartSpanFields implements opentracing.SpanOptions { childOf?: SpanContext; references?: opentracing.Reference[]; tags?: any; diff --git a/src/tracer.ts b/src/tracer.ts index b5756c1..d57a708 100644 --- a/src/tracer.ts +++ b/src/tracer.ts @@ -28,10 +28,10 @@ import TextMapPropagator from './propagators/textmap_propagator'; import URLCodex from './propagators/url_codex'; import StartSpanFields from './start_span_fields'; -export default class Tracer { +export default class Tracer extends opentracing.Tracer { _serviceName: string; _dispatcher: Dispatcher; - _commonTags: any; + _commonTags: { [key: string]: any }; _logger: any; _registry: PropagationRegistry; @@ -39,6 +39,7 @@ export default class Tracer { dispatcher = new NoopDispatcher(), commonTags: any = {}, logger = new NullLogger()) { + super(); this._commonTags = commonTags || {}; this._serviceName = serviceName; this._dispatcher = dispatcher; @@ -49,6 +50,10 @@ export default class Tracer { } startSpan(operationName: string, fields?: StartSpanFields): Span { + return this._startSpan(operationName, fields); + } + + protected _startSpan(operationName: string, fields: StartSpanFields): Span { fields = fields || {}; const references = fields.references || []; const spanTags = fields.tags || {}; @@ -63,12 +68,12 @@ export default class Tracer { const ref = references[i]; if (ref.type() === opentracing.REFERENCE_CHILD_OF) { if (!parent || followsFromIsParent) { - parent = ref.referencedContext(); + parent = ref.referencedContext() as SpanContext; break; } } else if (ref.type() === opentracing.REFERENCE_FOLLOWS_FROM) { if (!parent) { - parent = ref.referencedContext(); + parent = ref.referencedContext() as SpanContext; followsFromIsParent = true; } } @@ -76,14 +81,14 @@ export default class Tracer { } const ctx = Tracer._createSpanContext(parent, fields.callerSpanContext); - return this._startSpan(operationName, ctx, startTime, references, spanTags); + return this._spanStart(operationName, ctx, startTime, references, spanTags); } - private _startSpan(operationName: string, + private _spanStart(operationName: string, ctx: SpanContext, startTime: number, references: opentracing.Reference[], - spanTags: any): Span { + spanTags: { [key: string]: any }): Span { const span = new Span(this, operationName, ctx, startTime, references); span.addTags(this._commonTags) .addTags(spanTags); @@ -123,6 +128,14 @@ export default class Tracer { } inject(spanContext: SpanContext, format: string, carrier: any): void { + return this._inject(spanContext, format, carrier); + } + + extract(format: string, carrier: any): SpanContext { + return this._extract(format, carrier); + } + + protected _inject(spanContext: SpanContext, format: string, carrier: any): void { if (!spanContext) { return; } @@ -135,7 +148,7 @@ export default class Tracer { propagator.inject(spanContext, carrier); } - extract(format: string, carrier: any): SpanContext { + protected _extract(format: string, carrier: any): SpanContext | any { if (!carrier) { return null; } @@ -148,7 +161,7 @@ export default class Tracer { return propagator.extract(carrier); } - static initTracer(config): Tracer { + static initTracer(config): opentracing.Tracer { if (config.disable) { return new opentracing.Tracer(); } diff --git a/tests/tracer.spec.ts b/tests/tracer.spec.ts index a6c10c8..69bde78 100644 --- a/tests/tracer.spec.ts +++ b/tests/tracer.spec.ts @@ -34,9 +34,8 @@ const expectSpansInStore = (inMemSpanStore: InMemoryDispatcher, expectedCount: n expect(inMemSpanStore.spans().length).eq(expectedCount); inMemSpanStore.spans().forEach(receivedSpan => { expect(receivedSpan.isFinished()).eq(true); - const receivedSpanTag = receivedSpan.tags()[0]; - expect(receivedSpanTag.key).eq('version'); - expect(receivedSpanTag.value).eq('1.1'); + const versionTagValue = receivedSpan.tags()['version']; + expect(versionTagValue).eq('1.1'); expect(receivedSpan.serviceName()).eq(dummyServiceName); expect(isUndefined(receivedSpan.context().traceId())).eq(false); expect(isUndefined(receivedSpan.context().spanId())).eq(false); @@ -46,7 +45,7 @@ const expectSpansInStore = (inMemSpanStore: InMemoryDispatcher, expectedCount: n const findSpan = (inMemSpanStore: InMemoryDispatcher, spanKind: string): Span => { return inMemSpanStore .spans() - .filter(span => span.tags().filter(tag => tag.key === 'span.kind' && tag.value === spanKind).length > 0)[0]; + .filter(span => span.tags()['span.kind'] === spanKind)[0]; }; describe('Tracer tests', () => { From d5c352cb2bdde92203f2b3139ec980e0b4cb4067 Mon Sep 17 00:00:00 2001 From: Ashish Aggarwal Date: Thu, 2 Aug 2018 16:36:49 +0530 Subject: [PATCH 2/2] adding opentracing api compatibility test spec --- examples/index.js | 3 ++ src/dispatchers/remote.ts | 8 ++--- src/propagators/binary_propagator.ts | 27 +++++++++++++++ src/propagators/textmap_propagator.ts | 10 +++--- src/span.ts | 2 +- src/span_context.ts | 48 +++++++++------------------ src/tracer.ts | 12 ++++--- tests/api-compat.spec.ts | 28 ++++++++++++++++ tests/tracer.spec.ts | 28 ++++++++++------ 9 files changed, 109 insertions(+), 57 deletions(-) create mode 100644 src/propagators/binary_propagator.ts create mode 100644 tests/api-compat.spec.ts diff --git a/examples/index.js b/examples/index.js index 9afae4e..8c2f53e 100644 --- a/examples/index.js +++ b/examples/index.js @@ -92,6 +92,9 @@ const clientChildSpan = tracer.startSpan('downstream-service-call', { clientChildSpan.setTag(opentracing.Tags.ERROR, true); clientChildSpan.setTag(opentracing.Tags.HTTP_STATUS_CODE, 503); clientChildSpan.addTags({'child-custom-tag-1': 1, 'child-custom-tag-2': 'someval'}); +clientChildSpan.log({ + eventCode: 1001 +}); serverSpan.setTag(opentracing.Tags.ERROR, true); serverSpan.setTag('my-custom-tag', 10.5); diff --git a/src/dispatchers/remote.ts b/src/dispatchers/remote.ts index 08660b1..8ffc61d 100644 --- a/src/dispatchers/remote.ts +++ b/src/dispatchers/remote.ts @@ -27,9 +27,9 @@ export default class RemoteDispatcher implements Dispatcher { _logger: any; constructor(agentHost: string, agentPort: number, logger = new NullLogger()) { - logger.info(`Initializing the remote dispatcher, connecting at ${agentHost}:${agentPort}`); agentHost = agentHost || 'haystack-agent'; agentPort = agentPort || 35000; + logger.info(`Initializing the remote dispatcher, connecting at ${agentHost}:${agentPort}`); this._client = new services.SpanAgentClient(`${agentHost}:${agentPort}`, grpc.credentials.createInsecure()); this._logger = logger; } @@ -63,9 +63,9 @@ export default class RemoteDispatcher implements Dispatcher { const protoSpan = new messages.Span(); protoSpan.setServicename(span.serviceName()); protoSpan.setOperationname(span.operationName()); - protoSpan.setTraceid(span.context().traceId()); - protoSpan.setSpanid(span.context().spanId()); - protoSpan.setParentspanid(span.context().parentSpanId()); + protoSpan.setTraceid(span.context().traceId); + protoSpan.setSpanid(span.context().spanId); + protoSpan.setParentspanid(span.context().parentSpanId); protoSpan.setStarttime(span.startTime()); protoSpan.setDuration(span.duration()); diff --git a/src/propagators/binary_propagator.ts b/src/propagators/binary_propagator.ts new file mode 100644 index 0000000..df10407 --- /dev/null +++ b/src/propagators/binary_propagator.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2018 Expedia, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {Propagator} from './propagator'; +import SpanContext from '../span_context'; + +export default class BinaryPropagator implements Propagator { + inject(spanContext: SpanContext, carrier: any): void { + } + + extract(carrier: any): SpanContext { + return null; + } +} diff --git a/src/propagators/textmap_propagator.ts b/src/propagators/textmap_propagator.ts index bf2ea45..beb11a9 100644 --- a/src/propagators/textmap_propagator.ts +++ b/src/propagators/textmap_propagator.ts @@ -28,14 +28,14 @@ export default class TextMapPropagator implements Propagator { } inject(spanContext: SpanContext, carrier: any): void { - carrier[this._opts.traceIdKey()] = spanContext.traceId(); - carrier[this._opts.spanIdKey()] = spanContext.spanId(); - carrier[this._opts.parentSpanIdKey()] = spanContext.parentSpanId(); + carrier[this._opts.traceIdKey()] = spanContext.traceId; + carrier[this._opts.spanIdKey()] = spanContext.spanId; + carrier[this._opts.parentSpanIdKey()] = spanContext.parentSpanId; - const baggage = spanContext.baggage(); + const baggage = spanContext.baggage; for (const key in baggage) { if (baggage.hasOwnProperty(key)) { - carrier[`${this._opts.baggageKeyPrefix()}${key}`] = this._codex.encode(spanContext.baggage()[key]); + carrier[`${this._opts.baggageKeyPrefix()}${key}`] = this._codex.encode(spanContext.baggage[key]); } } } diff --git a/src/span.ts b/src/span.ts index ba87a31..a5043f4 100644 --- a/src/span.ts +++ b/src/span.ts @@ -169,7 +169,7 @@ export default class Span extends opentracing.Span { } protected _getBaggageItem(key: string): string | any { - return this._spanContext.baggage()[key]; + return this._spanContext.baggage[key]; } protected _context(): SpanContext { diff --git a/src/span_context.ts b/src/span_context.ts index 94b1906..9447528 100644 --- a/src/span_context.ts +++ b/src/span_context.ts @@ -18,10 +18,10 @@ import Utils from './utils'; import * as opentracing from 'opentracing'; export default class SpanContext extends opentracing.SpanContext { - _traceId: string; - _spanId: string; - _parentSpanId: string; - _baggage: any; + traceId: string; + spanId: string; + parentSpanId: string; + baggage: any; constructor( traceId, @@ -29,50 +29,34 @@ export default class SpanContext extends opentracing.SpanContext { parentSpanId, baggage = {}) { super(); - this._traceId = traceId; - this._spanId = spanId; - this._parentSpanId = parentSpanId; - this._baggage = baggage; - } - - traceId(): string { - return this._traceId; - } - - spanId(): string { - return this._spanId; - } - - parentSpanId(): string { - return this._parentSpanId; - } - - baggage(): any { - return this._baggage; + this.traceId = traceId; + this.spanId = spanId; + this.parentSpanId = parentSpanId; + this.baggage = baggage; } setTraceId(traceId: string): void { - this._traceId = traceId; + this.traceId = traceId; } setSpanId(spanId: string): void { - this._spanId = spanId; + this.spanId = spanId; } setParentSpanId(parentSpanId: string): void { - this._parentSpanId = parentSpanId; + this.parentSpanId = parentSpanId; } addBaggageItem(key: string, value: any): SpanContext { - const newBaggage = Utils.assign(this._baggage, key, value); + const newBaggage = Utils.assign(this.baggage, key, value); return new SpanContext( - this._traceId, - this._spanId, - this._parentSpanId, + this.traceId, + this.spanId, + this.parentSpanId, newBaggage); } isValid(): boolean { - return !!(this._traceId && this._spanId); + return !!(this.traceId && this.spanId); } } diff --git a/src/tracer.ts b/src/tracer.ts index d57a708..05800c3 100644 --- a/src/tracer.ts +++ b/src/tracer.ts @@ -27,6 +27,7 @@ import PropagationRegistry from './propagators/propagation_registry'; import TextMapPropagator from './propagators/textmap_propagator'; import URLCodex from './propagators/url_codex'; import StartSpanFields from './start_span_fields'; +import BinaryPropagator from './propagators/binary_propagator'; export default class Tracer extends opentracing.Tracer { _serviceName: string; @@ -46,6 +47,7 @@ export default class Tracer extends opentracing.Tracer { this._logger = logger; this._registry = new PropagationRegistry(); this._registry.register(opentracing.FORMAT_TEXT_MAP, new TextMapPropagator()); + this._registry.register(opentracing.FORMAT_BINARY, new BinaryPropagator()); this._registry.register(opentracing.FORMAT_HTTP_HEADERS, new TextMapPropagator(new URLCodex())); } @@ -98,13 +100,13 @@ export default class Tracer extends opentracing.Tracer { static _createSpanContext(parent: SpanContext, callerContext: SpanContext): SpanContext { if (!parent || !parent.isValid) { if (callerContext) { - return new SpanContext(callerContext.traceId(), callerContext.spanId(), callerContext.parentSpanId(), callerContext.baggage()); + return new SpanContext(callerContext.traceId, callerContext.spanId, callerContext.parentSpanId, callerContext.baggage); } else { - const parentBaggage = parent && parent.baggage(); + const parentBaggage = parent && parent.baggage; return new SpanContext(Utils.randomUUID(), Utils.randomUUID(), parentBaggage); } } else { - return new SpanContext(parent.traceId(), Utils.randomUUID(), parent.spanId(), parent.baggage()); + return new SpanContext(parent.traceId, Utils.randomUUID(), parent.spanId, parent.baggage); } } @@ -142,7 +144,7 @@ export default class Tracer extends opentracing.Tracer { const propagator = this._registry.propagator(format); if (!propagator) { - throw new Error('injector for the given format is not supported'); + throw new Error('injector is not supported for format=' + format); } propagator.inject(spanContext, carrier); @@ -155,7 +157,7 @@ export default class Tracer extends opentracing.Tracer { const propagator = this._registry.propagator(format); if (!propagator) { - throw new Error('extractor for the given format is not supported'); + throw new Error('extractor is not supported for format=' + format); } return propagator.extract(carrier); diff --git a/tests/api-compat.spec.ts b/tests/api-compat.spec.ts new file mode 100644 index 0000000..feba7b3 --- /dev/null +++ b/tests/api-compat.spec.ts @@ -0,0 +1,28 @@ +/* + * Copyright 2018 Expedia, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Tracer from '../src/tracer'; + +describe('OpenTracing Api Compatibility Tests', () => { + + describe('OpenTracing Api', () => { + it("should be compatible", () => { + const apiCompatibilityChecks = require('opentracing/lib/test/api_compatibility.js').default; + apiCompatibilityChecks(() => new Tracer('my-service')); + }); + }); +}); + diff --git a/tests/tracer.spec.ts b/tests/tracer.spec.ts index 69bde78..81c6470 100644 --- a/tests/tracer.spec.ts +++ b/tests/tracer.spec.ts @@ -37,8 +37,8 @@ const expectSpansInStore = (inMemSpanStore: InMemoryDispatcher, expectedCount: n const versionTagValue = receivedSpan.tags()['version']; expect(versionTagValue).eq('1.1'); expect(receivedSpan.serviceName()).eq(dummyServiceName); - expect(isUndefined(receivedSpan.context().traceId())).eq(false); - expect(isUndefined(receivedSpan.context().spanId())).eq(false); + expect(isUndefined(receivedSpan.context().traceId)).eq(false); + expect(isUndefined(receivedSpan.context().spanId)).eq(false); }); }; @@ -62,7 +62,7 @@ describe('Tracer tests', () => { expectSpansInStore(inMemSpanStore, 1); const receivedSpan = inMemSpanStore.spans()[0]; expect(receivedSpan.operationName()).eq(dummyOperation); - expect(isUndefined(receivedSpan.context().parentSpanId())).eq(true); + expect(isUndefined(receivedSpan.context().parentSpanId)).eq(true); }); it('should start and dispatch server and client spans', () => { @@ -77,6 +77,9 @@ describe('Tracer tests', () => { startClientSpanFields.childOf = serverSpan.context(); startClientSpanFields.tags = { 'span.kind': 'client' }; const clientSpan = tracer.startSpan(downstreamOperation, startClientSpanFields); + clientSpan.log({ + eventCode: 100 + }); expect(serverSpan.isFinished()).eq(false); expect(inMemSpanStore.spans().length).equal(0); @@ -85,16 +88,21 @@ describe('Tracer tests', () => { expectSpansInStore(inMemSpanStore, 2); - expect(inMemSpanStore.spans().map(span => span.operationName())).includes(downstreamOperation); - expect(inMemSpanStore.spans().map(span => span.operationName())).includes(dummyOperation); - const receivedClientSpan = findSpan(inMemSpanStore, 'client'); const receivedServerSpan = findSpan(inMemSpanStore, 'server'); + expect(receivedClientSpan.operationName()).eq(downstreamOperation); + expect(receivedServerSpan.operationName()).eq(dummyOperation); expect(receivedClientSpan.duration() <= receivedServerSpan.duration()).eq(true); - expect(receivedClientSpan.context().parentSpanId()).eq(receivedServerSpan.context().spanId()); - expect(isUndefined(receivedServerSpan.context().parentSpanId())).eq(true); - expect(receivedServerSpan.context().traceId()).eq(receivedClientSpan.context().traceId()); + expect(receivedClientSpan.context().parentSpanId).eq(receivedServerSpan.context().spanId); + expect(isUndefined(receivedServerSpan.context().parentSpanId)).eq(true); + expect(receivedServerSpan.context().traceId).eq(receivedClientSpan.context().traceId); + + expect(receivedClientSpan.logs().length).eq(1); + receivedClientSpan.logs().forEach(log => { + expect(log.keyValuePairs['eventCode']).eq(100); + expect(log.timestamp <= (Date.now() * 1000)).eq(true); + }) }); it('should inject the span in the carrier', () => { @@ -111,7 +119,7 @@ describe('Tracer tests', () => { const tracer = new Tracer(dummyServiceName, inMemSpanStore, commonTags); const carrier = {'Trace-ID': 'a' , 'Span-ID': 'b', 'Parent-ID': 'c', 'Baggage-myKey': 'myVal'}; const spanContext = tracer.extract(opentracing.FORMAT_TEXT_MAP, carrier); - expect(JSON.stringify(spanContext)).eq('{"_traceId":"a","_spanId":"b","_parentSpanId":"c","_baggage":{"myKey":"myVal"}}'); + expect(JSON.stringify(spanContext)).eq('{"traceId":"a","spanId":"b","parentSpanId":"c","baggage":{"myKey":"myVal"}}'); }); }); });