mcpField
O
oodle-logs

oodle-logs

github.com/oodle-ai云与 DevOps0125 次安装3 周前更新
代码仓库

关于 oodle-logs

oodle-logs 是一项使用 OpenSearch Query DSL 搜索 Oodle 日志并发现索引模式的技能,指导 Agent 在查询前确认模式和字段,并指定时间范围。

主要功能

  1. 01发现日志索引模式和字段
  2. 02用 OpenSearch Query DSL 构建 NDJSON 查询
  3. 03按指定时间范围搜索日志
  4. 04按日志字段聚合结果
  5. 05用 jq 在客户端提取纯文本值

适用场景

  1. 01调查时查找匹配的日志事件
  2. 02按服务统计错误
  3. 03检查历史日志行并提取其中的值

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/oodle-ai/agent-skills --skill oodle-logs

安装后在 Claude Code 中输入/oodle-logs确认已加载。

详细介绍

Oodle 日志 — 搜索与索引模式发现

此技能教会 Agent 使用兼容 OpenSearch 的查询 DSL 搜索日志数据,并发现可用的日志索引模式。

前置条件

brew install oodle-ai/oodle/oodle
oodle configure

确认日志端点可用:

oodle logs index-patterns -o json | jq 'length'

命令执行顺序

运行任何日志查询之前:

  1. 运行 oodle logs index-patterns -o json,发现可用的日志索引模式。
  2. 为查询选择合适的索引模式 title。
  3. 使用发现的索引模式和 OpenSearch Query DSL 构建 NDJSON 查询文件。
  4. 设置 --start 和 --end,覆盖所需的时间范围。默认值分别为 -1h 和 now。
  5. 不要猜测索引名称——务必先通过 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:第一行用于选择索引,第二行包含使用 OpenSearch Query DSL 编写的搜索查询。通过 -f <file> 传入正文。

重要限制:

  • CLI 仅支持单个搜索正文(恰好 2 行 NDJSON:一个标头 + 一个搜索)。不支持多个搜索对。
  • 使用 --start 和 --end 标志筛选时间范围。值可以是 Unix 时间戳(毫秒;例如 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 无法做到。请提供以下方案之一:

  1. 日志指标规则(oodle-log-metrics 技能):使用正则表达式提取值,并将其存入带标签的指标。适用于对新日志进行计数、延迟统计和告警。
  2. 历史数据:使用 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 小时),然后合并结果。若要从现在起按用户触发告警,请创建一个使用正则表达式 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 UnauthorizedAPI 密钥无效或缺失运行 oodle configure 或设置 OODLE_API_KEY
400 Bad RequestNDJSON 正文或 Query DSL 无效验证 NDJSON 文件是否恰好有两行;检查 OpenSearch Query DSL 语法
结果为空(非错误)索引或时间范围内没有匹配的日志扩大时间范围,或使用 oodle logs index-patterns 检查索引名称
较早数据的结果为 0--start 默认为 -1h;此时间窗口以外的数据会被排除对较早的数据传入显式的 --start,例如 --start -24h 或 --start <epoch_ms>
connection refusedOODLE_DEPLOYMENT URL 错误检查 OODLE_DEPLOYMENT 环境变量,并确保末尾没有斜杠
429 Too Many Requests请求频率受限添加 --retries 3,延长重试间隔,并降低查询频率
regexp、script 或运行时字段出现 400 错误不受支持使用 match_phrase 或日志指标规则(参见“纯文本日志行中的值”)
required flag(s) "file" not set日志查询缺少必需标志添加 -f 标志并指定 NDJSON 文件的路径

参考资料

评论

支持 Markdown