Skip to content

Commit f309783

Browse files
seemkpichlermarc
authored andcommitted
feat: allow adding links after span creation (open-telemetry#4536)
* feat: allow adding links after span creation * update changelog * improve docs * test: increase coverage * Update api/CHANGELOG.md Co-authored-by: Marc Pichler <[email protected]> * update changelog --------- Co-authored-by: Marc Pichler <[email protected]>
1 parent 1c375cb commit f309783

File tree

7 files changed

+103
-24
lines changed

7 files changed

+103
-24
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ For experimental package changes, see the [experimental CHANGELOG](experimental/
6161
* feat(instrumentation): Make `init()` method public [#4418](https://github.com/open-telemetry/opentelemetry-js/pull/4418)
6262
* feat(context-zone-peer-dep, context-zone): support zone.js 0.13.x, 0.14.x [#4469](https://github.com/open-telemetry/opentelemetry-js/pull/4469) @pichlermarc
6363
* chore: Semantic Conventions export individual strings [4185](https://github.com/open-telemetry/opentelemetry-js/issues/4185)
64+
* feat(sdk-trace-base): allow adding span links after span creation [#4536](https://github.com/open-telemetry/opentelemetry-js/pull/4536) @seemk
6465

6566
### :bug: (Bug Fix)
6667

api/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ All notable changes to this project will be documented in this file.
88

99
### :rocket: (Enhancement)
1010

11+
* feat(api): allow adding span links after span creation [#4536](https://github.com/open-telemetry/opentelemetry-js/pull/4536) @seemk
12+
* This change is non-breaking for end-users, but breaking for Trace SDK implmentations in accordance with the [specification](https://github.com/open-telemetry/opentelemetry-specification/blob/a03382ada8afa9415266a84dafac0510ec8c160f/specification/upgrading.md?plain=1#L97-L122) as new features need to be implemented.
1113
* feat: support node 22 [#4666](https://github.com/open-telemetry/opentelemetry-js/pull/4666) @dyladan
1214

1315
### :bug: (Bug Fix)

api/src/trace/NonRecordingSpan.ts

+9
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { INVALID_SPAN_CONTEXT } from './invalid-span-constants';
2121
import { Span } from './span';
2222
import { SpanContext } from './span_context';
2323
import { SpanStatus } from './status';
24+
import { Link } from './link';
2425

2526
/**
2627
* The NonRecordingSpan is the default {@link Span} that is used when no Span
@@ -52,6 +53,14 @@ export class NonRecordingSpan implements Span {
5253
return this;
5354
}
5455

56+
addLink(_link: Link): this {
57+
return this;
58+
}
59+
60+
addLinks(_links: Link[]): this {
61+
return this;
62+
}
63+
5564
// By default does nothing
5665
setStatus(_status: SpanStatus): this {
5766
return this;

api/src/trace/span.ts

+21
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { TimeInput } from '../common/Time';
1919
import { SpanAttributes, SpanAttributeValue } from './attributes';
2020
import { SpanContext } from './span_context';
2121
import { SpanStatus } from './status';
22+
import { Link } from './link';
2223

2324
/**
2425
* An interface that represents a span. A span represents a single operation
@@ -76,6 +77,26 @@ export interface Span {
7677
startTime?: TimeInput
7778
): this;
7879

80+
/**
81+
* Adds a single link to the span.
82+
*
83+
* Links added after the creation will not affect the sampling decision.
84+
* It is preferred span links be added at span creation.
85+
*
86+
* @param link the link to add.
87+
*/
88+
addLink(link: Link): this;
89+
90+
/**
91+
* Adds multiple links to the span.
92+
*
93+
* Links added after the creation will not affect the sampling decision.
94+
* It is preferred span links be added at span creation.
95+
*
96+
* @param links the links to add.
97+
*/
98+
addLinks(links: Link[]): this;
99+
79100
/**
80101
* Sets a status to the span. If used, this will override the default Span
81102
* status. Default is {@link SpanStatusCode.UNSET}. SetStatus overrides the value

api/test/common/noop-implementations/noop-span.test.ts

+8
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ describe('NonRecordingSpan', () => {
3636
my_number_attribute: 123,
3737
});
3838

39+
const linkContext = {
40+
traceId: 'e4cda95b652f4a1592b449d5929fda1b',
41+
spanId: '7e0c63257de34c92',
42+
traceFlags: TraceFlags.SAMPLED,
43+
};
44+
span.addLink({ context: linkContext });
45+
span.addLinks([{ context: linkContext }]);
46+
3947
span.addEvent('sent');
4048
span.addEvent('sent', { id: '42', key: 'value' });
4149

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

+10
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,16 @@ export class Span implements APISpan, ReadableSpan {
210210
return this;
211211
}
212212

213+
addLink(link: Link): this {
214+
this.links.push(link);
215+
return this;
216+
}
217+
218+
addLinks(links: Link[]): this {
219+
this.links.push(...links);
220+
return this;
221+
}
222+
213223
setStatus(status: SpanStatus): this {
214224
if (this._isSpanEnded()) return this;
215225
this.status = status;

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

+52-24
Original file line numberDiff line numberDiff line change
@@ -771,30 +771,6 @@ describe('Span', () => {
771771
});
772772
});
773773

774-
it('should set a link', () => {
775-
const spanContext: SpanContext = {
776-
traceId: 'a3cda95b652f4a1592b449d5929fda1b',
777-
spanId: '5e0c63257de34c92',
778-
traceFlags: TraceFlags.SAMPLED,
779-
};
780-
const linkContext: SpanContext = {
781-
traceId: 'b3cda95b652f4a1592b449d5929fda1b',
782-
spanId: '6e0c63257de34c92',
783-
traceFlags: TraceFlags.SAMPLED,
784-
};
785-
const attributes = { attr1: 'value', attr2: 123, attr3: true };
786-
const span = new Span(
787-
tracer,
788-
ROOT_CONTEXT,
789-
name,
790-
spanContext,
791-
SpanKind.CLIENT,
792-
'12345',
793-
[{ context: linkContext }, { context: linkContext, attributes }]
794-
);
795-
span.end();
796-
});
797-
798774
it('should drop extra events', () => {
799775
const span = new Span(
800776
tracer,
@@ -959,6 +935,58 @@ describe('Span', () => {
959935
span.end();
960936
});
961937

938+
it('should be possible to add a link after span creation', () => {
939+
const span = new Span(
940+
tracer,
941+
ROOT_CONTEXT,
942+
'my-span',
943+
spanContext,
944+
SpanKind.CONSUMER
945+
);
946+
947+
span.addLink({ context: linkContext });
948+
949+
span.end();
950+
951+
assert.strictEqual(span.links.length, 1);
952+
assert.deepStrictEqual(span.links, [
953+
{
954+
context: linkContext,
955+
},
956+
]);
957+
});
958+
959+
it('should be possible to add multiple links after span creation', () => {
960+
const span = new Span(
961+
tracer,
962+
ROOT_CONTEXT,
963+
'my-span',
964+
spanContext,
965+
SpanKind.CONSUMER
966+
);
967+
968+
span.addLinks([
969+
{ context: linkContext },
970+
{
971+
context: linkContext,
972+
attributes: { attr1: 'value', attr2: 123, attr3: true },
973+
},
974+
]);
975+
976+
span.end();
977+
978+
assert.strictEqual(span.links.length, 2);
979+
assert.deepStrictEqual(span.links, [
980+
{
981+
context: linkContext,
982+
},
983+
{
984+
attributes: { attr1: 'value', attr2: 123, attr3: true },
985+
context: linkContext,
986+
},
987+
]);
988+
});
989+
962990
it('should return ReadableSpan with events', () => {
963991
const span = new Span(
964992
tracer,

0 commit comments

Comments
 (0)