Skip to content

Commit 8876167

Browse files
committed
test: added additional test
1 parent 0e7a12b commit 8876167

File tree

2 files changed

+116
-3
lines changed

2 files changed

+116
-3
lines changed

packages/core/src/tracing/opentelemetry-instrumentations/opentelemetryApi.js

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,24 @@
88
* Exports the singleton OpenTelemetry API instance from the root-level
99
* @opentelemetry installation in node_modules.
1010
*
11-
* This ensures that all instrumentations share the same API instance,
12-
* preventing conflicts that can occur when multiple versions (root vs nested)
11+
* Resolution Logic:
12+
* 1. Attempt to resolve @opentelemetry/api from the current working directory (root-level).
13+
* 2. If not found, fall back to a nested (child) installation of @opentelemetry/api.
14+
*
15+
* This ensures that all instrumentations share the same API instance when possible,
16+
* avoiding conflicts that can arise when multiple versions (root vs nested)
1317
* are loaded within the same process.
18+
*
19+
* Example structure:
20+
* ├── node_modules/@opentelemetry/api/ # root (preferred)
21+
* └── packages/service/node_modules/@opentelemetry/api/ # fallback
1422
*/
15-
module.exports = require(require.resolve('@opentelemetry/api', { paths: [process.cwd()] }));
23+
let api;
24+
25+
try {
26+
api = require(require.resolve('@opentelemetry/api', { paths: [process.cwd()] }));
27+
} catch {
28+
api = require('@opentelemetry/api');
29+
}
30+
31+
module.exports = api;
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* (c) Copyright IBM Corp. 2025
3+
*/
4+
5+
'use strict';
6+
7+
const path = require('path');
8+
const fs = require('fs');
9+
const Module = require('module');
10+
const { expect } = require('chai');
11+
12+
describe('opentelemetry/api module', () => {
13+
let tempDir;
14+
let originalCwd;
15+
let originalResolve;
16+
17+
before(() => {
18+
tempDir = fs.mkdtempSync(path.join(__dirname, 'tempDir-'));
19+
originalCwd = process.cwd();
20+
process.chdir(tempDir);
21+
22+
const makeModule = (filePath, content) => {
23+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
24+
fs.writeFileSync(filePath, content);
25+
};
26+
27+
/**
28+
* test structure:
29+
*
30+
* ├── node_modules/
31+
* │ └── @opentelemetry/
32+
* │ └── api/ # root API
33+
* │ └── index.js
34+
* └── packages/
35+
* └── service/
36+
* └── node_modules/
37+
* └── @opentelemetry/
38+
* └── api/ # fallback API
39+
* └── index.js
40+
*/
41+
makeModule(
42+
path.join(tempDir, 'node_modules/@opentelemetry/api/index.js'),
43+
"module.exports = { __source: 'root-api' };"
44+
);
45+
46+
makeModule(
47+
path.join(tempDir, 'packages/service/node_modules/@opentelemetry/api/index.js'),
48+
"module.exports = { __source: 'child-api' };"
49+
);
50+
51+
originalResolve = Module._resolveFilename;
52+
Module._resolveFilename = function (request, parent, isMain, options) {
53+
if (request === '@opentelemetry/api') {
54+
const rootApi = path.join(tempDir, 'node_modules/@opentelemetry/api/index.js');
55+
const childApi = path.join(tempDir, 'packages/service/node_modules/@opentelemetry/api/index.js');
56+
57+
if (options?.paths?.includes(process.cwd())) {
58+
if (fs.existsSync(path.join(process.cwd(), 'node_modules/@opentelemetry/api/index.js'))) {
59+
return path.join(process.cwd(), 'node_modules/@opentelemetry/api/index.js');
60+
}
61+
throw new Error('Cannot find local module');
62+
}
63+
64+
if (fs.existsSync(rootApi)) return rootApi;
65+
if (fs.existsSync(childApi)) return childApi;
66+
}
67+
68+
return originalResolve.call(this, request, parent, isMain, options);
69+
};
70+
});
71+
72+
after(() => {
73+
process.chdir(originalCwd);
74+
Module._resolveFilename = originalResolve;
75+
fs.rmSync(tempDir, { recursive: true, force: true });
76+
});
77+
78+
it('should load @opentelemetry/api from the root-level node_modules by default', () => {
79+
process.chdir(tempDir);
80+
81+
delete require.cache[require.resolve('../../../src/tracing/opentelemetry-instrumentations/opentelemetryApi')];
82+
const otelApi = require('../../../src/tracing/opentelemetry-instrumentations/opentelemetryApi');
83+
84+
expect(otelApi.__source).to.equal('root-api');
85+
});
86+
87+
it('should fall back to @opentelemetry/api in child node_modules if root-level is missing', () => {
88+
fs.rmSync(path.join(tempDir, 'node_modules/@opentelemetry'), { recursive: true, force: true });
89+
90+
const nestedPath = path.join(tempDir, 'packages/service');
91+
process.chdir(nestedPath);
92+
93+
delete require.cache[require.resolve('../../../src/tracing/opentelemetry-instrumentations/opentelemetryApi')];
94+
const otelApi = require('../../../src/tracing/opentelemetry-instrumentations/opentelemetryApi');
95+
expect(otelApi.__source).to.equal('child-api');
96+
});
97+
});

0 commit comments

Comments
 (0)