From 265000ae755e13aee82ff5d97a52b307831840ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ketil=20=C3=98vreb=C3=B8?= Date: Thu, 16 May 2024 02:26:29 +0200 Subject: [PATCH] fix(instr-hapi): fix instrumentation of ESM-imported hapi (#2184) --- package-lock.json | 2 + .../package.json | 1 + .../src/instrumentation.ts | 8 ++- .../test/fixtures/use-hapi.mjs | 64 +++++++++++++++++++ .../test/hapi.test.ts | 35 ++++++++++ 5 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 plugins/node/opentelemetry-instrumentation-hapi/test/fixtures/use-hapi.mjs diff --git a/package-lock.json b/package-lock.json index a8c210eec2..0763fb489f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37888,6 +37888,7 @@ "@hapi/hapi": "21.3.3", "@opentelemetry/api": "^1.3.0", "@opentelemetry/context-async-hooks": "^1.8.0", + "@opentelemetry/contrib-test-utils": "^0.39.0", "@opentelemetry/sdk-trace-base": "^1.8.0", "@opentelemetry/sdk-trace-node": "^1.8.0", "@types/mocha": "7.0.2", @@ -46688,6 +46689,7 @@ "@hapi/hapi": "21.3.3", "@opentelemetry/api": "^1.3.0", "@opentelemetry/context-async-hooks": "^1.8.0", + "@opentelemetry/contrib-test-utils": "^0.39.0", "@opentelemetry/core": "^1.8.0", "@opentelemetry/instrumentation": "^0.51.0", "@opentelemetry/sdk-trace-base": "^1.8.0", diff --git a/plugins/node/opentelemetry-instrumentation-hapi/package.json b/plugins/node/opentelemetry-instrumentation-hapi/package.json index 94c82f6f92..f0f454b0dc 100644 --- a/plugins/node/opentelemetry-instrumentation-hapi/package.json +++ b/plugins/node/opentelemetry-instrumentation-hapi/package.json @@ -46,6 +46,7 @@ "@hapi/hapi": "21.3.3", "@opentelemetry/api": "^1.3.0", "@opentelemetry/context-async-hooks": "^1.8.0", + "@opentelemetry/contrib-test-utils": "^0.39.0", "@opentelemetry/sdk-trace-base": "^1.8.0", "@opentelemetry/sdk-trace-node": "^1.8.0", "@types/mocha": "7.0.2", diff --git a/plugins/node/opentelemetry-instrumentation-hapi/src/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-hapi/src/instrumentation.ts index ac930ffa68..0b18fc5dfd 100644 --- a/plugins/node/opentelemetry-instrumentation-hapi/src/instrumentation.ts +++ b/plugins/node/opentelemetry-instrumentation-hapi/src/instrumentation.ts @@ -57,7 +57,9 @@ export class HapiInstrumentation extends InstrumentationBase { return new InstrumentationNodeModuleDefinition( HapiComponentName, ['>=17 <22'], - (moduleExports: typeof Hapi) => { + (module: any) => { + const moduleExports: typeof Hapi = + module[Symbol.toStringTag] === 'Module' ? module.default : module; if (!isWrapped(moduleExports.server)) { this._wrap( moduleExports, @@ -75,7 +77,9 @@ export class HapiInstrumentation extends InstrumentationBase { } return moduleExports; }, - (moduleExports: typeof Hapi) => { + (module: any) => { + const moduleExports: typeof Hapi = + module[Symbol.toStringTag] === 'Module' ? module.default : module; this._massUnwrap([moduleExports], ['server', 'Server']); } ); diff --git a/plugins/node/opentelemetry-instrumentation-hapi/test/fixtures/use-hapi.mjs b/plugins/node/opentelemetry-instrumentation-hapi/test/fixtures/use-hapi.mjs new file mode 100644 index 0000000000..f79b48f8e3 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-hapi/test/fixtures/use-hapi.mjs @@ -0,0 +1,64 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Use hapi from an ES module: +// node --experimental-loader=@opentelemetry/instrumentation/hook.mjs use-hapi.mjs + +import { createTestNodeSdk } from '@opentelemetry/contrib-test-utils'; + +import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'; +import { HapiInstrumentation } from '../../build/src/index.js'; + +const sdk = createTestNodeSdk({ + serviceName: 'use-hapi', + instrumentations: [ + new HttpInstrumentation(), + new HapiInstrumentation() + ] +}) +sdk.start(); + +import Hapi from '@hapi/hapi'; +import http from 'http'; + +// Start a Hapi server. +const server = new Hapi.Server({ + port: 0, + host: 'localhost' +}); + +server.route({ + method: 'GET', + path: '/route/{param}', + handler: function() { + return { hello: 'world' }; + } +}); + +await server.start(); + +// Make a single request to it. +await new Promise(resolve => { + http.get(`http://${server.info.host}:${server.info.port}/route/test`, (res) => { + res.resume(); + res.on('end', () => { + resolve(); + }); + }) +}); + +await server.stop(); +await sdk.shutdown(); diff --git a/plugins/node/opentelemetry-instrumentation-hapi/test/hapi.test.ts b/plugins/node/opentelemetry-instrumentation-hapi/test/hapi.test.ts index 7ecd84384f..af87e04901 100644 --- a/plugins/node/opentelemetry-instrumentation-hapi/test/hapi.test.ts +++ b/plugins/node/opentelemetry-instrumentation-hapi/test/hapi.test.ts @@ -22,6 +22,10 @@ import { InMemorySpanExporter, SimpleSpanProcessor, } from '@opentelemetry/sdk-trace-base'; +import { + runTestFixture, + TestCollector, +} from '@opentelemetry/contrib-test-utils'; import { getPlugin } from './plugin'; const plugin = getPlugin(); @@ -537,4 +541,35 @@ describe('Hapi Instrumentation - Core Tests', () => { ); }); }); + + describe('ESM', () => { + it('should work with ESM modules', async () => { + await runTestFixture({ + cwd: __dirname, + argv: ['fixtures/use-hapi.mjs'], + env: { + NODE_OPTIONS: + '--experimental-loader=@opentelemetry/instrumentation/hook.mjs', + NODE_NO_WARNINGS: '1', + }, + checkResult: (err, stdout, stderr) => { + assert.ifError(err); + }, + checkCollector: (collector: TestCollector) => { + const spans = collector.sortedSpans; + assert.strictEqual(spans.length, 2); + assert.strictEqual(spans[0].name, 'GET /route/{param}'); + assert.strictEqual( + spans[0].instrumentationScope.name, + '@opentelemetry/instrumentation-http' + ); + assert.strictEqual(spans[1].name, 'route - /route/{param}'); + assert.strictEqual( + spans[1].instrumentationScope.name, + '@opentelemetry/instrumentation-hapi' + ); + }, + }); + }); + }); });