mcpField
O
otel-node

otel-node

github.com/mizchiクラウド・DevOps41644 回インストール1 週間前に更新
リポジトリ

otel-node について

Node.js アプリの OpenTelemetry 計装とトレース出力の問題解決を扱うスキルです。特に ESM バンドルでの自動計装の制約を診断し、開発者が収集パイプラインを確認する方法を示します。

主な機能

  1. 01NodeSDK の初期化と OTLP エクスポート
  2. 02HTTP、Express、PostgreSQL、Redis の自動計装
  3. 03手動スパンとコンテキスト伝搬
  4. 04ESM バンドル計装の問題診断と回避策
  5. 05Collector パイプラインの確認

活用シーン

  1. 01Node.js サービスへのトレース追加
  2. 02esbuild の ESM 出力でスパンが届かない問題の調査
  3. 03Hono への明示的なミドルウェア計装

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mizchi/skills --skill otel-node

インストール後、Claude Code で/otel-nodeを入力して読み込まれたか確認します。

同梱ファイルREADME.md

詳細

OpenTelemetry — Node.js

SDK の初期化

// otel.ts — import before everything else
import { NodeSDK } from "@opentelemetry/sdk-node";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
import { Resource } from "@opentelemetry/resources";
import { SEMRESATTRS_SERVICE_NAME } from "@opentelemetry/semantic-conventions";

const exporter = new OTLPTraceExporter({
  url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT + "/v1/traces",
});

export const sdk = new NodeSDK({
  resource: new Resource({
    [SEMRESATTRS_SERVICE_NAME]: process.env.SERVICE_NAME ?? "my-service",
  }),
  spanProcessor: new BatchSpanProcessor(exporter),
});

sdk.start();
process.on("SIGTERM", () => sdk.shutdown());

アプリのエントリーポイントより前に読み込みます:node --import ./otel.js server.js または tsx --import ./otel.ts server.ts。

自動計装パッケージ

必要なものだけを追加します。各パッケージは特定のモジュールにパッチを適用します:

pnpm add @opentelemetry/instrumentation-http       # node:http / node:https
pnpm add @opentelemetry/instrumentation-express    # Express routing spans
pnpm add @opentelemetry/instrumentation-pg         # postgres queries
pnpm add @opentelemetry/instrumentation-ioredis    # Redis commands

SDK の初期化時に登録します:

import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
import { ExpressInstrumentation } from "@opentelemetry/instrumentation-express";

export const sdk = new NodeSDK({
  instrumentations: [new HttpInstrumentation(), new ExpressInstrumentation()],
  // ...
});

Hono:公式の計装パッケージはありません。手動のミドルウェアを使用してください(下記を参照)。

esbuild ESM — 自動計装がひそかに失敗する場合

症状

アプリは正常に起動し、SDK 初期化ログも表示されますが、コレクターにスパンが届きません。エラーは発生しません。次の場合に発生します:

  • 出力形式が --format=esm
  • @opentelemetry/instrumentation-* による自動計装を使用している
  • バンドラーが esbuild(Vite/SWC も同じ根本原因です)
根本原因

@opentelemetry/instrumentation-* は require-in-the-middle を使用して require() をフックし、対象モジュール(node:http など)にモンキーパッチを適用します。esbuild の ESM バンドルでは、import はバンドル時に静的に解決されます。実行時に require() が呼び出されないため、フックが発火せず、パッチも適用されず、スパンも生成されません。エラーは発生しません(ひそかな失敗)。

修正方法 A — 手動スパン(Hono/esbuild では推奨)

スパンを明示的に作成するミドルウェアを記述します:

import { context, propagation, SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";

const tracer = trace.getTracer("app");

app.use(async (c, next) => {
  const ctx = propagation.extract(context.active(), c.req.raw.headers);
  const route = new URL(c.req.url).pathname;

  await tracer.startActiveSpan(
    `${c.req.method} ${route}`,
    { kind: SpanKind.SERVER, attributes: { "http.method": c.req.method, "http.route": route } },
    ctx,
    async (span) => {
      try {
        await next();
        span.setAttribute("http.status_code", c.res.status);
        span.setStatus({ code: SpanStatusCode.OK });
      } catch (e: any) {
        span.recordException(e);
        span.setStatus({ code: SpanStatusCode.ERROR, message: e?.message });
        throw e;
      } finally {
        span.end();
      }
    }
  );
});

メタデータを介して、送信する gRPC 呼び出しにコンテキストを伝搬させます:

const callUnary = (method, req) => {
  const metadata = new grpc.Metadata();
  propagation.inject(context.active(), metadata, {
    set: (carrier, key, value) => (carrier as grpc.Metadata).set(key, value),
  });
  return new Promise((resolve, reject) =>
    client[method](req, metadata, (err, res) => (err ? reject(err) : resolve(res)))
  );
};
修正方法 B — CJS 出力に切り替える

esbuild を --format=cjs に変更します。require() フックが通常どおり発火します。ESM 専用の依存関係がない場合に機能します。Hono は CJS に対応しています。

修正方法 C — バンドルせずに実行する

tsx または node --loader ts-node/esm + --import @opentelemetry/auto-instrumentations-node/register を使用します。Node プロセスのバンドルを省略します。コンテナイメージのサイズが大きくなるため、本番環境には推奨しません。

パイプラインの検証

一時的に、OTel Collector にデバッグエクスポーターを追加します:

exporters:
  debug:
    verbosity: detailed

service:
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [otlphttp/tempo, debug]

スパンが届くと、コレクターのログに Trace ID: ... Name: GET /api/users と表示されます。出力がない場合は、コレクターに到達する前のどこかで問題が発生しています。

関連項目

  • opentelemetry — シグナル設計、スパン名、サンプリング、W3C 伝搬
  • cloudflare-workers-otel-utels — Cloudflare Workers のテレメトリー(Node ランタイムなし、fetch 境界方式)
  • esbuild、Vite、SWC はすべて、同じ require-in-the-middle の障害モードを共有しています
  • instrumentation-* パッケージは、2026-05 時点で静的インポートへのパッチ適用に対応していません

コメント