oodle-logs について
oodle-logsは、OpenSearch Query DSLでOodleのログを検索し、利用可能なインデックスパターンを調べるスキルです。クエリ前のパターンとフィールドの確認、明示的な時間範囲の指定を案内します。
主な機能
- 01ログのインデックスパターンとフィールドの発見
- 02OpenSearch Query DSLによるNDJSONクエリ作成
- 03指定した時間範囲でのログ検索
- 04ログフィールドによる結果の集計
- 05jqを使ったクライアント側でのプレーンテキスト値抽出
活用シーン
- 01調査対象となるログイベントの検索
- 02サービス別のエラー件数集計
- 03過去のログ行の確認と埋め込み値の抽出
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ oodle-ai/ agent-skills --skill oodle-logsインストール後、Claude Code で/oodle-logsを入力して読み込まれたか確認します。
詳細
Oodle Logs — 検索とインデックスパターンの検出
このスキルでは、OpenSearch 互換のクエリー DSL を使ってログデータを検索し、利用可能なログのインデックスパターンを検出する方法を説明します。
前提条件
brew install oodle-ai/oodle/oodle
oodle configure
ログのエンドポイントが動作することを確認します。
oodle logs index-patterns -o json | jq 'length'
コマンドの実行順序
ログクエリーを実行する前に、次の手順に従います。
oodle logs index-patterns -o jsonを実行して、利用可能なログのインデックスパターンを確認します。- クエリーに適したインデックスパターンの
titleを選びます。 - 確認したインデックスパターンと OpenSearch Query DSL を使って、NDJSON クエリーファイルを作成します。
- 必要な期間をカバーするように
--startと--endを設定します。デフォルト値は-1hとnowです。 - インデックス名を推測してはいけません。必ず先に
index-patternsで確認してください。
クイックリファレンス
| タスク | コマンド |
|---|---|
| ログのインデックスパターンを一覧表示 | oodle logs index-patterns -o json |
| ログを検索 | oodle logs query -f query.ndjson --start <start> --end <end> -o json |
よく使う操作
ログのインデックスパターンを一覧表示
ログクエリーを作成する前に、利用可能なログのインデックスパターンを確認します。返される title フィールドは、NDJSON クエリーファイルの index 値として使用します。
# CORRECT — list all available index patterns
oodle logs index-patterns -o json
# CORRECT — extract just the pattern titles
oodle logs index-patterns -o json | jq '.[].title'
# CORRECT — use a discovered pattern in a log query
oodle logs index-patterns -o json | jq '.[].title'
# Then use the title in your NDJSON file:
# {"index": "logs-*"}
# {"query": {"match_all": {}}, "size": 10}
ログクエリー
OpenSearch 互換のマルチサーチ API を使ってログデータを検索します。リクエスト本文は NDJSON 形式で、JSON の行がちょうど 2 行含まれます。1 行目はインデックスを選択し、2 行目には OpenSearch Query DSL を使った検索クエリーを指定します。本文は -f <file> で渡します。
重要な制約:
- CLI がサポートするのは単一の検索本文のみです(NDJSON の行がちょうど 2 行、ヘッダー 1 行と検索 1 行)。検索ペアを複数指定することはできません。
- 時間範囲のフィルタリングには
--startと--endフラグを使います。値にはエポックミリ秒(例:1716825600000)、RFC 3339(例:2026-01-02T00:00:00Z)、now、または相対表現(例:-1h、-24h、-7d)を指定できます。 --startのデフォルト値は-1h、--endのデフォルト値はnowです。 1 時間より前のデータを検索する場合は、明示的に--startを指定する必要があります。指定しないと、クエリーの結果はエラーなく 0 件になります。- クエリー本文に
timestampの範囲フィルターを指定してはいけません。CLI が--start/--endからtimestampの範囲フィルターを自動挿入します。
# CORRECT — basic query (searches last 1 hour by default)
cat > query.ndjson <<'EOF'
{"index": "logs-*"}
{"query": {"match_all": {}}, "size": 10}
EOF
oodle logs query -f query.ndjson -o json
# CORRECT — search for specific log messages with explicit time range
cat > query.ndjson <<'EOF'
{"index": "logs-*"}
{"query": {"bool": {"must": [{"match_phrase": {"message": "error"}}]}}, "size": 50, "sort": [{"timestamp": {"order": "desc"}}]}
EOF
oodle logs query -f query.ndjson --start -6h --end now -o json
# CORRECT — search older data using relative time
cat > query.ndjson <<'EOF'
{"index": "logs-*"}
{"query": {"bool": {"must": [{"match_phrase": {"message": "OOMKilled"}}]}}, "size": 100}
EOF
oodle logs query -f query.ndjson --start -7d --end -6d -o json
# CORRECT — search older data using epoch milliseconds
cat > query.ndjson <<'EOF'
{"index": "logs-*"}
{"query": {"match_phrase": {"message": "connection refused"}}, "size": 50}
EOF
oodle logs query -f query.ndjson --start 1716825600000 --end 1716912000000 -o json
# WRONG — omitting --start when searching for data older than 1 hour
cat > query.ndjson <<'EOF'
{"index": "logs-*"}
{"query": {"match_phrase": {"message": "yesterday's deploy error"}}, "size": 50}
EOF
oodle logs query -f query.ndjson -o json
# ^^^ Returns 0 results! --start defaults to -1h, so older data is excluded.
# FIX: add --start -24h (or whatever range covers the target timeframe)
# WRONG — putting a range filter on timestamp in the query body
cat > query.ndjson <<'EOF'
{"index": "logs-*"}
{"query": {"bool": {"must": [{"range": {"timestamp": {"gte": "now-1h", "lte": "now"}}}]}}, "size": 100}
EOF
# The CLI already injects a timestamp range from --start/--end. In-query range filters conflict.
# FIX: use --start and --end flags instead.
# WRONG — passing the query inline without -f
oodle logs query --body '{"index":"logs-*"}'
# WRONG — using JSON instead of NDJSON format
oodle logs query -f query.json # file must be valid NDJSON (exactly two lines)
集計
OpenSearch の集計は aggs ブロックに指定します。集計結果のみが必要な場合は "size": 0 を設定します。結果は jq '.responses[0].aggregations' で読み取ります。以下のフィールド名は例です。oodle logs index-patterns で実際のフィールドを確認してください。数値の集計には、message 内のテキストではなく、数値フィールドが必要です。
# CORRECT — error lines per service (top 20)
cat > query.ndjson <<'EOF'
{"index": "logs-*"}
{"size": 0, "query": {"term": {"level": "error"}}, "aggs": {"by_service": {"terms": {"field": "service_name", "size": 20}}}}
EOF
oodle logs query -f query.ndjson --start -24h --end now -o json \
| jq -r '.responses[0].aggregations.by_service.buckets[] | "\(.key)\t\(.doc_count)"'
# CORRECT — error lines per hour
cat > query.ndjson <<'EOF'
{"index": "logs-*"}
{"size": 0, "query": {"match_phrase": {"message": "error"}}, "aggs": {"per_hour": {"date_histogram": {"field": "timestamp", "fixed_interval": "1h"}}}}
EOF
oodle logs query -f query.ndjson --start -24h --end now -o json \
| jq -r '.responses[0].aggregations.per_hour.buckets[] | "\(.key_as_string)\t\(.doc_count)"'
プレーンテキストのログ行に含まれる値
regexp クエリー、スクリプト、ランタイムフィールドはサポートされていません。そのため、プレーンテキストのログ行のテキスト内にしか存在しない値では、ログクエリーによるフィルタリングやグループ化はできません。tool Bash ok in 12345 ms のような行を対象にする場合、クエリーで「10000 ms 超」を選択したり、ツール名でグループ化したりすることはできません。Oodle では実現できないとユーザーに伝えてはいけません。次のいずれかを提案してください。
- ログメトリクスルール(oodle-log-metrics スキル):正規表現で値を抽出し、ラベル付きのメトリクスにします。新しいログに対するカウント、レイテンシー、アラートに使用します。
- 過去のデータ:
match_phraseで該当する行を見つけ、クライアント側でjqを使って値を抽出します。
| 必要な操作 | 使用するもの |
|---|---|
| 行の検索、イベントの確認、過去の調査 | oodle logs query |
| 過去のデータで実際のフィールドをカウントまたはグループ化 | aggs を使った oodle logs query |
| プレーンテキスト内にしか存在しない値でのフィルタリングまたはグループ化 | ログメトリクスルール(新しいデータ)、またはクライアント側で jq(過去のデータ) |
| ログ行のアラート(カウント、レート、レイテンシー、ユーザーごと) | ログメトリクスルール + モニター |
| ダッシュボードで数週間にわたる傾向を表示 | ログメトリクスルール |
実例:過去24時間にクレジットが切れたユーザーを調べる
まず、これらの行をカウントするログメトリクスルールがすでにあるか確認します:oodle log-metrics list -o json。ルールがある場合は、そのメトリクスを確認します。たとえば、oodle metrics query --query 'sum by (user) (increase(oodle_logs_credit_exhausted[24h])) > 0' -o json を実行します。ルールがカウントするのは、作成後に届いた行だけです。古いデータには、以下のログを使用してください。
cat > credit.ndjson <<'EOF'
{"index": "logs-*"}
{"query": {"match_phrase": {"message": "credit exhausted"}}, "size": 1000, "sort": [{"timestamp": {"order": "desc"}}]}
EOF
# If the user is a real field (for example user_id): use a terms aggregation on it.
# If the user is only inside the text ("... for user=alice ..."): extract it on the client.
oodle logs query -f credit.ndjson --start -24h --end now -o json \
| jq -r '.responses[0].hits.hits[]._source.message | capture("user=(?<user>[^ ]+)").user' \
| sort | uniq -c | sort -rn
クエリが size 件の行を返した場合、さらに結果がある可能性があります。時間範囲を分割し(たとえば、6時間のクエリを4回実行)、結果をまとめてください。今後、ユーザーごとにアラートを出すには、正規表現 user=(\S+) で user を抽出するログメトリクスルールと、sum by (user) (increase(oodle_logs_credit_exhausted[10m])) によるモニターを作成します。ルールの JSON は oodle-log-metrics スキルにあります。
ベストプラクティス
クエリを実行する前にインデックスパターンを確認する
正しいインデックス名を見つけるため、必ず oodle logs index-patterns を実行してください。インデックス名を推測すると、空の結果が返されたり、エラーになったりすることがあります。
# CORRECT — discover first, then query
oodle logs index-patterns -o json | jq '.[].title'
# Use the discovered title in your NDJSON file
# WRONG — guessing index names
cat > query.ndjson <<'EOF'
{"index": "my-logs"}
{"query": {"match_all": {}}, "size": 10}
EOF
oodle logs query -f query.ndjson -o json
時間範囲の絞り込みには必ず --start と --end を使う
CLI は --start/--end に基づく timestamp の範囲フィルターを自動的に追加します。クエリ本文に独自の timestamp 範囲フィルターを追加しないでください。CLI が追加するフィルターと競合します。
# CORRECT — use CLI flags for time range
oodle logs query -f query.ndjson --start -24h --end now -o json
# CORRECT — use epoch milliseconds for precise ranges
oodle logs query -f query.ndjson --start 1716825600000 --end 1716912000000 -o json
# WRONG — relying on the default 1-hour window for older data
oodle logs query -f query.ndjson -o json
# ^^^ Only searches the last 1 hour. If the data you need is older, you get 0 results.
# WRONG — putting range filters on timestamp in the query body
{"query": {"bool": {"must": [{"range": {"timestamp": {"gte": "now-6h"}}}]}}}
# FIX: remove the range from the query body and use --start -6h instead.
ログクエリの結果には -o json を使う
ログクエリのレスポンスには、ネストされた JSON 構造が含まれます。必ず -o json を使い、jq に渡して値を抽出してください。
# CORRECT — extract log messages from the response
oodle logs query -f query.ndjson -o json | jq '.responses[].hits.hits[]._source.message'
# WRONG — using table output for complex nested log data
oodle logs query -f query.ndjson -o table
インデックスパターンのフィールドを使って正確なクエリを作成する
各インデックスパターンには、フィールド名と型を含む fields 配列があります。match_all を使う代わりに、これらを利用して対象を絞ったクエリを作成してください。
# CORRECT — check available fields first
oodle logs index-patterns -o json | jq '.[0].fields[].name'
# Then build a query using confirmed field names
エラーへの対処
| エラー | 原因 | 対処方法 |
|---|---|---|
| 401 Unauthorized | API キーが無効、または設定されていない | oodle configure を実行するか、OODLE_API_KEY を設定します |
| 400 Bad Request | NDJSON 本文または Query DSL が無効 | NDJSON ファイルがちょうど2行であることを確認し、OpenSearch Query DSL の構文を確認します |
| 空の結果(エラーではない) | インデックスまたは時間範囲に一致するログがない | 時間範囲を広げるか、oodle logs index-patterns でインデックス名を確認します |
| 古いデータの結果が0件 | --start の既定値は -1h であり、その範囲外のデータは除外される | 古いデータには --start を明示します。例:--start -24h または --start <epoch_ms> |
| connection refused | OODLE_DEPLOYMENT の URL が正しくない | OODLE_DEPLOYMENT 環境変数を確認し、末尾にスラッシュがないことを確認します |
| 429 Too Many Requests | レート制限に達している | --retries 3 を追加し、待機時間を置いて、クエリの頻度を減らします |
regexp、script、またはランタイムフィールドで400エラー | サポートされていない | match_phrase またはログメトリクスルールを使います(「プレーンテキストのログ行内の値」を参照) |
required flag(s) "file" not set | ログクエリに必要なフラグが指定されていない | NDJSON ファイルのパスを指定して -f フラグを追加します |