opentelemetry-ottl について
OpenTelemetry Collectorの設定を行う人向けのOTTLスキルです。変換、フィルタリング、ルーティングの記述とデバッグを、コンテキストやエラー処理の解説とともに支援します。
主な機能
- 01OTTL文の作成とデバッグ
- 02シグナルコンテキストとパス式の解説
- 03Collectorエラーパターンの診断
- 04テレメトリーの変換・フィルタリング・ルーティング
- 05カーディナリティ制御とPIIの秘匿
活用シーン
- 01transformプロセッサーのフィールド変換を修正
- 02コンテキストや型の不一致を調査
- 03メトリクス属性のカーディナリティを削減
- 04ログ内の個人情報を秘匿
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ coralogix/ cx-skills --skill opentelemetry-ottlインストール後、Claude Code で/opentelemetry-ottlを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
evals/datapoint-filter-missing-tenant/capability.txtcriteria.jsontask.mdevals/delete-matching-keys-header-prefix/capability.txtcriteria.jsontask.mdevals/error-mode-propagate-vs-ignore/capability.txtcriteria.jsontask.mdevals/filter-vs-transform-dropping/capability.txtcriteria.jsontask.mdevals/first-non-nil-fallback-chain/capability.txtcriteria.jsontask.mdevals/histogram-bucket-extraction-drop/capability.txtcriteria.jsontask.mdevals/json-body-parsejson-extraction/capability.txtcriteria.jsontask.mdevals/keep-keys-ismap-guard/capability.txtcriteria.jsontask.mdevals/log-attr-to-resource-for-exporter/capability.txtcriteria.jsontask.mdevals/log-timestamp-mutation/capability.txtcriteria.jsontask.md詳細
OTTL
OpenTelemetry Transformation Language(OTTL)は、アプリケーションコードを変更せずに、OTel Collector のパイプライン内でテレメトリを変換、フィルタリング、ルーティングします。transform プロセッサ、filter プロセッサ、routing コネクターで OTTL ステートメントを記述またはデバッグする際に、このスキルを読み込んでください。
このスキルを使用する場面
| ユースケース | 対応方法 |
|---|---|
| 条件に応じて値やフィールドを変更する | 適切なコンテキストを指定した transform プロセッサ |
| テレメトリを完全に破棄する(一致条件=破棄) | filter プロセッサ |
| 静的なリソース属性をすべての場所で設定する | OTTL よりシンプルな resource プロセッサ |
| リソースフィールドをスパンまたはログにコピーする | 適切なコンテキストを指定した transform |
| テレメトリを異なるパイプラインにルーティングする | routing コネクター |
| メトリクスまたはトレースのカーディナリティを削減する | keep_keys / delete_matching_keys を使った transform → references/cardinality.md |
| ヒストグラムの _sum/_count を単独のメトリクスとして抽出し、ヒストグラムを破棄する | context: metric で extract_sum_metric / extract_count_metric を使った transform の後、元のヒストグラムを破棄する filter |
| PII をマスキングまたは仮名化する | SHA256 / replace_all_patterns を使った transform → references/redaction.md |
| データがない、DNS、レシーバー/エクスポーターの問題、またはパイプラインの接続をデバッグする | OTTL の問題ではありません。先にその旨を伝えてください |
各トピックの参考資料は references/ にあり、このファイルの末尾にあるリファレンスに一覧があります。質問に、最近確認していない特定のプロセッサ、コンテキスト、関数が関係する場合、またはユーザーが Collector のエラーを貼り付けた場合は、回答する前に該当するリファレンスファイルを確認してください。記憶を頼りに推測するより、対象を絞って1、2か所読むほうが確実です。
主な概念
コンテキストとパス式
context: によって attributes が何を意味するかが決まります。context: resource では、attributes["k"] はリソース属性です。context: log または context: span では、attributes["k"] はレコードレベルの属性です。リソースにアクセスするには resource.attributes["k"] を使います。コンテキストを間違えても、nil になってエラーは発生しません。→ references/contexts.md
| シグナル | 有効なコンテキスト |
|---|---|
| ログ | resource、scope、log |
| トレース | resource、scope、span、spanevent |
| メトリクス | resource、scope、metric、datapoint |
メトリクスレベルの編集(名前、説明、単位)は context: metric で行います。シリーズごとのラベル/属性の編集は context: datapoint で行います。同じブロック内で両方を混在させると、一方がエラーなしで何も実行しません。→ references/contexts.md
ログイベントのタイムスタンプは、context: log で Time(...) を使って time を設定するか、整数のナノ秒値で time_unix_nano を設定して変更できます。スパンステータスの確認は context: span で行います。生の数値との比較よりも、STATUS_CODE_ERROR、STATUS_CODE_OK、STATUS_CODE_UNSET を優先してください。→ references/transformations.md
エラーモード
| モード | 動作 |
|---|---|
propagate(デフォルト) | OTTL のランタイムエラーが発生するとパイプラインを停止します — データ損失の原因になります |
ignore | エラーをログに記録し、ステートメントをスキップしてパイプラインを続行します — 本番環境で使用してください |
silent | ステートメントをスキップし、エラーのログ記録を抑制します |
すべての transform プロセッサと filter プロセッサで error_mode を明示的に設定してください。デフォルトの propagate は、最初のランタイムエラー(オプションフィールドの欠落、型の不一致、nil のインデックス参照など)でパイプライン全体を停止し、それ以降のレコードをすべて暗黙的に破棄します。「1回の失敗の後にパイプラインが無反応になる」問題は、ほとんどの場合、error_mode キーが設定されていないことが原因です。
processors:
transform:
error_mode: ignore # log, skip the statement, continue the pipeline
log_statements:
- context: log
statements:
- set(attributes["env"], resource.attributes["deployment.environment"])
エラーパターン
修正を提案する前に、Collector のメッセージを根本原因に対応付けます。
| Collector のメッセージ | 根本原因 | 最初の対応 |
|---|---|---|
INVALID_ARGUMENT | 型の不一致、無効な関数入力、または現在のコンテキストに対して無効なパス | nil/型ガードを追加し、現在のコンテキストを確認します |
... cannot be indexed | マップ以外の値(文字列または空の body)のインデックス参照 | body をインデックス参照する前に IsMap(body) ガードを追加します |
segment "..." is not a valid path | コンテキストの誤り、または選択したコンテキストでフィールドを使用できない | 正しいコンテキストに切り替え、パスの参照を確認します |
one or more paths were modified to include their context prefix | 明示的なプレフィックスが必要な場所で、プレフィックスのない attributes[...] を使用している | resource.attributes、datapoint.attributes などを使うように書き換えます |
statement has invalid syntax: ... invalid quoted string | YAML と OTTL の引用符が衝突し、OTTL に届く前に YAML パーサーが文字列を処理している | 外側を YAML のシングルクォート、内側を OTTL のダブルクォートにします → references/processors.md |
| ステートメントは読み込まれるが、目に見える効果がない | 条件に一致しない、シグナルブロックが誤っている、またはプロセッサーが誤ったパイプライン段階にある | デバッグ属性を表示して一致を確認し、パイプライン内の配置を検証します |
標準的なパイプライン構成
transform と filter を使ったパイプライン(ログ/トレース/メトリクスのステートメント、error_mode、conditions: [IsMap(body)]、filter を transform より前に置く順序)の注釈付き完全版は、references/processors.md にあります。
一般的なワークフロー
1. OTTL ステートメントをデバッグする
- 問題が実際に OTTL に関するものかを確認します。コンポーネントの選択、パイプラインの接続、インフラストラクチャの問題ではないことを確認します。
- シグナル(ログ/トレース/メトリクス)と具体的なコンテキストを特定します。
- 上記のエラーパターンの表で、エラーの正確なテキストを確認します。
- nil ガードまたは型ガード(
IsMap、IsString、!= nil)が不足していないか確認します。 - コンテキストプレフィックス(
attributesとresource.attributes)が誤っていないか確認します。 conditions:のセマンティクス、またはテールサンプリングポリシーの順序を確認します。- その後で初めて、修正したステートメントと最小限の YAML を提案します。
2. JSON のログ body を属性に変換する
body が未加工の JSON 文字列として届く場合(IsMap(body) が false)、IsString(body) でガードしてから ParseJSON で解析します。not IsMap(body) よりも IsString(body) を優先してください。肯定形のチェックであり、空または nil の body への一致を避けられます。
- context: log
conditions:
- IsString(body) # body is a JSON string (affirmative guard)
statements:
# Promote every top-level JSON field into attributes
- merge_maps(attributes, ParseJSON(body), "insert")
# Or lift specific fields only:
- set(attributes["user_id"], ParseJSON(body)["user_id"]) where ParseJSON(body)["user_id"] != nil
- set(attributes["request_id"], ParseJSON(body)["request_id"]) where ParseJSON(body)["request_id"] != nil
ParseJSON はコンバーターです。値を返しますが、それ自体に副作用はないため、エディター(set、merge_maps)でラップする必要があります。単独の ParseJSON(body) 行はエラーなく読み込まれますが、何も行いません。→ references/transformations.md
3. メトリクスのカーディナリティを削減する
- context: datapoint
statements:
- keep_keys(attributes, ["service.name", "http.route", "http.response.status_code"])
- delete_matching_keys(attributes, "^k8s\\.pod\\.uid$")
多数の delete_key 呼び出し(ブロックリスト)よりも、keep_keys(許可リスト)を優先してください。→ references/cardinality.md
4. リソース属性を参照するエクスポーターに値を渡す
属性から出力先を選択するエクスポーター、特に Coralogix エクスポーターの application_name_attributes と subsystem_name_attributes は、ログレコードやスパンの属性ではなく、リソース属性を参照します。元の値がレコード上にある場合は、context: log(または context: span)から set(resource.attributes[...], attributes[...]) を使ってリソースにコピーします。アプリケーション内でフィールド名を変更したり、エクスポーターの設定を変更したりしないでください。
両方の属性ペア、error_mode、パイプラインの順序を含む完全なパターンは、→ references/contexts.md にあります。
5. ヒストグラム集約を抽出し、元のメトリクスを削除する
平均レイテンシの計算に必要な_sumと_countを残しつつ、元のバケットデータを削除するには、次のようにします。
processors:
transform:
error_mode: ignore
metric_statements:
- context: metric
conditions:
- type == METRIC_DATA_TYPE_HISTOGRAM
statements:
- extract_sum_metric(true) # creates <name>_sum as a new Sum metric; true = monotonic
- extract_count_metric(true) # creates <name>_count as a new Counter metric
filter:
error_mode: ignore
metrics:
metric:
- 'type == METRIC_DATA_TYPE_HISTOGRAM and name == "http.server.request.duration"'
extract_sum_metric(monotonic)とextract_count_metric(monotonic)は、context: metricで実行されるOTTL Editor関数で、パイプラインの出力に新しい単独のメトリクスを追加します。元のヒストグラムは、filterプロセッサーで削除されるまで残ります。**ヒストグラムを削除する前に新しいメトリクスを作成できるよう、パイプラインではtransformプロセッサーをfilterより前に配置する必要があります。**累積/単調カウンターにはtrueを、デルタにはfalseを渡します。
6. 属性全体のPIIをマスキングする
- context: log
statements:
- set(attributes["user.id"], SHA256(attributes["user.id"])) where attributes["user.id"] != nil
- replace_all_patterns(attributes, "value", "(?i)bearer\\s+[a-z0-9._-]+", "bearer ***")
SHA256を使うと、生の識別子を公開せずに相関関係を維持できます。replace_all_patternsを使えば、キーを一つずつ列挙することなく、すべての属性値を対象にマスキングできます。→ redaction.mdへの参照
ベストプラクティス
パイプラインと順序
- **transformより前にfilterを実行します。**破棄するレコードの変換にCPUを費やさないようにします。
- **
error_mode: ignoreを明示的に設定します。**デフォルトのpropagateでは、実行時エラーが発生するとデータが失われます。 - **
conditions:を使ってブロックの適用範囲を指定します。**列挙した条件のいずれかに一致すると、文が実行されます(ORの意味)。各文にwhere句を付けるよりも効率的です。厳密なAND条件にするには、a and bを組み合わせるか、文ごとにwhereを使います。
堅牢なOTTL
- **インデックス参照の前にガードを設けます。**マップへのアクセス前に
IsMap(body)、文字列操作の前にIsString(body)を使い、任意のフィールドを読み取る前にwhere attributes["x"] != nilを指定します。型を確認せずにインデックス参照するとINVALID_ARGUMENTが発生し、デフォルトのerror_modeではパイプラインが停止します。 - **比較の前に、数値に見える文字列を変換します。**属性が
"5"または5になり得る場合は、IsString/IsIntで分岐し、>/<による比較の前にInt(...)またはDouble(...)を使います。 - **
conditions:はORであり、ANDではありません。**厳密なAND条件にするには、1つのブール式(a and b)にまとめるか、各文にwhereを追加します。
記述スタイル
- **まずシグナルとコンテキストを特定します。**トレース、メトリクス、ログを分け、参照するフィールドに適したコンテキストを使います。
- **密な式を1つ書くより、短い文を複数使います。**明確さが重要な場合は、パスのプレフィックスを正確に示します。
- **多数の
delete_key呼び出しより、keep_keysを優先します。**許可リストのほうが簡潔で、内容も把握しやすくなります。
制限事項
OTTLでは、レシーバーの接続、エクスポーターの接続、DNSまたはKubernetesのサービスディスカバリー、ロードバランシング、ゲートウェイへの到達性、パイプラインの接続ミス、プロセッサーに到達しないテレメトリーは解決できません。先にその旨を伝えてください。
適用範囲の制約:
- OTTLで使用できるのは、アクティブなシグナルとコンテキストモデルで公開されているフィールドだけです。
- Collectorが認識するのはテレメトリーペイロードであり、受信したリクエストそのものではありません。レシーバーで取り込まれた後は、上流のHTTPヘッダーを利用できないのが一般的です。
- アクティブなコンテキストにフィールドがなければ、OTTLで推測したり再構築したりすることはできません。
OTTL関数の一覧は、Collectorのリリースごとに更新されます。このスキルではパターンとよくある誤用を解説しています。最新の関数シグネチャについては、以下のReferencesフッターにある上流ドキュメントを参照してください。
参考資料
- references/contexts.md — OTTL のコンテキスト、パス式、よくあるコンテキストの間違い
- references/processors.md —
transform、filter、routingコネクターの設定 - references/filtering.md — filter プロセッサーでログ、メトリクス、スパンを除外する方法
- references/transformations.md — スパン名、semconv の移行、本文の操作、
ParseJSON、フォールバックチェーン - references/cardinality.md —
keep_keys、delete_matching_keys、replace_patternでメトリクスとトレースのカーディナリティを削減する方法 - references/redaction.md — PII のマスキング、
SHA256による仮名化、トークン/カード/認証ヘッダーの秘匿
上流: