{"id":"grafana","kind":"sdk","name":"Grafana","slug":"grafana","description":"Observability stack clients and tooling around Grafana, Prometheus, Loki, and Tempo.","vendor":"Grafana Labs","languages":["go","typescript","python"],"categories":["observability"],"homepage":"https://grafana.com","docsUrl":"https://grafana.com/docs","githubUrl":"https://github.com/grafana/skills","packages":[{"registry":"npm","name":"@grafana/data","url":"https://www.npmjs.com/package/@grafana/data"}],"tags":["dashboards","metrics","logs"],"skills":[{"name":"dashboarding","url":"https://skills.sh/grafana/skills/dashboarding","install":"npx skills add grafana/skills --skill dashboarding","sdk":"grafana","key":"grafana/dashboarding","description":"Build, modify, and ship Grafana dashboards as JSON via the HTTP API — panel types (timeseries / stat / gauge / table / heatmap / logs / traces / node-graph), `gridPos` 24-column layout, units, thresholds, template + datasource + chained variables, transformations (`organize` / `calculateField` / `filterByValue`), panel + dashboard links with `${__field.labels.x}` / `${__from}`, and Loki/Prometheus annotations. Use when scripting dashboard creation, writing the dashboard JSON for a new service, adding a `$job` dropdown variable, computing an \"Error %\" column with a transformation, overlaying deploys as annotations, or pushing a dashboard via `POST /api/dashboards/db` — even when the user says \"create a dashboard for this metric\", \"add a service dropdown\", \"show errors as percentage\", \"overlay our deploys\", or \"export the dashboard JSON\" without naming the API or schema. After every API push, verify with the returned `version` plus a GET on the dashboard UID.","hasContent":true,"content":"---\nname: dashboarding\nlicense: Apache-2.0\ndescription: Build, modify, and ship Grafana dashboards as JSON via the HTTP API — panel types (timeseries / stat / gauge / table / heatmap / logs / traces / node-graph), `gridPos` 24-column layout, units, thresholds, template + datasource + chained variables, transformations (`organize` / `calculateField` / `filterByValue`), panel + dashboard links with `${__field.labels.x}` / `${__from}`, and Loki/Prometheus annotations. Use when scripting dashboard creation, writing the dashboard JSON for a new service, adding a `$job` dropdown variable, computing an \"Error %\" column with a transformation, overlaying deploys as annotations, or pushing a dashboard via `POST /api/dashboards/db` — even when the user says \"create a dashboard for this metric\", \"add a service dropdown\", \"show errors as percentage\", \"overlay our deploys\", or \"export the dashboard JSON\" without naming the API or schema. After every API push, verify with the returned `version` plus a GET on the dashboard UID.\n---\n\n# Grafana Dashboard Authoring\n\n> **Docs**: https://grafana.com/docs/grafana/latest/dashboards/\n\nDashboards are JSON. Author once, push via API, share by `uid`.\n\n## Prerequisites\n\n- Grafana stack (OSS, Enterprise, or Cloud) reachable from your machine\n- API token with `dashboards:write` (`Authorization: Bearer <token>`)\n- `jq` for inspecting responses\n- The JSON-schema cheat sheet in [`references/json-schema.md`](references/json-schema.md)\n\n## Common Workflows\n\n### 1. Push a new dashboard via the API + verify\n\n```bash\n# 1. Build the payload — wrap the dashboard JSON, set folder, mark overwrite\ncat > /tmp/dash.json <<'JSON'\n{\n  \"dashboard\": {\n    \"uid\": \"demo-svc-v1\",\n    \"title\": \"Demo Service\",\n    \"schemaVersion\": 41,\n    \"tags\": [\"demo\"],\n    \"time\": { \"from\": \"now-1h\", \"to\": \"now\" },\n    \"templating\": { \"list\": [] },\n    \"panels\": [{\n      \"id\": 1, \"type\": \"timeseries\", \"title\": \"Request Rate\",\n      \"gridPos\": { \"x\": 0, \"y\": 0, \"w\": 24, \"h\": 8 },\n      \"datasource\": { \"type\": \"prometheus\", \"uid\": \"prometheus\" },\n      \"targets\": [{\n        \"expr\": \"sum(rate(http_requests_total[5m])) by (status_code)\",\n        \"legendFormat\": \"{{status_code}}\", \"refId\": \"A\"\n      }],\n      \"fieldConfig\": { \"defaults\": { \"unit\": \"reqps\" }, \"overrides\": [] }\n    }]\n  },\n  \"folderUid\": \"\",\n  \"overwrite\": true,\n  \"message\": \"initial push\"\n}\nJSON\n\n# 2. Validate the JSON BEFORE you send it (catches trailing-comma typos)\njq empty /tmp/dash.json && echo \"json ok\"\n\n# 3. POST\nRESP=$(curl -s -X POST -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  \"$GRAFANA/api/dashboards/db\" -d @/tmp/dash.json)\necho \"$RESP\" | jq '{status, uid, url, version}'\n# Expect: status=\"success\", url=\"/d/demo-svc-v1/...\", version=1 (incremented on each push)\n\n# 4. Verify the round-trip — read it back and confirm one panel + the expected title\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\n  \"$GRAFANA/api/dashboards/uid/demo-svc-v1\" \\\n  | jq '{title: .dashboard.title, panels: (.dashboard.panels | length)}'\n# Expect: {\"title\":\"Demo Service\",\"panels\":1}\n\n# 5. Open the dashboard in a browser — confirm the panel renders with data.\n```\n\n### 2. Add a `$job` template variable to an existing dashboard\n\n```bash\n# 1. Fetch existing dashboard\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\n  \"$GRAFANA/api/dashboards/uid/demo-svc-v1\" > /tmp/dash.json\n\n# 2. Edit templating.list — append:\n#   { \"name\":\"job\", \"type\":\"query\",\n#     \"datasource\":{\"type\":\"prometheus\",\"uid\":\"prometheus\"},\n#     \"query\":{\"query\":\"label_values(up, job)\",\"refId\":\"A\"},\n#     \"refresh\":2, \"includeAll\":true, \"multi\":true, \"label\":\"Service\" }\n#  (Use jq, an editor, or the Grafana UI — schema in references/json-schema.md.)\n\n# 3. Update the panel expr to use the variable: rate(http_requests_total{job=~\"$job\"}[5m])\n\n# 4. POST it back with overwrite: true. Verify the variable appears in the UI dropdown.\n```\n\n### 3. Compute an \"Error %\" column with a transformation\n\n```json\n{\n  \"id\": \"calculateField\",\n  \"options\": {\n    \"alias\": \"Error %\", \"mode\": \"reduceRow\",\n    \"reduce\": { \"reducer\": \"last\" },\n    \"binary\": { \"left\": \"errors\", \"right\": \"total\", \"operator\": \"/\" }\n  }\n}\n```\n\nAdd this to the panel's `transformations: []`. Verify in the UI panel inspector — the new field should appear and update with the variable selection.\n\nFull schema (panels, units, all transformations, annotations, links): [`references/json-schema.md`](references/json-schema.md).\n\n## API reference\n\n```bash\n# Get\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\n  \"$GRAFANA/api/dashboards/uid/<uid>\" | jq '.dashboard'\n\n# Search\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\n  \"$GRAFANA/api/search?query=kubernetes&type=dash-db\" | jq '.[] | {uid,title,folderTitle}'\n\n# Create folder\ncurl -s -X POST -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \"$GRAFANA/api/folders\" \\\n  -d '{\"uid\":\"platform-team\",\"title\":\"Platform Team\"}'\n```\n\nFor dashboards embedded in app plugins, use `@grafana/scenes` (skill `grafana-o11y:grafana-scenes`).\n\n## Resources\n\n- [Dashboard JSON model](https://grafana.com/docs/grafana/latest/dashboards/build-dashboards/view-dashboard-json-model/)\n- [HTTP API — dashboards](https://grafana.com/docs/grafana/latest/developers/http_api/dashboard/)\n- [Panel types](https://grafana.com/docs/grafana/latest/panels-visualizations/)\n- [Variables](https://grafana.com/docs/grafana/latest/dashboards/variables/)\n- [Transformations](https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/transform-data/)\n","contentSource":"skills.sh/api/download/grafana/skills/dashboarding","contentFetchedAt":"2026-07-28T23:15:41.702Z"},{"name":"promql","url":"https://skills.sh/grafana/skills/promql","install":"npx skills add grafana/skills --skill promql","sdk":"grafana","key":"grafana/promql","description":"Write, validate, and optimize PromQL for Prometheus / Grafana Mimir / Grafana Cloud Metrics. Covers `rate` vs `irate` vs `increase`, label matchers and regex, `sum / avg / topk / by / without` aggregation, classic + native `histogram_quantile`, ratios with divide-by-zero guards, `absent` / `changes` for staleness, time offsets and `predict_linear`, recording-rule naming, SLO + burn-rate math, and a cardinality-hunting playbook. Use when writing a metric query, fixing wrong p95s, building an error-budget alert, debugging \"query is slow\", finding the noisy label that blew up cardinality, or migrating a dashboard query to a recording rule — even when the user says \"calculate the error rate\", \"p99 latency\", \"sum by service\", \"why is this query slow\", or \"what's filling Mimir\" without naming PromQL.","hasContent":true,"content":"---\nname: promql\nlicense: Apache-2.0\ndescription: Write, validate, and optimize PromQL for Prometheus / Grafana Mimir / Grafana Cloud Metrics. Covers `rate` vs `irate` vs `increase`, label matchers and regex, `sum / avg / topk / by / without` aggregation, classic + native `histogram_quantile`, ratios with divide-by-zero guards, `absent` / `changes` for staleness, time offsets and `predict_linear`, recording-rule naming, SLO + burn-rate math, and a cardinality-hunting playbook. Use when writing a metric query, fixing wrong p95s, building an error-budget alert, debugging \"query is slow\", finding the noisy label that blew up cardinality, or migrating a dashboard query to a recording rule — even when the user says \"calculate the error rate\", \"p99 latency\", \"sum by service\", \"why is this query slow\", or \"what's filling Mimir\" without naming PromQL.\n---\n\n# PromQL Query Patterns\n\n> **Docs**: https://prometheus.io/docs/prometheus/latest/querying/basics/\n\nPromQL returns either an **instant vector**, a **range vector**, or a **scalar**.\n\n**Golden rule:** `rate()` / `increase()` require a range vector ≥ 4× the scrape interval. 60s scrape → use `[5m]` minimum.\n\n## Prerequisites\n\n- A Prometheus / Mimir / Grafana Cloud endpoint to query (`/api/v1/query` or via Grafana Explore)\n- The PromQL pattern library in [`references/patterns.md`](references/patterns.md)\n\n## Common Workflows\n\n### 1. Write + validate a query\n\n```bash\n# 0. Point at your Prometheus/Mimir. For Grafana Cloud, use the metrics endpoint\n#    and add basic auth (-u \"<metrics_user>:<token>\") to each curl below.\nPROM=http://localhost:9090   # or https://prometheus-prod-XX.grafana.net/api/prom\n\n# 1. Sketch the query — for \"5xx error rate per service\":\nEXPR='sum(rate(http_requests_total{status_code=~\"5..\"}[5m])) by (service)'\n\n# 2. Validate syntax + that the metric/labels exist\ncurl -sG --data-urlencode \"query=${EXPR}\" \\\n  \"$PROM/api/v1/query\" | jq '.status, (.data.result|length)'\n# Expect: \"success\" and result count > 0. If 0 — check label spelling and scrape activity:\ncurl -sG --data-urlencode \"match[]=http_requests_total\" \"$PROM/api/v1/series\" | jq '.data | length'\n\n# 3. Sanity-check the magnitude — open Grafana Explore, paste the expr,\n#    confirm the values look right against a known ground truth (k6 run, log count, etc.)\n```\n\n### 2. Common patterns to copy\n\n**Per-status request rate** (aggregate AFTER rate):\n\n```promql\nsum(rate(http_requests_total{job=\"api\"}[5m])) by (status_code)\n```\n\n**p95 latency** (must keep `le` in the inner aggregation):\n\n```promql\nhistogram_quantile(0.95,\n  sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service))\n```\n\n**Error rate with divide-by-zero guard:**\n\n```promql\nsum(rate(http_requests_total{status_code=~\"5..\"}[5m]))\n  / (sum(rate(http_requests_total[5m])) > 0)\n```\n\nFull library (recording rules, SLO burn-rate, offsets, cardinality hunt, native histograms): [`references/patterns.md`](references/patterns.md).\n\n### 3. Convert a slow dashboard query into a recording rule\n\n```yaml\n# 1. Pick the slow expression, give it a recording-rule name\ngroups:\n  - name: http_request_rates\n    interval: 1m\n    rules:\n      - record: job:http_request_duration_p95:rate5m\n        expr: |\n          histogram_quantile(0.95,\n            sum(rate(http_request_duration_seconds_bucket[5m])) by (le, job))\n```\n\n```bash\n# 2. After rules load, verify the new metric exists\ncurl -sG --data-urlencode \"query=job:http_request_duration_p95:rate5m\" \\\n  \"$PROM/api/v1/query\" | jq '.data.result | length'   # → > 0\n\n# 3. Verify it matches the original expression for at least one sample window\n# (Both queries should produce the same value at the same timestamp.)\n\n# 4. Replace the dashboard panel expression with the recording-rule metric.\n```\n\n## Common bugs\n\n- `histogram_quantile` returns NaN → forgot `by (le)` in the inner aggregation\n- \"No data\" → check the metric exists (`/api/v1/series`) and the window ≥ 4× scrape interval\n- Wrong rate magnitude → counter was aggregated before `rate()` (always `rate()` first)\n- Query timeout → series count too high; use `topk(...)` + a recording rule + drop high-cardinality labels (see [`references/patterns.md`](references/patterns.md))\n\n## Resources\n\n- [PromQL basics](https://prometheus.io/docs/prometheus/latest/querying/basics/)\n- [Operators](https://prometheus.io/docs/prometheus/latest/querying/operators/)\n- [Functions](https://prometheus.io/docs/prometheus/latest/querying/functions/)\n- [Grafana Mimir](https://grafana.com/docs/mimir/latest/)\n","contentSource":"skills.sh/api/download/grafana/skills/promql","contentFetchedAt":"2026-07-28T23:15:43.980Z"}],"official":true,"generatedAt":"2026-07-28T23:15:45.680Z"}