mcpField
L
logql-generator

logql-generator

github.com/akin-ozer云与 DevOps329605 次安装16 周前更新
代码仓库

关于 logql-generator

logql-generator 是用于 Loki 日志的交互式 LogQL 查询生成技能,适合查询、仪表板、告警和故障排查。它按阶段收集需求与版本信息,再生成兼顾兼容性的查询。

主要功能

  1. 01引导收集查询目标和日志详情
  2. 02根据 Loki 与 Grafana 版本调整语法
  3. 03支持查询规划及最终或分步输出
  4. 04复杂查询执行参考资料检查
  5. 05提供运行指引与兼容性说明

适用场景

  1. 01为服务创建 Loki 错误率查询
  2. 02构建 LogQL 告警表达式
  3. 03将排障目标转换为日志查询
  4. 04根据 Loki 日志生成仪表板指标

安装

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

$npx skills add https://github.com/akin-ozer/cc-devops-skills --skill logql-generator

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

examples/
common_queries.logql
references/
best_practices.md
scripts/
run_regression_checks.sh
tests/
test_loki_runtime_integration.py
test_skill_contract.py

详细介绍

LogQL 查询生成器

概述

用于生成可投入生产的 LogQL 查询的交互式工作流。LogQL 是 Grafana Loki 的查询语言,支持索引标签选择、日志行筛选、解析和指标聚合。

触发提示

  • “编写一个按服务统计错误率的 LogQL 查询。”
  • “帮我构建一个 Loki 告警查询。”
  • “把这项故障排查需求转换成 LogQL。”
  • “我需要逐步构建 LogQL 查询。”

使用此技能通过 Loki 日志生成查询、仪表板查询和告警表达式,以及进行故障排查。

执行流程(确定性)

始终按顺序执行各阶段。不要跳过必需阶段。

阶段 1(必需):收集意图

使用 AskUserQuestion 收集目标和使用场景。

模板:

  • “你的主要目标是什么:调试、告警、仪表板指标,还是调查?”
  • “你需要日志查询(原始日志行)还是指标查询(数值输出)?”
  • “需要覆盖多长的时间范围(例如,过去 15m、1h、24h)?”

如果 AskUserQuestion 不可用,则:

  • 用纯文本提出相同问题,然后继续。
阶段 2(必需):收集日志来源详情

收集:

  1. 流选择器的标签(job、namespace、app、service_name、cluster)
  2. 日志格式(JSON、logfmt、纯文本、混合格式)
  3. 已知的筛选/聚合字段(status、level、duration、path、trace_id)

处理信息模糊或回答不完整的情况:

  1. 如果缺少必需字段,提出一个有针对性的追问。
  2. 如果仍未获取信息,则基于明确假设继续。
  3. 在输出中以 Assumptions: 为假设添加前缀,方便用户快速更正。
阶段 3(必需):确认 Loki 和 Grafana 版本

收集或推断:

  • Loki 版本(例如,2.9.x、3.0+、未知)
  • Grafana 版本(例如,10.x、11.x、未知)
  • 部署环境(可自托管的 Loki、Grafana Cloud、未知)

版本兼容性策略:

  1. 如果版本已知,仅使用最新的兼容语法。
  2. 如果版本未知,优先采用兼容性最高的语法,默认避免仅适用于 3.x 的功能。
  3. 如果版本未知,另外提供可选的“3.x 优化版本”。

默认避免使用以下功能(版本未知时):

  • 模式匹配运算符 |> 和 !>
  • approx_topk
  • 特定于结构化元数据的行为(detected_level、对加速元数据筛选的假设)
阶段 4(必需):确认计划和输出模式

用通俗语言展示计划,然后请用户选择输出模式。

计划模板:

LogQL Query Plan
Goal: <goal>
Query type: <log or metric>
Streams: <selector>
Filters/parsing: <filters + parser>
Aggregation window: <function and [range]>
Compatibility mode: <version-aware or compatibility-first>

模式选择模板:

  • “你想要 final query only(默认),还是 incremental build(逐步构建)?”

如果用户未选择,默认使用 final query only。

阶段 5(有条件,阻塞):复杂查询的参考检查点

以下情况视为复杂查询:

  • 嵌套聚合(topk(sum by(...))、多个 sum by、百分位数)
  • 对性能敏感的查询(高流量日志流、长时间范围)
  • 告警表达式
  • 模板函数(line_format、label_format)
  • 大量使用正则表达式进行提取、IP 匹配、模式解析
  • 使用 Loki 3.x 功能

阻塞检查点规则:

  1. 生成查询前,通过明确的文件打开/读取操作读取相关文件。
  2. 最少读取以下文件:
    • examples/common_queries.logql,用于检查语法和查询模式
    • references/best_practices.md,用于了解性能和告警指导
  3. 完成此检查点前,不得生成最终查询。

文件读取工具不可用时的回退方案:

  1. 说明在此环境中无法读取参考文件。
  2. 生成保守查询(优先兼容性,使用较简单的运算符)。
  3. 将结果标记为 Unverified against local references。
第 6 阶段(条件):外部文档查询策略(先查 Context7,再查 WebSearch)

仅在需要了解特定版本的行为、语法不明确,或本地参考资料未涵盖的高级功能时,才进行外部查询。

查询顺序:

  1. 优先使用 Context7:
    • 使用 mcp__context7__resolve-library-id,并设置 libraryName="grafana loki"
    • 使用 mcp__context7__query-docs 查询具体主题
  2. 其次使用 WebSearch(仅作回退),适用于以下情况:
    • Context7 不可用
    • Context7 未提供所需的特定版本详情
    • 需要确认最新版本或弃用情况

WebSearch 回退限制:

  • 优先查阅 Grafana/Loki 官方文档和发行说明。
  • 标明哪些说法来自回退搜索。
第 7 阶段(必需):生成查询
第 7A 阶段(默认):仅返回最终查询

返回一条可用于生产环境的查询,并附简短说明。

第 7B 阶段(可选):增量构建模式

在用户要求时,或调试复杂流水线时使用。

分步模板:

  1. 流选择器
  2. 行过滤器
  3. 解析器
  4. 解析字段过滤器
  5. 聚合/时间窗口
第 8 阶段(必需):提供用法和检查项

始终包括:

  1. 最终查询或增量查询序列
  2. 如何运行(Grafana Explore/面板或 logcli)
  3. 可调参数(标签、阈值、范围)
  4. 任何假设和兼容性说明

AskUserQuestion 模板

信息收集模板
  • “要针对哪个系统/服务生成此查询?”
  • “哪些标签可用于可靠地选择流?”
  • “如何定义匹配项(错误文本、状态码、延迟阈值、用户路径)?”
  • “输出应为原始日志,还是用于告警/仪表板的指标?”
版本模板
  • “你运行的是哪个 Loki 版本?”
  • “你使用的是哪个 Grafana 版本?”
  • “如果不清楚,我是否应生成兼容性优先的查询,并附上可选的 3.x 变体?”
歧义追问模板
  • “我缺少 <field>。是否可以假设为 <default>,以便继续?”

核心模式

流选择与过滤
{job="app"} |= "error" |= "timeout"
{job="app"} |~ "error|fatal|critical"
{job="app"} != "debug"
解析
{app="api"} | json | level="error" | status_code >= 500
{app="api"} | logfmt | caller="database.go"
{job="nginx"} | pattern "<ip> - - [<_>] \"<method> <path>\" <status> <size>"
指标聚合
rate({job="app"} | json | level="error" [5m])
sum by (app) (count_over_time({namespace="prod"} | json [5m]))
sum(rate({app="api"} | json | level="error" [5m])) / sum(rate({app="api"}[5m])) * 100
quantile_over_time(0.95, {app="api"} | json | unwrap duration [5m])
topk(10, sum by (error_type) (count_over_time({job="app"} | json | level="error" [1h])))
格式化与 IP 匹配
{job="app"} | json | line_format "{{.level}}: {{.message}}"
{job="app"} | json | label_format env=`{{.environment}}`
{job="nginx"} | logfmt | remote_addr = ip("192.168.4.0/24")

查询构建规则

  1. 使用具体的流选择器(优先使用索引标签)。
  2. 优先采用以下过滤顺序:行过滤 -> 解析 -> 解析字段过滤。
  3. 优先采用以下解析器成本顺序:pattern > logfmt > json > regexp。
  4. 如果 Loki 版本未知,请使用兼容性优先的语法。
  5. 对于复杂/关键查询,在最终输出前完成第 5 阶段检查点。

高级技巧

多个解析器
{app="api"} | json | regexp "user_(?P<user_id>\\d+)"
使用 Unwrap 获取数值指标
sum(sum_over_time({app="api"} | json | unwrap duration [5m]))
模式匹配运算符(Loki 3.0+,比正则表达式快 10 倍)
{service_name=`app`} |> "<_> level=debug <_>"
逻辑运算符
{app="api"} | json | (status_code >= 400 and status_code < 500) or level="error"
Offset 修饰符
sum(rate({app="api"} | json | level="error" [5m])) - sum(rate({app="api"} | json | level="error" [5m] offset 1d))
标签操作
{app="api"} | json | keep namespace, pod, level
{app="api"} | json | drop pod, instance

注意:LogQL 没有 dedup 或 distinct 运算符。请使用 sum by (field) 等指标聚合来以编程方式去重。

Loki 3.x 主要功能

结构化元数据

无需索引的高基数数据(trace_id、user_id、request_id):

# Filter AFTER stream selector, NOT in it
{app="api"} | trace_id="abc123" | json | level="error"
查询加速(Bloom 过滤器)

在解析器之前放置结构化元数据过滤器:

# ACCELERATED
{cluster="prod"} | detected_level="error" | logfmt | json
# NOT ACCELERATED
{cluster="prod"} | logfmt | json | detected_level="error"
approx_topk(概率性)
approx_topk(10, sum by (endpoint) (rate({app="api"}[5m])))
用于告警的 vector()
sum(count_over_time({app="api"} | json | level="error" [5m])) or vector(0)
自动标签
  • service_name:根据容器名称自动填充
  • detected_level:当 discover_log_levels: true 时自动检测(存储为结构化元数据)

函数参考

日志范围聚合
函数描述
rate(log-range)每秒条目数
count_over_time(log-range)条目数
bytes_rate(log-range)每秒字节数
bytes_over_time(log-range)时间范围内的总字节数
absent_over_time(log-range)无日志时返回 1

规则:

  • 对于原始日志字节量,请使用 bytes_over_time(<log-range>)。
  • 对于从日志内容中提取的数值字节字段,请使用 | unwrap bytes(field) 和解包后的范围聚合函数。
未展开范围聚合
函数描述
sum_over_time、avg_over_time、max_over_time、min_over_time聚合数值
quantile_over_time(φ, range)φ 分位数(0 ≤ φ ≤ 1)
first_over_time、last_over_time区间内的第一个/最后一个值
stddev_over_time未展开值的总体标准差
stdvar_over_time未展开值的总体方差
rate_counter将值视为单调递增计数器,计算每秒速率
聚合运算符

sum、avg、min、max、count、stddev、topk、bottomk、approx_topk、sort、sort_desc

分组方式:sum by (label1, label2) 或 sum without (label1)

转换函数
函数描述
duration_seconds(label)转换时长字符串
bytes(label)转换字节字符串(KB、MB)
label_replace()
label_replace(rate({job="api"} |= "err" [1m]), "foo", "$1", "service", "(.*):.*")

解析器参考

logfmt
| logfmt [--strict] [--keep-empty]
  • --strict:遇到格式错误的条目时返回错误
  • --keep-empty:保留独立键
JSON
| json                                           # All fields
| json method="request.method", status="response.status"  # Specific fields
| json servers[0], headers="request.headers[\"User-Agent\"]"  # Nested/array
pattern
| pattern "<ip> - - [<timestamp>] \"<method> <path> <_>\" <status> <size>"

命名占位符会成为提取出的标签;<_> 会丢弃字段。

regexp
| regexp "(?P<level>\\w+): (?P<message>.+)"

使用命名捕获组(?P<name>)。速度比 pattern/logfmt/json 慢。

decolorize
| decolorize

移除 ANSI 颜色转义码。当日志来自终端输出时,请在解析前应用此解析器。

unpack
| unpack

解包由 Promtail 的 pack 管道阶段打包的日志条目。还原原始日志行及其中嵌入的标签。

模板函数

line_format 和 label_format 常用函数:

字符串:trim、upper、lower、replace、trunc、substr、printf、contains、hasPrefix 数学:add、sub、mul、div、addf、subf、floor、ceil、round 日期:date、now、unixEpoch、toDate、duration_seconds 正则表达式:regexReplaceAll、count 其他:fromJson、default、int、float64、__line__、__timestamp__

详细用法请参阅 examples/common_queries.logql。

告警规则

# Alert when error rate exceeds 5%
(sum(rate({app="api"} | json | level="error" [5m])) / sum(rate({app="api"}[5m]))) > 0.05

# With vector() to avoid "no data"
sum(rate({app="api"} | json | level="error" [5m])) or vector(0) > 10

错误处理

问题解决方案
没有结果检查标签是否存在,确认时间范围,并单独测试流选择器
查询缓慢使用具体的选择器,在解析前进行筛选,并缩短时间范围
解析错误确认日志格式与解析器匹配,测试 JSON 是否有效
高基数对唯一值使用行筛选器而非标签筛选器,并进行聚合

文档查询

使用第 6 阶段策略。遇到以下情况时查询外部文档:

触发条件要搜索的主题使用的工具
用户提及 Loki 3.x 功能structured metadata、bloom filters、detected_level优先使用 Context7
需要 approx_topk 函数approx_topk probabilistic优先使用 Context7
模式匹配运算符(|>、!>)pattern match operator优先使用 Context7
用于告警的 vector() 函数vector function alerting优先使用 Context7
记录规则配置recording rules loki优先使用 Context7
语法或边界情况不明确具体函数/运算符优先使用 Context7
询问特定版本的行为版本 + 功能备用方案:WebSearch
Grafana Alloy 集成grafana alloy loki备用方案:WebSearch

资源

  • examples/common_queries.logql:查询模式、模板函数示例
  • references/best_practices.md:优化、反模式、告警指南

示例流程

示例 A:仅输出最终查询(默认)
  1. 用户请求按服务统计过去 15 分钟的 5xx 速率。
  2. 捕获标签并设置格式(json)。
  3. 确认版本和模式(final query only)。
  4. 生成一个查询:
sum by (service) (rate({namespace="prod", app="api"} | json | status_code >= 500 [15m]))
示例 B:增量构建(可选)
  1. 用户请求排查登录失败问题,并要求逐步模式。
  2. 提供分阶段构建:
{app="auth"}
{app="auth"} |= "login failed"
{app="auth"} |= "login failed" | json
sum(count_over_time({app="auth"} |= "login failed" | json [5m]))
  1. 说明如果任何步骤返回零结果,应在哪里停止。

完成标准

仅当所有检查均通过时,才将任务标记为完成:

  1. 已完成所需阶段(1、2、3、4、7、8)。
  2. 对于任何复杂查询,已完成阶段 5 检查点。
  3. 需要查阅外部文档时,已按顺序先使用 Context7,再使用 WebSearch。
  4. 已明确选择输出模式或采用默认模式(final query only)。
  5. 版本未知时,已说明 Loki/Grafana 兼容性假设。
  6. 最终输出包含查询文本、使用说明、可调参数和假设。

版本说明

  • Loki 3.0+:布隆过滤器、结构化元数据、模式匹配运算符(|>、!>)
  • Loki 3.3+:approx_topk 函数
  • Loki 3.5+:Promtail 已弃用(请使用 Grafana Alloy)
  • Loki 3.6+:可水平扩展的压缩器,Loki UI 作为 Grafana 插件

弃用项:Promtail(请使用 Alloy)、BoltDB 存储(请使用带有 v13 架构的 TSDB)

评论

支持 Markdown