@intentius/chant-lexicon-grafana 0.98.0 → 0.100.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (532) hide show
  1. package/README.md +24 -8
  2. package/dist/actions/grafana.d.ts +24 -0
  3. package/dist/actions/grafana.d.ts.map +1 -0
  4. package/dist/actions/index.d.ts +2 -0
  5. package/dist/actions/index.d.ts.map +1 -0
  6. package/dist/alerting-build.d.ts +128 -0
  7. package/dist/alerting-build.d.ts.map +1 -0
  8. package/dist/alerting.d.ts +273 -0
  9. package/dist/alerting.d.ts.map +1 -0
  10. package/dist/annotations.d.ts +61 -0
  11. package/dist/annotations.d.ts.map +1 -0
  12. package/dist/api/apply.d.ts +160 -0
  13. package/dist/api/apply.d.ts.map +1 -0
  14. package/dist/api/bind.d.ts +32 -0
  15. package/dist/api/bind.d.ts.map +1 -0
  16. package/dist/api/client.d.ts +76 -0
  17. package/dist/api/client.d.ts.map +1 -0
  18. package/dist/api/converge.d.ts +33 -0
  19. package/dist/api/converge.d.ts.map +1 -0
  20. package/dist/api/dashboards.d.ts +102 -0
  21. package/dist/api/dashboards.d.ts.map +1 -0
  22. package/dist/api/datasources.d.ts +26 -0
  23. package/dist/api/datasources.d.ts.map +1 -0
  24. package/dist/api/fake-grafana-writes.d.ts +41 -0
  25. package/dist/api/fake-grafana-writes.d.ts.map +1 -0
  26. package/dist/api/fake-grafana.d.ts +63 -0
  27. package/dist/api/fake-grafana.d.ts.map +1 -0
  28. package/dist/api/folders.d.ts +146 -0
  29. package/dist/api/folders.d.ts.map +1 -0
  30. package/dist/api/library-panels.d.ts +52 -0
  31. package/dist/api/library-panels.d.ts.map +1 -0
  32. package/dist/build.d.ts +55 -6
  33. package/dist/build.d.ts.map +1 -1
  34. package/dist/catalog.d.ts +1 -1
  35. package/dist/catalog.d.ts.map +1 -1
  36. package/dist/codegen/docs.d.ts.map +1 -1
  37. package/dist/codegen/generate.d.ts +7 -1
  38. package/dist/codegen/generate.d.ts.map +1 -1
  39. package/dist/codegen/schema-types.d.ts +3 -3
  40. package/dist/codegen/schema-types.d.ts.map +1 -1
  41. package/dist/composites/agent-dashboard.d.ts.map +1 -1
  42. package/dist/composites/catalog.d.ts.map +1 -1
  43. package/dist/composites/index.d.ts +4 -2
  44. package/dist/composites/index.d.ts.map +1 -1
  45. package/dist/composites/red-dashboard.d.ts +21 -2
  46. package/dist/composites/red-dashboard.d.ts.map +1 -1
  47. package/dist/composites/shared.d.ts +11 -3
  48. package/dist/composites/shared.d.ts.map +1 -1
  49. package/dist/composites/slo-alert-rules.d.ts +92 -0
  50. package/dist/composites/slo-alert-rules.d.ts.map +1 -0
  51. package/dist/config.d.ts +111 -0
  52. package/dist/config.d.ts.map +1 -0
  53. package/dist/contact-point-secrets.d.ts +17 -0
  54. package/dist/contact-point-secrets.d.ts.map +1 -0
  55. package/dist/dashboard.d.ts +51 -9
  56. package/dist/dashboard.d.ts.map +1 -1
  57. package/dist/datasource-refs.d.ts +99 -0
  58. package/dist/datasource-refs.d.ts.map +1 -0
  59. package/dist/datasource-settings.d.ts +834 -0
  60. package/dist/datasource-settings.d.ts.map +1 -0
  61. package/dist/datasource.d.ts +82 -11
  62. package/dist/datasource.d.ts.map +1 -1
  63. package/dist/deep-observe-hooks.d.ts +64 -0
  64. package/dist/deep-observe-hooks.d.ts.map +1 -0
  65. package/dist/deep-observe.d.ts +47 -0
  66. package/dist/deep-observe.d.ts.map +1 -0
  67. package/dist/describe-resources.d.ts +50 -0
  68. package/dist/describe-resources.d.ts.map +1 -0
  69. package/dist/detect.d.ts +32 -3
  70. package/dist/detect.d.ts.map +1 -1
  71. package/dist/export-resources.d.ts +38 -0
  72. package/dist/export-resources.d.ts.map +1 -0
  73. package/dist/folder.d.ts +68 -0
  74. package/dist/folder.d.ts.map +1 -0
  75. package/dist/import/alerting.d.ts +40 -0
  76. package/dist/import/alerting.d.ts.map +1 -0
  77. package/dist/import/edits.d.ts +47 -0
  78. package/dist/import/edits.d.ts.map +1 -0
  79. package/dist/import/embedded.d.ts +14 -0
  80. package/dist/import/embedded.d.ts.map +1 -0
  81. package/dist/import/generator.d.ts +60 -0
  82. package/dist/import/generator.d.ts.map +1 -0
  83. package/dist/import/live-export.d.ts +108 -0
  84. package/dist/import/live-export.d.ts.map +1 -0
  85. package/dist/import/mappings.d.ts +89 -0
  86. package/dist/import/mappings.d.ts.map +1 -0
  87. package/dist/import/model.d.ts +105 -0
  88. package/dist/import/model.d.ts.map +1 -0
  89. package/dist/import/normalize-alerting.d.ts +26 -0
  90. package/dist/import/normalize-alerting.d.ts.map +1 -0
  91. package/dist/import/normalize.d.ts +74 -0
  92. package/dist/import/normalize.d.ts.map +1 -0
  93. package/dist/import/parser.d.ts +125 -0
  94. package/dist/import/parser.d.ts.map +1 -0
  95. package/dist/import/report.d.ts +26 -0
  96. package/dist/import/report.d.ts.map +1 -0
  97. package/dist/import/testdata/fixtures.d.ts +41 -0
  98. package/dist/import/testdata/fixtures.d.ts.map +1 -0
  99. package/dist/import/v2.d.ts +73 -0
  100. package/dist/import/v2.d.ts.map +1 -0
  101. package/dist/index.d.ts +31 -12
  102. package/dist/index.d.ts.map +1 -1
  103. package/dist/init-templates.d.ts +27 -0
  104. package/dist/init-templates.d.ts.map +1 -0
  105. package/dist/integrity.json +22 -12
  106. package/dist/k8s.d.ts +107 -0
  107. package/dist/k8s.d.ts.map +1 -0
  108. package/dist/lint/audit-catalog.d.ts +2 -1
  109. package/dist/lint/audit-catalog.d.ts.map +1 -1
  110. package/dist/lint/post-synth/graf101.d.ts +2 -2
  111. package/dist/lint/post-synth/graf102.d.ts +1 -1
  112. package/dist/lint/post-synth/graf104.d.ts +2 -2
  113. package/dist/lint/post-synth/graf106.d.ts +2 -2
  114. package/dist/lint/post-synth/graf107.d.ts +1 -1
  115. package/dist/lint/post-synth/graf108.d.ts +8 -0
  116. package/dist/lint/post-synth/graf108.d.ts.map +1 -0
  117. package/dist/lint/post-synth/graf109.d.ts +8 -0
  118. package/dist/lint/post-synth/graf109.d.ts.map +1 -0
  119. package/dist/lint/post-synth/graf110.d.ts +8 -0
  120. package/dist/lint/post-synth/graf110.d.ts.map +1 -0
  121. package/dist/lint/post-synth/graf111.d.ts +8 -0
  122. package/dist/lint/post-synth/graf111.d.ts.map +1 -0
  123. package/dist/lint/post-synth/graf112.d.ts +8 -0
  124. package/dist/lint/post-synth/graf112.d.ts.map +1 -0
  125. package/dist/lint/post-synth/graf113.d.ts +8 -0
  126. package/dist/lint/post-synth/graf113.d.ts.map +1 -0
  127. package/dist/lint/post-synth/graf114.d.ts +8 -0
  128. package/dist/lint/post-synth/graf114.d.ts.map +1 -0
  129. package/dist/lint/post-synth/graf115.d.ts +8 -0
  130. package/dist/lint/post-synth/graf115.d.ts.map +1 -0
  131. package/dist/lint/post-synth/grafana-helpers.d.ts +7 -5
  132. package/dist/lint/post-synth/grafana-helpers.d.ts.map +1 -1
  133. package/dist/lint/post-synth/index.d.ts.map +1 -1
  134. package/dist/lint/rules/literal-secret.d.ts +7 -3
  135. package/dist/lint/rules/literal-secret.d.ts.map +1 -1
  136. package/dist/lsp/hover.d.ts.map +1 -1
  137. package/dist/manifest.json +1 -1
  138. package/dist/members.d.ts +27 -0
  139. package/dist/members.d.ts.map +1 -0
  140. package/dist/meta.json +205 -0
  141. package/dist/okf/index.md +53 -4
  142. package/dist/okf/rules/GRAF002.md +3 -2
  143. package/dist/okf/rules/GRAF101.md +3 -2
  144. package/dist/okf/rules/GRAF102.md +1 -0
  145. package/dist/okf/rules/GRAF104.md +2 -2
  146. package/dist/okf/rules/GRAF106.md +2 -2
  147. package/dist/okf/rules/GRAF108.md +11 -0
  148. package/dist/okf/rules/GRAF109.md +15 -0
  149. package/dist/okf/rules/GRAF110.md +11 -0
  150. package/dist/okf/rules/GRAF111.md +11 -0
  151. package/dist/okf/rules/GRAF112.md +16 -0
  152. package/dist/okf/rules/GRAF113.md +16 -0
  153. package/dist/okf/rules/GRAF114.md +11 -0
  154. package/dist/okf/rules/GRAF115.md +11 -0
  155. package/dist/okf/types/AdhocVariable.md +9 -0
  156. package/dist/okf/types/AlertListPanel.md +9 -0
  157. package/dist/okf/types/AlertQuery.md +9 -0
  158. package/dist/okf/types/AlertRule.md +9 -0
  159. package/dist/okf/types/AlertRuleGroup.md +9 -0
  160. package/dist/okf/types/AzureMonitorQuery.md +9 -0
  161. package/dist/okf/types/BarChartPanel.md +9 -0
  162. package/dist/okf/types/BarGaugePanel.md +9 -0
  163. package/dist/okf/types/BigQueryQuery.md +9 -0
  164. package/dist/okf/types/CanvasPanel.md +9 -0
  165. package/dist/okf/types/ClassicConditionsExpression.md +9 -0
  166. package/dist/okf/types/CloudMonitoringQuery.md +9 -0
  167. package/dist/okf/types/CloudWatchQuery.md +9 -0
  168. package/dist/okf/types/ContactPoint.md +14 -0
  169. package/dist/okf/types/Dashboard.md +2 -1
  170. package/dist/okf/types/Datasource.md +3 -2
  171. package/dist/okf/types/DatasourceProvisioning.md +9 -0
  172. package/dist/okf/types/ElasticsearchQuery.md +9 -0
  173. package/dist/okf/types/ExternalDatasource.md +15 -0
  174. package/dist/okf/types/FlameGraphPanel.md +9 -0
  175. package/dist/okf/types/Folder.md +9 -0
  176. package/dist/okf/types/GeomapPanel.md +9 -0
  177. package/dist/okf/types/GroupByVariable.md +9 -0
  178. package/dist/okf/types/HistogramPanel.md +9 -0
  179. package/dist/okf/types/MSSQLQuery.md +9 -0
  180. package/dist/okf/types/MathExpression.md +9 -0
  181. package/dist/okf/types/MuteTiming.md +13 -0
  182. package/dist/okf/types/MySQLQuery.md +9 -0
  183. package/dist/okf/types/NodeGraphPanel.md +9 -0
  184. package/dist/okf/types/NotificationPolicy.md +9 -0
  185. package/dist/okf/types/NotificationTemplate.md +9 -0
  186. package/dist/okf/types/PieChartPanel.md +9 -0
  187. package/dist/okf/types/PostgresQuery.md +9 -0
  188. package/dist/okf/types/PyroscopeQuery.md +9 -0
  189. package/dist/okf/types/ReduceExpression.md +9 -0
  190. package/dist/okf/types/ResampleExpression.md +9 -0
  191. package/dist/okf/types/SqlExpression.md +9 -0
  192. package/dist/okf/types/StateTimelinePanel.md +9 -0
  193. package/dist/okf/types/StatusHistoryPanel.md +9 -0
  194. package/dist/okf/types/SwitchVariable.md +9 -0
  195. package/dist/okf/types/ThresholdExpression.md +9 -0
  196. package/dist/okf/types/TrendPanel.md +9 -0
  197. package/dist/okf/types/XYChartPanel.md +9 -0
  198. package/dist/op/activities/grafana-apply.d.ts +86 -0
  199. package/dist/op/activities/grafana-apply.d.ts.map +1 -0
  200. package/dist/op/activities/index.d.ts +9 -0
  201. package/dist/op/activities/index.d.ts.map +1 -0
  202. package/dist/op/builders.d.ts +24 -0
  203. package/dist/op/builders.d.ts.map +1 -0
  204. package/dist/ownership.d.ts +78 -0
  205. package/dist/ownership.d.ts.map +1 -0
  206. package/dist/panel-options.d.ts +65 -0
  207. package/dist/panel-options.d.ts.map +1 -0
  208. package/dist/panels.d.ts +46 -9
  209. package/dist/panels.d.ts.map +1 -1
  210. package/dist/pin.d.ts +29 -7
  211. package/dist/pin.d.ts.map +1 -1
  212. package/dist/plugin.d.ts.map +1 -1
  213. package/dist/promql-check.d.ts +51 -0
  214. package/dist/promql-check.d.ts.map +1 -0
  215. package/dist/query-models.d.ts +95 -0
  216. package/dist/query-models.d.ts.map +1 -0
  217. package/dist/query.d.ts +116 -18
  218. package/dist/query.d.ts.map +1 -1
  219. package/dist/rules/graf101.ts +3 -3
  220. package/dist/rules/graf102.ts +1 -1
  221. package/dist/rules/graf104.ts +3 -3
  222. package/dist/rules/graf106.ts +3 -3
  223. package/dist/rules/graf107.ts +1 -1
  224. package/dist/rules/graf108.ts +17 -0
  225. package/dist/rules/graf109.ts +17 -0
  226. package/dist/rules/graf110.ts +17 -0
  227. package/dist/rules/graf111.ts +17 -0
  228. package/dist/rules/graf112.ts +17 -0
  229. package/dist/rules/graf113.ts +17 -0
  230. package/dist/rules/graf114.ts +17 -0
  231. package/dist/rules/graf115.ts +17 -0
  232. package/dist/rules/grafana-helpers.ts +27 -10
  233. package/dist/rules/literal-secret.ts +60 -6
  234. package/dist/schema/azuremonitor.gen.d.ts +354 -0
  235. package/dist/schema/azuremonitor.gen.d.ts.map +1 -0
  236. package/dist/schema/barchart.gen.d.ts +198 -0
  237. package/dist/schema/barchart.gen.d.ts.map +1 -0
  238. package/dist/schema/bargauge.gen.d.ts +97 -0
  239. package/dist/schema/bargauge.gen.d.ts.map +1 -0
  240. package/dist/schema/bigquery.gen.d.ts +93 -0
  241. package/dist/schema/bigquery.gen.d.ts.map +1 -0
  242. package/dist/schema/canvas.gen.d.ts +152 -0
  243. package/dist/schema/canvas.gen.d.ts.map +1 -0
  244. package/dist/schema/cloudwatch.gen.d.ts +394 -0
  245. package/dist/schema/cloudwatch.gen.d.ts.map +1 -0
  246. package/dist/schema/dashboard.gen.d.ts +196 -21
  247. package/dist/schema/dashboard.gen.d.ts.map +1 -1
  248. package/dist/schema/elasticsearch.gen.d.ts +444 -0
  249. package/dist/schema/elasticsearch.gen.d.ts.map +1 -0
  250. package/dist/schema/expr.gen.d.ts +606 -0
  251. package/dist/schema/expr.gen.d.ts.map +1 -0
  252. package/dist/schema/gauge.gen.d.ts.map +1 -1
  253. package/dist/schema/geomap.gen.d.ts +100 -0
  254. package/dist/schema/geomap.gen.d.ts.map +1 -0
  255. package/dist/schema/googlecloudmonitoring.gen.d.ts +312 -0
  256. package/dist/schema/googlecloudmonitoring.gen.d.ts.map +1 -0
  257. package/dist/schema/grafanapyroscope.gen.d.ts +60 -0
  258. package/dist/schema/grafanapyroscope.gen.d.ts.map +1 -0
  259. package/dist/schema/heatmap.gen.d.ts.map +1 -1
  260. package/dist/schema/histogram.gen.d.ts +132 -0
  261. package/dist/schema/histogram.gen.d.ts.map +1 -0
  262. package/dist/schema/index.d.ts +18 -0
  263. package/dist/schema/index.d.ts.map +1 -1
  264. package/dist/schema/logs.gen.d.ts +1 -0
  265. package/dist/schema/logs.gen.d.ts.map +1 -1
  266. package/dist/schema/loki.gen.d.ts.map +1 -1
  267. package/dist/schema/nodegraph.gen.d.ts +49 -0
  268. package/dist/schema/nodegraph.gen.d.ts.map +1 -0
  269. package/dist/schema/piechart.gen.d.ts +127 -0
  270. package/dist/schema/piechart.gen.d.ts.map +1 -0
  271. package/dist/schema/prometheus.gen.d.ts.map +1 -1
  272. package/dist/schema/stat.gen.d.ts.map +1 -1
  273. package/dist/schema/statetimeline.gen.d.ts +124 -0
  274. package/dist/schema/statetimeline.gen.d.ts.map +1 -0
  275. package/dist/schema/statushistory.gen.d.ts +114 -0
  276. package/dist/schema/statushistory.gen.d.ts.map +1 -0
  277. package/dist/schema/table.gen.d.ts +35 -3
  278. package/dist/schema/table.gen.d.ts.map +1 -1
  279. package/dist/schema/tempo.gen.d.ts.map +1 -1
  280. package/dist/schema/text.gen.d.ts.map +1 -1
  281. package/dist/schema/timeseries.gen.d.ts +5 -1
  282. package/dist/schema/timeseries.gen.d.ts.map +1 -1
  283. package/dist/schema/trend.gen.d.ts +180 -0
  284. package/dist/schema/trend.gen.d.ts.map +1 -0
  285. package/dist/schema/xychart.gen.d.ts +145 -0
  286. package/dist/schema/xychart.gen.d.ts.map +1 -0
  287. package/dist/schema-validate.d.ts +39 -4
  288. package/dist/schema-validate.d.ts.map +1 -1
  289. package/dist/serializer.d.ts +11 -3
  290. package/dist/serializer.d.ts.map +1 -1
  291. package/dist/skill-defs.d.ts.map +1 -1
  292. package/dist/skills/chant-grafana-alerting.md +49 -0
  293. package/dist/skills/chant-grafana-operations.md +108 -0
  294. package/dist/skills/chant-grafana-provisioning.md +3 -3
  295. package/dist/skills/chant-grafana.md +15 -8
  296. package/dist/spec/fetch-units-cli.d.ts +3 -0
  297. package/dist/spec/fetch-units-cli.d.ts.map +1 -0
  298. package/dist/spec/overlay.d.ts +43 -0
  299. package/dist/spec/overlay.d.ts.map +1 -0
  300. package/dist/spec/schemas.d.ts +21 -13
  301. package/dist/spec/schemas.d.ts.map +1 -1
  302. package/dist/spec/schemas.gen.d.ts +3 -0
  303. package/dist/spec/schemas.gen.d.ts.map +1 -0
  304. package/dist/spec/units.d.ts +35 -0
  305. package/dist/spec/units.d.ts.map +1 -0
  306. package/dist/spec/units.gen.d.ts +2 -0
  307. package/dist/spec/units.gen.d.ts.map +1 -0
  308. package/dist/transformations.d.ts +459 -0
  309. package/dist/transformations.d.ts.map +1 -0
  310. package/dist/util.d.ts +6 -0
  311. package/dist/util.d.ts.map +1 -1
  312. package/dist/validate-alerting.d.ts +65 -0
  313. package/dist/validate-alerting.d.ts.map +1 -0
  314. package/dist/validate-output.d.ts +62 -9
  315. package/dist/validate-output.d.ts.map +1 -1
  316. package/dist/validate.d.ts.map +1 -1
  317. package/dist/validation.d.ts +14 -0
  318. package/dist/validation.d.ts.map +1 -0
  319. package/dist/variables.d.ts +109 -7
  320. package/dist/variables.d.ts.map +1 -1
  321. package/package.json +12 -4
  322. package/src/actions/actions.test.ts +24 -0
  323. package/src/actions/grafana.ts +40 -0
  324. package/src/actions/index.ts +1 -0
  325. package/src/alerting-build.ts +376 -0
  326. package/src/alerting.e2e.test.ts +212 -0
  327. package/src/alerting.test.ts +272 -0
  328. package/src/alerting.ts +435 -0
  329. package/src/annotations.ts +84 -0
  330. package/src/api/apply.test.ts +256 -0
  331. package/src/api/apply.ts +394 -0
  332. package/src/api/bind.ts +58 -0
  333. package/src/api/client.ts +148 -0
  334. package/src/api/converge.ts +63 -0
  335. package/src/api/dashboards.ts +247 -0
  336. package/src/api/datasources.ts +33 -0
  337. package/src/api/fake-grafana-writes.ts +201 -0
  338. package/src/api/fake-grafana.ts +190 -0
  339. package/src/api/folders.ts +339 -0
  340. package/src/api/library-panels.ts +101 -0
  341. package/src/build.test.ts +351 -10
  342. package/src/build.ts +294 -55
  343. package/src/catalog.ts +104 -2
  344. package/src/codegen/docs.ts +50 -10
  345. package/src/codegen/generate.ts +27 -1
  346. package/src/codegen/schema-types.ts +16 -6
  347. package/src/composites/agent-dashboard.ts +6 -3
  348. package/src/composites/catalog.test.ts +2 -2
  349. package/src/composites/catalog.ts +82 -0
  350. package/src/composites/composites.test.ts +73 -9
  351. package/src/composites/index.ts +4 -2
  352. package/src/composites/queries.e2e.test.ts +374 -0
  353. package/src/composites/red-dashboard.ts +83 -12
  354. package/src/composites/shared.ts +14 -2
  355. package/src/composites/slo-alert-rules.ts +149 -0
  356. package/src/config.test.ts +61 -0
  357. package/src/config.ts +138 -0
  358. package/src/contact-point-secrets.ts +63 -0
  359. package/src/dashboard.ts +68 -9
  360. package/src/datasource-refs.test.ts +56 -0
  361. package/src/datasource-refs.ts +213 -0
  362. package/src/datasource-settings.test.ts +106 -0
  363. package/src/datasource-settings.ts +941 -0
  364. package/src/datasource.ts +123 -11
  365. package/src/deep-observe-hooks.ts +267 -0
  366. package/src/deep-observe.test.ts +311 -0
  367. package/src/deep-observe.ts +187 -0
  368. package/src/describe-resources.test.ts +271 -0
  369. package/src/describe-resources.ts +244 -0
  370. package/src/detect.ts +82 -5
  371. package/src/export-resources.test.ts +129 -0
  372. package/src/export-resources.ts +84 -0
  373. package/src/folder.ts +118 -0
  374. package/src/generated/lexicon-grafana.json +205 -0
  375. package/src/import/alerting-roundtrip.test.ts +161 -0
  376. package/src/import/alerting.ts +500 -0
  377. package/src/import/edits.ts +95 -0
  378. package/src/import/embedded.test.ts +45 -0
  379. package/src/import/embedded.ts +47 -0
  380. package/src/import/generated-types.e2e.test.ts +130 -0
  381. package/src/import/generator.test.ts +210 -0
  382. package/src/import/generator.ts +463 -0
  383. package/src/import/live-export.ts +264 -0
  384. package/src/import/mappings.ts +336 -0
  385. package/src/import/model.ts +117 -0
  386. package/src/import/normalize-alerting.ts +101 -0
  387. package/src/import/normalize.test.ts +117 -0
  388. package/src/import/normalize.ts +393 -0
  389. package/src/import/parser.test.ts +516 -0
  390. package/src/import/parser.ts +1387 -0
  391. package/src/import/report.ts +62 -0
  392. package/src/import/roundtrip.test.ts +563 -0
  393. package/src/import/testdata/fixtures.ts +137 -0
  394. package/src/import/v2.test.ts +292 -0
  395. package/src/import/v2.ts +804 -0
  396. package/src/import.e2e.test.ts +31 -84
  397. package/src/import.test.ts +9 -3
  398. package/src/index.ts +308 -14
  399. package/src/init-templates.test.ts +74 -0
  400. package/src/init-templates.ts +349 -0
  401. package/src/k8s.test.ts +98 -0
  402. package/src/k8s.ts +197 -0
  403. package/src/lint/audit-catalog.ts +68 -3
  404. package/src/lint/core-lint.test.ts +43 -0
  405. package/src/lint/post-synth/graf101.ts +3 -3
  406. package/src/lint/post-synth/graf102.ts +1 -1
  407. package/src/lint/post-synth/graf104.ts +3 -3
  408. package/src/lint/post-synth/graf106.ts +3 -3
  409. package/src/lint/post-synth/graf107.ts +1 -1
  410. package/src/lint/post-synth/graf108.ts +17 -0
  411. package/src/lint/post-synth/graf109.ts +17 -0
  412. package/src/lint/post-synth/graf110.ts +17 -0
  413. package/src/lint/post-synth/graf111.ts +17 -0
  414. package/src/lint/post-synth/graf112.ts +17 -0
  415. package/src/lint/post-synth/graf113.ts +17 -0
  416. package/src/lint/post-synth/graf114.ts +17 -0
  417. package/src/lint/post-synth/graf115.ts +17 -0
  418. package/src/lint/post-synth/grafana-helpers.ts +27 -10
  419. package/src/lint/post-synth/index.ts +16 -0
  420. package/src/lint/post-synth/post-synth.test.ts +333 -12
  421. package/src/lint/rules/literal-secret.ts +60 -6
  422. package/src/lint/rules/rules.test.ts +27 -0
  423. package/src/load-cost.test.ts +35 -0
  424. package/src/lsp/completions.test.ts +5 -0
  425. package/src/lsp/hover.test.ts +7 -0
  426. package/src/lsp/hover.ts +8 -1
  427. package/src/members.ts +68 -0
  428. package/src/observe.e2e.test.ts +255 -0
  429. package/src/op/activities/grafana-apply.e2e.test.ts +184 -0
  430. package/src/op/activities/grafana-apply.test.ts +243 -0
  431. package/src/op/activities/grafana-apply.ts +197 -0
  432. package/src/op/activities/index.ts +8 -0
  433. package/src/op/builders.test.ts +40 -0
  434. package/src/op/builders.ts +34 -0
  435. package/src/ownership.ts +122 -0
  436. package/src/panel-options.ts +66 -0
  437. package/src/panels.test.ts +53 -0
  438. package/src/panels.ts +148 -10
  439. package/src/pin.ts +69 -6
  440. package/src/plugin.test.ts +12 -2
  441. package/src/plugin.ts +75 -0
  442. package/src/promql-check.test.ts +108 -0
  443. package/src/promql-check.ts +193 -0
  444. package/src/query-models.ts +94 -0
  445. package/src/query.test.ts +166 -0
  446. package/src/query.ts +190 -20
  447. package/src/schema/azuremonitor.gen.ts +381 -0
  448. package/src/schema/barchart.gen.ts +221 -0
  449. package/src/schema/bargauge.gen.ts +111 -0
  450. package/src/schema/bigquery.gen.ts +110 -0
  451. package/src/schema/canvas.gen.ts +176 -0
  452. package/src/schema/cloudwatch.gen.ts +423 -0
  453. package/src/schema/dashboard.gen.ts +206 -22
  454. package/src/schema/elasticsearch.gen.ts +508 -0
  455. package/src/schema/expr.gen.ts +618 -0
  456. package/src/schema/gauge.gen.ts +2 -1
  457. package/src/schema/geomap.gen.ts +112 -0
  458. package/src/schema/googlecloudmonitoring.gen.ts +330 -0
  459. package/src/schema/grafanapyroscope.gen.ts +66 -0
  460. package/src/schema/heatmap.gen.ts +2 -1
  461. package/src/schema/histogram.gen.ts +151 -0
  462. package/src/schema/index.ts +18 -0
  463. package/src/schema/logs.gen.ts +3 -1
  464. package/src/schema/loki.gen.ts +2 -1
  465. package/src/schema/nodegraph.gen.ts +58 -0
  466. package/src/schema/piechart.gen.ts +146 -0
  467. package/src/schema/prometheus.gen.ts +2 -1
  468. package/src/schema/stat.gen.ts +2 -1
  469. package/src/schema/statetimeline.gen.ts +143 -0
  470. package/src/schema/statushistory.gen.ts +132 -0
  471. package/src/schema/table.gen.ts +41 -4
  472. package/src/schema/tempo.gen.ts +2 -1
  473. package/src/schema/text.gen.ts +2 -1
  474. package/src/schema/timeseries.gen.ts +7 -2
  475. package/src/schema/trend.gen.ts +208 -0
  476. package/src/schema/xychart.gen.ts +167 -0
  477. package/src/schema-overlay.test.ts +282 -0
  478. package/src/schema-validate.ts +199 -57
  479. package/src/schema.test.ts +4 -2
  480. package/src/serializer.test.ts +13 -1
  481. package/src/serializer.ts +11 -3
  482. package/src/skill-defs.ts +34 -0
  483. package/src/skills/chant-grafana-alerting.md +49 -0
  484. package/src/skills/chant-grafana-operations.md +108 -0
  485. package/src/skills/chant-grafana-provisioning.md +3 -3
  486. package/src/skills/chant-grafana.md +15 -8
  487. package/src/spec/fetch-cli.ts +3 -3
  488. package/src/spec/fetch-units-cli.ts +37 -0
  489. package/src/spec/overlay/canvas.overlay.json +142 -0
  490. package/src/spec/overlay/dashboard.overlay.json +378 -0
  491. package/src/spec/overlay/expr.overlay.json +14 -0
  492. package/src/spec/overlay/geomap.overlay.json +35 -0
  493. package/src/spec/overlay/logs.overlay.json +14 -0
  494. package/src/spec/overlay/nodegraph.overlay.json +31 -0
  495. package/src/spec/overlay/piechart.overlay.json +17 -0
  496. package/src/spec/overlay/table.overlay.json +103 -0
  497. package/src/spec/overlay/timeseries.overlay.json +21 -0
  498. package/src/spec/overlay/trend.overlay.json +17 -0
  499. package/src/spec/overlay/xychart.overlay.json +16 -0
  500. package/src/spec/overlay.ts +105 -0
  501. package/src/spec/schemas/azuremonitor.jsonschema.json +679 -0
  502. package/src/spec/schemas/barchart.jsonschema.json +419 -0
  503. package/src/spec/schemas/bargauge.jsonschema.json +224 -0
  504. package/src/spec/schemas/bigquery.jsonschema.json +290 -0
  505. package/src/spec/schemas/canvas.jsonschema.json +356 -0
  506. package/src/spec/schemas/cloudwatch.jsonschema.json +721 -0
  507. package/src/spec/schemas/dashboardv2.jsonschema.json +3387 -0
  508. package/src/spec/schemas/elasticsearch.jsonschema.json +1695 -0
  509. package/src/spec/schemas/expr.jsonschema.json +987 -0
  510. package/src/spec/schemas/geomap.jsonschema.json +220 -0
  511. package/src/spec/schemas/googlecloudmonitoring.jsonschema.json +488 -0
  512. package/src/spec/schemas/grafanapyroscope.jsonschema.json +93 -0
  513. package/src/spec/schemas/histogram.jsonschema.json +308 -0
  514. package/src/spec/schemas/nodegraph.jsonschema.json +77 -0
  515. package/src/spec/schemas/piechart.jsonschema.json +275 -0
  516. package/src/spec/schemas/statetimeline.jsonschema.json +324 -0
  517. package/src/spec/schemas/statushistory.jsonschema.json +292 -0
  518. package/src/spec/schemas/trend.jsonschema.json +449 -0
  519. package/src/spec/schemas/xychart.jsonschema.json +428 -0
  520. package/src/spec/schemas.gen.ts +40 -0
  521. package/src/spec/schemas.ts +30 -16
  522. package/src/spec/units.gen.ts +281 -0
  523. package/src/spec/units.ts +77 -0
  524. package/src/transformations.test.ts +65 -0
  525. package/src/transformations.ts +574 -0
  526. package/src/util.ts +8 -0
  527. package/src/validate-alerting.test.ts +255 -0
  528. package/src/validate-alerting.ts +430 -0
  529. package/src/validate-output.ts +427 -104
  530. package/src/validate.ts +28 -0
  531. package/src/validation.ts +27 -0
  532. package/src/variables.ts +120 -8
package/src/catalog.ts CHANGED
@@ -5,13 +5,24 @@
5
5
  */
6
6
 
7
7
  import type { LexiconEntry } from "@intentius/chant/lsp/lexicon-providers";
8
- import { DATASOURCE_TYPE } from "./datasource";
8
+ import { DATASOURCE_PROVISIONING_TYPE, DATASOURCE_TYPE, EXTERNAL_DATASOURCE_TYPE } from "./datasource";
9
+ import { FOLDER_TYPE } from "./folder";
9
10
  import { DASHBOARD_TYPE, DASHBOARD_PROVIDER_TYPE } from "./dashboard";
10
11
  import * as panels from "./panels";
11
12
  import * as queries from "./query";
12
13
  import { VARIABLE_TYPE_PREFIX } from "./variables";
14
+ import {
15
+ ALERT_QUERY_TYPE,
16
+ ALERT_RULE_GROUP_TYPE,
17
+ ALERT_RULE_TYPE,
18
+ CONTACT_POINT_TYPE,
19
+ EXPRESSION_TYPE_PREFIX,
20
+ MUTE_TIMING_TYPE,
21
+ NOTIFICATION_POLICY_TYPE,
22
+ NOTIFICATION_TEMPLATE_TYPE,
23
+ } from "./alerting";
13
24
 
14
- export type CatalogKind = "dashboard" | "datasource" | "provider" | "panel" | "row" | "query" | "variable";
25
+ export type CatalogKind = "dashboard" | "folder" | "datasource" | "provider" | "panel" | "row" | "query" | "variable" | "alerting" | "expression";
15
26
 
16
27
  export interface CatalogEntry {
17
28
  className: string;
@@ -57,6 +68,18 @@ const VARIABLES: Array<[string, string, string]> = [
57
68
  ["DatasourceVariable", "datasource", "A choice of datasource of one plugin type; usable wherever a datasource is"],
58
69
  ["ConstantVariable", "constant", "A hidden, fixed value"],
59
70
  ["TextboxVariable", "textbox", "A free-text box"],
71
+ ["AdhocVariable", "adhoc", "Key/value filters Grafana adds to every query sent to the variable's datasource"],
72
+ ["GroupByVariable", "groupby", "A choice of label keys Grafana groups every query to the variable's datasource by (experimental in Grafana)"],
73
+ ["SwitchVariable", "switch", "An on/off switch with a value for each state (Grafana 12.3 and later)"],
74
+ ];
75
+
76
+ const EXPRESSIONS: Array<[string, string, string]> = [
77
+ ["ReduceExpression", "reduce", "A server-side expression reducing each series to one number (last, mean, max, ...)"],
78
+ ["MathExpression", "math", "A server-side math expression over other results by refId, e.g. $A / $B"],
79
+ ["ThresholdExpression", "threshold", "A server-side threshold, with an optional recovery threshold"],
80
+ ["ResampleExpression", "resample", "A server-side expression resampling a time series to a fixed window"],
81
+ ["ClassicConditionsExpression", "classic_conditions", "Grafana's legacy classic conditions, as a server-side expression"],
82
+ ["SqlExpression", "sql", "A server-side SQL expression over the other results"],
60
83
  ];
61
84
 
62
85
  export const BUILTIN_CATALOG: CatalogEntry[] = [
@@ -74,6 +97,27 @@ export const BUILTIN_CATALOG: CatalogEntry[] = [
74
97
  entityKind: "resource",
75
98
  description: "A datasource, declared once and referenced by panels, queries and variables",
76
99
  },
100
+ {
101
+ className: "ExternalDatasource",
102
+ entityType: EXTERNAL_DATASOURCE_TYPE,
103
+ kind: "datasource",
104
+ entityKind: "resource",
105
+ description: "A datasource that already exists in Grafana: referenced like a Datasource and checked by GRAF101/GRAF102, never provisioned",
106
+ },
107
+ {
108
+ className: "Folder",
109
+ entityType: FOLDER_TYPE,
110
+ kind: "folder",
111
+ entityKind: "resource",
112
+ description: "A folder with a stable uid, nested with parent; a dashboard's folder may be one instead of a path",
113
+ },
114
+ {
115
+ className: "DatasourceProvisioning",
116
+ entityType: DATASOURCE_PROVISIONING_TYPE,
117
+ kind: "provider",
118
+ entityKind: "resource",
119
+ description: "The datasource provisioning file's prune (on by default) and deleteDatasources",
120
+ },
77
121
  {
78
122
  className: "DashboardProvider",
79
123
  entityType: DASHBOARD_PROVIDER_TYPE,
@@ -88,6 +132,64 @@ export const BUILTIN_CATALOG: CatalogEntry[] = [
88
132
  entityKind: "property",
89
133
  description: "A full-width row header; its panels are placed below it, or inside it when collapsed",
90
134
  },
135
+ {
136
+ className: "AlertRuleGroup",
137
+ entityType: ALERT_RULE_GROUP_TYPE,
138
+ kind: "alerting",
139
+ entityKind: "resource",
140
+ description: "A group of Grafana-managed alert and recording rules in a folder, evaluated together at one interval",
141
+ },
142
+ {
143
+ className: "ContactPoint",
144
+ entityType: CONTACT_POINT_TYPE,
145
+ kind: "alerting",
146
+ entityKind: "resource",
147
+ description: "A contact point: the integrations (email, Slack, webhook, ...) alerts are sent to, under one name",
148
+ },
149
+ {
150
+ className: "NotificationPolicy",
151
+ entityType: NOTIFICATION_POLICY_TYPE,
152
+ kind: "alerting",
153
+ entityKind: "resource",
154
+ description: "An organisation's notification policy tree: the root receiver and the routes that match alerts to contact points",
155
+ },
156
+ {
157
+ className: "MuteTiming",
158
+ entityType: MUTE_TIMING_TYPE,
159
+ kind: "alerting",
160
+ entityKind: "resource",
161
+ description: "A named time interval that mutes (or, as active_time_intervals, enables) notifications",
162
+ },
163
+ {
164
+ className: "NotificationTemplate",
165
+ entityType: NOTIFICATION_TEMPLATE_TYPE,
166
+ kind: "alerting",
167
+ entityKind: "resource",
168
+ description: "A notification template group, Go templates contact point settings can use",
169
+ },
170
+ {
171
+ className: "AlertRule",
172
+ entityType: ALERT_RULE_TYPE,
173
+ kind: "alerting",
174
+ entityKind: "property",
175
+ description: "A Grafana-managed alert or recording rule: queries, expressions and the condition that fires it",
176
+ },
177
+ {
178
+ className: "AlertQuery",
179
+ entityType: ALERT_QUERY_TYPE,
180
+ kind: "alerting",
181
+ entityKind: "property",
182
+ description: "A datasource query of an alert rule, with its model as Grafana stores it and its time range",
183
+ },
184
+ ...EXPRESSIONS.map(
185
+ ([className, type, description]): CatalogEntry => ({
186
+ className,
187
+ entityType: `${EXPRESSION_TYPE_PREFIX}${type}`,
188
+ kind: "expression",
189
+ entityKind: "property",
190
+ description,
191
+ }),
192
+ ),
91
193
  ...panelEntries,
92
194
  ...queryEntries,
93
195
  ...VARIABLES.map(
@@ -13,7 +13,8 @@ function serviceFromType(resourceType: string): string {
13
13
  }
14
14
 
15
15
  const overview = `The grafana lexicon types what a [Grafana](https://grafana.com/docs/grafana/latest/) dashboard
16
- shows: datasources, dashboards, rows, panels, queries and variables. \`chant build\`
16
+ shows: datasources, dashboards, rows, panels, queries and variables, and
17
+ Grafana-managed alerting. \`chant build\`
17
18
  writes one JSON file per dashboard, the JSON Grafana imports as it is, plus the
18
19
  provisioning files Grafana reads for dashboards and datasources. Grafana server
19
20
  settings, users and plugins are out of scope.
@@ -28,11 +29,36 @@ const requests = new TimeSeriesPanel({ title: "Requests per second", datasource:
28
29
  export const overview = new Dashboard({ title: "Overview", panels: [requests] });
29
30
  \`\`\`
30
31
 
31
- Panels: time series, stat, gauge, table, logs, traces, heatmap and text, plus
32
- rows. Queries: Prometheus (PromQL), Tempo (TraceQL) and Loki (LogQL). Panel
33
- options and query fields are generated from Grafana's own schemas at a pinned
34
- version, and every build validates the dashboards against the same schemas.
32
+ Panels: time series, stat, gauge, table, logs, traces, heatmap, text, bar
33
+ chart, bar gauge, pie chart, state timeline, status history, histogram, node
34
+ graph, XY chart, trend, canvas, geomap, flame graph and alert list, plus rows.
35
+ Queries: Prometheus (PromQL), Tempo (TraceQL), Loki (LogQL), Elasticsearch,
36
+ CloudWatch, Azure Monitor, Cloud Monitoring, BigQuery, Pyroscope, and SQL for
37
+ PostgreSQL, MySQL and MSSQL. Panel options and query fields are generated from
38
+ Grafana's own schemas at a pinned version, corrected against Grafana's CUE, and
39
+ track Grafana 12.4 and 13.x. Every build validates the dashboards against the
40
+ same schemas.
41
+ Dashboards are written in the classic (v1) JSON model. Grafana 13's v2 model
42
+ (tabs, auto grids, conditional rendering) cannot be declared yet; import and
43
+ drift read a v2 dashboard by converting it to the classic model, and say what
44
+ the conversion loses.
35
45
  \`definePanel\` and \`defineQuery\` add plugins chant doesn't ship.
46
+ \`chant import\` turns dashboard JSON exported from Grafana into this TypeScript,
47
+ and it builds back to the same dashboard (see
48
+ [Importing Dashboards](./importing/)). \`chant lifecycle diff --live\` reports
49
+ a dashboard edited in Grafana as drift, property by property, and
50
+ \`chant import --from <env>\` writes a running Grafana's dashboards as
51
+ TypeScript (see [Drift and Live Export](./observing/)). \`grafanaApply\` writes
52
+ a build to a running Grafana over its HTTP API, with folders and library
53
+ panels, and prunes the project's own dashboards and folders (see
54
+ [Apply over the API](./applying/)).
55
+
56
+ Grafana-managed alerting is typed too: rule groups with their queries and
57
+ server-side expressions (reduce, math, threshold, resample, classic
58
+ conditions, SQL), contact points, the notification policy tree, mute timings
59
+ and templates, written to Grafana's alerting provisioning file.
60
+ \`SloAlertRules\` turns a prometheus \`Slo\` into burn-rate alert rules. See
61
+ [Alerting](./alerting/).
36
62
 
37
63
  Three composites build whole dashboards from declarations in other lexicons:
38
64
  \`RedDashboard\` from an otel \`spanmetrics\` connector, \`SloDashboard\` from a
@@ -40,10 +66,17 @@ prometheus \`Slo\` and \`AgentDashboard\` from the otel GenAI preset. Metric nam
40
66
  come from the declaration, so renaming one moves the panels. See
41
67
  [Dashboards from Declarations](./composites/).
42
68
 
43
- Checks catch a query aimed at a datasource nobody declared (GRAF101) or of the
69
+ Checks catch a query aimed at a datasource nobody declared, with
70
+ \`Datasource\` or \`ExternalDatasource\` (GRAF101), or of the
44
71
  wrong type (GRAF102), a \`$variable\` the dashboard doesn't declare (GRAF103),
45
72
  duplicate uids and ids (GRAF104), panels off the grid or overlapping (GRAF105),
46
- and anything Grafana's dashboard schema rejects (GRAF107).
73
+ anything Grafana's dashboard schema rejects (GRAF107), PromQL sent to a
74
+ Prometheus that doesn't parse (GRAF108), dashboard providers that load a
75
+ dashboard twice or not into its declared folder (GRAF109), a panel repeated over a variable that only ever
76
+ holds one value (GRAF110), and a unit Grafana doesn't know (GRAF115). For alerting, they catch rules whose condition or expressions name
77
+ no query (GRAF111), queries to undeclared datasources (GRAF112), routes to
78
+ undeclared contact points or mute timings (GRAF113), and uids, intervals and
79
+ duplicates Grafana refuses (GRAF114).
47
80
  `;
48
81
 
49
82
  const outputFormat = `The grafana lexicon writes Grafana's own files, keyed by path under the
@@ -54,9 +87,12 @@ directory of the \`-o\` output:
54
87
  - \`provisioning/datasources/chant.yaml\`: every declared datasource.
55
88
  - \`provisioning/dashboards/chant.yaml\`: a file provider for the dashboards
56
89
  directory; a default one unless a \`DashboardProvider\` is declared.
90
+ - \`provisioning/alerting/chant.yaml\`: rule groups, contact points, the
91
+ notification policy tree, mute timings and templates, when the build
92
+ declares any.
57
93
 
58
94
  The primary output (the \`-o\` file itself) is a JSON index of the dashboards,
59
- datasources and files that were built.
95
+ datasources, alerting and files that were built.
60
96
 
61
97
  - Dashboard JSON carries the pinned schema's \`schemaVersion\`, no numeric \`id\`,
62
98
  and every field Grafana's schema requires (link defaults, an empty
@@ -67,8 +103,12 @@ datasources and files that were built.
67
103
  referenced, and as its uid inside another datasource's \`jsonData\`.
68
104
  - \`chant build\` rewrites JSON files with sorted keys; Grafana does not care
69
105
  about key order.
70
- - Grafana's files have no metadata channel chant could use without changing
71
- what Grafana imports, so no ownership marker is stamped.
106
+ - The dashboard JSON carries no ownership marker. Grafana keeps who manages a
107
+ dashboard in the resource's metadata on its \`dashboard.grafana.app\` API,
108
+ not in the JSON: for a provisioned dashboard, the name of the provider that
109
+ loaded it, which is \`chant\` unless a \`DashboardProvider\` names another.
110
+ \`chant lifecycle diff --live\` reads that back (see
111
+ [Drift and Live Export](../observing/)).
72
112
  `;
73
113
 
74
114
  export async function generateDocs(opts?: { verbose?: boolean }): Promise<void> {
@@ -4,7 +4,11 @@
4
4
  * 1. `src/schema/<name>.gen.ts` from each vendored schema in `src/spec/schemas/`
5
5
  * (see `src/pin.ts`). These are committed, and a test fails when they
6
6
  * drift from what this step would write.
7
- * 2. `src/generated/lexicon-grafana.json`, the registry of entity classes
7
+ * 2. `src/spec/schemas.gen.ts`, the same schemas with the overlay applied, as
8
+ * JSON text. Validation (GRAF107, the `/validation` subpath) reads them
9
+ * from there rather than from the files, so it needs no filesystem access
10
+ * and works bundled. Committed and checked the same way.
11
+ * 3. `src/generated/lexicon-grafana.json`, the registry of entity classes
8
12
  * the package exports, derived from the catalog so the packaged
9
13
  * `dist/meta.json` cannot disagree with the classes.
10
14
  */
@@ -29,6 +33,27 @@ function dashboardExtras(schema: Record<string, unknown>): string[] {
29
33
  return ["/** The dashboard `schemaVersion` the pinned schema defaults to, and the one chant emits. */", `export const DASHBOARD_SCHEMA_VERSION = ${v};`];
30
34
  }
31
35
 
36
+ /** `src/spec/schemas.gen.ts`: each schema validation uses, overlay applied, as one line of JSON text. */
37
+ export function schemaDataModule(): string {
38
+ const lines = [
39
+ "// Code generated by chant generate. DO NOT EDIT.",
40
+ "// The vendored Grafana schemas (src/spec/schemas/, see src/pin.ts) with the",
41
+ "// correction overlay (src/spec/overlay/) applied, as JSON text, for",
42
+ "// src/schema-validate.ts. A module rather than a file read, so validation",
43
+ "// needs no filesystem access and survives bundling; text rather than object",
44
+ "// literals, so loading it costs little until a schema is parsed.",
45
+ "",
46
+ 'import type { SchemaName } from "../pin";',
47
+ "",
48
+ "export const SCHEMA_JSON: Readonly<Record<SchemaName, string>> = {",
49
+ ];
50
+ for (const name of SCHEMA_NAMES) {
51
+ lines.push(` ${JSON.stringify(name)}: ${JSON.stringify(JSON.stringify(loadSchema(name as SchemaName)))},`);
52
+ }
53
+ lines.push("};", "");
54
+ return lines.join("\n");
55
+ }
56
+
32
57
  /** Every generated schema module, keyed by path relative to the package root. */
33
58
  export function schemaModules(): Record<string, string> {
34
59
  const out: Record<string, string> = {};
@@ -37,6 +62,7 @@ export function schemaModules(): Record<string, string> {
37
62
  const extra = name === "dashboard" ? dashboardExtras(schema) : [];
38
63
  out[`src/schema/${name}.gen.ts`] = schemaModule(name, schema, extra).source;
39
64
  }
65
+ out["src/spec/schemas.gen.ts"] = schemaDataModule();
40
66
  return out;
41
67
  }
42
68
 
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * JSON Schema (draft-07, the subset cog emits) to TypeScript declarations.
3
3
  *
4
- * Each vendored schema becomes one module under `src/schema/`: one exported
5
- * type per entry in `definitions`, with the schema's descriptions as doc
6
- * comments. `required` is kept, so the types say what the schema says; the
4
+ * Each vendored schema, with its correction overlay applied, becomes one
5
+ * module under `src/schema/`: one exported type per entry in `definitions`,
6
+ * with the schema's descriptions as doc comments. `required` is kept, so the types say what the schema says; the
7
7
  * entity props wrap panel options in `DeepPartial` where Grafana fills the
8
8
  * rest in on import.
9
9
  */
@@ -99,6 +99,15 @@ function objectType(node: Node, indent: string): string {
99
99
  return lines.length === 2 ? "Record<string, never>" : lines.join("\n");
100
100
  }
101
101
 
102
+ /**
103
+ * A branch that only constrains which keys are present (`{ required: [...] }`),
104
+ * like the overlay's "a panel has a `type` or a `libraryPanel`". It says
105
+ * nothing about the shape, so the type ignores it and validation enforces it.
106
+ */
107
+ function constraintOnly(branches: Node[] | undefined): boolean {
108
+ return Array.isArray(branches) && branches.every((b) => Object.keys(b).every((k) => k === "required"));
109
+ }
110
+
102
111
  /** The TypeScript type for one schema node. */
103
112
  export function tsType(node: Node | boolean | undefined, indent = ""): string {
104
113
  if (node === undefined || node === true) return "unknown";
@@ -106,8 +115,8 @@ export function tsType(node: Node | boolean | undefined, indent = ""): string {
106
115
  if (node.$ref) return refName(node.$ref);
107
116
  if (node.const !== undefined) return literal(node.const);
108
117
  if (Array.isArray(node.enum)) return union(node.enum.map(literal));
109
- if (node.oneOf) return union(node.oneOf.map((n) => paren(tsType(n, indent))));
110
- if (node.anyOf) return union(node.anyOf.map((n) => paren(tsType(n, indent))));
118
+ if (node.oneOf && !constraintOnly(node.oneOf)) return union(node.oneOf.map((n) => paren(tsType(n, indent))));
119
+ if (node.anyOf && !constraintOnly(node.anyOf)) return union(node.anyOf.map((n) => paren(tsType(n, indent))));
111
120
  if (node.allOf) return node.allOf.map((n) => paren(tsType(n, indent))).join(" & ");
112
121
 
113
122
  const types = Array.isArray(node.type) ? node.type : node.type ? [node.type] : [];
@@ -154,7 +163,8 @@ export function schemaModule(name: SchemaName, schema: Record<string, unknown>,
154
163
  const defs = (schema.definitions ?? {}) as Record<string, Node>;
155
164
  const out: string[] = [
156
165
  "// Code generated by chant generate from the vendored Grafana schema",
157
- `// src/spec/schemas/${name}.jsonschema.json (see src/pin.ts). DO NOT EDIT.`,
166
+ `// src/spec/schemas/${name}.jsonschema.json (see src/pin.ts) and its correction`,
167
+ "// overlay in src/spec/overlay/ (see src/spec/overlay.ts). DO NOT EDIT.",
158
168
  "/* eslint-disable */",
159
169
  "",
160
170
  ];
@@ -18,6 +18,7 @@ import { slugUid } from "../util";
18
18
  import {
19
19
  dashboardProps,
20
20
  durationUnit,
21
+ errorRatio,
21
22
  legend,
22
23
  quantile,
23
24
  quantileName,
@@ -75,8 +76,7 @@ export function agentQueries(m: GenAiMetrics, q = 0.95) {
75
76
  const err: Matcher = [status, "=", SPAN_STATUS_ERROR];
76
77
  const calls = m.calls.prometheus;
77
78
  const buckets = `${m.duration.prometheus}_bucket`;
78
- const ratio = (matchers: Matcher[], by: string[]) =>
79
- `${sumRate(selector(calls, [...matchers, err]), by)}\n/\n${sumRate(selector(calls, matchers), by)}`;
79
+ const ratio = (matchers: Matcher[], by: string[]) => errorRatio(selector(calls, [...matchers, err]), selector(calls, matchers), by);
80
80
  const tokens: Matcher[] = [[tokenModel, "=~", "$model"]];
81
81
 
82
82
  return {
@@ -191,13 +191,16 @@ export const AgentDashboard = Composite<AgentDashboardProps, AgentDashboardMembe
191
191
  }),
192
192
  ],
193
193
  });
194
+ // One instant query at the end of the range: `increase(...[$__range])`
195
+ // is the total over the whole range, so evaluating it at every step of a
196
+ // range query would only repeat that work for points the stat throws away.
194
197
  const tokenStat = (title: string, expr: string) =>
195
198
  new StatPanel({
196
199
  title,
197
200
  description: "Over the dashboard's time range.",
198
201
  datasource: ds,
199
202
  gridPos: { w: 4, h: 8 },
200
- targets: [new PromQuery({ expr, legendFormat: title })],
203
+ targets: [new PromQuery({ expr, legendFormat: title, instant: true, range: false })],
201
204
  options: { graphMode: "none", colorMode: "none", reduceOptions: { calcs: ["lastNotNull"] } },
202
205
  fieldConfig: { defaults: { unit: "short", decimals: 0 } },
203
206
  });
@@ -19,7 +19,7 @@ const catalogued = compositeCatalog.map((entry) => entry.name).sort();
19
19
 
20
20
  describe("the grafana composite catalog", () => {
21
21
  test("every exported composite has an entry, and every entry names an exported composite", () => {
22
- expect(exported).toEqual(["AgentDashboard", "RedDashboard", "SloDashboard"]);
22
+ expect(exported).toEqual(["AgentDashboard", "RedDashboard", "SloAlertRules", "SloDashboard"]);
23
23
  expect(catalogued, "regenerate with `npm run generate:composite-catalogs -- grafana`").toEqual(exported);
24
24
  });
25
25
 
@@ -27,7 +27,7 @@ describe("the grafana composite catalog", () => {
27
27
  for (const entry of compositeCatalog) {
28
28
  expect(entry.lexicon, entry.name).toBe("grafana");
29
29
  expect(entry.description.length, entry.name).toBeGreaterThan(0);
30
- expect(entry.bundles, entry.name).toEqual(["Dashboard"]);
30
+ expect(entry.bundles, entry.name).toEqual(entry.name === "SloAlertRules" ? ["AlertRuleGroup"] : ["Dashboard"]);
31
31
  }
32
32
  });
33
33
 
@@ -102,6 +102,12 @@ export const compositeCatalog: CompositeEntry[] = [
102
102
  "required": false,
103
103
  "description": "Duration quantiles, one panel each (default p50, p95 and p99)."
104
104
  },
105
+ {
106
+ "name": "spanKinds",
107
+ "type": "SpanKind[]",
108
+ "required": false,
109
+ "description": "The span kinds the queries count (default server and consumer spans)."
110
+ },
105
111
  {
106
112
  "name": "datasource",
107
113
  "type": "DatasourceInput<\"prometheus\">",
@@ -154,6 +160,82 @@ export const compositeCatalog: CompositeEntry[] = [
154
160
  }
155
161
  ]
156
162
  },
163
+ {
164
+ "name": "SloAlertRules",
165
+ "lexicon": "grafana",
166
+ "description": "Grafana-managed burn-rate alerts for an `Slo`: one rule per window pair, with the labels and annotations the `Slo`'s Prometheus alerts carry.",
167
+ "bundles": [
168
+ "AlertRuleGroup"
169
+ ],
170
+ "params": [
171
+ {
172
+ "name": "slo",
173
+ "type": "SloInstance | RuleGroupEntity | SloMetrics",
174
+ "required": true,
175
+ "description": "The `Slo(...)` the rules alert on, its rule group, or what `sloMetrics()` returned for it."
176
+ },
177
+ {
178
+ "name": "datasource",
179
+ "type": "DatasourceInput<\"prometheus\">",
180
+ "required": true,
181
+ "description": "The Prometheus holding the `Slo`'s recorded series: a declared `Datasource`, an `ExternalDatasource`, or `{ type: \"prometheus\", uid }`."
182
+ },
183
+ {
184
+ "name": "folder",
185
+ "type": "string",
186
+ "required": true,
187
+ "description": "The Grafana folder the rules are stored in, by title."
188
+ },
189
+ {
190
+ "name": "group",
191
+ "type": "string",
192
+ "required": false,
193
+ "description": "The rule group's name."
194
+ },
195
+ {
196
+ "name": "interval",
197
+ "type": "string",
198
+ "required": false,
199
+ "description": "How often the rules are evaluated, a multiple of 10s."
200
+ },
201
+ {
202
+ "name": "contactPoint",
203
+ "type": "ContactPointEntity | string",
204
+ "required": false,
205
+ "description": "Send the alerts straight to this contact point."
206
+ },
207
+ {
208
+ "name": "for",
209
+ "type": "string",
210
+ "required": false,
211
+ "description": "How long a pair must hold before its alert fires."
212
+ },
213
+ {
214
+ "name": "labels",
215
+ "type": "Record<string, string>",
216
+ "required": false,
217
+ "description": "More labels on every rule, e.g. `team`."
218
+ },
219
+ {
220
+ "name": "annotations",
221
+ "type": "Record<string, string>",
222
+ "required": false,
223
+ "description": "More annotations on every rule, e.g. `runbook_url`."
224
+ },
225
+ {
226
+ "name": "noDataState",
227
+ "type": "NoDataState",
228
+ "required": false,
229
+ "description": "What no data does."
230
+ },
231
+ {
232
+ "name": "execErrState",
233
+ "type": "ExecErrState",
234
+ "required": false,
235
+ "description": "What a query error does."
236
+ }
237
+ ]
238
+ },
157
239
  {
158
240
  "name": "SloDashboard",
159
241
  "lexicon": "grafana",
@@ -15,7 +15,7 @@ import { Datasource } from "../datasource";
15
15
  import { buildGrafana, type DashboardJson } from "../build";
16
16
  import { validateGrafanaOutput } from "../validate-output";
17
17
  import { validateDashboardSchema } from "../schema-validate";
18
- import { AgentDashboard, RedDashboard, SloDashboard } from "./index";
18
+ import { AgentDashboard, RedDashboard, redQueries, SloDashboard } from "./index";
19
19
 
20
20
  const prometheus = new Datasource({ name: "Prometheus", type: "prometheus", url: "http://prometheus:9090" });
21
21
 
@@ -78,16 +78,64 @@ describe("RedDashboard", () => {
78
78
  expectClean(json, out);
79
79
  expect(json.uid).toBe("red-traces-span-metrics");
80
80
  expect(panels(json).map((p) => p.title)).toEqual(["Rate", "Errors", "Duration p50", "Duration p95", "Duration p99"]);
81
- expect(panelByTitle(json, "Rate").targets).toMatchObject([
82
- { expr: 'sum by (service_name) (rate(traces_span_metrics_calls_total{service_name=~"$service"}[$__rate_interval]))' },
83
- ]);
84
- expect((panelByTitle(json, "Errors").targets as Json[])[0].expr).toContain('status_code="STATUS_CODE_ERROR"');
81
+ const calls = 'traces_span_metrics_calls_total{service_name=~"$service", span_kind=~"SPAN_KIND_SERVER|SPAN_KIND_CONSUMER"}';
82
+ const errors = 'traces_span_metrics_calls_total{service_name=~"$service", span_kind=~"SPAN_KIND_SERVER|SPAN_KIND_CONSUMER", status_code="STATUS_CODE_ERROR"}';
83
+ expect(panelByTitle(json, "Rate").targets).toMatchObject([{ expr: `sum by (service_name) (rate(${calls}[$__rate_interval]))` }]);
84
+ expect(panelByTitle(json, "Rate").description).toBe("Server and consumer spans per second by service, from traces_span_metrics_calls_total.");
85
+ expect((panelByTitle(json, "Errors").targets as Json[])[0].expr).toBe(
86
+ "(\n" +
87
+ `sum by (service_name) (rate(${errors}[$__rate_interval]))\n` +
88
+ "or\n" +
89
+ `sum by (service_name) (rate(${calls}[$__rate_interval])) * 0\n` +
90
+ ")\n/\n" +
91
+ `sum by (service_name) (rate(${calls}[$__rate_interval]))`,
92
+ );
85
93
  expect((panelByTitle(json, "Duration p95").targets as Json[])[0].expr).toBe(
86
- 'histogram_quantile(0.95, sum by (le, service_name) (rate(traces_span_metrics_duration_milliseconds_bucket{service_name=~"$service"}[$__rate_interval])))',
94
+ 'histogram_quantile(0.95, sum by (le, service_name) (rate(traces_span_metrics_duration_milliseconds_bucket{service_name=~"$service", span_kind=~"SPAN_KIND_SERVER|SPAN_KIND_CONSUMER"}[$__rate_interval])))',
87
95
  );
88
96
  expect((panelByTitle(json, "Duration p95").fieldConfig as { defaults: Json }).defaults.unit).toBe("ms");
89
97
  const templating = json.templating as unknown as { list: Json[] };
90
- expect(templating.list.map((v) => [v.name, v.query])).toEqual([["service", "label_values(traces_span_metrics_calls_total, service_name)"]]);
98
+ expect(templating.list.map((v) => [v.name, v.query])).toEqual([
99
+ ["service", 'label_values(traces_span_metrics_calls_total{span_kind=~"SPAN_KIND_SERVER|SPAN_KIND_CONSUMER"}, service_name)'],
100
+ ]);
101
+ });
102
+
103
+ test("spanKinds picks the kinds counted; [] counts every kind", () => {
104
+ const names = spanMetricsNames(new SpanMetricsConnector({ namespace: "shop" }));
105
+ const all = redQueries(names, [0.5], "$service", []);
106
+ expect(all.rate).toBe('sum by (service_name) (rate(shop_calls_total{service_name=~"$service"}[$__rate_interval]))');
107
+ expect(all.services).toBe("label_values(shop_calls_total, service_name)");
108
+
109
+ const client = redQueries(names, [0.5], "checkout", ["SPAN_KIND_CLIENT", "SPAN_KIND_PRODUCER", "SPAN_KIND_CLIENT"]);
110
+ expect(client.rate).toBe(
111
+ 'sum by (service_name) (rate(shop_calls_total{service_name=~"checkout", span_kind=~"SPAN_KIND_CLIENT|SPAN_KIND_PRODUCER"}[$__rate_interval]))',
112
+ );
113
+ for (const e of [client.rate, client.errorRatio, ...client.duration.map((d) => d.expr)]) {
114
+ expect(checkPromql(asPromql(e)), e).toEqual({ ok: true });
115
+ }
116
+
117
+ const { json, out } = built(
118
+ RedDashboard({ spanMetrics: new SpanMetricsConnector({ namespace: "shop" }), spanKinds: ["SPAN_KIND_SERVER"], datasource: prometheus }).dashboard,
119
+ );
120
+ expectClean(json, out);
121
+ for (const e of exprs(json)) expect(e).toContain('span_kind=~"SPAN_KIND_SERVER"');
122
+ expect(panelByTitle(json, "Errors").description).toBe('Share of server spans with status_code="STATUS_CODE_ERROR", by service.');
123
+
124
+ const every = built(RedDashboard({ spanMetrics: new SpanMetricsConnector({ namespace: "shop" }), spanKinds: [], datasource: prometheus }).dashboard);
125
+ for (const e of exprs(every.json)) expect(e).not.toContain("span_kind");
126
+ expect(panelByTitle(every.json, "Rate").description).toBe("Spans per second by service, from shop_calls_total.");
127
+ });
128
+
129
+ test("a connector that excludes span.kind gets no kind filter by default, and naming kinds for it is an error", () => {
130
+ const connector = new SpanMetricsConnector({ exclude_dimensions: ["span.kind"] });
131
+ const { json, out } = built(RedDashboard({ spanMetrics: connector, datasource: prometheus }).dashboard);
132
+ expectClean(json, out);
133
+ for (const e of exprs(json)) expect(e).not.toContain("span_kind");
134
+ expect(() => RedDashboard({ spanMetrics: connector, spanKinds: ["SPAN_KIND_SERVER"], datasource: prometheus })).toThrow(/excludes span\.kind/);
135
+ expect(() => RedDashboard({ spanMetrics: connector, spanKinds: [], datasource: prometheus })).not.toThrow();
136
+ expect(() =>
137
+ RedDashboard({ spanMetrics: new SpanMetricsConnector({}), spanKinds: ["SERVER" as never], datasource: prometheus }),
138
+ ).toThrow(/unknown span kind "SERVER"/);
91
139
  });
92
140
 
93
141
  test("renaming the connector's namespace moves every query; its histogram unit moves the duration metric", () => {
@@ -259,10 +307,26 @@ describe("AgentDashboard", () => {
259
307
  "Input tokens",
260
308
  "Output tokens",
261
309
  ]);
310
+ const calls = 'genai_calls_total{service_name=~"$service", gen_ai_request_model=~"$model"}';
311
+ const errors = 'genai_calls_total{service_name=~"$service", gen_ai_request_model=~"$model", status_code="STATUS_CODE_ERROR"}';
262
312
  expect((panelByTitle(json, "Errors by model").targets as Json[])[0].expr).toBe(
263
- 'sum by (gen_ai_request_model) (rate(genai_calls_total{service_name=~"$service", gen_ai_request_model=~"$model", status_code="STATUS_CODE_ERROR"}[$__rate_interval]))\n/\n' +
264
- 'sum by (gen_ai_request_model) (rate(genai_calls_total{service_name=~"$service", gen_ai_request_model=~"$model"}[$__rate_interval]))',
313
+ "(\n" +
314
+ `sum by (gen_ai_request_model) (rate(${errors}[$__rate_interval]))\n` +
315
+ "or\n" +
316
+ `sum by (gen_ai_request_model) (rate(${calls}[$__rate_interval])) * 0\n` +
317
+ ")\n/\n" +
318
+ `sum by (gen_ai_request_model) (rate(${calls}[$__rate_interval]))`,
265
319
  );
320
+ expect((panelByTitle(json, "Errors by tool").targets as Json[])[0].expr).toMatch(/^\(\nsum by \(gen_ai_tool_name\) .*\nor\n.* \* 0\n\)\n\/\n/s);
321
+ // The token totals are one instant query each, not a range query of full-range increases.
322
+ for (const [title, metric] of [["Input tokens", "genai_tokens_input_total"], ["Output tokens", "genai_tokens_output_total"]]) {
323
+ expect(panelByTitle(json, title).targets).toMatchObject([
324
+ { expr: `sum(increase(${metric}{gen_ai_request_model=~"$model"}[$__range]))`, instant: true, range: false },
325
+ ]);
326
+ }
327
+ for (const title of ["Input tokens by model", "Errors by model"]) {
328
+ expect((panelByTitle(json, title).targets as Json[])[0].instant).toBeUndefined();
329
+ }
266
330
  expect((panelByTitle(json, "Latency p95 by tool").targets as Json[])[0].expr).toBe(
267
331
  'histogram_quantile(0.95, sum by (le, gen_ai_tool_name) (rate(genai_duration_seconds_bucket{service_name=~"$service", gen_ai_request_model=~"$model", gen_ai_tool_name!=""}[$__rate_interval])))',
268
332
  );
@@ -3,10 +3,12 @@
3
3
  * read, so renaming a metric at its source moves it in the panels.
4
4
  */
5
5
 
6
- export { RedDashboard, redQueries } from "./red-dashboard";
7
- export type { RedDashboardProps, RedDashboardMembers, RedDashboardInstance } from "./red-dashboard";
6
+ export { RedDashboard, redQueries, RED_DEFAULT_SPAN_KINDS } from "./red-dashboard";
7
+ export type { RedDashboardProps, RedDashboardMembers, RedDashboardInstance, SpanKind } from "./red-dashboard";
8
8
  export { SloDashboard, sloQueries } from "./slo-dashboard";
9
9
  export type { SloDashboardProps, SloDashboardMembers, SloDashboardInstance } from "./slo-dashboard";
10
10
  export { AgentDashboard, agentQueries } from "./agent-dashboard";
11
11
  export type { AgentDashboardProps, AgentDashboardMembers, AgentDashboardInstance } from "./agent-dashboard";
12
12
  export type { DashboardOptions } from "./shared";
13
+ export { SloAlertRules, sloAlertQueries } from "./slo-alert-rules";
14
+ export type { SloAlertRulesProps, SloAlertRulesMembers, SloAlertRulesInstance } from "./slo-alert-rules";