OpenTelemetry を使用してサポートされていないランタイムをインスツルメントする。

概要

アプリケーションのランタイムが Datadog SDK でネイティブにサポートされていない場合は、OpenTelemetry SDK を使用して Datadog にテレメトリを送信できます。このアプローチでは、ネイティブランタイムのサポートを待たずにトレースとメトリクスを取得できます。

このガイドでは、例として Bun アプリケーションをインスツルメントする手順を説明します。Bun はほとんどの Node.js API と互換性があるため、OpenTelemetry Node.js SDK を使用して Bun アプリケーションをインスツルメントできます。OpenTelemetry SDK と互換性のある他のサポートされていないランタイムにも、同じパターンを適用できます。

サポートレベル

このガイドはCustom Components サポートレベルに該当します。Datadog はこのドキュメントを出発点として提供しますが、ランタイムの機能やその中での OpenTelemetry SDK の動作を直接サポートするものではありません。ランタイム固有の問題については、OpenTelemetry コミュニティまたはランタイムのメンテナーにお問い合わせください。

前提条件

  • Datadog にデータを送信するように構成された OpenTelemetry 互換バックエンド。DDOT Collector、OpenTelemetry Collector、または直接 OTLP インジェストなどのセットアップオプションについては、Send OpenTelemetry Data to Datadog を参照してください。
  • Bun がインストールされていること (v1.0 以降)。
  • インスツルメントする Bun アプリケーション。

Bun アプリケーションのインスツルメント

OpenTelemetry パッケージのインストール

プロジェクトのルートディレクトリから、必要な OpenTelemetry パッケージをインストールします。

bun add @opentelemetry/api \
  @opentelemetry/sdk-node \
  @opentelemetry/sdk-metrics \
  @opentelemetry/auto-instrumentations-node \
  @opentelemetry/exporter-trace-otlp-http \
  @opentelemetry/exporter-metrics-otlp-http \
  @opentelemetry/resources \
  @opentelemetry/semantic-conventions

テレメトリ初期化モジュールの作成

Node.js では、OpenTelemetry は通常 --require フラグに基づいて読み込まれ、アプリケーションコードが実行される前にインスツルメンテーションをプリロードします。Bun のモジュール解決システムは動作が異なるため、代わりにプログラムで OpenTelemetry を初期化する必要があります。

OpenTelemetry Node.js SDK を構成する tracing.ts ファイルを作成します。

tracing.ts

import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';
import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';
import { resourceFromAttributes } from '@opentelemetry/resources';
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';

const resource = resourceFromAttributes({
  [ATTR_SERVICE_NAME]: process.env.OTEL_SERVICE_NAME || '<YOUR_SERVICE_NAME>',
  [ATTR_SERVICE_VERSION]: process.env.OTEL_SERVICE_VERSION || '1.0.0',
  'telemetry.sdk.runtime': 'bun',
});

const sdk = new NodeSDK({
  resource,
  traceExporter: new OTLPTraceExporter(),
  metricReaders: [new PeriodicExportingMetricReader({
    exporter: new OTLPMetricExporter(),
  })],
  instrumentations: [getNodeAutoInstrumentations({
    // Disable fs instrumentation to avoid compatibility issues with Bun
    '@opentelemetry/instrumentation-fs': { enabled: false },
  })],
});

sdk.start();

process.on('SIGTERM', () => {
  sdk.shutdown()
    .then(() => console.log('OpenTelemetry SDK shut down'))
    .catch((err) => console.error('Error shutting down OpenTelemetry SDK', err))
    .finally(() => process.exit(0));
});

<YOUR_SERVICE_NAME> をアプリケーションのサービス名に置き換えます。

アプリケーションのエントリポイントでテレメトリを初期化する

他のアプリケーションをインポートする前に、tracing.ts モジュールをインポートします。自動インスツルメンテーションのためにライブラリにパッチを適用するには、OpenTelemetry SDK を最初に初期化する必要があります。

index.ts

import './tracing';

// Import your application code after tracing is initialized
import { startApp } from './app';

startApp();

環境変数の構成

OTLP エクスポーターエンドポイントとサービス ID を構成するには、次の環境変数を設定します。

export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"
export OTEL_SERVICE_NAME="<YOUR_SERVICE_NAME>"

OTEL_EXPORTER_OTLP_ENDPOINT の値は、セットアップによって異なります。

  • ローカルコレクター (DDOT または OpenTelemetry Collector): http://localhost:4318 (デフォルトは HTTP) または http://localhost:4317 (gRPC)
  • リモートコレクター: コレクターのアドレスとポートを使用します。

その他の構成オプションについては、OpenTelemetry 環境変数の仕様 を参照してください。

アプリケーションの実行

Bun アプリケーションを開始します。

bun run index.ts

Bun ネイティブ API の手動インスツルメンテーションの追加

Bun.serve()、bun:sqlite、およびネイティブファイル I/O API などの組み込み Bun API は、自動的にインスツルメントされません。これらの API からテレメトリをキャプチャするには、@opentelemetry/api パッケージを使用して手動でスパンを作成してください。

次の例では、Bun.serve() ルートハンドラーをカスタムスパンでラップしています。

server.ts

import { trace, SpanKind } from '@opentelemetry/api';

const tracer = trace.getTracer('bun-app');

export function startServer() {
  Bun.serve({
    port: 3000,
    fetch(req) {
      return tracer.startActiveSpan('handleRequest', { kind: SpanKind.SERVER }, (span) => {
        try {
          span.setAttribute('http.method', req.method);
          span.setAttribute('http.url', req.url);
          return new Response('Hello from Bun!');
        } finally {
          span.end();
        }
      });
    },
  });
}

その他の手動インスツルメンテーションパターンについては、OpenTelemetry JS インスツルメンテーションのドキュメント を参照してください。

Datadog でのトレースの確認

アプリケーションでいくつかのリクエストが処理された後に、次のようにします。

  1. Datadog の [APM] > [Traces] (トレース) に移動します。
  2. サービス名を検索します。
  3. 期待されるスパンとメタデータを含むトレースが表示されることを確認します。

制限事項

  • 自動インスツルメンテーションの対応範囲: OpenTelemetry Node.js 自動インスツルメンテーションライブラリは、Bun の Node.js 互換レイヤーに依存しています。一般的なライブラリ (HTTP クライアント、Express、データベースドライバなど) は動作しますが、一部のインスツルメンテーションパッケージは期待どおりに機能しない場合があります。
  • Bun ネイティブ API: Bun.serve()、bun:sqlite、およびネイティブのファイル I/O API などの組み込み Bun API は、自動的にインスツルメントされません。例については、Bun ネイティブ API の手動インスツルメンテーションの追加を参照してください。
  • ライブラリの互換性: すべての Node.js インスツルメンテーションライブラリが Bun で動作することは保証されていません。特定の依存関係をテストし、エラーの原因となるインスツルメンテーションがある場合は、getNodeAutoInstrumentations() に構成オプションを渡してそのインスツルメンテーションを無効にしてください。@opentelemetry/instrumentation-fs パッケージは問題の原因となることが多く、上記の構成例では無効にされています。

参考資料