Skip to content

Commit 9e114d1

Browse files
authored
feat: start a root span with spanOptions.parent = null (open-telemetry#889)
* feat: start a root span with spanOptions.parent = null * chore: lint * chore: add return type for readability
1 parent e9bc887 commit 9e114d1

File tree

3 files changed

+35
-3
lines changed

3 files changed

+35
-3
lines changed

packages/opentelemetry-api/src/trace/SpanOptions.ts

+3
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ export interface SpanOptions {
4444
* A parent `SpanContext` (or `Span`, for convenience) that the newly-started
4545
* span will be the child of. This overrides the parent span extracted from
4646
* the currently active context.
47+
*
48+
* A null value here should prevent the SDK from extracting a parent from
49+
* the current context, forcing the new span to be a root span.
4750
*/
4851
parent?: Span | SpanContext | null;
4952

packages/opentelemetry-tracing/src/Tracer.ts

+17-3
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,7 @@ export class Tracer implements api.Tracer {
6666
options: api.SpanOptions = {},
6767
context = api.context.active()
6868
): api.Span {
69-
const parentContext = options.parent
70-
? getContext(options.parent)
71-
: getParentSpanContext(context);
69+
const parentContext = getParent(options, context);
7270
// make sampling decision
7371
const samplingDecision = this._sampler.shouldSample(parentContext);
7472
const spanId = randomSpanId();
@@ -149,6 +147,22 @@ export class Tracer implements api.Tracer {
149147
}
150148
}
151149

150+
/**
151+
* Get the parent to assign to a started span. If options.parent is null,
152+
* do not assign a parent.
153+
*
154+
* @param options span options
155+
* @param context context to check for parent
156+
*/
157+
function getParent(
158+
options: api.SpanOptions,
159+
context: api.Context
160+
): api.SpanContext | undefined {
161+
if (options.parent === null) return undefined;
162+
if (options.parent) return getContext(options.parent);
163+
return getParentSpanContext(context);
164+
}
165+
152166
function getContext(span: api.Span | api.SpanContext) {
153167
return isSpan(span) ? span.context() : span;
154168
}

packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts

+15
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,21 @@ describe('BasicTracerProvider', () => {
239239
childSpan.end();
240240
});
241241

242+
it('should create a root span when parent is null', () => {
243+
const tracer = new BasicTracerProvider().getTracer('default');
244+
const span = tracer.startSpan('my-span');
245+
const overrideParent = tracer.startSpan('my-parent-override-span');
246+
const rootSpan = tracer.startSpan(
247+
'root-span',
248+
{ parent: null },
249+
setActiveSpan(Context.ROOT_CONTEXT, span)
250+
);
251+
const context = rootSpan.context();
252+
assert.notStrictEqual(context.traceId, overrideParent.context().traceId);
253+
span.end();
254+
rootSpan.end();
255+
});
256+
242257
it('should start a span with name and with invalid parent span', () => {
243258
const tracer = new BasicTracerProvider().getTracer('default');
244259
const span = tracer.startSpan(

0 commit comments

Comments
 (0)