From ed10a405f6571f38079f7ab615012eb44bfee156 Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Mon, 3 Feb 2025 20:21:13 -0800 Subject: [PATCH 1/6] feat!: better ESM instrumentation; bump min-supported node to ^18.19.0 || >=20.6.0 This uses the IITM feature to only hook ES modules that will be patched by instrumentations. This means instr-openai can possibly work with ESM usage of openai -- before this it would crash from IITM hook changes. This drops Node.js 14 and 16 support, in favour of the new base versions that support module.register(). This is the same base version for coming upstream OTel JS SDK 2.0. This allows us to simplify the ESM story: both for docs and implementation. Using --experimental-loader to somewhat support ESM for older node.js versions is no longer supported. The main recommendation is to use node --import @elastic/opentelemetry-node ... I.e. to use --import rather than --require. Only with --import will EDOT Node.js register the loader hook for ESM instrumentation. Using --require is still fine for CommonJS-only instr. --- .../hook.mjs => examples/openai/chat.mjs | 21 +++- examples/openai/package.json | 3 +- packages/opentelemetry-node/CHANGELOG.md | 27 +++++ packages/opentelemetry-node/README.md | 2 +- .../opentelemetry-node/docs/get-started.md | 6 +- packages/opentelemetry-node/docs/metrics.md | 4 +- .../docs/supported-technologies.md | 4 +- packages/opentelemetry-node/import.mjs | 58 +++------ packages/opentelemetry-node/package-lock.json | 17 +-- packages/opentelemetry-node/package.json | 8 +- packages/opentelemetry-node/require.js | 50 ++------ .../opentelemetry-node/test/esm-usage.test.js | 112 ++---------------- .../test/fixtures/use-fetch.mjs | 2 +- .../test/fixtures/use-ioredis.mjs | 2 +- .../test/fixtures/use-redis.mjs | 2 +- .../test/instr-ioredis.test.js | 7 +- .../test/instr-redis-4.test.js | 4 +- .../test/instr-undici.test.js | 3 + 18 files changed, 108 insertions(+), 224 deletions(-) rename packages/opentelemetry-node/hook.mjs => examples/openai/chat.mjs (68%) diff --git a/packages/opentelemetry-node/hook.mjs b/examples/openai/chat.mjs similarity index 68% rename from packages/opentelemetry-node/hook.mjs rename to examples/openai/chat.mjs index d16b2de8..f2bf6ac6 100644 --- a/packages/opentelemetry-node/hook.mjs +++ b/examples/openai/chat.mjs @@ -17,9 +17,18 @@ * under the License. */ -export { - load, - resolve, - getFormat, - getSource, -} from '@opentelemetry/instrumentation/hook.mjs'; +import {OpenAI} from 'openai'; + +let chatModel = process.env.CHAT_MODEL ?? 'gpt-4o-mini'; + +const client = new OpenAI(); +const completion = await client.chat.completions.create({ + model: chatModel, + messages: [ + { + role: 'user', + content: 'Answer in up to 3 words: Which ocean contains Bouvet Island?', + }, + ], +}); +console.log(completion.choices[0].message.content); diff --git a/examples/openai/package.json b/examples/openai/package.json index 6b438820..cfdc09d0 100644 --- a/examples/openai/package.json +++ b/examples/openai/package.json @@ -8,7 +8,8 @@ }, "scripts": { "chat": "node --env-file .env --require @elastic/opentelemetry-node chat.js", - "embeddings": "node --env-file .env --require @elastic/opentelemetry-node embeddings.js" + "embeddings": "node --env-file .env --require @elastic/opentelemetry-node embeddings.js", + "chat:esm": "node --env-file .env --import @elastic/opentelemetry-node chat.mjs" }, "dependencies": { "@elastic/opentelemetry-node": "*", diff --git a/packages/opentelemetry-node/CHANGELOG.md b/packages/opentelemetry-node/CHANGELOG.md index 6f704595..4a07ba47 100644 --- a/packages/opentelemetry-node/CHANGELOG.md +++ b/packages/opentelemetry-node/CHANGELOG.md @@ -2,12 +2,39 @@ ## Unreleased +- BREAKING CHANGE: Bump min-supported node to `^18.19.0 || >=20.6.0`. + This raises the minimum-supported Node.js to the same as coming releases of OpenTelemetry JS. + This base version range ensures that `module.register()` is available for improved ES module + (ESM) auto-instrumentation. + This drops support for Node.js 14 and 16. + +- feat: Improve ES module (ESM) instrumentation. + + As part of this change, using `--require @elastic/opentelemetry-node` will + *no longer* setup a module hook for instrumenting ES modules; only using + `--import @elastic/opentelemetry-node` will do so. **The recommendation now + is to use `--import @elastic/opentelemetry-node` to start EDOT Node.js.** + Using `--require ...` is still fine when you know your application is only + using CommonJS modules. + + Implementation details: The underlying module hook mechanism for ESM has been + changed to only hook modules that will potentially be patched by configured + instrumentations. This allows some instrumentations to work that could not + before due to some ESM files not being hookable (at least via the imperfect + mechanism for hooking ES modules). One such example is + `@elastic/instrumentation-openai`. See + for internal + details. + - feat: Add `@opentelemetry/instrumentation-mysql` to the default set of instrumentations. See + - feat: Add `@opentelemetry/instrumentation-mysql2` to the default set of instrumentations. See + - feat: Add `@opentelemetry/instrumentation-cassandra-driver` to the default set of instrumentations. See + - test: Test that the native instrumentation in `@elastic/elasticsearch@8.15.0` and later works. diff --git a/packages/opentelemetry-node/README.md b/packages/opentelemetry-node/README.md index fb49e710..8120a85c 100644 --- a/packages/opentelemetry-node/README.md +++ b/packages/opentelemetry-node/README.md @@ -31,7 +31,7 @@ npm install --save @elastic/opentelemetry-node ## Run ```sh -node -r @elastic/opentelemetry-node my-service.js +node --import @elastic/opentelemetry-node my-service.js ``` ## Read the docs diff --git a/packages/opentelemetry-node/docs/get-started.md b/packages/opentelemetry-node/docs/get-started.md index 99450dc3..9deba7f0 100644 --- a/packages/opentelemetry-node/docs/get-started.md +++ b/packages/opentelemetry-node/docs/get-started.md @@ -92,11 +92,11 @@ for example, before `express` or `http` are loaded. The recommended way to get the -distro started is by using the `-r, --require` Node.js -[CLI option](https://nodejs.org/api/cli.html#-r---require-module): +distro started is by using the `--import` Node.js +[CLI option](https://nodejs.org/api/cli.html#--importmodule): ```sh -node --require @elastic/opentelemetry-node my-service.js +node --import @elastic/opentelemetry-node my-service.js ``` EDOT Node.js will automatically instrument popular modules (listed in [Supported technologies](./supported-technologies.md)) diff --git a/packages/opentelemetry-node/docs/metrics.md b/packages/opentelemetry-node/docs/metrics.md index 245f71a7..09cc8bfa 100644 --- a/packages/opentelemetry-node/docs/metrics.md +++ b/packages/opentelemetry-node/docs/metrics.md @@ -21,7 +21,7 @@ variable `ELASTIC_OTEL_METRICS_DISABLED` to the string `true`. export OTEL_EXPORTER_OTLP_ENDPOINT="${ELASTIC_APM_SERVER_URL}" export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer ${ELASTIC_APM_SECRET_TOKEN}" export ELASTIC_OTEL_METRICS_DISABLED=true -node -r @elastic/opentelemetry-node/start.js my-app.js +node --import @elastic/opentelemetry-node/start.js my-app.js ``` ## Advanced configuration @@ -57,4 +57,4 @@ issues when doing an overview of the instrumented service. These are: If your service is instrumented by EDOT Node.js, or by custom instrumentation that includes the packages mentioned above, Kibana will -display them as part of the [service metrics](https://www.elastic.co/guide/en/observability/current/apm-metrics.html) in its UI. \ No newline at end of file +display them as part of the [service metrics](https://www.elastic.co/guide/en/observability/current/apm-metrics.html) in its UI. diff --git a/packages/opentelemetry-node/docs/supported-technologies.md b/packages/opentelemetry-node/docs/supported-technologies.md index 129b6403..a894af69 100644 --- a/packages/opentelemetry-node/docs/supported-technologies.md +++ b/packages/opentelemetry-node/docs/supported-technologies.md @@ -83,7 +83,7 @@ node --import @elastic/opentelemetry-node my-app.js ## ECMAScript Modules (ESM) -This Distro includes **limited and experimental** support for instrumenting [ECMAScript module imports](https://nodejs.org/api/esm.html#modules-ecmascript-modules), i.e. modules that are loaded via `import ...` statements and `import('...')` (dynamic import). +This Distro includes **limited and experimental** support for instrumenting [ECMAScript module (ESM) imports](https://nodejs.org/api/esm.html#modules-ecmascript-modules), i.e. modules that are loaded via `import ...` statements and `import('...')` (dynamic import). To enable ESM instrumentation, use `node --import @elastic/opentelemetry-node ...` to start the SDK. (Using `node --require @elastic/opentelemetry-node ...` will not enable ESM instrumentation. It is intended to signal that only CommonJS module usage should be instrumented.) ## TypeScript versions From f5e8f6cfc4c76ef382570b053df650c433e61343 Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Tue, 4 Feb 2025 08:32:37 -0800 Subject: [PATCH 6/6] correct the version range here --- packages/opentelemetry-node/docs/supported-technologies.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/opentelemetry-node/docs/supported-technologies.md b/packages/opentelemetry-node/docs/supported-technologies.md index 2a1d9b4b..d3984f5e 100644 --- a/packages/opentelemetry-node/docs/supported-technologies.md +++ b/packages/opentelemetry-node/docs/supported-technologies.md @@ -92,5 +92,5 @@ See the [ECMAScript module support](./esm.md) document for details. Limitations: -* ESM instrumentation is only support for Node.js versions `>=20.6.0 || >=18.19.0`. These are the versions that include `module.register()` support. Using the older `node --experimental-loader=...` option is not supported. +* ESM instrumentation is only support for Node.js versions `^18.19.0 || >=20.6.0`. These are the versions that include `module.register()` support. Using the older `node --experimental-loader=...` option is not supported. * Currently only a subset of instrumentations support ESM: `express`, `ioredis`, `koa`, `pg`, `pino`. See [this OpenTelemetry JS tracking issue](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1942) for progress.