Skip to content

Commit 44a3f65

Browse files
ArtAhmetajsatazor
authored andcommitted
fix(sdk-trace-base): processor onStart called with a span having empty attributes
1 parent f5ef8de commit 44a3f65

File tree

5 files changed

+91
-8
lines changed

5 files changed

+91
-8
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ For experimental package changes, see the [experimental CHANGELOG](experimental/
2020

2121
### :bug: (Bug Fix)
2222

23+
* fix(sdk-trace-base): processor onStart called with a span having empty attributes
24+
2325
## 1.18.1
2426

2527
### :bug: (Bug Fix)

packages/opentelemetry-exporter-zipkin/test/common/transform.test.ts

+34
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,40 @@ describe('transform', () => {
236236
version: '1',
237237
});
238238
});
239+
it('should map OpenTelemetry constructor attributes to a Zipkin tag', () => {
240+
const span = new Span(
241+
tracer,
242+
api.ROOT_CONTEXT,
243+
'my-span',
244+
spanContext,
245+
api.SpanKind.SERVER,
246+
parentId,
247+
[],
248+
undefined,
249+
undefined,
250+
{
251+
key1: 'value1',
252+
key2: 'value2',
253+
}
254+
);
255+
const tags: zipkinTypes.Tags = _toZipkinTags(
256+
span,
257+
defaultStatusCodeTagName,
258+
defaultStatusErrorTagName
259+
);
260+
261+
assert.deepStrictEqual(tags, {
262+
key1: 'value1',
263+
key2: 'value2',
264+
[SemanticResourceAttributes.SERVICE_NAME]: 'zipkin-test',
265+
'telemetry.sdk.language': language,
266+
'telemetry.sdk.name': 'opentelemetry',
267+
'telemetry.sdk.version': VERSION,
268+
cost: '112.12',
269+
service: 'ui',
270+
version: '1',
271+
});
272+
});
239273
it('should map OpenTelemetry SpanStatus.code to a Zipkin tag', () => {
240274
const span = new Span(
241275
tracer,

packages/opentelemetry-sdk-trace-base/src/Span.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ export class Span implements APISpan, ReadableSpan {
100100
parentSpanId?: string,
101101
links: Link[] = [],
102102
startTime?: TimeInput,
103-
_deprecatedClock?: unknown // keeping this argument even though it is unused to ensure backwards compatibility
103+
_deprecatedClock?: unknown, // keeping this argument even though it is unused to ensure backwards compatibility
104+
initAttributes?: SpanAttributes
104105
) {
105106
this.name = spanName;
106107
this._spanContext = spanContext;
@@ -119,6 +120,11 @@ export class Span implements APISpan, ReadableSpan {
119120
this.resource = parentTracer.resource;
120121
this.instrumentationLibrary = parentTracer.instrumentationLibrary;
121122
this._spanLimits = parentTracer.getSpanLimits();
123+
124+
if (initAttributes != null) {
125+
this.setAttributes(initAttributes);
126+
}
127+
122128
this._spanProcessor = parentTracer.getActiveSpanProcessor();
123129
this._spanProcessor.onStart(this, context);
124130
this._attributeValueLengthLimit =

packages/opentelemetry-sdk-trace-base/src/Tracer.ts

+9-7
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,12 @@ export class Tracer implements api.Tracer {
132132
return nonRecordingSpan;
133133
}
134134

135+
// Set initial span attributes. The attributes object may have been mutated
136+
// by the sampler, so we sanitize the merged attributes before setting them.
137+
const initAttributes = sanitizeAttributes(
138+
Object.assign(attributes, samplingResult.attributes)
139+
);
140+
135141
const span = new Span(
136142
this,
137143
context,
@@ -140,14 +146,10 @@ export class Tracer implements api.Tracer {
140146
spanKind,
141147
parentSpanId,
142148
links,
143-
options.startTime
144-
);
145-
// Set initial span attributes. The attributes object may have been mutated
146-
// by the sampler, so we sanitize the merged attributes before setting them.
147-
const initAttributes = sanitizeAttributes(
148-
Object.assign(attributes, samplingResult.attributes)
149+
options.startTime,
150+
undefined,
151+
initAttributes
149152
);
150-
span.setAttributes(initAttributes);
151153
return span;
152154
}
153155

packages/opentelemetry-sdk-trace-base/test/common/Span.test.ts

+39
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,27 @@ describe('Span', () => {
10541054
assert.ok(started);
10551055
});
10561056

1057+
it('should call onStart synchronously when span is started with initial attributes', () => {
1058+
let initAttributes;
1059+
const processor: SpanProcessor = {
1060+
onStart: span => {
1061+
initAttributes = { ...span.attributes };
1062+
},
1063+
forceFlush: () => Promise.resolve(),
1064+
onEnd() {},
1065+
shutdown: () => Promise.resolve(),
1066+
};
1067+
1068+
const provider = new BasicTracerProvider();
1069+
1070+
provider.addSpanProcessor(processor);
1071+
1072+
provider
1073+
.getTracer('default')
1074+
.startSpan('test', { attributes: { foo: 'bar' } });
1075+
assert.deepStrictEqual(initAttributes, { foo: 'bar' });
1076+
});
1077+
10571078
it('should call onEnd synchronously when span is ended', () => {
10581079
let ended = false;
10591080
const processor: SpanProcessor = {
@@ -1222,5 +1243,23 @@ describe('Span', () => {
12221243
});
12231244
});
12241245
});
1246+
1247+
describe('when initial attributes are specified', () => {
1248+
it('should store specified attributes', () => {
1249+
const span = new Span(
1250+
tracer,
1251+
ROOT_CONTEXT,
1252+
name,
1253+
spanContext,
1254+
SpanKind.CLIENT,
1255+
undefined,
1256+
undefined,
1257+
undefined,
1258+
undefined,
1259+
{ foo: 'bar' }
1260+
);
1261+
assert.deepStrictEqual(span.attributes, { foo: 'bar' });
1262+
});
1263+
});
12251264
});
12261265
});

0 commit comments

Comments
 (0)