loki — skill for Claude Code, Codex and Cursor
Grafana's loki skill gives your coding agent a LogQL reference and Loki setup notes. It covers stream selectors, parsers, metric queries, ingestion through Alloy, Promtail and Fluent Bit.
npx skills add grafana/skills --skill loki -a claude-codeWhat loki does
Loki indexes labels, not log content. Queries stay cheap, but you have to be precise: a stream selector first, then line filters. The skill keeps that order in front of the agent.
Inside is a LogQL reference — stream selectors, line filters, the json, logfmt, pattern, regexp and unpack parsers, label filters, line_format, label_format, drop and keep. A separate section covers metric queries: rate, count_over_time, bytes_rate, absent_over_time, aggregations with sum by and topk, numeric values pulled out with unwrap, and offset for comparing against an earlier window.
Worked examples are included: an error-rate alert, slow request lookup, nginx 5xx breakdown, credential leak detection. Ingestion configs too — loki.source.file and loki.process in Alloy, a Kubernetes DaemonSet, the HTTP push API with curl.
Architecture gets a short treatment: the write path from Distributor to object storage, the read path through Query Frontend and Querier, plus the roles of Ingester and Compactor. Enough that the agent won't mix up components when a pipeline breaks.
Worth installing if you already run Loki, or if you're still deciding where logs should live. The agent stops guessing at LogQL syntax and reads it from the reference instead.
What it helps with
- write a LogQL query with a selector, parser and label filter
- compute error rate per service and turn it into an alert
- set up log shipping to Loki with Alloy or Promtail
- debug why logs never reach the store
- extract numeric values from logs and build a metric from them
Example prompts for the agent
- Write a LogQL query for the 5xx rate per service over the last 5 minutes
- Build an Alloy config that tails /var/log/app/*.log and pushes to Loki
- Figure out why logs from Kubernetes pods aren't showing up in Loki
How to install loki
1Skills CLI (Vercel)
npx skills add grafana/skills --skill loki -a claude-code2Manually: put the files in place
~/.claude/skills/loki/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/loki/
1Skills CLI (Vercel)
npx skills add grafana/skills --skill loki -a codex2Manually: put the files in place
.agents/skills/loki/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add grafana/skills --skill loki -a cursor2Manually: put the files in place
.cursor/skills/loki/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install grafana/skills loki2Manually: put the files in place
.github/skills/loki/SKILL.md1Skills CLI (Vercel)
npx skills add grafana/skills --skill loki -a gemini-cli2Platform CLI
gemini skills install https://github.com/grafana/skills --path skills/grafana-lgtm/lokiManually: put the files in place
.devin/skills/loki/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add grafana/skills --skill loki -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about loki
How do I install loki in Claude?
Run npx skills add grafana/skills --skill loki -a claude-code. The skill lands in ~/.claude/skills/loki/SKILL.md.
What does the loki skill do?
It hands the agent a LogQL and Loki reference: selectors, parsers, metric queries, architecture, ingestion. Queries and configs come out with correct syntax.
Which platforms does loki support?
Claude, Codex, Cursor, GitHub Copilot, Gemini CLI and OpenCode. Each takes its own install flag, such as -a cursor or -a opencode.
Source text
SKILL.md · Apache-2.0
---
name: loki
license: Apache-2.0
description: >
Grafana Loki log aggregation and LogQL query language. Covers LogQL syntax (log queries, metric queries,
label matchers, line filters, parsers: json/logfmt/pattern/regexp/unpack, label filters, line_format),
Loki architecture, log ingestion via Alloy/Promtail/Fluent Bit, structured metadata, and Logs Drilldown.
Use when writing LogQL queries, configuring Loki, troubleshooting log pipelines, or analyzing logs.
---
# Grafana Loki - Log Aggregation
> **Docs**: https://grafana.com/docs/loki/latest/
Indexes only metadata (labels), not full log content — dramatically cheaper than full-text search systems.
## LogQL Quick Reference
### Log Stream Selector (required in every query)
```logql
{app="nginx"} # exact match
{app!="nginx"} # not equal
{app=~"nginx|apache"} # regex match
{app!~"debug.*"} # regex not match
{app="nginx", env="prod"} # AND (multiple labels)
```
### Line Filters (pipeline stage 1 - put first for performance)
```logql
{app="nginx"} |= "error" # contains string
{app="nginx"} != "info" # does not contain
{app="nginx"} |~ "error|warn" # regex match
{app="nginx"} !~ "health.*check" # regex not match
{app="nginx"} |= `"status":5` # backtick avoids escaping
```
### Parsers
```logql
# JSON
{app="api"} | json
{app="api"} | json status="http_status", path="request.path"
# Logfmt
{app="api"} | logfmt
{app="api"} | logfmt --strict
{app="api"} | logfmt --keep-empty
# Pattern (positional, _ discards)
{app="nginx"} | pattern `<ip> - - <_> "<method> <uri> <_>" <status> <bytes>`
# Regexp (named capture groups)
{app="nginx"} | regexp `(?P<method>\w+) (?P<path>\S+) HTTP/(?P<version>\S+)`
# Unpack (unwrap Promtail packed labels)
{app="api"} | unpack
```
### Label Filters (after parsers)
```logql
{app="api"} | json | status >= 500
{app="api"} | json | status == 200 and method != "OPTIONS"
{app="api"} | logfmt | duration > 1s
{app="api"} | json | level =~ "error|warn"
{app="api"} | json | bytes > 20MB
{app="api"} | json | path != "/healthz"
```
### Line Format
```logql
{app="api"} | json | line_format "{{.method}} {{.path}} -> {{.status}} ({{.duration}})"
{app="api"} | logfmt | line_format `{{.level | upper}}: {{.msg}}`
```
### Label Format
```logql
{app="api"} | logfmt | label_format new_name=old_name
{app="api"} | logfmt | label_format severity=level, svc=app
{app="api"} | logfmt | label_format msg=`{{.level}}: {{.message}}`
```
### Drop/Keep Labels
```logql
{app="api"} | json | drop filename, level="debug"
{app="api"} | json | keep level, status, method
```
### Decolorize
```logql
{app="cli-tool"} | decolorize
```
## Metric Queries
### Log Range Aggregations
```logql
# Requests per second
rate({app="nginx"}[5m])
# Total log lines in window
count_over_time({app="nginx"}[1h])
# Bytes per second
bytes_rate({app="nginx"}[5m])
# Total bytes
bytes_over_time({app="nginx"}[1h])
# Returns 1 if no logs in range (for absence alerting)
absent_over_time({app="nginx"}[5m])
```
### Aggregation
```logql
# Error rate by service
sum(rate({env="prod"} |= "error" [5m])) by (app)
# Top 5 most active services
topk(5, sum(rate({env="prod"}[5m])) by (app))
# Total errors across all services
sum(count_over_time({env="prod"} |= "error" [5m]))
```
### Unwrapped Range Aggregations (numeric values from logs)
```logql
# Average request duration from logfmt
avg_over_time({app="api"} | logfmt | unwrap duration [5m])
# 95th percentile latency
quantile_over_time(0.95, {app="api"} | logfmt | unwrap duration [5m]) by (app)
# Sum of bytes from JSON logs
sum_over_time({app="api"} | json | unwrap bytes [5m])
# With conversion (duration string → seconds)
avg_over_time({app="api"} | logfmt | unwrap duration | duration_seconds [5m])
```
### Offset Modifier
```logql
# Compare current rate vs 1 hour ago
rate({app="nginx"}[5m]) / rate({app="nginx"}[5m] offset 1h)
```
## Practical Examples
### Error rate alert query
```logql
sum(rate({env="prod"} |= "error" [5m])) by (service)
/
sum(rate({env="prod"}[5m])) by (service)
> 0.05
```
### Slow requests
```logql
{app="api"} | logfmt | duration > 1s | line_format "SLOW: {{.method}} {{.path}} {{.duration}}"
```
### HTTP 5xx errors with details
```logql
{app="nginx"} | pattern `<ip> - - <_> "<method> <uri> <_>" <status> <bytes>` | status >= 500
```
### Credential leak detection
```logql
{namespace="prod"} |~ `https?://\w+:\w+@`
```
## Sending Logs to Loki
### Via Grafana Alloy
```alloy
loki.source.file "app" {
targets = [{__path__ = "/var/log/app/*.log", job = "app"}]
forward_to = [loki.process.parse.receiver]
}
loki.process "parse" {
forward_to = [loki.write.cloud.receiver]
stage.json {
expressions = { level = "level", msg = "message" }
}
stage.labels {
values = { level = "" }
}
stage.drop {
expression = ".*healthcheck.*"
}
}
loki.write "cloud" {
endpoint {
url = "https://logs-xxx.grafana.net/loki/api/v1/push"
basic_auth {
username = sys.env("LOKI_USER")
password = sys.env("GRAFANA_API_KEY")
}
}
external_labels = { cluster = "prod" }
}
```
### Via Kubernetes (Alloy DaemonSet)
```alloy
discovery.kubernetes "pods" {
role = "pod"
}
loki.source.kubernetes "pods" {
targets = discovery.kubernetes.pods.targets
forward_to = [loki.write.cloud.receiver]
}
```
### Loki HTTP Push API
```bash
curl -X POST https://logs-xxx.grafana.net/loki/api/v1/push \
-u "user:apikey" \
-H 'Content-Type: application/json' \
-d '{
"streams": [{
"stream": { "app": "myapp", "env": "prod" },
"values": [
["1609459200000000000", "log line here"]
]
}]
}'
```
## Architecture
```
Push path: Client → Distributor → Ingester (WAL) → Object Storage (chunks)
Read path: Query → Query Frontend → Querier → Ingester + Store (chunks)
```
**Components:**
- **Distributor**: Validates and hashes incoming log streams
- **Ingester**: Buffers chunks in memory, flushes to object storage
- **Querier**: Executes LogQL queries
- **Query Frontend**: Caches, splits, and parallelizes queries
- **Compactor**: Manages retention and deduplication
## References
- [LogQL Reference](references/logql.md)
- [Configuration](references/configuration.md)
- [Sending Data](references/send-data.md)
© grafana · Apache-2.0 · grafana/skills