oodle-log-metrics について
oodle-log-metricsは、ログ行をメトリクスに変換するルール作成をエージェントに案内するスキルです。フィルターの検証、ラベルのカーディナリティ管理、更新時の既存ルール保持を重視します。
主な機能
- 01ルール作成前のログフィルター検証
- 02ラベルのカーディナリティ推定
- 03カウント、カウンター、ゲージ、ヒストグラムの定義
- 04正規表現によるラベルと値の抽出
- 05更新前の既存ルール取得
活用シーン
- 01一致するログ行のメトリクス化
- 02ログイベントからのアラート作成
- 03プレーンテキストログのツール遅延測定
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ oodle-ai/ agent-skills --skill oodle-log-metricsインストール後、Claude Code で/oodle-log-metricsを入力して読み込まれたか確認します。
詳細
Oodle Log Metrics — ルールとカーディナリティ
このスキルでは、ログストリームを安全にメトリクスへ変換する方法を説明します。フィルターを検証し、labels を絞り込み、カーディナリティの高い時系列を作成しないようにします。ログメトリクスルールは、ログ行内の値をカウントしたり、その値についてアラートを出したりする方法でもあります。モニターは、ルールが出力するメトリクスに対してアラートを出します。
前提条件
brew install oodle-ai/oodle/oodle
oodle configure
ログメトリクスのエンドポイントが動作することを確認します。
oodle log-metrics list -o json | jq 'length'
コマンドの実行順序
oodle コマンドを実行する前に、次の手順を実行してください。
- ルールのフィルターと
labelsがすでにコンテキストにあるか確認します。 - ない場合は、サンプルログクエリを実行し(例:
oodle logs query。oodle-logs スキルまたはログエクスプローラーを参照)、フィルターに実際に一致するログがあることを確認します。 - カーディナリティを見積もります。各ラベルの異なる値の数を掛け合わせます。
- フィルターの検証後にのみ、
oodle log-metrics create -f rule.jsonを実行します。 - 既存のルールを取得するために
getを実行せずに、updateを実行しないでください。
クイックリファレンス
| タスク | コマンド |
|---|---|
| ルールの一覧表示 | oodle log-metrics list -o json |
| ルールの取得 | oodle log-metrics get <id> -o json |
| ルールの作成 | oodle log-metrics create -f rule.json |
| ルールの更新 | oodle log-metrics update <id> -f rule.json |
| ルールの削除 | oodle log-metrics delete <id> --force |
一般的な操作
ルールのスキーマ
{
"name": "http_errors_from_logs",
"filter": {
"all": [
{"field": "level", "operator": "is", "value": "error"},
{"field": "service", "operator": "is", "value": "api"}
]
},
"labels": [
{"name": "service", "valueExtractor": {"field": "service"}},
{"name": "env", "valueExtractor": {"field": "env"}}
],
"metricDefinitions": [
{"name": "http_errors", "type": "log_count"}
]
}
フィールドの意味:
| フィールド | 意味 |
|---|---|
name | ルールを識別する名前です。必須です。 |
filter | ルールが読み取るログ行を指定します。条件 {"field", "operator", "value", "jsonPath"}、または {"all": [...]}(AND)、{"any": [...]}(OR)、{"not": <filter>} を指定します。これらはネストできます。演算子は is、contains、matches regex、exists です。!= はありません。not を使用してください。 |
labels | 出力するメトリクスに追加されるラベルです。それぞれに name と静的な value、または valueExtractor {"field", "jsonPath", "regex"} を指定します。 |
metricDefinitions | 出力するメトリクスです。少なくとも1つ必要です。それぞれに name と type を指定します。log_count(一致した行数)、counter(値の合計)、gauge(最後の値)、histogram(値の分布)を指定できます。counter、gauge、histogram は、field から値を読み取り、任意で jsonPath または regex を指定できます。 |
fieldはログのトップレベルフィールドです。使用できるのは英字、数字、アンダースコアのみです。ネストされた JSON 値を読み取るには、たとえば{"field": "log", "jsonPath": "user.id"}のようにjsonPathを使用します。regexでは Rust の構文を使用します。キャプチャグループ1が値になるため、必要な部分を1つのグループで囲みます。JSON では、各バックスラッシュをエスケープします。\dは"\\d"です。- 正規表現が行に一致しない場合、ラベルは空になり、値は
0になります。そのため、値を含む行だけを選択するフィルターを指定してください。 - 出力されるメトリクス名は
oodle_logs_<name>(oodle_logs_http_errors)です。histogramは_bucket、_sum、_countの各時系列を出力します。log_countとcounterのクエリにはincrease(...)またはrate(...)を使用し、sum by (...)で集計します。 - ルールは、作成後に到着したログにのみ適用されます。過去のデータには
oodle logs queryを使用してください。 - 例のように、
allリストには条件を1つだけ指定します。この形式はすべての CLI およびサーバーのバージョンで動作します。
ルールの作成
# ✅ CORRECT — validate filter first, then create
# (preview with the log explorer or `oodle logs query`)
oodle log-metrics create -f rule.json
# ❌ WRONG — creating with an untested filter; the resulting metric is silently empty
oodle log-metrics create -f <(echo '{"name":"x","filter":{"all":[{"field":"levl","operator":"is","value":"eror"}]},"metricDefinitions":[{"name":"x","type":"log_count"}]}')
ルールの更新
# ✅ CORRECT — get → edit → update
oodle log-metrics get lm_123 -o json > rule.json
jq '.labels = [{"name":"service","valueExtractor":{"field":"service"}},{"name":"env","valueExtractor":{"field":"env"}}]' rule.json > rule.new.json
oodle log-metrics update lm_123 -f rule.new.json
# ❌ WRONG — partial payload removes existing fields (and has no `id`, so it is rejected)
oodle log-metrics update lm_123 -f <(echo '{"labels":[{"name":"service","valueExtractor":{"field":"service"}}]}')
ルールの削除
# ✅ CORRECT — verify and delete
oodle log-metrics get lm_123 -o json > /dev/null
oodle log-metrics delete lm_123 --force
# ❌ WRONG — speculative delete by name match
oodle log-metrics delete "$(oodle log-metrics list | grep errors | awk '{print $1}')" --force
ログ行のアラート設定
モニターはログクエリではなく、PromQL を実行します。ログ行に対してアラートを設定するには、ログメトリクスルールを作成し、そのルールが出力するメトリクスを対象とするモニターを作成します(oodle-monitors スキルを参照)。ルールは正規表現で未加工の行テキストを読み取るため、プレーンテキストの行で機能し、ログ変換は不要です。行から抽出したラベル(ユーザー、ツール、テナント)が、アラートの系列名になります。
例:次のような行から、クレジットが切れたユーザーごとにアラートを発生させます。
2026-10-07T10:12:03Z WARN credit exhausted for user=alice plan=pro
credit-exhausted.json:
{
"name": "credit-exhausted",
"filter": {"all": [{"field": "message", "operator": "contains", "value": "credit exhausted"}]},
"labels": [
{"name": "user", "valueExtractor": {"field": "message", "regex": "user=(\\S+)"}}
],
"metricDefinitions": [{"name": "credit_exhausted", "type": "log_count"}]
}
credit-exhausted-monitor.json(op の 2 は > です):
{
"name": "Credit exhausted",
"promql_query": "sum by (user) (increase(oodle_logs_credit_exhausted[10m]))",
"conditions": {"critical": {"op": 2, "value": 0}},
"labels": {"team": "billing", "env": "prod"},
"annotations": {"summary": "User {{ $labels.user }} ran out of credit"}
}
oodle log-metrics create -f credit-exhausted.json
oodle monitors create -f credit-exhausted-monitor.json
# Later: whose credit ran out in the last 24 hours
oodle metrics query --query 'sum by (user) (increase(oodle_logs_credit_exhausted[24h])) > 0' -o json
この場合、ユーザーごとにラベルを付けても問題ありません。イベントの発生頻度が低いためです(「labels はカーディナリティの低いラベルを 2~3 個にする」を参照)。
例:tool Bash ok in 12345 ms の継続時間のように、行内の値を使用する場合です。値ごとにキャプチャグループを 1 つ含む正規表現を 1 つ使い、値を必須とするフィルターを指定します。
{
"name": "tool-latency",
"filter": {"all": [{"field": "message", "operator": "matches regex", "value": "tool \\S+ (?:ok|failed) in \\d+ ms"}]},
"labels": [
{"name": "tool", "valueExtractor": {"field": "message", "regex": "tool (\\S+) "}},
{"name": "status", "valueExtractor": {"field": "message", "regex": " (ok|failed) in "}}
],
"metricDefinitions": [
{"name": "tool_calls", "type": "log_count"},
{"name": "tool_duration_ms", "type": "histogram", "field": "message", "regex": " in (\\d+) ms"}
]
}
# p95 tool latency in ms, per tool
histogram_quantile(0.95, sum by (le, tool) (rate(oodle_logs_tool_duration_ms_bucket[5m])))
# failed calls per tool
sum by (tool) (increase(oodle_logs_tool_calls{status="failed"}[10m]))
ベストプラクティス
ルールを作成する前に、実際のログ量に対して filter を検証する
フィルターのタイプミス(levl=eror)があると、ルールはデータポイントをひそかに 0 件出力します。
# ✅ CORRECT — preview matching log volume in the log explorer first;
# only then run `oodle log-metrics create`
# (or run `oodle logs query` with the same condition and confirm count > 0)
# ❌ WRONG — create the rule, then notice the dashboard panel is empty next week
oodle log-metrics create -f rule.json
labels はカーディナリティの低いラベルを 2~3 個にする
ラベルごとに時系列数が増加します。request_id、user_id、trace_id、(ID を含む)path は避けてください。クレジット拒否のようなまれなイベントに限り、ユーザーラベルを使用できます。
# ✅ CORRECT — bounded labels
"labels": [{"name": "service", "valueExtractor": {"field": "service"}}, {"name": "env", "valueExtractor": {"field": "env"}}]
# ❌ WRONG — `user_id` on every request blows up cardinality (one series per user)
"labels": [{"name": "service", "valueExtractor": {"field": "service"}}, {"name": "user_id", "valueExtractor": {"field": "user_id"}}]
フィールドを保持するため、必ず update の前に get を実行する
update はドキュメントを置き換えます。フィールドを 1 つだけ送信すると、それ以外はすべて null になります。
# ✅ CORRECT
oodle log-metrics get lm_123 -o json > rule.json
jq '.filter.all += [{"field": "status", "operator": "matches regex", "value": "^5"}]' rule.json > rule.new.json
oodle log-metrics update lm_123 -f rule.new.json
# ❌ WRONG — clobbers labels and metricDefinitions
oodle log-metrics update lm_123 -f <(echo '{"filter":{"all":[{"field":"level","operator":"is","value":"error"}]}}')
安定した説明的なメトリクス名を使用する
出力される名前は oodle_logs_<name> です。<domain>_<measurement> という名前にすると、ダッシュボードやドロップルールでメトリクスを簡単に見つけられます。使用できるのは英字、数字、アンダースコアのみです。
# ✅ CORRECT
"metricDefinitions": [{"name": "http_errors", "type": "log_count"}]
# ❌ WRONG — generic name collides with other rules
"metricDefinitions": [{"name": "errors", "type": "log_count"}]
エラーへの対処
| エラー | 原因 | 解決方法 |
|---|---|---|
| 401 Unauthorized | API キーが無効または未設定 | oodle configure を実行するか、OODLE_API_KEY を設定します |
| 404 Not Found | ログメトリクスルール ID が存在しない | oodle log-metrics list -o json で確認します |
| connection refused | OODLE_DEPLOYMENT の URL が誤っている | OODLE_DEPLOYMENT 環境変数を確認します |
400 Match must have a valid Operator | 演算子が is、contains、matches regex、exists のいずれでもない | 4 つのいずれかを使用します。「等しくない」場合は、条件を not で囲みます |
400 Field ... must contain only alphanumeric characters and underscores | field にドットを含むフィールド名が指定されている | トップレベルのフィールドを使用し、パスは jsonPath に指定します |
400 Regex ... is not a valid rust regex | 正規表現の構文エラー、または JSON のエスケープ漏れ | JSON 内のバックスラッシュをエスケープします(\\d)。後読み・先読みは使用できません |
400 'logCount' metric definition has a Field, JSONPath, or Regex | log_count に field、jsonPath、または regex が指定されている | これらを削除します |
400 Log Metrics ID in path and body don't match | 本文の id がないか、<id> と異なる | get を実行し、その出力を編集します |
| メトリクスは存在するがデータポイントがない | フィルターがどのログにも一致しない、またはルール作成後に新しい行がない | ログエクスプローラーまたは oodle logs query でフィルターを再テストし、フィールド名がログスキーマと一致することを確認します。ルールは過去のログを補完しません |
| ラベルが空/値がすべて 0 | 正規表現が一致しない、またはグループ 1 が数値ではない | サンプル行で正規表現をテストし、値を必須とするフィルターにします |
| UI にカーディナリティアラームが表示される | labels にカーディナリティの高いフィールドが含まれている | ルールを編集してそのラベルを削除します。古い系列は通常の保持期間が経過すると消滅します |
| 429 Too Many Requests | ルールの一括作成 | --retries 3 を追加し、作成頻度を毎秒 10 件未満に抑えます |