From d859e92c0cbfd2dc340b86947957de0ad384abd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ketil=20=C3=98vreb=C3=B8?= Date: Mon, 13 May 2024 11:17:42 +0200 Subject: [PATCH] fix(hapi): fix instrumentation of ESM-imported hapi --- package-lock.json | 7 +- .../package.json | 1 + .../src/instrumentation.ts | 8 ++- .../test/fixtures/use-hapi.mjs | 64 +++++++++++++++++++ .../test/hapi.test.ts | 35 ++++++++++ 5 files changed, 110 insertions(+), 5 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 a948005334..66facbae91 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37276,11 +37276,10 @@ "version": "0.1.0", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api": "^1.0.0", "@opentelemetry/sdk-trace-base": "^1.0.0" }, "devDependencies": { - "@opentelemetry/api": "^1.3.0", + "@opentelemetry/api": "^1.0.0", "@types/mocha": "8.2.3", "@types/node": "18.6.5", "expect": "29.2.0", @@ -38524,6 +38523,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", @@ -46856,7 +46856,7 @@ "@opentelemetry/baggage-span-processor": { "version": "file:packages/baggage-span-processor", "requires": { - "@opentelemetry/api": "^1.3.0", + "@opentelemetry/api": "^1.0.0", "@opentelemetry/sdk-trace-base": "^1.0.0", "@types/mocha": "8.2.3", "@types/node": "18.6.5", @@ -47548,6 +47548,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 0f3bda5fb2..59ff9547f4 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' + ); + }, + }); + }); + }); });