OpenTelemetryは、アプリからトレースなどの観測データを作り、共通形式で送る仕組みです。今回はNode.jsのHTTPリクエストを自動計装し、OpenTelemetry Collectorが受け取った1件を確認します。
初出日: 2026-04-24 / 最終確認日: 2026-07-25
今回やること
curl → Node.jsアプリ → OTLP/HTTP → Collector → ターミナル出力
- Node.jsアプリへ自動計装を読み込む
- OTLP/HTTPでトレースをCollectorへ送る
- Collectorのdebug exporterでspanを確認する
メトリクス、ログ、sampling、可視化バックエンドは扱いません。まず一つのリクエストが届く経路を理解します。
最初に知る3つの言葉
| 言葉 | この実習での意味 |
|---|---|
| span | HTTPリクエストなど、一つの処理区間の記録 |
| trace | 同じtrace IDで結ばれたspanのまとまり |
| Collector | アプリから受け取り、確認先や保存先へ中継するプロセス |
OpenTelemetry自体はトレースを長期保存する画面ではありません。アプリはCollectorへ送り、CollectorがJaegerやTempoなどのバックエンドへ渡します。この実習では保存先の代わりにdebug exporterを使います。
自動計装は、対応ライブラリのHTTP処理などをコード変更なしで記録します。業務上重要な「課題を提出した」のような区間は、後から手動spanで補います。最初から両方を混ぜず、今回は自動計装で通信経路が成立することだけを確かめます。
アプリを準備する
空のディレクトリで依存関係を入れます。
npm init -y
npm install express @opentelemetry/sdk-node \
@opentelemetry/auto-instrumentations-node \
@opentelemetry/exporter-trace-otlp-proto
app.jsを作ります。
const express = require("express");
const app = express();
app.get("/hello", (_req, res) => {
res.json({ message: "hello" });
});
app.listen(8080, () => {
console.log("http://localhost:8080/hello");
});
このアプリだけを普通に起動しても、まだspanは作られません。次の計装ファイルをアプリより先に読み込ませることで、ExpressとNode.jsのHTTP処理を自動計装します。
次にinstrumentation.jsを作ります。計装はアプリより先に読み込む必要があります。
const { NodeSDK } = require("@opentelemetry/sdk-node");
const {
getNodeAutoInstrumentations,
} = require("@opentelemetry/auto-instrumentations-node");
const {
OTLPTraceExporter,
} = require("@opentelemetry/exporter-trace-otlp-proto");
const sdk = new NodeSDK({
traceExporter: new OTLPTraceExporter({
url: "http://localhost:4318/v1/traces",
}),
instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
Collectorを起動する
collector-config.yamlを作ります。
receivers:
otlp:
protocols:
http:
endpoint: 0.0.0.0:4318
exporters:
debug:
verbosity: detailed
service:
pipelines:
traces:
receivers: [otlp]
exporters: [debug]
1つ目のターミナルでCollectorを起動します。
docker run --rm -p 4318:4318 \
-v "$PWD/collector-config.yaml:/etc/otelcol/config.yaml" \
otel/opentelemetry-collector:0.153.0
この固定タグは、初出日2026-04-24の記事を最終確認日2026-07-25に検証した版です。後日試す場合は、Collectorのリリースで利用可能な版を確認してください。
トレースを送る
2つ目のターミナルでアプリを起動します。
OTEL_SERVICE_NAME=demo-api \
node --require ./instrumentation.js app.js
3つ目のターミナルからリクエストします。
curl http://localhost:8080/hello
成功確認
Collector側の出力に、次の内容が含まれれば成功です。
- service名が
demo-api - HTTPリクエストに対応するspan
trace_idとspan_id- HTTP statusが成功を示す値
トレースは「ログを置き換えるもの」ではありません。一つの処理が複数サービスを通る時に、共通のtrace IDで経路を追うための材料です。
もう一度curlを実行すると別のtrace IDが作られます。同じリクエスト内のspanは同じtrace IDを共有し、個々の処理区間は異なるspan IDを持つことも確認してください。
よくあるつまずき
Collectorに何も出ない
アプリをnode app.jsだけで起動すると、計装が先に読み込まれません。--require ./instrumentation.jsを確認します。また、Collectorが4318を公開しているか確認してください。
ESMのプロジェクトで同じコマンドを使う
この例はCommonJSです。ES Modulesでは読み込み方法が異なるため、OpenTelemetry公式のESM手順に従います。
Collectorを本番へそのまま公開する
この設定は認証も保存先もないローカル確認用です。4318をインターネットへ公開せず、本番では通信経路、認証、送信量、保持先を運用設計に合わせて設定します。
URL、header、属性へ認証token、パスワード、個人情報を入れると、トレースの保存先にも複製されます。便利そうな値をすべて記録せず、調査に必要で保存してよい属性だけを選びます。
練習
/users/:idというGETルートを一つ追加し、curl http://localhost:8080/users/42を実行してください。Collectorのspan名やHTTP routeが/helloとどう違うか比べます。
後片付け
アプリとCollectorを起動した各ターミナルでCtrl + Cを押します。Collectorは--rm付きなので、停止後にコンテナが削除されます。