# OpenTelemetry cho Node.js (CommonJS và ES modules)

> Instrumentation không cần sửa code bằng auto-instrumentations-node, hook cho ES modules, log Pino/Winston gắn trace và cách chạy trong Docker hoặc PaaS.

Node.js không cần sửa code: auto-instrumentations của OpenTelemetry vá `http`, `fetch` (undici), Express, Fastify, NestJS, client cơ sở dữ liệu, Pino, Winston và nhiều thư viện khác khi chúng được nạp, còn SDK đọc [bộ biến chuẩn](https://belvador.dev/vi/docs/otel/quickstart#2-dat-cac-bien-chuan).

> **Đã kiểm ngày 2026-10-24** với node 22.23.4, @opentelemetry/sdk-node 0.300.0, @opentelemetry/auto-instrumentations-node 0.82.0, pino 10.4.0: traces đạt, logs đạt, log mang trace/span của request.

## Cài đặt

```bash
npm install @opentelemetry/api @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node
```

## CommonJS (`require`)

Nạp file register trước app:

```bash
export OTEL_SEMCONV_STABILITY_OPT_IN=http
export OTEL_NODE_RESOURCE_DETECTORS=env,host,os
node --require @opentelemetry/auto-instrumentations-node/register app.js
```

Nếu không đổi được lệnh khởi động (PaaS, `npm start`, trình quản lý tiến trình), hãy đặt cờ vào `NODE_OPTIONS`: `NODE_OPTIONS="--require @opentelemetry/auto-instrumentations-node/register"`.

## ES modules (`import`)

ES modules cần thêm loader hook, nếu không thì không thứ gì code của bạn `import` được gắn instrumentation — app vẫn chạy, nhưng không gửi span nào và log không mang trace ID:

```bash
export OTEL_SEMCONV_STABILITY_OPT_IN=http
export OTEL_NODE_RESOURCE_DETECTORS=env,host,os
node --experimental-loader=@opentelemetry/instrumentation/hook.mjs --import @opentelemetry/auto-instrumentations-node/register app.mjs
```

App là ESM khi `package.json` có `"type": "module"` hoặc file vào có đuôi `.mjs`. TypeScript biên dịch ra CommonJS là CommonJS, dù mã nguồn trông thế nào.

## Logs

Pino và Bunyan được nối tự động: mỗi lệnh ghi log trong lúc xử lý request trở thành một bản ghi log OpenTelemetry mang trace ID và span ID của request đó, còn đầu ra thường (stdout, file) giữ nguyên. Winston cần thêm gói `@opentelemetry/winston-transport` cài cạnh nó. `console.log` không được thu — hãy dùng logger. (Lần chạy của Belvador dùng Pino.)

## Các biến ở trên làm gì

- `OTEL_SEMCONV_STABILITY_OPT_IN=http` cho span HTTP dùng tên thuộc tính ổn định (`url.path`, `http.request.method`, `http.response.status_code`) mà bộ lọc của Belvador dùng.
- `OTEL_NODE_RESOURCE_DETECTORS=env,host,os` mô tả máy mà không dùng detector `process`, vốn chép nguyên dòng lệnh — kèm mọi bí mật truyền trong đó — vào từng span.

## Tắt bớt instrumentation

Mỗi instrumentation tắt được theo tên, ví dụ các span hệ thống file gây nhiễu:

```bash
export OTEL_NODE_DISABLED_INSTRUMENTATIONS=fs,dns,net
```

## Tiến trình chạy ngắn

Script, CLI và handler serverless có thể thoát trước khi lô dữ liệu của exporter được gửi (mặc định khoảng năm giây). File register tự gửi nốt khi nhận `SIGTERM` và khi thoát bình thường; tiến trình gọi thẳng `process.exit()` hoặc bị kill sẽ mất lô cuối.

## Cùng SDK Belvador

Với lỗi, giữ SDK Belvador hoặc Sentry của bạn và đưa API OpenTelemetry cho SDK Belvador để lỗi mang ID của span đang chạy — xem [Liên kết request](https://belvador.dev/vi/docs/sdk/tracing#khi-da-dung-opentelemetry). Đừng để hai công cụ cùng tạo span trong một tiến trình ([một bên làm chủ tracing](https://belvador.dev/vi/docs/otel/overview#chi-mot-ben-lam-chu-tracing)); với `@sentry/node`, xem [Cùng SDK Sentry](https://belvador.dev/vi/docs/otel/sentry-coexistence#node-js-sentry-node).
