Skip to content

Commit d915a45

Browse files
committed
feat(instrumentation): add support for '_latest_experimental' semantic conventions opt-in value
1 parent 681c136 commit d915a45

File tree

3 files changed

+163
-5
lines changed

3 files changed

+163
-5
lines changed

experimental/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2
2222
* feat(opentelemetry-sdk-node): set instrumentation and propagators for experimental start [#6148](https://github.com/open-telemetry/opentelemetry-js/pull/6148) @maryliag
2323
* refactor(configuration): set console exporter as empty object [#6164](https://github.com/open-telemetry/opentelemetry-js/pull/6164) @maryliag
2424
* feat(instrumentation-http, instrumentation-fetch, instrumentation-xml-http-request): support "QUERY" as a known HTTP method
25+
* feat(instrumentation): add support for "_latest_experimental" semantic conventions opt-in value [6224](https://github.com/open-telemetry/opentelemetry-js/pull/6224) @pichlermarc
2526

2627
### :bug: Bug Fixes
2728

experimental/packages/opentelemetry-instrumentation/src/semconvStability.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ export enum SemconvStability {
2121
OLD = 0x2,
2222
/** Emit both stable and old semantic conventions. */
2323
DUPLICATE = 0x1 | 0x2,
24+
/**
25+
* Emit both stable and latest in-development semantic conventions.
26+
* @experimental this flag is not yet supported by any semconv specification, and thus may change or be removed in the future.
27+
*/
28+
LATEST_EXPERIMENTAL = 0x4 | 0x1,
2429
}
2530

2631
// Common namespaces mentioned in semantic-conventions docs, but allow
@@ -90,12 +95,21 @@ export function semconvStabilityFromStr(
9095
.map(v => v.trim())
9196
.filter(s => s !== '');
9297
for (const entry of entries ?? []) {
93-
if (entry.toLowerCase() === namespace + '/dup') {
94-
// DUPLICATE takes highest precedence.
95-
semconvStability = SemconvStability.DUPLICATE;
98+
const normalizedEntry = entry.toLowerCase();
99+
if (normalizedEntry === namespace + '/latest_experimental') {
100+
// LATEST_EXPERIMENTAL takes highest precedence, always set it.
101+
semconvStability = SemconvStability.LATEST_EXPERIMENTAL;
102+
// Highest precedence, no need to read the others.
96103
break;
97-
} else if (entry.toLowerCase() === namespace) {
98-
semconvStability = SemconvStability.STABLE;
104+
} else if (normalizedEntry === namespace + '/dup') {
105+
// DUPLICATE takes precedence over STABLE and OLD.
106+
// Don't break here in case LATEST_EXPERIMENTAL appears later.
107+
semconvStability = SemconvStability.DUPLICATE;
108+
} else if (normalizedEntry === namespace) {
109+
// Only set STABLE if we haven't already found DUPLICATE.
110+
if (semconvStability === SemconvStability.OLD) {
111+
semconvStability = SemconvStability.STABLE;
112+
}
99113
}
100114
}
101115

experimental/packages/opentelemetry-instrumentation/test/common/semconvStability.test.ts

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,38 @@ import { inspect } from 'util';
1818
import * as assert from 'assert';
1919
import { SemconvStability, semconvStabilityFromStr } from '../../src';
2020

21+
describe('SemconvStability', function () {
22+
it('should have correct bitwise flag values', function () {
23+
// STABLE is 0x1
24+
assert.strictEqual(SemconvStability.STABLE, 0x1);
25+
26+
// OLD is 0x2
27+
assert.strictEqual(SemconvStability.OLD, 0x2);
28+
29+
// DUPLICATE is 0x3 (STABLE | OLD)
30+
assert.strictEqual(SemconvStability.DUPLICATE, 0x3);
31+
assert.strictEqual(
32+
SemconvStability.DUPLICATE & SemconvStability.STABLE,
33+
SemconvStability.STABLE
34+
);
35+
assert.strictEqual(
36+
SemconvStability.DUPLICATE & SemconvStability.OLD,
37+
SemconvStability.OLD
38+
);
39+
40+
// LATEST_EXPERIMENTAL is 0x5 (0x4 | STABLE)
41+
assert.strictEqual(SemconvStability.LATEST_EXPERIMENTAL, 0x5);
42+
assert.strictEqual(
43+
SemconvStability.LATEST_EXPERIMENTAL & SemconvStability.STABLE,
44+
SemconvStability.STABLE
45+
);
46+
assert.strictEqual(
47+
SemconvStability.LATEST_EXPERIMENTAL & SemconvStability.OLD,
48+
0
49+
);
50+
});
51+
});
52+
2153
describe('semconvStabilityFromStr', function () {
2254
const table = [
2355
{ namespace: 'http', str: undefined, expected: SemconvStability.OLD },
@@ -73,6 +105,117 @@ describe('semconvStabilityFromStr', function () {
73105
str: 'just,bogus,values',
74106
expected: SemconvStability.OLD,
75107
},
108+
109+
// LATEST_EXPERIMENTAL tests for http namespace
110+
{
111+
namespace: 'http',
112+
str: 'http/latest_experimental',
113+
expected: SemconvStability.LATEST_EXPERIMENTAL,
114+
},
115+
{
116+
namespace: 'http',
117+
str: 'HTTP/LATEST_EXPERIMENTAL',
118+
expected: SemconvStability.LATEST_EXPERIMENTAL,
119+
},
120+
{
121+
namespace: 'http',
122+
str: ', http/latest_experimental,bar',
123+
expected: SemconvStability.LATEST_EXPERIMENTAL,
124+
},
125+
{
126+
namespace: 'http',
127+
str: ', http/latest_experimental\t ,blah',
128+
expected: SemconvStability.LATEST_EXPERIMENTAL,
129+
},
130+
// LATEST_EXPERIMENTAL takes precedence over DUPLICATE
131+
{
132+
namespace: 'http',
133+
str: 'http/dup,http/latest_experimental',
134+
expected: SemconvStability.LATEST_EXPERIMENTAL,
135+
},
136+
{
137+
namespace: 'http',
138+
str: 'http/latest_experimental,http/dup',
139+
expected: SemconvStability.LATEST_EXPERIMENTAL,
140+
},
141+
// LATEST_EXPERIMENTAL takes precedence over STABLE
142+
{
143+
namespace: 'http',
144+
str: 'http,http/latest_experimental',
145+
expected: SemconvStability.LATEST_EXPERIMENTAL,
146+
},
147+
{
148+
namespace: 'http',
149+
str: 'http/latest_experimental,http',
150+
expected: SemconvStability.LATEST_EXPERIMENTAL,
151+
},
152+
153+
// LATEST_EXPERIMENTAL tests for database namespace
154+
{
155+
namespace: 'database',
156+
str: 'database/latest_experimental',
157+
expected: SemconvStability.LATEST_EXPERIMENTAL,
158+
},
159+
{
160+
namespace: 'database',
161+
str: 'DATABASE/LATEST_EXPERIMENTAL',
162+
expected: SemconvStability.LATEST_EXPERIMENTAL,
163+
},
164+
{
165+
namespace: 'database',
166+
str: ', database/latest_experimental,bar',
167+
expected: SemconvStability.LATEST_EXPERIMENTAL,
168+
},
169+
{
170+
namespace: 'database',
171+
str: ', database/latest_experimental\t ,blah',
172+
expected: SemconvStability.LATEST_EXPERIMENTAL,
173+
},
174+
// LATEST_EXPERIMENTAL takes precedence over DUPLICATE
175+
{
176+
namespace: 'database',
177+
str: 'database/dup,database/latest_experimental',
178+
expected: SemconvStability.LATEST_EXPERIMENTAL,
179+
},
180+
{
181+
namespace: 'database',
182+
str: 'database/latest_experimental,database/dup',
183+
expected: SemconvStability.LATEST_EXPERIMENTAL,
184+
},
185+
// LATEST_EXPERIMENTAL takes precedence over STABLE
186+
{
187+
namespace: 'database',
188+
str: 'database,database/latest_experimental',
189+
expected: SemconvStability.LATEST_EXPERIMENTAL,
190+
},
191+
{
192+
namespace: 'database',
193+
str: 'database/latest_experimental,database',
194+
expected: SemconvStability.LATEST_EXPERIMENTAL,
195+
},
196+
197+
// Namespace isolation: http/latest_experimental doesn't affect database namespace
198+
{
199+
namespace: 'database',
200+
str: 'http/latest_experimental',
201+
expected: SemconvStability.OLD,
202+
},
203+
{
204+
namespace: 'http',
205+
str: 'database/latest_experimental',
206+
expected: SemconvStability.OLD,
207+
},
208+
// Mixed namespaces: only the matching namespace applies
209+
{
210+
namespace: 'http',
211+
str: 'database,http/latest_experimental',
212+
expected: SemconvStability.LATEST_EXPERIMENTAL,
213+
},
214+
{
215+
namespace: 'database',
216+
str: 'http/latest_experimental,database/dup',
217+
expected: SemconvStability.DUPLICATE,
218+
},
76219
];
77220
for (const { namespace, str, expected } of table) {
78221
it(`str: ${inspect(str)}`, function () {

0 commit comments

Comments
 (0)