|
| 1 | +# OpenTelemetry |
| 2 | + |
| 3 | +<!--introduced_in=REPLACEME--> |
| 4 | + |
| 5 | +<!-- YAML |
| 6 | +added: REPLACEME |
| 7 | +--> |
| 8 | + |
| 9 | +> Stability: 1 - Experimental |
| 10 | +
|
| 11 | +<!-- source_link=lib/otel.js --> |
| 12 | + |
| 13 | +The `node:otel` module provides built-in [OpenTelemetry][] tracing support for |
| 14 | +Node.js core components. When enabled, it automatically creates spans for HTTP |
| 15 | +server and client operations and exports them using the [OTLP/HTTP JSON][] |
| 16 | +protocol. |
| 17 | + |
| 18 | +To access it: |
| 19 | + |
| 20 | +```cjs |
| 21 | +const otel = require('node:otel'); |
| 22 | +``` |
| 23 | + |
| 24 | +```mjs |
| 25 | +import otel from 'node:otel'; |
| 26 | +``` |
| 27 | + |
| 28 | +This module is only available under the `node:` scheme. It requires the |
| 29 | +`--experimental-otel` CLI flag or one of the `NODE_OTEL` / `NODE_OTEL_ENDPOINT` |
| 30 | +environment variables. |
| 31 | + |
| 32 | +## Activation |
| 33 | + |
| 34 | +There are two ways to activate OpenTelemetry tracing: |
| 35 | + |
| 36 | +### Environment variables |
| 37 | + |
| 38 | +Setting `NODE_OTEL=1` enables tracing with the default collector endpoint |
| 39 | +(`http://localhost:4318`): |
| 40 | + |
| 41 | +```bash |
| 42 | +NODE_OTEL=1 node app.js |
| 43 | +``` |
| 44 | + |
| 45 | +To use a custom collector endpoint, set `NODE_OTEL_ENDPOINT` instead (or in |
| 46 | +addition): |
| 47 | + |
| 48 | +```bash |
| 49 | +NODE_OTEL_ENDPOINT=http://collector.example.com:4318 node app.js |
| 50 | +``` |
| 51 | + |
| 52 | +Both variables also make the `node:otel` module available without requiring the |
| 53 | +`--experimental-otel` flag. |
| 54 | + |
| 55 | +### Programmatic API |
| 56 | + |
| 57 | +```cjs |
| 58 | +const otel = require('node:otel'); |
| 59 | + |
| 60 | +// Start with the default endpoint (http://localhost:4318): |
| 61 | +otel.start(); |
| 62 | + |
| 63 | +// Or with a custom endpoint: |
| 64 | +otel.start({ endpoint: 'http://collector.example.com:4318' }); |
| 65 | + |
| 66 | +// ... application code ... |
| 67 | +otel.stop(); |
| 68 | +``` |
| 69 | + |
| 70 | +## Environment variables |
| 71 | + |
| 72 | +### `NODE_OTEL` |
| 73 | + |
| 74 | +When set to a non-empty value, enables the OpenTelemetry tracing subsystem |
| 75 | +using the default collector endpoint (`http://localhost:4318`). If |
| 76 | +`NODE_OTEL_ENDPOINT` is also set, it takes precedence. |
| 77 | + |
| 78 | +### `NODE_OTEL_ENDPOINT` |
| 79 | + |
| 80 | +When set to a non-empty value, enables the OpenTelemetry tracing subsystem and |
| 81 | +directs spans to the specified OTLP collector endpoint. The endpoint should be |
| 82 | +the base URL of an |
| 83 | +OTLP/HTTP collector (e.g. `http://localhost:4318`). The `/v1/traces` path is |
| 84 | +appended automatically. |
| 85 | + |
| 86 | +### `NODE_OTEL_FILTER` |
| 87 | + |
| 88 | +Accepts a comma-separated list of core modules to instrument. When not set, all |
| 89 | +supported modules are instrumented. For example, setting |
| 90 | +`NODE_OTEL_FILTER=node:http` would enable tracing only for the `node:http` |
| 91 | +module. |
| 92 | + |
| 93 | +Supported module filter values: |
| 94 | + |
| 95 | +* `node:http` — HTTP server and client operations |
| 96 | +* `node:undici` — Undici HTTP client operations |
| 97 | +* `node:fetch` — Fetch API operations (alias for undici) |
| 98 | + |
| 99 | +### `OTEL_SERVICE_NAME` |
| 100 | + |
| 101 | +Standard OpenTelemetry environment variable used to set the service name in |
| 102 | +exported resource attributes. Defaults to `node-<pid>`. |
| 103 | + |
| 104 | +## `otel.start(options)` |
| 105 | + |
| 106 | +<!-- YAML |
| 107 | +added: REPLACEME |
| 108 | +--> |
| 109 | + |
| 110 | +* `options` {Object} |
| 111 | + * `endpoint` {string} The OTLP collector endpoint URL. |
| 112 | + **Default:** `'http://localhost:4318'`. |
| 113 | + * `filter` {string|string\[]} Optional comma-separated string or array of |
| 114 | + core module names to instrument (e.g. `['node:http']` or |
| 115 | + `'node:http,node:undici'`). When omitted, all supported modules are |
| 116 | + instrumented. |
| 117 | + * `maxBufferSize` {number} Maximum number of spans buffered in memory before |
| 118 | + triggering an immediate flush to the collector. Must be a positive integer. |
| 119 | + **Default:** `100`. |
| 120 | + * `flushInterval` {number} Interval in milliseconds between periodic flushes |
| 121 | + of buffered spans to the collector. Must be a positive integer. |
| 122 | + **Default:** `10000`. |
| 123 | + |
| 124 | +Enables the OpenTelemetry tracing subsystem. Spans are created for supported |
| 125 | +core module operations and exported to the specified collector using the |
| 126 | +OTLP/HTTP JSON protocol. |
| 127 | + |
| 128 | +If tracing is already active, calling `start()` will stop the current session |
| 129 | +and start a new one with the provided options. |
| 130 | + |
| 131 | +## `otel.stop()` |
| 132 | + |
| 133 | +<!-- YAML |
| 134 | +added: REPLACEME |
| 135 | +--> |
| 136 | + |
| 137 | +Disables the OpenTelemetry tracing subsystem. Any buffered spans are sent to |
| 138 | +the collector before stopping. Because the export is asynchronous, delivery is |
| 139 | +not confirmed before `stop()` returns. After calling `stop()`, no new spans are |
| 140 | +created. |
| 141 | + |
| 142 | +Calling `stop()` when tracing is not active is a no-op. |
| 143 | + |
| 144 | +## `otel.active` |
| 145 | + |
| 146 | +<!-- YAML |
| 147 | +added: REPLACEME |
| 148 | +--> |
| 149 | + |
| 150 | +* {boolean} |
| 151 | + |
| 152 | +Returns `true` if the OpenTelemetry tracing subsystem is currently active. |
| 153 | + |
| 154 | +## Instrumented operations |
| 155 | + |
| 156 | +When tracing is active, spans are automatically created for the following |
| 157 | +operations: |
| 158 | + |
| 159 | +### HTTP server |
| 160 | + |
| 161 | +A span with kind `SERVER` is created for each incoming HTTP request. The span |
| 162 | +starts when the request is received and ends when the response finishes. If the |
| 163 | +client disconnects before the response completes, the span ends with an error |
| 164 | +status. |
| 165 | + |
| 166 | +Server spans receive error status (`STATUS_ERROR`) for 5xx response codes. 4xx |
| 167 | +responses are not treated as server errors per OpenTelemetry semantic |
| 168 | +conventions. |
| 169 | + |
| 170 | +Attributes set on server spans: |
| 171 | + |
| 172 | +| Attribute | Description | Condition | |
| 173 | +| --------------------------- | -------------------------------- | ----------------------------- | |
| 174 | +| `http.request.method` | HTTP method (e.g. `GET`, `POST`) | Always | |
| 175 | +| `url.path` | Request URL path (without query) | Always | |
| 176 | +| `url.query` | Query string (without `?`) | When query string is present | |
| 177 | +| `url.scheme` | `http` or `https` | Always | |
| 178 | +| `server.address` | Host header value | When `Host` header is present | |
| 179 | +| `network.protocol.version` | HTTP version (e.g. `1.1`) | Always | |
| 180 | +| `http.response.status_code` | Response status code | When response finishes | |
| 181 | +| `error.type` | HTTP status code as string | On 5xx responses | |
| 182 | + |
| 183 | +### HTTP client |
| 184 | + |
| 185 | +A span with kind `CLIENT` is created for each outgoing HTTP request made via |
| 186 | +`node:http`. The span starts when the request is created and ends when the |
| 187 | +response finishes or an error occurs. |
| 188 | + |
| 189 | +Client spans receive error status (`STATUS_ERROR`) for 4xx and 5xx response |
| 190 | +codes. On connection errors, an `exception` event is added to the span with |
| 191 | +`exception.type`, `exception.message`, and `exception.stacktrace` attributes. |
| 192 | + |
| 193 | +Attributes set on client spans: |
| 194 | + |
| 195 | +| Attribute | Description | Condition | |
| 196 | +| --------------------------- | ------------------------- | ------------------------- | |
| 197 | +| `http.request.method` | HTTP method | Always | |
| 198 | +| `url.full` | Full request URL | Always | |
| 199 | +| `server.address` | Target host | Always | |
| 200 | +| `server.port` | Target port | When available | |
| 201 | +| `http.response.status_code` | Response status code | When response is received | |
| 202 | +| `network.protocol.version` | HTTP version | When response is received | |
| 203 | +| `error.type` | Status code or error name | On 4xx/5xx or errors | |
| 204 | + |
| 205 | +### Undici/Fetch client |
| 206 | + |
| 207 | +A span with kind `CLIENT` is created for each outgoing request made via |
| 208 | +`fetch()` or undici's `request()`. |
| 209 | + |
| 210 | +Error status and `exception` event behavior is the same as for HTTP client |
| 211 | +spans above. |
| 212 | + |
| 213 | +Attributes set on undici/fetch client spans: |
| 214 | + |
| 215 | +| Attribute | Description | Condition | |
| 216 | +| --------------------------- | ------------------------- | ------------------------- | |
| 217 | +| `http.request.method` | HTTP method | Always | |
| 218 | +| `url.full` | Full request URL | Always | |
| 219 | +| `server.address` | Target origin | Always | |
| 220 | +| `http.response.status_code` | Response status code | When response is received | |
| 221 | +| `error.type` | Status code or error name | On 4xx/5xx or errors | |
| 222 | + |
| 223 | +## W3C Trace Context propagation |
| 224 | + |
| 225 | +The tracing subsystem automatically propagates [W3C Trace Context][] across HTTP |
| 226 | +boundaries: |
| 227 | + |
| 228 | +* **Incoming requests**: The `traceparent` header is read from incoming HTTP |
| 229 | + requests. Child spans created during request processing inherit the trace ID. |
| 230 | +* **Outgoing requests**: The `traceparent` header is injected into outgoing HTTP |
| 231 | + and undici/fetch requests, enabling distributed tracing across services. |
| 232 | + |
| 233 | +[OTLP/HTTP JSON]: https://opentelemetry.io/docs/specs/otlp/#otlphttp |
| 234 | +[OpenTelemetry]: https://opentelemetry.io/ |
| 235 | +[W3C Trace Context]: https://www.w3.org/TR/trace-context/ |
0 commit comments