Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Describe support for ESM #4876

Merged
merged 17 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ This is the JavaScript version of [OpenTelemetry](https://opentelemetry.io/), a

## Quick Start

**Much of OpenTelemetry JS documentation is written assuming the compiled application is run as CommonJS.**
For more details on ECMAScript Modules vs CommonJS, refer to [esm-support](https://github.com/open-telemetry/opentelemetry-js/blob/main/doc/esm-support.md).

The following describes how to set up tracing for a basic web application.
For more detailed documentation, see the website at <https://opentelemetry.io/docs/instrumentation/js/>.

Expand Down Expand Up @@ -110,7 +113,7 @@ If you are a library author looking to build OpenTelemetry into your library, pl
## Supported Runtimes

| Platform Version | Supported |
|---------------------|-----------------------------------------------|
| ------------------- | --------------------------------------------- |
| Node.JS `v22` | :heavy_check_mark: |
| Node.JS `v20` | :heavy_check_mark: |
| Node.JS `v18` | :heavy_check_mark: |
Expand Down Expand Up @@ -143,13 +146,13 @@ There may also be API packages for experimental signals in the experimental dire
All stable packages are released with the same version, and all experimental packages are released with the same version.
The below table describes which versions of each set of packages are expected to work together.

| Stable Packages | Experimental Packages |
|-----------------------------------------------------------------|-----------------------|
| 1.21.x | 0.48.x |
| 1.20.x | 0.47.x |
| 1.19.x | 0.46.x |
| 1.18.x | 0.45.x |
| 1.17.x | 0.44.x |
| Stable Packages | Experimental Packages |
| --------------- | --------------------- |
| 1.21.x | 0.48.x |
| 1.20.x | 0.47.x |
| 1.19.x | 0.46.x |
| 1.18.x | 0.45.x |
| 1.17.x | 0.44.x |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The table cleanup is cool. This makes me realize this section is way out of date and a maintenance pain.

The "semconv" package is now a new category for the "OpenTelemetry is released as a set of distinct packages in 3 categories:" sentence at the start of this section.

Anyway... not for this PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh actually I didn't mean to reformat anything in this doc. It must have auto-formatted when I added the first section and saved.


<details>
<summary>Older version compatibility matrix</summary>
Expand Down
131 changes: 131 additions & 0 deletions doc/esm-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# ECMAScript Modules vs. CommonJS

Node.js uses a different module loader for ECMAScript Modules (ESM) vs. CommonJS (CJS).
To verify whether your application is ESM or CJS, refer to [Node.js docs for Determining Module System](https://nodejs.org/api/packages.html#determining-module-system).

An `.mjs` extension or `type:module` in the built app's `package.json` indicates the app is ESM.

**Much of OpenTelemetry JS documentation is written assuming the compiled application is run as CJS.**
ESM support is ongoing; a few adjustments are needed for configuration and startup commands.

For more explanation about CJS and ESM, see the [Node.js docs](https://nodejs.org/api/modules.html#enabling).

## TypeScript

Many TypeScript projects today are written using ESM syntax, regardless of how they are compiled.
In the `tsconfig.json`, there is an option to compile to ESM or CJS.
If the compiled code is ESM, those import statements will remain the same (e.g. `import { foo } from 'bar';`).
If the compiled code is CJS, those import statements will become `require()` statements (e.g. `const { foo } = require('bar');`)

## Initializing the SDK

Instrumentation setup and configuration must be run before your application code.
If the SDK is initialized in a separate file (recommended), ensure it is imported first in application startup, or use the `--require` or `--import` flag during startup to preload the module.

For CJS, the `NODE_OPTIONS` for the startup command should include `--require ./telemetry.js`.

For ESM, minimum Node.js version of `18.19.0` is required.
The `NODE_OPTIONS` for the startup command should include `--import ./telemetry.js`.

## Instrumentation Hook Required for ESM

If your application is written in JavaScript as ESM, or compiled to ESM from TypeScript, then a loader hook is required to properly patch instrumentation.
The custom hook for ESM instrumentation is `--experimental-loader=@opentelemetry/instrumentation/hook.mjs`.
This flag must be passed to the `node` binary, which is often done as a startup command and/or in the `NODE_OPTIONS` environment variable.

### Additional Notes on Experimental Loaders

Though the OpenTelemetry loader currently relies on `import-in-the-middle`, direct usage of `import-in-the-middle/hook.mjs` may cease to work in the future.
The only currently supported loader hook is `@opentelemetry/instrumentation/hook.mjs`.

**Note:** Eventually the recommendation for how to setup OpenTelemetry for usage with ESM will change to no longer require `--experimental-loader=@opentelemetry/instrumentation/hook.mjs`.
Instead the bootstrap code (in `./telemetry.js`) will use Node.js's newer `module.register(...)`.
Refer to this [issue](https://github.com/open-telemetry/opentelemetry-js/issues/4933) for details.

Because of ongoing issues with loaders running TypeScript code as ESM in development environments, results may vary.

To use `ts-node` to run the uncompiled TypeScript code, the module must be CJS.
To use `tsx` to run the uncompiled TypeScript code as ESM, the `--import` flag must be used.

## Using the Zero Code Option with `auto-instrumentations-node`

The `auto-instrumentations-node` package contains a `register` entry-point that can be used with `--require` or `--import` to setup and start the SDK easily, without application code changes.
For ESM, the package also requires the usage of the loader hook.

Startup command for CJS:

```sh
node --require @opentelemetry/auto-instrumentations-node/register app.js
```

Startup command for ESM:

```sh
node --experimental-loader=@opentelemetry/instrumentation/hook.mjs --import @opentelemetry/auto-instrumentations-node/register app.js
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Side note: It is also fine to use --require here, even for ESM support.
I don't think we need to mention that here, however.

```

## Examples

### Example Written in JavaScript as CJS

```javascript
/*telemetry.cjs*/
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { ConsoleSpanExporter } = require('@opentelemetry/sdk-trace-node');
const {
getNodeAutoInstrumentations,
} = require('@opentelemetry/auto-instrumentations-node');

const sdk = new NodeSDK({
traceExporter: new ConsoleSpanExporter(),
instrumentations: [getNodeAutoInstrumentations()],
});

sdk.start();
```

Startup command:

```sh
node --require ./telemetry.cjs app.js
```

### Example Written in JavaScript as ESM or TypeScript

```typescript
/*telemetry.ts | telemetry.mjs*/
import { NodeSDK } from '@opentelemetry/sdk-node';
import { ConsoleSpanExporter } from '@opentelemetry/sdk-trace-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';

const sdk = new NodeSDK({
traceExporter: new ConsoleSpanExporter(),
instrumentations: [getNodeAutoInstrumentations()],
});

sdk.start();
```

Startup command for compiled CJS:

```sh
node --require ./telemetry.js app.js
```

Startup command for compiled ESM:

```sh
node --experimental-loader=@opentelemetry/instrumentation/hook.mjs --import ./telemetry.js app.js
```

### ESM Options for Different Versions of Node.js

The entire startup command should include the following `NODE_OPTIONS`:

| Node.js Version | NODE_OPTIONS |
| ----------------- | ----------------------------------------------------------------------------------------- |
| 16.x | `--require ./telemetry.cjs --experimental-loader=@opentelemetry/instrumentation/hook.mjs` |
| >=18.1.0 <18.19.0 | `--require ./telemetry.cjs --experimental-loader=@opentelemetry/instrumentation/hook.mjs` |
| ^18.19.0 | `--import ./telemetry.mjs --experimental-loader=@opentelemetry/instrumentation/hook.mjs` |
| 20.x | `--import ./telemetry.mjs --experimental-loader=@opentelemetry/instrumentation/hook.mjs` |
| 22.x | `--import ./telemetry.mjs --experimental-loader=@opentelemetry/instrumentation/hook.mjs` |
18 changes: 13 additions & 5 deletions experimental/packages/opentelemetry-instrumentation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

## Installation

**Note: Much of OpenTelemetry JS documentation is written assuming the compiled application is run as CommonJS.**
For more details on ECMAScript Modules vs CommonJS, refer to [esm-support](https://github.com/open-telemetry/opentelemetry-js/blob/main/doc/esm-support.md).

```bash
npm install --save @opentelemetry/instrumentation
```
Expand Down Expand Up @@ -108,7 +111,7 @@ export class MyInstrumentation extends InstrumentationBase {

// Later, but before the module to instrument is required

const myInstrumentationn = new MyInstrumentation();
const myInstrumentation = new MyInstrumentation();
myInstrumentation.setTracerProvider(provider); // this is optional, only if global TracerProvider shouldn't be used
myInstrumentation.setMeterProvider(meterProvider); // this is optional
myInstrumentation.enable();
Expand Down Expand Up @@ -219,12 +222,17 @@ If nothing is specified the global registered provider is used. Usually this is
There might be use case where someone has the need for more providers within an application. Please note that special care must be takes in such setups
to avoid leaking information from one provider to the other because there are a lot places where e.g. the global `ContextManager` or `Propagator` is used.

## Instrumentation for ES Modules In Node.js (experimental)
## Instrumentation for ECMAScript Modules (ESM) in Node.js (experimental)

Node.js uses a different module loader for ECMAScript Modules (ESM) vs. CommonJS (CJS).
A `require()` call will cause Node.js to use the CommonJS module loader.
An `import ...` statement or `import()` call will cause Node.js to use the ECMAScript module loader.

As the module loading mechanism for ESM is different than CJS, you need to select a custom loader so instrumentation can load hook on the ESM module it want to patch. To do so, you must provide the `--experimental-loader=@opentelemetry/instrumentation/hook.mjs` flag to the `node` binary. Alternatively you can set the `NODE_OPTIONS` environment variable to `NODE_OPTIONS="--experimental-loader=@opentelemetry/instrumentation/hook.mjs"`.
As the ESM module loader from Node.js is experimental, so is our support for it. Feel free to provide feedback or report issues about it.
If your application is written in JavaScript as ESM, or it must compile to ESM from TypeScript, then a loader hook is required to properly patch instrumentation.
The custom hook for ESM instrumentation is `--experimental-loader=@opentelemetry/instrumentation/hook.mjs`.
This flag must be passed to the `node` binary, which is often done as a startup command and/or in the `NODE_OPTIONS` environment variable.

**Note**: ESM Instrumentation is not yet supported for Node 20.
For more details on ECMAScript Modules vs CommonJS, refer to [esm-support](https://github.com/open-telemetry/opentelemetry-js/blob/main/doc/esm-support.md).

## Limitations

Expand Down
21 changes: 12 additions & 9 deletions experimental/packages/opentelemetry-sdk-node/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ This package provides the full OpenTelemetry SDK for Node.js including tracing a

## Quick Start

**Note: Much of OpenTelemetry JS documentation is written assuming the compiled application is run as CommonJS.**
For more details on ECMAScript Modules vs CommonJS, refer to [esm-support](https://github.com/open-telemetry/opentelemetry-js/blob/main/doc/esm-support.md).

To get started you need to install `@opentelemetry/sdk-node`, a metrics and/or tracing exporter, and any appropriate instrumentation for the node modules used by your application.

### Installation
Expand Down Expand Up @@ -191,19 +194,19 @@ This is an alternative to programmatically configuring an exporter or span proce

### Exporters

| Environment variable | Description |
|----------------------|-------------|
| Environment variable | Description |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| OTEL_TRACES_EXPORTER | List of exporters to be used for tracing, separated by commas. Options include `otlp`, `jaeger`, `zipkin`, and `none`. Default is `otlp`. `none` means no autoconfigured exporter. |
| OTEL_LOGS_EXPORTER | List of exporters to be used for logging, separated by commas. Options include `otlp`, `console` and `none`. Default is `otlp`. `none` means no autoconfigured exporter. |
| OTEL_LOGS_EXPORTER | List of exporters to be used for logging, separated by commas. Options include `otlp`, `console` and `none`. Default is `otlp`. `none` means no autoconfigured exporter. |

### OTLP Exporter

| Environment variable | Description |
|----------------------|-------------|
| OTEL_EXPORTER_OTLP_PROTOCOL | The transport protocol to use on OTLP trace, metric, and log requests. Options include `grpc`, `http/protobuf`, and `http/json`. Default is `http/protobuf`. |
| OTEL_EXPORTER_OTLP_TRACES_PROTOCOL | The transport protocol to use on OTLP trace requests. Options include `grpc`, `http/protobuf`, and `http/json`. Default is `http/protobuf`. |
| OTEL_EXPORTER_OTLP_METRICS_PROTOCOL | The transport protocol to use on OTLP metric requests. Options include `grpc`, `http/protobuf`, and `http/json`. Default is `http/protobuf`. |
| OTEL_EXPORTER_OTLP_LOGS_PROTOCOL | The transport protocol to use on OTLP log requests. Options include `grpc`, `http/protobuf`, and `http/json`. Default is `http/protobuf`. |
| Environment variable | Description |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| OTEL_EXPORTER_OTLP_PROTOCOL | The transport protocol to use on OTLP trace, metric, and log requests. Options include `grpc`, `http/protobuf`, and `http/json`. Default is `http/protobuf`. |
| OTEL_EXPORTER_OTLP_TRACES_PROTOCOL | The transport protocol to use on OTLP trace requests. Options include `grpc`, `http/protobuf`, and `http/json`. Default is `http/protobuf`. |
| OTEL_EXPORTER_OTLP_METRICS_PROTOCOL | The transport protocol to use on OTLP metric requests. Options include `grpc`, `http/protobuf`, and `http/json`. Default is `http/protobuf`. |
| OTEL_EXPORTER_OTLP_LOGS_PROTOCOL | The transport protocol to use on OTLP log requests. Options include `grpc`, `http/protobuf`, and `http/json`. Default is `http/protobuf`. |

Additionally, you can specify other applicable environment variables that apply to each exporter such as the following:

Expand Down
3 changes: 3 additions & 0 deletions packages/opentelemetry-sdk-trace-node/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ This module provides *automated instrumentation and tracing* for Node.js applica
For manual instrumentation see the
[@opentelemetry/sdk-trace-base](https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base) package.

**Note: Much of OpenTelemetry JS documentation is written assuming the compiled application is run as CommonJS.**
For more details on ECMAScript Modules vs CommonJS, refer to [esm-support](https://github.com/open-telemetry/opentelemetry-js/blob/main/doc/esm-support.md).

## How auto instrumentation works

This package exposes a `NodeTracerProvider`.
Expand Down