OpenTelemetryに入門してみる(トレースを取得してみる)
とりあえずブラウザ - サーバ間のトレース が取得できるところまでを試してみる。
試した結果は https://github.com/piyoppi/otel-browser-playground にある。 このサンプルアプリケーションはVite + Honoの構成で、シンプルなバックエンドをもつフロントエンドアプリケーションを想定している。
デモ
公式ドキュメントに、Dockerで動作する、いくつかのサービスで構成されるアプリケーションの計測に関するデモがある。雰囲気をつかむのに手っ取り早く動かすことができる。
概念の理解
日本語のドキュメントがある。
OpenTelemetryは、シグナル(トレース、メトリクス、ログ、バゲッジ)を収集、処理、エクスポートするための仕様やインタフェース、および計装コンポーネントなどで構成されている
- トレース: あるエンドポイントにアクセスしたときに何がどのくらいの時間行われてい るかを追跡するもの(データフェッチ, 描画, などなど...)。これらはスパンによって表現される。
- メトリクス: 測定値。(CPU使用率、レスポンスタイム、とかとか...)
ブラウザ側のイベントをトレースしてみる
OpenTelemetryのGetting Started を見ながらソースコードを書いてみる。 内容を理解するために、コードにコメントを書いてみた。
import { BatchSpanProcessor, WebTracerProvider } from '@opentelemetry/sdk-trace-web'
import { DocumentLoadInstrumentation } from '@opentelemetry/instrumentation-document-load'
import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch'
import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request'
import { ZoneContextManager } from '@opentelemetry/context-zone'
import { registerInstrumentations } from '@opentelemetry/instrumentation'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { Resource, browserDetector } from '@opentelemetry/resources'
import { detectResourcesSync } from '@opentelemetry/resources/build/src/detect-resources'
import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions'
// OTLPTraceExporter を用いてトレースをサーバに送信するexporterを定義
const exporter = new OTLPTraceExporter({
// Collectorのエンドポイントを指定
url: 'http://localhost:55681/v1/traces',
});
// リソース(=テレメトリを生成する対象を示す属性値)の定義
// see: https://opentelemetry.io/ja/docs/concepts/resources/
let resource = new Resource({
// サービス名を設定する
[ATTR_SERVICE_NAME]: 'my-service-frontend',
});
const detectedResources = detectResourcesSync({ detectors: [browserDetector] });
resource = resource.merge(detectedResources);
// トレーサープロバイダー(= Tracerのファクトリ)を生成
// https://opentelemetry.io/ja/docs/concepts/signals/traces/#tracer-provider
// トレーサープロバイダーからトレーサーが生成され、トレーサーがスパンを生成する
const provider = new WebTracerProvider({
resource,
// BatchSpanProcessorを使うことで、いくつかのスパンをまとめてエクスポートするようになる
spanProcessors: [new BatchSpanProcessor(exporter)],
});
// provider.registerを呼び出すことで、グローバルな部分にトレーサープロバイダが登録され、
// 各種instrumentationsで利用されるということぽい
// ref: https://github.com/open-telemetry/opentelemetry-js/blob/c00f36ee436f58906ff82cd9da978c44b69ec1e9/packages/opentelemetry-sdk-trace-base/src/BasicTracerProvider.ts#L119
provider.register({
contextManager: new ZoneContextManager(),
})
// instrumentations (=計測器)を登録する
registerInstrumentations({
instrumentations: [
// HTMLのロード時の様子を計測する
new DocumentLoadInstrumentation(),
],
})
Collectorでシグナルを収集して可視化する
生成したトレースを収集するサーバをたてる。これをCollectorと言う。
otel-collector-config.yml
を記述してCollectorを設定する
receivers:
otlp:
protocols:
http:
# CORSのための設定(フロントエンドアプリケーションがlocalhost:5174で動作しているという前提がある)
cors:
allowed_origins:
- "http://localhost:5174"
endpoint: "0.0.0.0:55681"
grpc:
exporters:
# debug exporterを使うとControllerのサーバログにトレースが流れるようになる(=トレースが流れていることを確認できる)
debug:
otlp:
endpoint: "tempo:4317"
# (開発環境での動作確認のためTLSを無効化している)
tls:
insecure: true
service:
# Pipelineを定義する
# ref: https://opentelemetry.io/docs/collector/architecture/#pipelines
# シグナルはreceiversから取得され、processorsを経てexportersに出力される
pipelines:
# (今回はトレースしか設定しない)
traces:
receivers: [otlp]
exporters: [debug, otlp]
docker-compose.yml
でcollectorを起動できるようにしておく
version: '3.8'
services:
sample-otel-collector:
image: otel/opentelemetry-collector
container_name: sample-otel-collector
command: ["--config=/etc/otel-collector-config.yml"]
volumes:
- ./otel-collector-config.yml:/etc/otel-collector-config.yml
ports:
- "55681:55681"
networks:
- monitoring
networks:
monitoring:
トレースはどこかに記録しておかないといけない。このためのストレージエンジンとしてTempoをたてる。 Tempoは分散トレーシングのためのバックエンドで、トレースを保存、リストアする役割。S3などのオブジェクトストレージを保存先として利用できる。
Tempoのリポジトリ に、シグナルの可視化を担うGrafanaとの連携サンプルがある。 Grafanaは様々なシグナルを可視化するためのウェブアプリケーション(というのが現状の筆者の認識)。様々なデータソースを指定することができ、ダッシュボードを構成できる。
tempo.yml を設定しておく(筆者はまだ設定項 目を詳細に理解していないので、説明は割愛)。
TempoとGrafanaを起動するように追記したdocker-compose.yml
は最終的には以下のようになった。
version: '3.8'
services:
sample-otel-collector:
image: otel/opentelemetry-collector
container_name: sample-otel-collector
command: ["--config=/etc/otel-collector-config.yml"]
volumes:
- ./otel-collector-config.yml:/etc/otel-collector-config.yml
ports:
# フロントエンドアプリケーションから収集するためのポートをあけておく
- "55681:55681"
networks:
- monitoring
# Tempo / Grafana 関連の記述は以下のサンプルコードから引用
# ref: https://github.com/grafana/tempo/tree/main/example/docker-compose/
init:
image: &tempoImage grafana/tempo:latest
user: root
entrypoint:
- "chown"
- "10001:10001"
- "/var/tempo"
volumes:
- ./tempo-data:/var/tempo
networks:
- monitoring
memcached:
image: memcached:1.6.29
container_name: memcached
ports:
- "11211:11211"
environment:
- MEMCACHED_MAX_MEMORY=64m # Set the maximum memory usage
- MEMCACHED_THREADS=4 # Number of threads to use
networks:
- monitoring
tempo:
image: *tempoImage
container_name: tempo
command: [ "-config.file=/etc/tempo.yaml" ]
volumes:
- ./tempo.yaml:/etc/tempo.yaml
- ./tempo-data:/var/tempo
ports:
- "3200:3200" # tempo
- "9095:9095" # tempo grpc
- "4317:4317" # otlp grpc
- "4318:4318" # otlp http
depends_on:
- init
- memcached
networks:
- monitoring
grafana:
image: grafana/grafana:11.2.0
environment:
- GF_AUTH_ANONYMOUS_ENABLED=true
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
- GF_AUTH_DISABLE_LOGIN_FORM=true
- GF_FEATURE_TOGGLES_ENABLE=traceqlEditor metricsSummary
- GF_INSTALL_PLUGINS=https://storage.googleapis.com/integration-artifacts/grafana-exploretraces-app/grafana-exploretraces-app-latest.zip;grafana-traces-app
ports:
- "3000:3000"
networks:
- monitoring
networks:
monitoring:
volumes:
grafana-storage:
tempo-storage:
ここまでの状態で、フロントエンドアプリケーションと計測バックエンド(上記のdocker-compose.ymlに記述したものたち)を起動したところ、ブラウザ側でHTMLの描画に利用される各種アセットの取得のトレースを得ることができた。
Node.jsバックエンドのトレース
書きかけ...