エクスポーター

テレメトリデータの処理とエクスポート

OpenTelemetryコレクターにテレメトリーを送信し、正しくエクスポートされることを確認してください。 本番環境でコレクターを使用することはベストプラクティスです。 テレメトリーを可視化するために、JaegerZipkinPrometheus、またはベンダー固有のようなバックエンドにエクスポートしてください。

使用可能なエクスポーター

レジストリには、JavaScript 用のエクスポーターのリストが含まれています。

エクスポーターの中でも、OpenTelemetry Protocol (OTLP)エクスポーターは、OpenTelemetryのデータモデルを考慮して設計されており、OTelデータを情報の損失なく出力します。 さらに、多くのテレメトリデータを扱うツールがOTLPに対応しており(たとえば、PrometheusJaegerやほとんどのベンダー)、必要なときに高い柔軟性を提供します。 OTLPについて詳細に学習したい場合は、OTLP仕様を参照してください。

このページでは、主要なOpenTelemetry JavaScript エクスポーターとその設定方法について説明します。

OTLP

コレクターのセットアップ

OTLPエクスポーターを試し、検証するために、テレメトリーを直接コンソールに書き込むDockerコンテナでコレクターを実行できます。 空のディレクトリで、以下の内容でcollector-config.yamlというファイルを作成します。

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318
exporters:
  debug:
    verbosity: detailed
service:
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [debug]
    metrics:
      receivers: [otlp]
      exporters: [debug]
    logs:
      receivers: [otlp]
      exporters: [debug]

次に、Docker コンテナでコレクターを実行します。

docker run -p 4317:4317 -p 4318:4318 --rm -v $(pwd)/collector-config.yaml:/etc/otelcol/config.yaml otel/opentelemetry-collector

このコレクターは、OTLPを介してテレメトリーを受け取ることができるようになりました。後で、テレメトリーを監視バックエンドに送信するためにコレクターを設定することもできます。

依存関係

テレメトリーデータをOTLPエンドポイント(OpenTelemetry CollectorJaegerPrometheusなど)に送信したい場合、データを転送するために3つの異なるプロトコルから選択できます。

まず、プロジェクトの依存関係として対応するエクスポーターパッケージをインストールします。

npm install --save @opentelemetry/exporter-trace-otlp-proto \
  @opentelemetry/exporter-metrics-otlp-proto
npm install --save @opentelemetry/exporter-trace-otlp-http \
  @opentelemetry/exporter-metrics-otlp-http
npm install --save @opentelemetry/exporter-trace-otlp-grpc \
  @opentelemetry/exporter-metrics-otlp-grpc

Node.jsでの使用法

次に、OTLPエンドポイントを指すようにエクスポーターを設定します。 たとえば、Getting Startedinstrumentation.ts(またはJavaScriptを使用する場合はinstrumentation.js)ファイルを以下のように更新して、OTLP(http/protobuf)経由でトレースとメトリクスをエクスポートできます。

/*instrumentation.ts*/
import * as opentelemetry from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-proto';
import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';

const sdk = new opentelemetry.NodeSDK({
  traceExporter: new OTLPTraceExporter({
    // オプション - デフォルトのURLはhttp://localhost:4318/v1/traces
    url: '<your-otlp-endpoint>/v1/traces',
    // オプション - 各リクエストで送信されるカスタムヘッダーのコレクション、デフォルトは空
    headers: {},
  }),
  metricReader: new PeriodicExportingMetricReader({
    exporter: new OTLPMetricExporter({
      url: '<your-otlp-endpoint>/v1/metrics', // urlはオプションで省略可能 - デフォルトはhttp://localhost:4318/v1/metrics
      headers: {}, // 各リクエストで送信されるカスタムヘッダーを含むオプションのオブジェクト
    }),
  }),
  instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
/*instrumentation.js*/
const opentelemetry = require('@opentelemetry/sdk-node');
const {
  getNodeAutoInstrumentations,
} = require('@opentelemetry/auto-instrumentations-node');
const {
  OTLPTraceExporter,
} = require('@opentelemetry/exporter-trace-otlp-proto');
const {
  OTLPMetricExporter,
} = require('@opentelemetry/exporter-metrics-otlp-proto');
const { PeriodicExportingMetricReader } = require('@opentelemetry/sdk-metrics');

const sdk = new opentelemetry.NodeSDK({
  traceExporter: new OTLPTraceExporter({
    // オプション - デフォルトのURLはhttp://localhost:4318/v1/traces
    url: '<your-otlp-endpoint>/v1/traces',
    // オプション - 各リクエストで送信されるカスタムヘッダーのコレクション、デフォルトは空
    headers: {},
  }),
  metricReader: new PeriodicExportingMetricReader({
    exporter: new OTLPMetricExporter({
      url: '<your-otlp-endpoint>/v1/metrics', // urlはオプションで省略可能 - デフォルトはhttp://localhost:4318/v1/metrics
      headers: {}, // 各リクエストで送信されるカスタムヘッダーを含むオプションのオブジェクト
      concurrencyLimit: 1, // 保留中のリクエストのオプション制限
    }),
  }),
  instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();

ブラウザでの使用法

ブラウザベースのアプリケーションでOTLPエクスポーターを使用する場合、以下の点に注意する必要があります。

  1. エクスポートにgRPCを使用することはサポートされていません
  2. WebサイトのContent Security Policies(CSP)がエクスポートをブロックする可能性があります
  3. Cross-Origin Resource Sharing(CORS)ヘッダーがエクスポートの送信を許可しない可能性があります
  4. コレクターをパブリックインターネットに公開する必要がある場合があります

以下では、適切なエクスポーターの使用、CSPとCORSヘッダーの設定、およびコレクターを公開する際に取るべき予防措置について説明します。

HTTP/JSONまたはHTTP/protobufでOTLPエクスポーターを使用

OpenTelemetry Collector Exporter with gRPCはNode.jsでのみ動作するため、OpenTelemetry Collector Exporter with HTTP/JSONまたはOpenTelemetry Collector Exporter with HTTP/protobufの使用に制限されます。

OpenTelemetry Collector Exporter with HTTP/JSONを使用している場合は、エクスポーターの受信側(コレクターまたはオブザーバビリティバックエンド)がhttp/jsonを受け入れることを確認し、ポートを4318に設定して適切なエンドポイントにデータをエクスポートしていることを確認してください。

CSPの設定

WebサイトでContent Security Policies(CSP)を使用している場合は、OTLPエンドポイントのドメインが含まれていることを確認してください。 コレクターエンドポイントがhttps://collector.example.com:4318/v1/tracesの場合、以下のディレクティブを追加します。

connect-src collector.example.com:4318/v1/traces

CSPがOTLPエンドポイントを含んでいない場合、エンドポイントへのリクエストがCSPディレクティブに違反していることを示すエラーメッセージが表示されます。

CORSヘッダーの設定

Webサイトとコレクターが異なるオリジンでホストされている場合、ブラウザがコレクターへのリクエストをブロックする可能性があります。 Cross-Origin Resource Sharing(CORS)のための特別なヘッダーを設定する必要があります。

OpenTelemetry Collectorは、httpベースのレシーバーがWebブラウザからのトレースを受け入れるために必要なヘッダーを追加する機能を提供しています。

receivers:
  otlp:
    protocols:
      http:
        include_metadata: true
        cors:
          allowed_origins:
            - https://foo.bar.com
            - https://*.test.com
          allowed_headers:
            - Example-Header
          max_age: 7200

コレクターの安全な公開

Webアプリケーションからテレメトリーを受信するには、エンドユーザーのブラウザがコレクターにデータを送信できるようにする必要があります。 Webアプリケーションがパブリックインターネットからアクセス可能な場合、コレクターもすべての人がアクセス可能にする必要があります。

コレクターを直接公開するのではなく、その前にリバースプロキシ(NGINX、Apache HTTP Server、…)を配置することをお勧めします。 リバースプロキシは、SSL オフロード、適切なCORSヘッダーの設定、およびWebアプリケーション固有の多くの機能を処理できます。

以下では、人気のあるNGINX Webサーバーの設定例を示します。

server {
    listen 80 default_server;
    server_name _;
    location / {
        # プリフライトリクエストの処理
        if ($request_method = 'OPTIONS') {
             add_header 'Access-Control-Max-Age' 1728000;
             add_header 'Access-Control-Allow-Origin' 'name.of.your.website.example.com' always;
             add_header 'Access-Control-Allow-Headers' 'Accept,Accept-Language,Content-Language,Content-Type' always;
             add_header 'Access-Control-Allow-Credentials' 'true' always;
             add_header 'Content-Type' 'text/plain charset=UTF-8';
             add_header 'Content-Length' 0;
             return 204;
        }

        add_header 'Access-Control-Allow-Origin' 'name.of.your.website.example.com' always;
        add_header 'Access-Control-Allow-Credentials' 'true' always;
        add_header 'Access-Control-Allow-Headers' 'Accept,Accept-Language,Content-Language,Content-Type' always;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://collector:4318;
    }
}

コンソール

計装をデバッグしたり、開発環境でローカルに値を確認したりするために、テレメトリーデータをコンソール(標準出力)に書き込むエクスポーターを使用できます。

Getting Started の Node.jsまたは手動計装ガイドに従った場合、コンソールエクスポーターはすでにインストールされています。

ConsoleSpanExporter@opentelemetry/sdk-trace-nodeパッケージに含まれており、ConsoleMetricExporter@opentelemetry/sdk-metricsパッケージに含まれています。

Jaeger

バックエンドのセットアップ

Jaegerは、トレースデータを受信するためにOTLPをネイティブでサポートしています。UIがポート16686でアクセス可能で、OTLPがポート4317と4318で有効になったDockerコンテナでJaegerを実行できます。

docker run --rm \
  -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
  -p 16686:16686 \
  -p 4317:4317 \
  -p 4318:4318 \
  -p 9411:9411 \
  jaegertracing/all-in-one:latest

使用方法

OTLPエクスポーターをセットアップするための手順に従ってください。

Prometheus

メトリクスデータをPrometheusに送信するには、PrometheusのOTLPレシーバーを有効にしてOTLPエクスポーターを使用するか、Prometheusエクスポーターを使用できます。 Prometheusエクスポーターは、メトリクスを収集しリクエストに応じてPrometheusテキスト形式にシリアライズするHTTPサーバーを起動するMetricReaderです。

バックエンドのセットアップ

PrometheusをDockerコンテナで実行し、ポート9090でアクセスできるようにするには、以下の手順に従ってください。

以下の内容でprometheus.ymlというファイルを作成します。

scrape_configs:
  - job_name: dice-service
    scrape_interval: 5s
    static_configs:
      - targets: [host.docker.internal:9464]

UIがポート9090でアクセス可能なDockerコンテナでPrometheusを実行します。

docker run --rm -v ${PWD}/prometheus.yml:/prometheus/prometheus.yml -p 9090:9090 prom/prometheus --enable-feature=otlp-write-receive

依存関係

アプリケーションの依存関係としてエクスポーターパッケージをインストールします。

npm install --save @opentelemetry/exporter-prometheus

エクスポーターを使用し、Prometheusバックエンドにデータを送信するようにOpenTelemetry設定を更新します。

import * as opentelemetry from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';

const sdk = new opentelemetry.NodeSDK({
  metricReader: new PrometheusExporter({
    port: 9464, // オプション - デフォルトは9464
  }),
  instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
const opentelemetry = require('@opentelemetry/sdk-node');
const {
  getNodeAutoInstrumentations,
} = require('@opentelemetry/auto-instrumentations-node');
const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus');
const { PeriodicExportingMetricReader } = require('@opentelemetry/sdk-metrics');
const sdk = new opentelemetry.NodeSDK({
  metricReader: new PrometheusExporter({
    port: 9464, // オプション - デフォルトは9464
  }),
  instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();

上記の設定により、http://localhost:9464/metricsでメトリクスにアクセスできます。 PrometheusまたはPrometheusレシーバーを持つOpenTelemetry Collectorが、このエンドポイントからメトリクスをスクレイプできます。

Zipkin

バックエンドのセットアップ

以下のコマンドを実行して、ZipkinをDockerコンテナで実行できます。

docker run --rm -d -p 9411:9411 --name zipkin openzipkin/zipkin

依存関係

トレースデータをZipkinに送信するには、ZipkinExporterを使用できます。

アプリケーションの依存関係としてエクスポーターパッケージをインストールします。

npm install --save @opentelemetry/exporter-zipkin

エクスポーターを使用し、Zipkinバックエンドにデータを送信するようにOpenTelemetry設定を更新します。

import * as opentelemetry from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { ZipkinExporter } from '@opentelemetry/exporter-zipkin';

const sdk = new opentelemetry.NodeSDK({
  traceExporter: new ZipkinExporter({}),
  instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
const opentelemetry = require('@opentelemetry/sdk-node');
const {
  getNodeAutoInstrumentations,
} = require('@opentelemetry/auto-instrumentations-node');
const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin');

const sdk = new opentelemetry.NodeSDK({
  traceExporter: new ZipkinExporter({}),
  instrumentations: [getNodeAutoInstrumentations()],
});

カスタムエクスポーター

最後に、独自のエクスポーターを作成することもできます。 詳細については、APIドキュメントのSpanExporterインターフェースを参照してください。

スパンとログレコードのバッチ処理

OpenTelemetry SDKは、スパンを1つずつ発行する(「シンプル」)か、バッチで発行するかを選択できるデフォルトのスパンプロセッサーとログレコードプロセッサーのセットを提供しています。 バッチ処理の使用が推奨されますが、スパンやログレコードをバッチ処理したくない場合は、かわりに以下のようにシンプルプロセッサーを使用できます。

/*instrumentation.ts*/
import * as opentelemetry from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';

const sdk = new NodeSDK({
  spanProcessors: [new SimpleSpanProcessor(exporter)],
  instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
/*instrumentation.js*/
const opentelemetry = require('@opentelemetry/sdk-node');
const {
  getNodeAutoInstrumentations,
} = require('@opentelemetry/auto-instrumentations-node');

const sdk = new opentelemetry.NodeSDK({
  spanProcessors: [new SimpleSpanProcessor(exporter)],
  instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();