コンテンツにスキップ

OpenTelemetry Node-JS

OpenTelemetry Node.js の自動インスツルメンテーションモジュールは、起動パラメータによるプリロードを使用して、アプリケーションの依存関係が読み込まれる前にフックを登録します。ビジネスコードを変更することなく、サポートされている Web フレームワーク、HTTP クライアント、データベース、メッセージキューなどの呼び出しを収集できます。

標準の OpenTelemetry 機能に加えて、Guance は Node.js 向けにプロファイル拡張機能を提供します。この機能は @cloudcare/profiler-nodejs@datadog/pprof に基づいており、wallheap プロファイルを収集し、DataKit の /profiling/v1/input エンドポイントを通じて報告します。プロファイル拡張は OpenTelemetry の公式標準機能ではなく、本ドキュメントではコードレス接続以外の補足的なソリューションとして記載しています。

本ドキュメントでは、DataKit の OpenTelemetry コレクターを使用して OTLP データを受信し、Guance に転送します:

Node.js アプリケーション + OpenTelemetry 自動インスツルメンテーションモジュール -> OTLP -> DataKit -> Guance

前提条件

  • OpenTelemetry JavaScript が現在サポートしている Node.js LTS バージョンを使用していること;
  • アプリケーションが npm、pnpm、または Yarn で依存関係を管理していること;
  • DataKit がインストールされ、対象の Guance ワークスペースに接続されていること;
  • Node.js アプリケーションから DataKit へのネットワーク到達性があること:OTLP/HTTP は DataKit HTTP ポート 9529 を使用し、OTLP/gRPC はデフォルトで 4317 を使用します。

バージョンと拡張サポート

  • Node.js:自動インスツルメンテーションパッケージは通常 ^18.19.0 または >=20.6.0 を必要とし、本番環境では現在サポートされている LTS バージョンを使用し、実際にインストールされたパッケージの engines 宣言に従うことを推奨します;
  • OpenTelemetry:現在の安定バージョンを使用し、ロックファイルで実際のデプロイバージョンを固定することを推奨します;
  • プロファイル拡張パッケージ:@cloudcare/profiler-nodejs
  • デフォルトのプロファイリング報告先:http://127.0.0.1:9529/profiling/v1/input

1. OpenTelemetry コレクターを有効にする

DataKit のインストールディレクトリ内の conf.d/opentelemetry に移動します。コレクターの設定がまだ作成されていない場合は、サンプルファイルをコピーします:

cd /usr/local/datakit/conf.d/opentelemetry
sudo cp opentelemetry.conf.sample opentelemetry.conf

opentelemetry.conf に少なくとも以下の受信設定が含まれていることを確認します:

[[inputs.opentelemetry]]
  # Guance でタグとして保持するカスタム属性をホワイトリストに追加します。
  customer_tags = ["team", "project"]

  [inputs.opentelemetry.http]
    http_status_ok = 200
    trace_api = "/otel/v1/traces"
    metric_api = "/otel/v1/metrics"
    logs_api = "/otel/v1/logs"

  [inputs.opentelemetry.grpc]
    addr = "127.0.0.1:4317"
    max_payload = 16777216

受信アドレスは以下の通りです:

プロトコル データタイプ DataKit 受信アドレス
OTLP/HTTP + Protobuf トレース http://<DataKit-IP>:9529/otel/v1/traces
OTLP/HTTP + Protobuf メトリクス http://<DataKit-IP>:9529/otel/v1/metrics
OTLP/HTTP + Protobuf ログ http://<DataKit-IP>:9529/otel/v1/logs
OTLP/gRPC トレース、メトリクス、ログ http://<DataKit-IP>:4317

Node.js アプリケーションと DataKit が同一ホストにない場合は、実際のデプロイに合わせて DataKit のリスニングアドレス、ファイアウォール、またはその他のネットワークアクセス制御を調整してください。gRPC の場合は、addr をアプリケーションがアクセス可能なリスニングアドレス(例:0.0.0.0:4317)に変更できます。OTLP 受信ポートをパブリックネットワークに直接公開しないでください。

DataKit を再起動し、サービスを確認します:

sudo datakit service restart
curl http://127.0.0.1:9529/v1/ping

2. アプリケーションを OpenTelemetry に接続する

自動インスツルメンテーションモジュールのインストール

アプリケーションプロジェクトのディレクトリで、npm 公式リポジトリから OpenTelemetry の公式パッケージをインストールします:

npm install --save \
  @opentelemetry/api \
  @opentelemetry/auto-instrumentations-node

@opentelemetry/auto-instrumentations-node には、Node.js SDK、自動インスツルメンテーションライブラリ、および一般的なエクスポーターが含まれています。このパッケージは、サポートされており、かつ実際に読み込まれたライブラリに対してのみテレメトリデータを生成します。アプリケーションが使用するフレームワークやクライアントがサポートリストに含まれていない場合、対応するスパンは自動的に生成されません。

環境変数による起動

以下は OTLP/HTTP + Protobuf を例としています。デフォルトではトレースを有効にし、メトリクスとログは一時的に無効にします:

export OTEL_SERVICE_NAME="order-service"
export OTEL_RESOURCE_ATTRIBUTES="env=prod,version=1.0.0,team=backend"

export OTEL_TRACES_EXPORTER="otlp"
export OTEL_METRICS_EXPORTER="none"
export OTEL_LOGS_EXPORTER="none"

export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
export OTEL_EXPORTER_OTLP_ENDPOINT="http://127.0.0.1:9529/otel"
export OTEL_PROPAGATORS="tracecontext,baggage"

export NODE_OPTIONS="--require @opentelemetry/auto-instrumentations-node/register"
node app.js

OTEL_EXPORTER_OTLP_ENDPOINT はベースアドレスです。OTLP/HTTP エクスポーターはデータタイプに応じて自動的に /v1/traces/v1/metrics、または /v1/logs を追加し、最終的に DataKit の /otel/v1/* ルートに対応します。

アプリケーションに既に NODE_OPTIONS がある場合は、元のパラメータを保持した上で --require @opentelemetry/auto-instrumentations-node/register を追加し、元の値を直接上書きしないでください。PM2、systemd、Supervisor、または npm スクリプトのシナリオでは、OTEL_*NODE_OPTIONS を実際のアプリケーションプロセスの起動環境に記述してください。

起動パラメータによるロード

NODE_OPTIONS を設定せずに、Node.js の起動コマンドでモジュールをプリロードすることもできます:

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

自動インスツルメンテーションモジュールは、アプリケーションコードとその依存関係が実行される前に読み込む必要があります。node app.js の起動後に動的にモジュールを読み込まないでください。既に読み込まれたライブラリがインスツルメンテーションされない可能性があります。

一般的な起動方法

npm スクリプトで起動:

NODE_OPTIONS="--require @opentelemetry/auto-instrumentations-node/register" npm start

PM2 で起動する場合は、変数を ecosystem.config.jsenv 設定に配置するか、プロセス管理プラットフォームの環境変数機能を使用して注入します。設定を変更した後はアプリケーションプロセスを再起動する必要があります。ホットリロードだけではプリロードモジュールが再読み込みされない場合があります。

OTLP/gRPC の使用

OTLP/gRPC に変更する場合は、プロトコルとエンドポイントを置き換えるだけです:

export OTEL_EXPORTER_OTLP_PROTOCOL="grpc"
export OTEL_EXPORTER_OTLP_ENDPOINT="http://127.0.0.1:4317"

gRPC エンドポイントには /v1/traces などの HTTP パスを追加できません。

3. データ報告パラメータ

基本パラメータ

環境変数 説明 推奨値または例
OTEL_SERVICE_NAME service.name を設定します。設定されていない場合、サービスは安定して識別できません。 order-service、本番環境では明示的に設定する必要があります。
OTEL_RESOURCE_ATTRIBUTES リソース属性。カンマ区切りの key=value 形式。 env=prod,version=1.0.0,team=backend
OTEL_TRACES_EXPORTER トレースエクスポーター。 DataKit に報告する場合は otlp を設定。無効にする場合は none を設定。
OTEL_METRICS_EXPORTER メトリクスエクスポーター。 メトリクスを報告する必要がある場合は otlp、それ以外の場合は none を設定。
OTEL_LOGS_EXPORTER ログエクスポーター。 ログを報告する必要がある場合は otlp、それ以外の場合は none を設定。
OTEL_PROPAGATORS サービス間のコンテキスト伝搬形式。 デフォルト tracecontext,baggage。全チェーンで互換性を維持する必要があります。
OTEL_SDK_DISABLED OpenTelemetry SDK を無効にします。 デフォルト false。緊急時に無効にする場合は true を設定。

service.name は Guance でのサービス所属に使用されます。envversion も併せて設定し、環境やバージョンによるフィルタリングを可能にすることを推奨します。その他のカスタムリソース属性は、タグとして保持されるために DataKit の customer_tags ホワイトリストに追加する必要があります。属性名の ._ に変換されます。

Node.js 自動インスツルメンテーションパラメータ

環境変数 説明 デフォルト値または例
NODE_OPTIONS アプリケーションの依存関係が読み込まれる前に、自動インスツルメンテーション登録モジュールをプリロードします。 --require @opentelemetry/auto-instrumentations-node/register
OTEL_NODE_RESOURCE_DETECTORS 指定されたリソース検出器を有効にします。複数ある場合はカンマ区切り。 デフォルト allenv,host,os,process または none に設定可能。
OTEL_NODE_ENABLED_INSTRUMENTATIONS リストされたインスツルメンテーションのみを有効にします。名前には @opentelemetry/instrumentation- プレフィックスは含めません。 http,express,pg
OTEL_NODE_DISABLED_INSTRUMENTATIONS デフォルトリストから指定されたインスツルメンテーションを無効にします。 fs,grpc
OTEL_LOG_LEVEL OpenTelemetry 内部診断ログレベル。 本番環境では info を推奨。トラブルシューティング時に一時的に debug を使用。

有効化リストと無効化リストを同時に設定する場合、最初に OTEL_NODE_ENABLED_INSTRUMENTATIONS が適用され、次に無効化リストが適用されます。同じインスツルメンテーションが両方のリストに存在する場合、最終的には無効になります。複雑な個別のインスツルメンテーション設定は、環境変数だけでは完全に実行できません。これらは本ドキュメントのコードレス接続の範囲外です。

OTLP パラメータ

環境変数 説明 推奨値または例
OTEL_EXPORTER_OTLP_PROTOCOL すべてのシグナルの OTLP プロトコル。 DataKit は http/protobuf または grpc をサポート。
OTEL_EXPORTER_OTLP_ENDPOINT すべてのシグナルで共通のベースアドレス。 HTTP:http://datakit-host:9529/otel;gRPC:http://datakit-host:4317
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT トレースのみに使用されるアドレス。共通アドレスより優先。 http://datakit-host:9529/otel/v1/traces
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT メトリクスのみに使用されるアドレス。共通アドレスより優先。 http://datakit-host:9529/otel/v1/metrics
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT ログのみに使用されるアドレス。共通アドレスより優先。 http://datakit-host:9529/otel/v1/logs
OTEL_EXPORTER_OTLP_HEADERS すべての OTLP リクエストに含まれるリクエストヘッダー。複数ある場合はカンマ区切り。 x-tenant=tenant-a。DataKit の expected_headers と一致させる必要があります。
OTEL_EXPORTER_OTLP_COMPRESSION OTLP リクエストの圧縮方式。 ホスト間の報告では gzip に設定可能。
OTEL_EXPORTER_OTLP_TIMEOUT 1回のエクスポートのタイムアウト(ミリ秒)。 10000

DataKit の OTLP/HTTP 収集は Protobuf のみをサポートしています。http/protobuf を使用し、http/json は使用しないでください。統一エンドポイントと特定のデータタイプのエンドポイントが両方存在する場合、特定のデータタイプの設定が優先されます。

サンプリングとバッチ報告パラメータ

環境変数 説明 デフォルト値または例
OTEL_TRACES_SAMPLER トレースヘッドサンプリング方式。 デフォルト parentbased_always_on。比率サンプリングには parentbased_traceidratio を使用。
OTEL_TRACES_SAMPLER_ARG サンプリング方式のパラメータ。 0.1 はルートトレースを 10% サンプリングすることを意味します。
OTEL_BSP_SCHEDULE_DELAY スパンのバッチエクスポート間隔(ミリ秒)。 デフォルト 5000
OTEL_BSP_MAX_QUEUE_SIZE エクスポート待ちのスパンキューの上限。 デフォルト 2048
OTEL_BSP_MAX_EXPORT_BATCH_SIZE 1バッチあたりの最大エクスポートスパン数。 デフォルト 512
OTEL_BSP_EXPORT_TIMEOUT スパンバッチエクスポートのタイムアウト(ミリ秒)。 デフォルト 30000
OTEL_METRIC_EXPORT_INTERVAL メトリクスエクスポート間隔(ミリ秒)。 デフォルト 60000

本番環境では、トラフィックとデータ予算に基づいてサンプリングレートを設定する必要があります。アプリケーション側のヘッドサンプリングと DataKit 側のサンプリングが同時に有効になっている場合、最終的な保持率は相乗効果で低下するため、サンプリングの場所を統一して計画する必要があります。

補足:コードによる接続

本ドキュメントでは、前述のコードレス方式を優先的に使用することを推奨します。Resource、Exporter、または個別のインスツルメンテーションを詳細に制御する必要がある場合は、従来の SDK コードによる接続方式も使用できます。

依存関係のインストール

npm install --save \
  @opentelemetry/api \
  @opentelemetry/sdk-node \
  @opentelemetry/resources \
  @opentelemetry/exporter-trace-otlp-proto \
  @opentelemetry/instrumentation-http

サンプルコード

OpenTelemetry はビジネスモジュールが読み込まれる前に初期化する必要があります:

const { NodeSDK } = require('@opentelemetry/sdk-node');
const { resourceFromAttributes } = require('@opentelemetry/resources');
const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http');
const {
  OTLPTraceExporter,
} = require('@opentelemetry/exporter-trace-otlp-proto');

const resource = resourceFromAttributes({
  'service.name': 'orders-api',
  'service.version': '1.0.0',
  'deployment.environment.name': 'prod',
});

const sdk = new NodeSDK({
  resource,
  traceExporter: new OTLPTraceExporter({
    url: 'http://127.0.0.1:9529/otel/v1/traces',
  }),
  instrumentations: [new HttpInstrumentation()],
});

async function main() {
  await sdk.start();
  require('./app');
}

process.once('SIGTERM', async () => {
  await sdk.shutdown();
  process.exit(0);
});

main().catch(error => {
  console.error(error);
  process.exit(1);
});

コード方式と NODE_OPTIONS=--require .../register で 2 つの SDK を重複して初期化しないでください。コード方式を選択した場合は、コードレス登録モジュールのプリロードパラメータを削除する必要があります。

補足:Node.js プロファイル拡張

Node.js プロファイルは、標準の OpenTelemetry トレースとメトリクス以外のパフォーマンスプロファイリングデータを補完するために使用されます。現在サポートされているプロファイルタイプ:

  • wall
  • heap

実際の接続時には、まず wall を有効にし、収集オーバーヘッドと報告パイプラインの安定性を確認した後、必要に応じて heap を有効にすることを推奨します。

プロファイル拡張のインストール

npm install --save \
  @cloudcare/profiler-nodejs \
  @datadog/pprof \
  @opentelemetry/resources

最小接続例

const { resourceFromAttributes } = require('@opentelemetry/resources');
const {
  DatakitProfilingExporter,
  NodeProfiling,
} = require('@cloudcare/profiler-nodejs');

const profiler = new NodeProfiling({
  resource: resourceFromAttributes({
    'service.name': 'orders-api',
    'service.version': '1.2.3',
    'deployment.environment.name': 'prod',
  }),
  exporter: new DatakitProfilingExporter({
    endpoint: 'http://127.0.0.1:9529/profiling/v1/input',
  }),
  profileTypes: ['wall'],
  cpuProfilingEnabled: true,
});

async function main() {
  await profiler.start();
  require('./app');
}

process.once('SIGTERM', async () => {
  await profiler.shutdown();
  process.exit(0);
});

main().catch(error => {
  console.error(error);
  process.exit(1);
});

OpenTelemetry SDK との併用

アプリケーションが前のセクションの SDK コード方式を採用している場合、同じ Resource を再利用できます:

const { NodeSDK } = require('@opentelemetry/sdk-node');
const { resourceFromAttributes } = require('@opentelemetry/resources');
const {
  DatakitProfilingExporter,
  NodeProfiling,
} = require('@cloudcare/profiler-nodejs');

const resource = resourceFromAttributes({
  'service.name': 'orders-api',
  'service.version': '1.2.3',
  'deployment.environment.name': 'prod',
});

const sdk = new NodeSDK({ resource });
const profiling = new NodeProfiling({
  resource,
  exporter: new DatakitProfilingExporter({
    endpoint: 'http://127.0.0.1:9529/profiling/v1/input',
  }),
});

async function main() {
  await sdk.start();
  await profiling.start();
  require('./app');
}

process.once('SIGTERM', async () => {
  await profiling.shutdown();
  await sdk.shutdown();
  process.exit(0);
});

main().catch(error => {
  console.error(error);
  process.exit(1);
});

パイプラインを検証する際に、手動で一度収集をトリガーできます:

await profiling.collectOnce();

プロファイル推奨設定

パラメータ デフォルト値 説明
endpoint http://127.0.0.1:9529/profiling/v1/input プロファイルのアップロード先アドレス。
profileTypes ['wall', 'heap'] 収集タイプ。最初は ['wall'] を使用することを推奨。
intervalMillis 60000 定期収集の間隔。
wallDurationMillis 10000 1回の wall プロファイルの継続時間。

デフォルトでは、拡張機能は 60 秒ごとに収集を実行し、wall プロファイルは 10 秒間継続し、データを /profiling/v1/input に送信します。現在のエクスポーターは、wall.pprofspace.pprof、および今回の収集を説明する event.json を送信します。ここで、profilerddtracefamilynodejsformatpprof であり、Guance の Node.js プロファイル解析パイプラインとの互換性のために使用されます。

実行環境に globalThis.fetch がない場合は、fetch の実装を明示的に提供する必要があります。プロセス終了前にプロファイルが失われるのを防ぐために、終了シグナルハンドラで shutdown() を呼び出す必要があります。トレースとメトリクスのみが必要な場合は、プロファイル拡張をインストールする必要はありません。

接続の確認

サポートされているインスツルメンテーションライブラリによって処理されたアプリケーションのルートにリクエストを送信し、DataKit ホストで受信ログを確認します:

curl http://127.0.0.1:8080/
sudo tail -f /usr/local/datakit/log/gin.log | grep '/otel/v1/'

/otel/v1/traces への POST リクエストがあり、応答コードが 200 の場合、DataKit がトレースを受信したことを示します。その後、Guance の「APM > トレース」に移動し、service:order-service で検索します。

データがない場合は、以下の順序で確認します:自動インスツルメンテーションパッケージがアプリケーションプロジェクトにインストールされているか、NODE_OPTIONS が実際の Node.js プロセスに渡されているか、登録モジュールがアプリケーションの依存関係の前に読み込まれているか、コードパスがサポートされているインスツルメンテーションライブラリにヒットしているか、OTLP エンドポイントに到達可能か。トラブルシューティング時は、一時的に OTEL_LOG_LEVEL=debug を設定し、確認が完了したら info に戻します。

プロファイルエンドポイントの到達可能性を確認するには、次を実行します:

curl -i http://127.0.0.1:9529/profiling/v1/input

プロファイルの報告が成功すると、拡張機能のデバッグログに通常 Datakit profiling export succeeded が表示されます。その後、Guance でサービスごとに Node.js プロファイルデータを確認できます。

参考資料

フィードバック

このページは役に立ちましたか?