From 9e114d119fa054718b8b375f456d1d4f604448fb Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Thu, 26 Mar 2020 16:02:52 -0400 Subject: [PATCH] feat: start a root span with spanOptions.parent = null (#889) * feat: start a root span with spanOptions.parent = null * chore: lint * chore: add return type for readability --- .../src/trace/SpanOptions.ts | 3 +++ packages/opentelemetry-tracing/src/Tracer.ts | 20 ++++++++++++++++--- .../test/BasicTracerProvider.test.ts | 15 ++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/packages/opentelemetry-api/src/trace/SpanOptions.ts b/packages/opentelemetry-api/src/trace/SpanOptions.ts index 131d6d4f70..bfda7e001c 100644 --- a/packages/opentelemetry-api/src/trace/SpanOptions.ts +++ b/packages/opentelemetry-api/src/trace/SpanOptions.ts @@ -44,6 +44,9 @@ export interface SpanOptions { * A parent `SpanContext` (or `Span`, for convenience) that the newly-started * span will be the child of. This overrides the parent span extracted from * the currently active context. + * + * A null value here should prevent the SDK from extracting a parent from + * the current context, forcing the new span to be a root span. */ parent?: Span | SpanContext | null; diff --git a/packages/opentelemetry-tracing/src/Tracer.ts b/packages/opentelemetry-tracing/src/Tracer.ts index f7fd4d6248..9ca8e6a80e 100644 --- a/packages/opentelemetry-tracing/src/Tracer.ts +++ b/packages/opentelemetry-tracing/src/Tracer.ts @@ -66,9 +66,7 @@ export class Tracer implements api.Tracer { options: api.SpanOptions = {}, context = api.context.active() ): api.Span { - const parentContext = options.parent - ? getContext(options.parent) - : getParentSpanContext(context); + const parentContext = getParent(options, context); // make sampling decision const samplingDecision = this._sampler.shouldSample(parentContext); const spanId = randomSpanId(); @@ -149,6 +147,22 @@ export class Tracer implements api.Tracer { } } +/** + * Get the parent to assign to a started span. If options.parent is null, + * do not assign a parent. + * + * @param options span options + * @param context context to check for parent + */ +function getParent( + options: api.SpanOptions, + context: api.Context +): api.SpanContext | undefined { + if (options.parent === null) return undefined; + if (options.parent) return getContext(options.parent); + return getParentSpanContext(context); +} + function getContext(span: api.Span | api.SpanContext) { return isSpan(span) ? span.context() : span; } diff --git a/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts b/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts index 85422703fc..832128e9c4 100644 --- a/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts +++ b/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts @@ -239,6 +239,21 @@ describe('BasicTracerProvider', () => { childSpan.end(); }); + it('should create a root span when parent is null', () => { + const tracer = new BasicTracerProvider().getTracer('default'); + const span = tracer.startSpan('my-span'); + const overrideParent = tracer.startSpan('my-parent-override-span'); + const rootSpan = tracer.startSpan( + 'root-span', + { parent: null }, + setActiveSpan(Context.ROOT_CONTEXT, span) + ); + const context = rootSpan.context(); + assert.notStrictEqual(context.traceId, overrideParent.context().traceId); + span.end(); + rootSpan.end(); + }); + it('should start a span with name and with invalid parent span', () => { const tracer = new BasicTracerProvider().getTracer('default'); const span = tracer.startSpan(