关于 kubesense-spl
kubesense-spl 是通过 SPL 查询 KubeSense 日志的技能,说明如何先验证再执行查询,并介绍字段命名、管道语义和访问限制。
主要功能
- 01验证 SPL 查询并查看编译后的 SQL
- 02执行只读日志查询,最多返回 1000 行
- 03用管道命令筛选和聚合日志
- 04通过 log_processed 查询解析后的 JSON 属性
- 05了解字段命名及角色权限限制
适用场景
- 01按 workload 统计错误数量
- 02在指定时间范围查找日志消息
- 03按 namespace 绘制日志数量趋势
MCP 相关
需要 KubeSense MCP 服务,并调用其日志相关工具验证和执行 SPL 查询。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ kubesense-ai/ kubesense-mcp-skills --skill kubesense-spl安装后在 Claude Code 中输入/kubesense-spl确认已加载。
详细介绍
KubeSense SPL
需要 KubeSense MCP 服务;有关连接和身份验证,请参阅 kubesense-mcp。
此处的工具会根据 logs 模块进行 RBAC 授权。
SPL 仅适用于日志。 没有用于追踪或指标的 SPL——请使用 kubesense-traces 和 kubesense-metrics。
工具
| 工具 | 使用时机 | 返回内容 |
|---|---|---|
get-trace-or-log-fields (signal: "logs") | 查找动态属性键——不是列名,见下文 | 当前时间窗口的字段目录 |
validate-spl | 提交任何查询之前 | valid 以及编译成的 ClickHouse SQL |
execute-spl | 自行回答问题时 | 行(TSV),最多 1000 行 |
执行前先验证。 SPL 的解析器对未知字段和未知函数一视同仁,因此名称错误也能编译,并会在运行时失败——此时扫描费用已经产生。
validate-spl 不产生扫描费用,因此先验证再执行的组合成本低,反过来则会造成浪费。
execute-spl 需要 clusters 和时间窗口;validate-spl 两者都不需要。若 search-logs
或 analyze-logs 能表达查询需求,请优先使用它们——它们会强制执行命名空间级和工作负载级访问规则,而 SPL 端点无法做到;这也是为何这两个 SPL 工具会直接拒绝范围受限角色的请求。
字段名称与其他所有地方正好相反
KubeSense 的所有其他界面——search-logs、analyze-logs、SQL 端点和字段目录——都使用目录标签,并拒绝存储列名。SPL 则相反。
| SPL 使用 | 其他所有工具使用 |
|---|---|
level | type |
pod_name | instance |
cluster | domain |
container_name(或 container) | container |
node_name(或 node) | node |
host | — 与 node_name 不同的列;两者都存在 |
SPL 识别的完整字段集合:timestamp(或 @timestamp)· body(或 @message)· level ·
cluster · namespace · workload · pod_name(或 @logstream)· container_name(或
container)· node_name(或 node)· host · service · source · format · env_type ·
raw · @loggroup(= workload)。
警告
SPL 没有
region、app_version、instance、type、domain、body_length或kuid。 SPL 不认识的名称不会报错——它会作为裸列名传给 ClickHouse,因此查询能够解析并编译,只有在有人运行时才会失败。
警告
get-trace-or-log-fields返回的名称不适用于 SPL。 它报告的是目录标签——type、instance、domain——SPL 不接受这些名称。仅使用它来发现动态属性键,并通过log_processed.<key>访问这些属性。列名请使用上表。
动态属性
通过 log_processed. 前缀访问已解析的 JSON 字段——这相当于 SQL 端点的
@attr:
filter log_processed.status = "500"
| stats count(*) as errors by log_processed.url
解析顺序为字符串属性 → 浮点属性 → JSON 解析的正文。
Pipeline
命令以 | 分隔,从左向右读取。
"connection refused"
| filter level = "ERROR" AND namespace = "production"
| stats count(*) as errors by workload
| sort errors desc
| head 20
命令: fields · filter(别名:where、search)· parse · rex · eval · stats ·
timechart · dedup · head · tail · sort · limit · rename · table · top · rare。
不带前缀的带引号字符串会对消息正文进行全文搜索,且必须放在最前面。# 用于开始注释。
顺序具有语义,而非仅是格式。 stats 前的 filter 会变成 WHERE;同一个 filter 放在 stats 后面则会对聚合结果执行 HAVING:
filter level = "ERROR" | stats count(*) as n by workload | filter n > 100
stats / timechart 的聚合函数:count(*) · sum · avg · min · max · dc
(不同值计数)· median · mode · range · stdev · stdevp · var · sumsq · latest ·
earliest · values · list · perc<N>。
警告
百分位数使用
perc95(x),绝不能写p95(x)。p95不是函数。它和未知字段一样,能够通过编译,但会在运行时失败——而且 KubeSense 自己的 SPL 手册曾有一段时间教了错误的写法,因此旧示例中会出现这种形式。
timechart 接受 span=<N><s|m|h|d>,并将分桶列命名为 _time:
timechart span=5m count(*) as errors by workload
时间范围由服务端管理
时间范围和集群筛选由服务端根据请求应用,而不是由查询决定。不要编写时间戳条件。这与 SQL 端点正好相反,后者必须使用 $__timeFilter(timestamp)。
始终进行验证
这里的 validate-spl 不是走过场,因为 SPL 解析器接受的内容比 ClickHouse 能执行的更多:
| 错误 | 能解析? | 能编译? | 检测方式 |
|---|---|---|---|
filter level =(语法错误) | ✗ | — | parse |
filter region = "x"(未知字段) | ✓ | ✓ | 只有 validate-spl |
stats p95(x)(未知函数) | ✓ | ✓ | 只有 validate-spl |
log_processed.typo | ✓ | ✓ | 无 — 返回 null |
validate-spl 会将每个标识符和函数与实际日志表进行比对解析,不会扫描任何行,并会在 ## translated_sql 下返回编译后的 SQL。请阅读它——这是确认 pod_name 是否解析为你想要的列的方法。
它无法检查属性键:错误的 log_processed.<key> 会静默返回 null,这与 SQL 侧的错误 @attr 完全相同。请先使用 get-trace-or-log-fields 确认键。
限制
- 最多 1000 行,除非管道以
| head N、| tail N或| limit N结尾。 - 只读;文件系统、网络和系统函数会被拒绝。
- 对限定到特定集群、命名空间或工作负载的角色不可用——SPL 端点只应用集群筛选,无法执行更精细的规则。请改用
search-logs/analyze-logs,它们可以执行这些规则。
示例
按工作负载统计错误数,最严重的排在最前
filter level = "ERROR"
| stats count(*) as errors by workload
| sort errors desc
查找超时并读取日志
"timeout"
| filter workload = "checkout"
| fields timestamp, pod_name, body
| head 50
按命名空间划分的错误率随时间变化
filter level = "ERROR"
| timechart span=5m count(*) as errors by namespace
从 JSON 字段计算延迟百分位数
filter log_processed.duration_ms > 0
| stats perc95(log_processed.duration_ms) as p95, avg(log_processed.duration_ms) as mean by log_processed.route
| sort p95 desc
从非结构化日志行中提取字段
"APICallLogs:"
| parse 'Path:* Method:* StatusCode:*' as path, method, code
| filter code != "200"
| stats count(*) as errors by path, code
规则
- 使用存储名称,而不是目录标签:
level而非type,pod_name而非instance,cluster而非domain。 get-trace-or-log-fields仅用于属性键——它返回的列名不适用于 SPL。- 交接或运行查询前,先调用
validate-spl,并阅读它返回的translated_sql。 - 使用
perc95(x),绝不能写p95(x)。 - 不要编写时间或集群筛选——服务端会应用这两项筛选。
- 不带前缀的带引号搜索字符串必须放在管道最前面。
stats前的filter是 WHERE;stats后的filter是 HAVING。- 在 SPL 中执行聚合;不要请求原始行再自行计数。最多 1000 行。
- 使用
log_processed.<key>获取已解析的 JSON 字段——错误的键会返回 null,而不是报错。 - 仅支持日志。Trace 和指标不支持 SPL。