New Relic Now+ New Relic’s most transformative platform update yet with 20+ product launches.
Watch the event on-demand now.

OpenTelemetry(OTel)は、テレメトリーデータを収集およびエクスポートするための標準化されたアプローチを提供し、最新のアプリケーション監視に不可欠なツールとなっています。強力なインテリジェントオブザーバビリティプラットフォームであるNew Relicと組み合わせると、 OpenTelemetryデータの可能性を最大限に活用して、インサイトの取得と最適化を行うことができます。

このブログ記事では、New Relicクエリ言語(NRQL)を使用して、New RelicでOpenTelemetryデータをクエリするプロセスについて説明します。この記事を読み終える頃には、OpenTelemetryデータがNew Relicデータベース(NRDB)にどのように保存されるか、またアプリケーションでその有用性を最大限に高める方法について、しっかりと理解できるようになります。

このブログ記事で使用されているコードは、こちらから入手できます。

OpenTelemetryのデータ型について

クエリプロセスに進む前に、OpenTelemetryデータの基本要素を把握することが重要です。OpenTelemetryはさまざまなメトリクスデータモデルを利用して、多様な種類のテレメトリー情報を取得します。これらには以下が含まれます。

  1. カウンター:処理されたリクエストの数や処理された例外の合計数など、累積的で減少しない値を表します。
  2. アップダウンカウンター:アクティブなデータベース接続の数など、時間の経過とともに増加または減少する可能性のある値を追跡します。
  3. ヒストグラム:カウント、合計、最小、最大などの集計された測定値を提供します。これは、アプリサーバーのレスポンスタイムに役立ちます。
  4. 監視可能なカウンター:カウンターに似ていますが、コールバックを介した非同期テレメトリーレポートが可能になります。これは、CPU時間などのプロセスメトリクスに最適です。

New Relicを使用したOpenTelemetryデータの保存とクエリ

このブログ記事を事前にお読みになり、OpenTelemetryに関連する3つの異なるメトリクスデータモデルをよく理解しておくことをお勧めします。大まかに言うと、このプロセスには4つのステップがあります。

1. 計装は、OpenTelemetryインストゥルメンテーションコードを使用して作成されます。

2. OpenTelemetry SDKはそれを送信用のOpenTelemetryプロトコル(OTLP)データ形式に変換します。

3. 送信されたデータはデータストア(この場合はNRDB)に保存されます。

4. NRQL使用して、NRDBに保存されているOpenTelemetryデータをクエリします。

以下の表-1は、計装、OTLP、データストア間のデータ型のマッピングを示しています。

表-1:OTLPへの計装からNew Relicへのマッピング

原点(コード内)

送信中(OTLP)

保存時(New Relic)

カウンター

単調な累積合計

カウント*

アップダウンカウンター

非単調な累積合計

ゲージ

ヒストグラム

ヒストグラム

分布

監視可能なカウンター

単調な累積合計

カウント*

*注意:以下の環境変数がdeltaに設定されている場合、カウンターおよび監視可能なカウンターデータ型はNew RelicのCountデータ型に変換されます。環境変数が設定されていない場合は、New RelicではCumulativeCountに変換されます。

set OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=delta

それぞれのデータ型を詳しく調べて、 New Relicでそれらを計装、保存、クエリする方法を探ってみましょう。

前提条件

このブログ記事で説明したデータ型を計装、保存、クエリする前に、以下が必要です。

  1. お気に入りのIDEを使用して、app.pyという名前のファイルを作成します。
  2. 次の3つの依存関係をインストールします。
  • pip install opentelemetry-api
  • pip install opentelemetry-sdk
  • pip install opentelemetry-exporter-otlp-proto-http
  1. 以下の環境変数を追加します。
export OTEL_SERVICE_NAME=MyPythonService
export OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.nr-data.net
export OTEL_EXPORTER_OTLP_HEADERS=api-key=<New Relic Ingest License Key>
export OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT=4095
export OTEL_EXPORTER_OTLP_COMPRESSION=gzip
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf 
export OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=delta
export OTEL_RESOURCE_ATTRIBUTES=service.instance.id=123
  1. app.pyに次のコードを追加します。
from opentelemetry import metrics
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.exporter.otlp.proto.http.metric_exporterimport OTLPMetricExporter
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
from opentelemetry.metrics import CallbackOptions, Observation
from typing import Iterable

metric_reader = PeriodicExportingMetricReader(OTLPMetricExporter(), export_interval_millis=5000) # 収集サイクルは5秒ごと
provider = MeterProvider(metric_readers=[metric_reader])

# グローバルなデフォルトのメータープロバイダーを設定する
metrics.set_meter_provider(provider)

# グローバルメータープロバイダーからメーターを作成する
meter = metrics.get_meter("my.meter.name")

カウンター

説明:これらは加算される非減少値です。

マッピング: 

原点(コード内)

送信中(OTLP)

保存時(New Relic)

カウンター

単調な累積合計

カウント

単調な累積合計の例をいくつか示します。

  • 処理されたリクエスト数
  • 処理された例外の合計数
  • 送信されたネットワークバイト数

ステップ1:OpenTelemetryによるインストゥルメンテーション

Pythonでカウンターを作成するには:このコードスニペットは、mycounter.incrementsという計装を作成します。次に、計装の3つの値をOTLPエンドポイントに送信します。収集サイクルは(前のステップで)5秒に1回と設定されているため、スリープ時間を導入すると、収集サイクルが3回発生します。

my_counter = meter.create_counter("mycounter.increments")
# 5秒の収集サイクルごとに1つの値が送信されるように、10秒間スリープする
my_counter.add(3)
time.sleep(10)
my_counter.add(5)
time.sleep(10)
my_counter.add(10)

ステップ2:NRDBへの保存

New Relicに到達すると、OpenTelemetryデータはNRDBに保存されます。以下の表-2は、カウンターのオリジン値がNew Relicにどのように保存されるかを示しています。この例では、OpenTelemetryの収集サイクルは5秒です。New RelicはOpenTelemetryの累積値を取り込み、両方のデルタ値をNRDBに保存します。

表-2

収集サイクル

オリジン値

OLTP値

New Relic値

1

3

3

3

2

5

8

5

3

10

18

10

注意:デルタ値累積値をNRDBに保存する場合は、この環境変数をUNSETにしてください。

unset OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE

ステップ3:NRQLによるクエリ

次は、NRQLを使用してデータをクエリするという、興味深い部分です。NRQLは、データ分析における柔軟性と精度のために設計された強力なクエリ言語です。

以下は、NRDBにデータがどのように保存されているかを確認するためのクエリです。以下のNRQLを実行します。

SELECT * FROM Metric WHERE entity.name = 'MyPythonService' AND metricName = 'mycounter.increments'SINCE 15 MINUTES AGO
カウンターを示す表

上記のスクリーンショットは、データ型がCountに設定されていることを示しています。

特定の期間のmycounter.incrementsメトリクス値の合計を表示するには、次のコマンドを実行します。

SELECT sum(mycounter.increments)
FROM Metric
WHERE metricName = 'mycounter.increments'
SINCE 15 minutes ago UNTIL now
クエリ結果を示す画像

より高度なインサイトの場合は、 NRQLのTIMESERIES関数を使用して、変化率を時系列に分析できます。

SELECT rate(sum(mycounter.increments), 1 minute) FROM Metric WHERE entity.name = 'MyPythonService' AND metricName = `mycounter.increments`SINCE 15 MINUTES AGO TIMESERIES

このクエリにより、時系列のメトリクスの変化率が提供され、傾向分析とパフォーマンス監視が可能になります。

時系列メトリクスを示すグラフ

アップダウンカウンター

説明:時間の経過とともに上昇または下降する可能性がある値。

マッピング:

原点(コード内)

送信中(OTLP)

保存時(New Relic)

アップダウンカウンター

非単調な累積合計

ゲージ

以下はアップダウンカウンターの例です。

  • データベース接続数
  • キャッシュのサイズ

ステップ1:OpenTelemetryによるインストゥルメンテーション

Pythonでアップダウンカウンターを作成するには:

# アップダウンカウンターの計装を作成する
my_updown_counter = meter.create_up_down_counter("my_updown_counter")

# 5秒の収集サイクルごとに1つの値が確保されるように、10秒間スリープする
my_updown_counter.add(3)
time.sleep(10)
my_updown_counter.add(-1)
time.sleep(10)
my_updown_counter.add(10)

ステップ2:NRDBへの保存

以下の表-3 は、OpenTelemetryデータ型がNew Relicのゲージデータ型にどのようにマッピングされるかを示しています。収集サイクル期間は5秒に設定されています。

表-3

収集サイクル

オリジン値

OTLP値

New Relic値

1

3

3

3

2

-1

2

2

3

10

12

12

ステップ3:NRQLによるクエリ

NRQLを使用してすべての myupdowncounterメトリクス値を表示するには(データ型がゲージであることに留意):

SELECT * FROM Metric WHERE entity.name = 'MyPythonService' AND metricName = 'myupdowncounter' SINCE 15 MINUTES AGO
該当なし

特定の期間のmyupdowncountermetriks値の最新値を表示するには、最新キーワードを使用します。上記のスクリーンショットに示すように、同様にキーワード合計、最小最大を使用することもできます。

SELECT latest(myupdowncounter) FROM Metric WHERE entity.name = 'MyPythonService' AND metricName = 'myupdowncounter' SINCE 15 MINUTES AGO
クエリの結果を示す画像

ヒストグラム

説明:カウント、合計、最小、最大などの複数の集計された測定値を提供する1つのメトリクス。

マッピング:

原点(コード内)

送信中(OTLP)

保存時(New Relic)

ヒストグラム

ヒストグラム

分布

ヒストグラムの例を次に示します。

  • アプリサーバーのレスポンスタイム

ステップ1:OpenTelemetryによるインストゥルメンテーション

重要:ヒストグラムにはこの環境変数を設定する必要があります。

set OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=delta

Pythonでヒストグラムを作成するには:

# ヒストグラム計装を作成する
my_histogram = meter.create_histogram("myhistogram")

# ヒストグラムの値を記録するこれにより、9 つの値/カウントを持つヒストグラムが作成されます。
for i in range(1, 10):
    latency  = random.randint(1,1000)
    my_histogram.record(latency,attributes={"attr1": "value1"})

ステップ2:NRQLによるクエリ

NRQLを使用してすべてのヒストグラムメトリクス値を表示するには:

SELECT * FROM Metric WHERE metricName = 'myhistogram' SINCE 5 minutes AGO
ヒストグラムを示す表

NRQL使用してヒストグラムメトリクス値の合計のみを表示するには(この場合、グラフタイプはJSONに設定済み):

SELECT sum(myhistogram) FROM Metric WHERE metricName = 'myhistogram' SINCE 5 minutes AGO
該当なし

監視可能なカウンター

説明:非同期の加算非減少値。

マッピング: 

原点(コード内)

送信中(OTLP)

保存時(New Relic)

監視可能なカウンター

単調な累積合計

カウント

以下に、監視可能なカウンターの例をいくつか示します。

  • プロセスあたりのページフォールト数
  • スレッドあたりのCPU時間

ステップ1:OpenTelemetryによるインストゥルメンテーション

Pythonで監視可能なカウンターを作成するには:

# コールバック関数を登録する
def pf_callback(options: CallbackOptions) -> Iterable[Observation]:
 # 登録されるとコールバック関数が自動的に呼び出される
# 収集サイクルごと(5秒ごと)
    return [Observation(random.randint(1,100), {"pid": 1}),
            Observation(random.randint(1,100),{"pid": 2}),
            Observation(random.randint(1,100),{"pid": 3})]

 # 監視可能なカウンターを作成する(非同期)
def createObservableCounter(meter):
 meter.create_observable_counter(name="myobservablecounter",description="process page faults", callbacks = [pf_callback])
 time.sleep(20)

ステップ2:NRDBへの保存

以下の表-4は、監視可能なカウンターのオリジン値がNew Relicにどのように保存されるかを示しています。この例では、OpenTelemetryの収集サイクルは5秒です。

表-4

収集サイクル

PID

オリジン値

OTLP値

New Relic値

1

1

56

56

56

1

2

76

76

76

1

3

12

12

12

2

1

74

130

74

2

2

42

118

42

2

3

51

63

51

注: NRDBに保存するデルタ値累積値のみを保存する場合は、この環境変数をUNSETにします。

unset OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE

このデータがNRDBにどのように保存されるかを見てみましょう。

SELECT myobservablecounter, pid, *
FROM Metric
WHERE metricName = 'myobservablecounter'
SINCE 5 minutes ago UNTIL now
該当なし

ステップ3:NRQLによるクエリ

特定の期間のmyobservablecounterメトリクス値の合計を表示するには、次のコマンドを実行します。

SELECT sum(myobservablecounter)
FROM Metric
WHERE metricName = 'myobservablecounter'
SINCE 15 minutes ago UNTIL now
該当なし

myobservablecounterメトリクス値の変化率をTIMESERIESとして表示するには、次のようにします。

SELECT rate(sum(myobservablecounter), 1 minute) FROM Metric WHERE entity.name = 'MyPythonService' AND metricName = 'myobservablecounter' SINCE 15 MINUTES AGO TIMESERIES
該当なし

監視可能なヒストグラムや監視可能なゲージなどの追加のメトリクスタイプも、上記と同様のアプローチを使用してNew Relicに送信できることに注意してください。詳細については、次のリソースをご覧ください。

まとめ

このステップバイステップガイドに従うことで、New RelicでOpenTelemetryデータを効果的にクエリできます。NRQLによるクエリ性能を使いこなして、貴重なインサイトの獲得、システムの最適化を行い、アプリケーションのオブザーバビリティを高めます。