Skip to content

Commit 3deda61

Browse files
committed
chore: fixes
1 parent b3d029e commit 3deda61

5 files changed

Lines changed: 148 additions & 17 deletions

File tree

packages/collector/src/announceCycle/agentready.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -152,18 +152,18 @@ function enter(_ctx) {
152152
// TODO: Add an EventEmitter functionality for the current process
153153
// such as `instana.on('instana.collector.initialized')`.
154154
// eslint-disable-next-line no-unused-expressions
155-
// process?.send?.('instana.collector.initialized');
155+
if (process.env.INSTANA_IPC_ENABLED === 'true') {
156+
process?.send?.('instana.collector.initialized');
156157

157-
/*
158-
if (!isMainThread) {
159-
const { parentPort } = require('worker_threads');
158+
if (!isMainThread) {
159+
const { parentPort } = require('worker_threads');
160160

161-
if (parentPort) {
162-
// CASE: This is for the worker thread if available.
163-
parentPort.postMessage('instana.collector.initialized');
161+
if (parentPort) {
162+
// CASE: This is for the worker thread if available.
163+
parentPort.postMessage('instana.collector.initialized');
164+
}
164165
}
165166
}
166-
*/
167167
}
168168

169169
function leave() {

packages/collector/src/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,9 @@ function init(userConfig = {}) {
100100
}
101101

102102
if (collectorIndexCacheKey) {
103-
// process?.send?.('instana.collector.initialized');
103+
if (process.env.INSTANA_IPC_ENABLED === 'true') {
104+
process?.send?.('instana.collector.initialized');
105+
}
104106

105107
return require.cache[collectorIndexCacheKey].exports;
106108
} else {

packages/collector/test/test_util/ProcessControls.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,8 @@ class ProcessControls {
151151
INSTANA_FIRE_MONITORING_EVENT_DURATION_IN_MS: 500,
152152
INSTANA_RETRY_AGENT_CONNECTION_IN_MS: 500,
153153
APP_USES_HTTPS: this.appUsesHttps ? 'true' : 'false',
154-
INSTANA_DISABLE_USE_OPENTELEMETRY: !this.enableOtelIntegration
154+
INSTANA_DISABLE_USE_OPENTELEMETRY: !this.enableOtelIntegration,
155+
INSTANA_IPC_ENABLED: 'true'
155156
},
156157
opts.env
157158
);

packages/core/src/util/requireHook.js

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,20 @@ function patchedModuleLoad(moduleName) {
6666
// However, when an ESM library imports a CommonJS package, our requireHook is triggered.
6767
// For native ESM libraries the iitmHook is triggered.
6868
if (path.isAbsolute(moduleName) && ['.node', '.json', '.ts'].indexOf(path.extname(moduleName)) === -1) {
69+
// Normalize Windows paths (backslashes) to forward slashes for regex matching
70+
const normalizedModuleName = moduleName.replace(/\\/g, '/');
6971
// EDGE CASE for ESM: mysql2/promise.js
70-
if (moduleName.indexOf('node_modules/mysql2/promise.js') !== -1) {
72+
if (normalizedModuleName.indexOf('node_modules/mysql2/promise.js') !== -1) {
7173
moduleName = 'mysql2/promise';
7274
} else {
7375
// e.g. path is node_modules/@elastic/elasicsearch/index.js
74-
let match = moduleName.match(/node_modules\/(@.*?(?=\/)\/.*?(?=\/))/);
76+
let match = normalizedModuleName.match(/node_modules\/(@.*?(?=\/)\/.*?(?=\/))/);
7577

7678
if (match && match.length > 1) {
7779
moduleName = match[1];
7880
} else {
7981
// e.g. path is node_modules/mysql/lib/index.js
80-
match = moduleName.match(/node_modules\/(.*?(?=\/))/);
82+
match = normalizedModuleName.match(/node_modules\/(.*?(?=\/))/);
8183

8284
if (match && match.length > 1) {
8385
moduleName = match[1];
@@ -145,8 +147,11 @@ function patchedModuleLoad(moduleName) {
145147
}
146148

147149
if (!cacheEntry.byFileNamePatternTransformersApplied) {
150+
// Normalize Windows paths (backslashes) to forward slashes for regex pattern matching
151+
// This ensures patterns with forward slashes (like /\/mongodb-core\/lib\/connection\/pool\.js/) work on Windows
152+
const normalizedFilename = filename.replace(/\\/g, '/');
148153
for (let i = 0; i < byFileNamePatternTransformers.length; i++) {
149-
if (byFileNamePatternTransformers[i].pattern.test(filename)) {
154+
if (byFileNamePatternTransformers[i].pattern.test(normalizedFilename)) {
150155
cacheEntry.moduleExports =
151156
byFileNamePatternTransformers[i].fn(cacheEntry.moduleExports, filename) || cacheEntry.moduleExports;
152157
}
@@ -191,15 +196,27 @@ exports.buildFileNamePattern = function buildFileNamePattern(arr) {
191196
return new RegExp(`${arr.reduce(buildFileNamePatternReducer, '')}$`);
192197
};
193198

199+
/**
200+
* Escapes special regex characters in a string
201+
* @param {string} str
202+
* @returns {string}
203+
*/
204+
function escapeRegex(str) {
205+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
206+
}
207+
194208
/**
195209
* @param {string} agg
196210
* @param {string} pathSegment
197211
* @returns {string}
198212
*/
199213
function buildFileNamePatternReducer(agg, pathSegment) {
200214
if (agg.length > 0) {
201-
agg += `\\${path.sep}`;
215+
// Always use forward slashes in patterns since we normalize filenames to forward slashes
216+
// This ensures patterns work consistently on both Windows and Unix systems
217+
agg += '\\/';
202218
}
203-
agg += pathSegment;
219+
// Escape special regex characters in path segments (e.g., '.' in 'express.js' should be '\.')
220+
agg += escapeRegex(pathSegment);
204221
return agg;
205222
}

packages/core/test/util/require_hook/requireHook_test.js

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,123 @@ describe('util/requireHook', () => {
183183
const pattern = requireHook.buildFileNamePattern(['node_modules', 'express', 'lib', 'express.js']);
184184
requireHook.onFileLoad(pattern, hook);
185185

186-
expect(require('express')).to.be.a('function');
186+
// Require the specific file that matches the pattern, not just 'express'
187+
// which loads index.js. This ensures the pattern is tested against the actual file.
188+
expect(require('express/lib/express')).to.be.a('function');
187189

188190
expect(hook.callCount).to.equal(1);
189191
expect(hook.getCall(0).args[0]).to.be.a('function');
190192
expect(hook.getCall(0).args[0].name).to.equal('createApplication');
191193
});
192194
});
195+
196+
it('must handle Windows paths with backslashes in onFileLoad patterns', () => {
197+
const testModule = { test: 'module' };
198+
const windowsPath =
199+
'C:\\Users\\aryamohanan\\Desktop\\code\\mongo-app\\node_modules\\mongodb-core\\lib\\connection\\pool.js';
200+
201+
// Create a function that will be captured as origLoad
202+
const originalLoad = function () {
203+
return testModule;
204+
};
205+
206+
// Create a mock Module that will be used when requireHook loads
207+
const mockModule = {
208+
_load: originalLoad,
209+
_resolveFilename: function () {
210+
return windowsPath;
211+
}
212+
};
213+
214+
// Use proxyquire to inject the mocked Module before requireHook loads
215+
const requireHookWithMock = proxyquire('../../../src/util/requireHook', {
216+
module: mockModule
217+
});
218+
219+
requireHookWithMock.init({ logger: testUtils.createFakeLogger() });
220+
// Use a pattern similar to mongodb.js that expects forward slashes
221+
requireHookWithMock.onFileLoad(/\/mongodb-core\/lib\/connection\/pool\.js/, hook);
222+
223+
// After init(), mockModule._load is now patchedModuleLoad
224+
// Call it with a Windows absolute path - this should trigger the pattern match
225+
const result = mockModule._load(
226+
'C:\\Users\\aryamohanan\\Desktop\\code\\mongo-app\\node_modules\\mongodb-core\\lib\\connection\\pool.js'
227+
);
228+
229+
// Verify the hook was called despite Windows path separators
230+
expect(hook.callCount).to.equal(1);
231+
expect(hook.getCall(0).args[0]).to.deep.equal(testModule);
232+
expect(hook.getCall(0).args[1]).to.equal(windowsPath);
233+
expect(result).to.deep.equal(testModule);
234+
235+
requireHookWithMock.teardownForTestPurposes();
236+
});
237+
238+
it('must extract module name correctly from Windows paths in onModuleLoad', () => {
239+
const path = require('path');
240+
const testMssqlModule = { test: 'mssql-module' };
241+
// Use a Windows path that will be normalized and matched
242+
// On non-Windows systems, path.isAbsolute() may return false for Windows paths,
243+
// so we need to ensure the path is treated as absolute in the test
244+
const windowsPath = 'C:\\Users\\aryamohanan\\Desktop\\code\\mongo-app\\node_modules\\mssql\\lib\\index.js';
245+
const windowsModuleName = 'C:\\Users\\aryamohanan\\Desktop\\code\\mongo-app\\node_modules\\mssql\\lib\\index.js';
246+
247+
// Store the originalLoad function reference so we can ensure same object is returned
248+
let loadCallCount = 0;
249+
const originalLoad = function () {
250+
loadCallCount++;
251+
// Must return the same object reference each time to pass cache check
252+
return testMssqlModule;
253+
};
254+
255+
// Create a mock Module that will be used when requireHook loads
256+
const mockModule = {
257+
_load: originalLoad,
258+
_resolveFilename: function () {
259+
// _resolveFilename receives the same arguments as _load was called with
260+
return windowsPath;
261+
}
262+
};
263+
264+
// Mock path.isAbsolute to return true for Windows paths (even on non-Windows systems)
265+
const pathMock = {
266+
isAbsolute: function (p) {
267+
// Treat Windows absolute paths (C:\, D:\, etc.) as absolute
268+
if (/^[A-Za-z]:[\\/]/.test(p)) {
269+
return true;
270+
}
271+
return path.isAbsolute(p);
272+
},
273+
extname: path.extname,
274+
sep: path.sep
275+
};
276+
277+
// Use proxyquire to inject the mocked Module and path before requireHook loads
278+
const requireHookWithMock = proxyquire('../../../src/util/requireHook', {
279+
module: mockModule,
280+
path: pathMock
281+
});
282+
283+
requireHookWithMock.init({ logger: testUtils.createFakeLogger() });
284+
// Register hook for mssql module (similar to mssql.js)
285+
requireHookWithMock.onModuleLoad('mssql', hook);
286+
287+
// After init(), mockModule._load is replaced with patchedModuleLoad
288+
// When we call it, patchedModuleLoad will:
289+
// 1. Extract module name from Windows path: 'C:\...\node_modules\mssql\lib\index.js' -> 'mssql'
290+
// 2. Call origLoad (our mock) which returns testMssqlModule
291+
// 3. Call _resolveFilename which returns windowsPath
292+
// 4. Check byModuleNameTransformers['mssql'] and call the hook
293+
const result = mockModule._load(windowsModuleName);
294+
295+
// Verify origLoad was called
296+
expect(loadCallCount).to.equal(1);
297+
// Verify the hook was called (module name 'mssql' should be extracted from Windows path)
298+
expect(hook.callCount).to.equal(1);
299+
expect(hook.getCall(0).args[0]).to.deep.equal(testMssqlModule);
300+
expect(result).to.deep.equal(testMssqlModule);
301+
302+
requireHookWithMock.teardownForTestPurposes();
303+
});
193304
});
194305
});

0 commit comments

Comments
 (0)