Loading...
Loading...
Write, validate and run KubeSense SPL — the piped log query language — via validate-spl and execute-spl. Covers the storage-name field contract that inverts every other KubeSense surface, log_processed attributes, the command and aggregation vocabulary, and why an SPL query can compile and still fail.
npx skill4agent add kubesense-ai/kubesense-mcp-skills kubesense-spllogs| Tool | Use when | Returns |
|---|---|---|
| To find dynamic attribute keys — not column names, see below | Field catalog for your window |
| Before handing any query over | |
| To answer a question yourself | Rows (TSV), capped at 1000 |
validate-splexecute-splclustersvalidate-splsearch-logsanalyze-logssearch-logsanalyze-logs| SPL uses | Every other tool uses |
|---|---|
| |
| |
| |
| |
| |
| — a different column from |
timestamp@timestampbody@messagelevelclusternamespaceworkloadpod_name@logstreamcontainer_namecontainernode_namenodehostservicesourceformatenv_typeraw@loggroupworkload[!WARNING] SPL has no,region,app_version,instance,type,domainorbody_length. A name SPL does not know is not an error — it is passed through to ClickHouse as a bare column name, so the query parses, compiles, and fails only when someone runs it.kuid
[!WARNING]returns the wrong names for SPL. It reports catalog labels —get-trace-or-log-fields,type,instance— which SPL does not accept. Use it only to discover dynamic attribute keys, and address those asdomain. For columns, use the table above.log_processed.<key>
log_processed.@attrfilter log_processed.status = "500"
| stats count(*) as errors by log_processed.url|"connection refused"
| filter level = "ERROR" AND namespace = "production"
| stats count(*) as errors by workload
| sort errors desc
| head 20fieldsfilterwheresearchparserexevalstatstimechartdedupheadtailsortlimitrenametabletoprare#filterstatsWHEREfilterstatsHAVINGfilter level = "ERROR" | stats count(*) as n by workload | filter n > 100statstimechartcount(*)sumavgminmaxdcmedianmoderangestdevstdevpvarsumsqlatestearliestvalueslistperc<N>[!WARNING] Percentiles are, neverperc95(x).p95(x)is not a function. Like an unknown field it compiles and fails at run time — and KubeSense's own SPL manual taught the wrong form for a while, so it appears in older examples.p95
timechartspan=<N><s|m|h|d>_timetimechart span=5m count(*) as errors by workload$__timeFilter(timestamp)validate-spl| Mistake | Parses? | Compiles? | Caught by |
|---|---|---|---|
| ✗ | — | parse |
| ✓ | ✓ | only |
| ✓ | ✓ | only |
| ✓ | ✓ | nothing — returns nulls |
validate-spl## translated_sqlpod_namelog_processed.<key>@attrget-trace-or-log-fields| head N| tail N| limit Nsearch-logsanalyze-logsfilter level = "ERROR"
| stats count(*) as errors by workload
| sort errors desc"timeout"
| filter workload = "checkout"
| fields timestamp, pod_name, body
| head 50filter level = "ERROR"
| timechart span=5m count(*) as errors by namespacefilter 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, codeleveltypepod_nameinstanceclusterdomainget-trace-or-log-fieldsvalidate-spltranslated_sqlperc95(x)p95(x)filterstatsstatslog_processed.<key>