@intentius/chant-lexicon-grafana 0.96.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.
- package/README.md +50 -0
- package/dist/build.d.ts +116 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/catalog.d.ts +26 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/codegen/docs-cli.d.ts +3 -0
- package/dist/codegen/docs-cli.d.ts.map +1 -0
- package/dist/codegen/docs.d.ts +8 -0
- package/dist/codegen/docs.d.ts.map +1 -0
- package/dist/codegen/generate-cli.d.ts +3 -0
- package/dist/codegen/generate-cli.d.ts.map +1 -0
- package/dist/codegen/generate.d.ts +21 -0
- package/dist/codegen/generate.d.ts.map +1 -0
- package/dist/codegen/package.d.ts +7 -0
- package/dist/codegen/package.d.ts.map +1 -0
- package/dist/codegen/schema-types.d.ts +41 -0
- package/dist/codegen/schema-types.d.ts.map +1 -0
- package/dist/composites/agent-dashboard.d.ts +70 -0
- package/dist/composites/agent-dashboard.d.ts.map +1 -0
- package/dist/composites/catalog.d.ts +3 -0
- package/dist/composites/catalog.d.ts.map +1 -0
- package/dist/composites/index.d.ts +12 -0
- package/dist/composites/index.d.ts.map +1 -0
- package/dist/composites/red-dashboard.d.ts +58 -0
- package/dist/composites/red-dashboard.d.ts.map +1 -0
- package/dist/composites/shared.d.ts +68 -0
- package/dist/composites/shared.d.ts.map +1 -0
- package/dist/composites/slo-dashboard.d.ts +62 -0
- package/dist/composites/slo-dashboard.d.ts.map +1 -0
- package/dist/dashboard.d.ts +84 -0
- package/dist/dashboard.d.ts.map +1 -0
- package/dist/datasource.d.ts +67 -0
- package/dist/datasource.d.ts.map +1 -0
- package/dist/detect.d.ts +20 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/integrity.json +22 -0
- package/dist/lint/audit-catalog.d.ts +13 -0
- package/dist/lint/audit-catalog.d.ts.map +1 -0
- package/dist/lint/post-synth/graf101.d.ts +8 -0
- package/dist/lint/post-synth/graf101.d.ts.map +1 -0
- package/dist/lint/post-synth/graf102.d.ts +8 -0
- package/dist/lint/post-synth/graf102.d.ts.map +1 -0
- package/dist/lint/post-synth/graf103.d.ts +8 -0
- package/dist/lint/post-synth/graf103.d.ts.map +1 -0
- package/dist/lint/post-synth/graf104.d.ts +8 -0
- package/dist/lint/post-synth/graf104.d.ts.map +1 -0
- package/dist/lint/post-synth/graf105.d.ts +8 -0
- package/dist/lint/post-synth/graf105.d.ts.map +1 -0
- package/dist/lint/post-synth/graf106.d.ts +8 -0
- package/dist/lint/post-synth/graf106.d.ts.map +1 -0
- package/dist/lint/post-synth/graf107.d.ts +8 -0
- package/dist/lint/post-synth/graf107.d.ts.map +1 -0
- package/dist/lint/post-synth/grafana-helpers.d.ts +16 -0
- package/dist/lint/post-synth/grafana-helpers.d.ts.map +1 -0
- package/dist/lint/post-synth/index.d.ts +3 -0
- package/dist/lint/post-synth/index.d.ts.map +1 -0
- package/dist/lint/rules/grafana-ast.d.ts +21 -0
- package/dist/lint/rules/grafana-ast.d.ts.map +1 -0
- package/dist/lint/rules/index.d.ts +6 -0
- package/dist/lint/rules/index.d.ts.map +1 -0
- package/dist/lint/rules/literal-secret.d.ts +12 -0
- package/dist/lint/rules/literal-secret.d.ts.map +1 -0
- package/dist/lint/rules/uid-syntax.d.ts +12 -0
- package/dist/lint/rules/uid-syntax.d.ts.map +1 -0
- package/dist/lsp/completions.d.ts +4 -0
- package/dist/lsp/completions.d.ts.map +1 -0
- package/dist/lsp/hover.d.ts +4 -0
- package/dist/lsp/hover.d.ts.map +1 -0
- package/dist/manifest.json +8 -0
- package/dist/meta.json +107 -0
- package/dist/okf/index.md +39 -0
- package/dist/okf/rules/GRAF001.md +16 -0
- package/dist/okf/rules/GRAF002.md +15 -0
- package/dist/okf/rules/GRAF101.md +15 -0
- package/dist/okf/rules/GRAF102.md +15 -0
- package/dist/okf/rules/GRAF103.md +11 -0
- package/dist/okf/rules/GRAF104.md +15 -0
- package/dist/okf/rules/GRAF105.md +11 -0
- package/dist/okf/rules/GRAF106.md +11 -0
- package/dist/okf/rules/GRAF107.md +11 -0
- package/dist/okf/types/ConstantVariable.md +9 -0
- package/dist/okf/types/CustomVariable.md +9 -0
- package/dist/okf/types/Dashboard.md +14 -0
- package/dist/okf/types/DashboardProvider.md +9 -0
- package/dist/okf/types/Datasource.md +16 -0
- package/dist/okf/types/DatasourceVariable.md +9 -0
- package/dist/okf/types/GaugePanel.md +9 -0
- package/dist/okf/types/HeatmapPanel.md +9 -0
- package/dist/okf/types/IntervalVariable.md +9 -0
- package/dist/okf/types/LogsPanel.md +9 -0
- package/dist/okf/types/LokiQuery.md +9 -0
- package/dist/okf/types/PromQuery.md +9 -0
- package/dist/okf/types/QueryVariable.md +9 -0
- package/dist/okf/types/Row.md +9 -0
- package/dist/okf/types/StatPanel.md +9 -0
- package/dist/okf/types/TablePanel.md +9 -0
- package/dist/okf/types/TempoQuery.md +9 -0
- package/dist/okf/types/TextPanel.md +9 -0
- package/dist/okf/types/TextboxVariable.md +9 -0
- package/dist/okf/types/TimeSeriesPanel.md +9 -0
- package/dist/okf/types/TracesPanel.md +9 -0
- package/dist/package-cli.d.ts +3 -0
- package/dist/package-cli.d.ts.map +1 -0
- package/dist/panels.d.ts +138 -0
- package/dist/panels.d.ts.map +1 -0
- package/dist/pin.d.ts +32 -0
- package/dist/pin.d.ts.map +1 -0
- package/dist/plugin.d.ts +12 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/query.d.ts +81 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/rules/graf101.ts +17 -0
- package/dist/rules/graf102.ts +17 -0
- package/dist/rules/graf103.ts +17 -0
- package/dist/rules/graf104.ts +17 -0
- package/dist/rules/graf105.ts +17 -0
- package/dist/rules/graf106.ts +17 -0
- package/dist/rules/graf107.ts +17 -0
- package/dist/rules/grafana-ast.ts +70 -0
- package/dist/rules/grafana-helpers.ts +68 -0
- package/dist/rules/literal-secret.ts +48 -0
- package/dist/rules/uid-syntax.ts +56 -0
- package/dist/schema/dashboard.gen.d.ts +1231 -0
- package/dist/schema/dashboard.gen.d.ts.map +1 -0
- package/dist/schema/gauge.gen.d.ts +57 -0
- package/dist/schema/gauge.gen.d.ts.map +1 -0
- package/dist/schema/heatmap.gen.d.ts +295 -0
- package/dist/schema/heatmap.gen.d.ts.map +1 -0
- package/dist/schema/index.d.ts +18 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/logs.gen.d.ts +29 -0
- package/dist/schema/logs.gen.d.ts.map +1 -0
- package/dist/schema/loki.gen.d.ts +69 -0
- package/dist/schema/loki.gen.d.ts.map +1 -0
- package/dist/schema/prometheus.gen.d.ts +169 -0
- package/dist/schema/prometheus.gen.d.ts.map +1 -0
- package/dist/schema/stat.gen.d.ts +75 -0
- package/dist/schema/stat.gen.d.ts.map +1 -0
- package/dist/schema/table.gen.d.ts +295 -0
- package/dist/schema/table.gen.d.ts.map +1 -0
- package/dist/schema/tempo.gen.d.ts +136 -0
- package/dist/schema/tempo.gen.d.ts.map +1 -0
- package/dist/schema/text.gen.d.ts +16 -0
- package/dist/schema/text.gen.d.ts.map +1 -0
- package/dist/schema/timeseries.gen.d.ts +179 -0
- package/dist/schema/timeseries.gen.d.ts.map +1 -0
- package/dist/schema-validate.d.ts +20 -0
- package/dist/schema-validate.d.ts.map +1 -0
- package/dist/serializer.d.ts +22 -0
- package/dist/serializer.d.ts.map +1 -0
- package/dist/skill-defs.d.ts +3 -0
- package/dist/skill-defs.d.ts.map +1 -0
- package/dist/skills/chant-grafana-provisioning.md +42 -0
- package/dist/skills/chant-grafana.md +93 -0
- package/dist/spec/fetch-cli.d.ts +3 -0
- package/dist/spec/fetch-cli.d.ts.map +1 -0
- package/dist/spec/schemas.d.ts +25 -0
- package/dist/spec/schemas.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/util.d.ts +17 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/validate-cli.d.ts +3 -0
- package/dist/validate-cli.d.ts.map +1 -0
- package/dist/validate-output.d.ts +42 -0
- package/dist/validate-output.d.ts.map +1 -0
- package/dist/validate.d.ts +12 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/variables.d.ts +100 -0
- package/dist/variables.d.ts.map +1 -0
- package/package.json +79 -0
- package/src/build.test.ts +210 -0
- package/src/build.ts +573 -0
- package/src/catalog.ts +116 -0
- package/src/codegen/docs-cli.ts +4 -0
- package/src/codegen/docs.ts +97 -0
- package/src/codegen/generate-cli.ts +8 -0
- package/src/codegen/generate.ts +83 -0
- package/src/codegen/package.ts +41 -0
- package/src/codegen/schema-types.ts +173 -0
- package/src/composites/agent-dashboard.ts +235 -0
- package/src/composites/catalog.test.ts +37 -0
- package/src/composites/catalog.ts +223 -0
- package/src/composites/composites.test.ts +314 -0
- package/src/composites/index.ts +12 -0
- package/src/composites/red-dashboard.ts +159 -0
- package/src/composites/shared.ts +94 -0
- package/src/composites/slo-dashboard.ts +177 -0
- package/src/dashboard.ts +123 -0
- package/src/datasource.ts +93 -0
- package/src/detect.ts +30 -0
- package/src/generated/lexicon-grafana.json +107 -0
- package/src/import.e2e.test.ts +147 -0
- package/src/import.test.ts +45 -0
- package/src/index.ts +178 -0
- package/src/lint/audit-catalog.ts +87 -0
- package/src/lint/post-synth/graf101.ts +17 -0
- package/src/lint/post-synth/graf102.ts +17 -0
- package/src/lint/post-synth/graf103.ts +17 -0
- package/src/lint/post-synth/graf104.ts +17 -0
- package/src/lint/post-synth/graf105.ts +17 -0
- package/src/lint/post-synth/graf106.ts +17 -0
- package/src/lint/post-synth/graf107.ts +17 -0
- package/src/lint/post-synth/grafana-helpers.ts +68 -0
- package/src/lint/post-synth/index.ts +19 -0
- package/src/lint/post-synth/post-synth.test.ts +231 -0
- package/src/lint/rules/grafana-ast.ts +70 -0
- package/src/lint/rules/index.ts +9 -0
- package/src/lint/rules/literal-secret.ts +48 -0
- package/src/lint/rules/rules.test.ts +70 -0
- package/src/lint/rules/uid-syntax.ts +56 -0
- package/src/lsp/completions.test.ts +31 -0
- package/src/lsp/completions.ts +15 -0
- package/src/lsp/hover.test.ts +25 -0
- package/src/lsp/hover.ts +28 -0
- package/src/package-cli.ts +17 -0
- package/src/panels.ts +275 -0
- package/src/pin.ts +68 -0
- package/src/plugin.test.ts +50 -0
- package/src/plugin.ts +116 -0
- package/src/query.ts +160 -0
- package/src/schema/dashboard.gen.ts +1289 -0
- package/src/schema/gauge.gen.ts +64 -0
- package/src/schema/heatmap.gen.ts +321 -0
- package/src/schema/index.ts +17 -0
- package/src/schema/logs.gen.ts +34 -0
- package/src/schema/loki.gen.ts +77 -0
- package/src/schema/prometheus.gen.ts +181 -0
- package/src/schema/stat.gen.ts +86 -0
- package/src/schema/table.gen.ts +334 -0
- package/src/schema/tempo.gen.ts +146 -0
- package/src/schema/text.gen.ts +22 -0
- package/src/schema/timeseries.gen.ts +208 -0
- package/src/schema-validate.ts +143 -0
- package/src/schema.test.ts +76 -0
- package/src/serializer.test.ts +170 -0
- package/src/serializer.ts +37 -0
- package/src/skill-defs.ts +31 -0
- package/src/skills/chant-grafana-provisioning.md +42 -0
- package/src/skills/chant-grafana.md +93 -0
- package/src/spec/fetch-cli.ts +27 -0
- package/src/spec/schemas/dashboard.jsonschema.json +1901 -0
- package/src/spec/schemas/gauge.jsonschema.json +114 -0
- package/src/spec/schemas/heatmap.jsonschema.json +480 -0
- package/src/spec/schemas/logs.jsonschema.json +94 -0
- package/src/spec/schemas/loki.jsonschema.json +118 -0
- package/src/spec/schemas/prometheus.jsonschema.json +276 -0
- package/src/spec/schemas/stat.jsonschema.json +163 -0
- package/src/spec/schemas/table.jsonschema.json +751 -0
- package/src/spec/schemas/tempo.jsonschema.json +225 -0
- package/src/spec/schemas/text.jsonschema.json +72 -0
- package/src/spec/schemas/timeseries.jsonschema.json +471 -0
- package/src/spec/schemas.ts +56 -0
- package/src/util.ts +43 -0
- package/src/validate-cli.ts +7 -0
- package/src/validate-output.ts +380 -0
- package/src/validate.ts +108 -0
- package/src/variables.ts +161 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
// Generated by scripts/generate-composite-catalogs.ts (#2662) from this
|
|
2
|
+
// lexicon's composite exports. Do not edit by hand: run
|
|
3
|
+
// `npm run generate:composite-catalogs`. catalog.test.ts holds it to the exports.
|
|
4
|
+
import type { CompositeEntry } from "@intentius/chant/lexicon";
|
|
5
|
+
|
|
6
|
+
export const compositeCatalog: CompositeEntry[] = [
|
|
7
|
+
{
|
|
8
|
+
"name": "AgentDashboard",
|
|
9
|
+
"lexicon": "grafana",
|
|
10
|
+
"description": "A dashboard for agents instrumented with GenAI spans.",
|
|
11
|
+
"bundles": [
|
|
12
|
+
"Dashboard"
|
|
13
|
+
],
|
|
14
|
+
"params": [
|
|
15
|
+
{
|
|
16
|
+
"name": "genAi",
|
|
17
|
+
"type": "GenAiMetrics | { metrics: GenAiMetrics }",
|
|
18
|
+
"required": true,
|
|
19
|
+
"description": "The preset's metrics: `genAiMetrics(options)` with the options the collector was built with, or `genAiComponents(options)`."
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"name": "quantile",
|
|
23
|
+
"type": "number",
|
|
24
|
+
"required": false,
|
|
25
|
+
"description": "The latency quantile per model and per tool (default 0.95)."
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "datasource",
|
|
29
|
+
"type": "DatasourceInput<\"prometheus\">",
|
|
30
|
+
"required": true,
|
|
31
|
+
"description": "The Prometheus the metrics are queried from: a declared `Datasource`, or `{ type: \"prometheus\", uid }` for one declared elsewhere."
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"name": "title",
|
|
35
|
+
"type": "string",
|
|
36
|
+
"required": false
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"name": "uid",
|
|
40
|
+
"type": "string",
|
|
41
|
+
"required": false,
|
|
42
|
+
"description": "The dashboard uid."
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"name": "description",
|
|
46
|
+
"type": "string",
|
|
47
|
+
"required": false
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"name": "tags",
|
|
51
|
+
"type": "string[]",
|
|
52
|
+
"required": false
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"name": "folder",
|
|
56
|
+
"type": "string",
|
|
57
|
+
"required": false,
|
|
58
|
+
"description": "The Grafana folder to provision it into."
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"name": "time",
|
|
62
|
+
"type": "{ from: string; to: string }",
|
|
63
|
+
"required": false,
|
|
64
|
+
"description": "Initial time range."
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"name": "refresh",
|
|
68
|
+
"type": "string",
|
|
69
|
+
"required": false,
|
|
70
|
+
"description": "Auto-refresh interval, e.g. `30s`."
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"name": "links",
|
|
74
|
+
"type": "DashboardLinkInput[]",
|
|
75
|
+
"required": false
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"name": "RedDashboard",
|
|
81
|
+
"lexicon": "grafana",
|
|
82
|
+
"description": "A RED dashboard (rate, errors, duration) per service, built from a `spanmetrics` connector declaration.",
|
|
83
|
+
"bundles": [
|
|
84
|
+
"Dashboard"
|
|
85
|
+
],
|
|
86
|
+
"params": [
|
|
87
|
+
{
|
|
88
|
+
"name": "spanMetrics",
|
|
89
|
+
"type": "OTelComponent<\"connector\", \"spanmetrics\", SpanMetricsConnectorConfig> | SpanMetricsNames",
|
|
90
|
+
"required": true,
|
|
91
|
+
"description": "The `spanmetrics` connector the metrics come from, or the names `spanMetricsNames()` returned for it."
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"name": "exporter",
|
|
95
|
+
"type": "OTelComponent<\"exporter\", \"prometheus\", PrometheusExporterConfig> | PrometheusNaming",
|
|
96
|
+
"required": false,
|
|
97
|
+
"description": "The `prometheus` exporter that serves them, when its `namespace` or `add_metric_suffixes` changes the names."
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"name": "quantiles",
|
|
101
|
+
"type": "number[]",
|
|
102
|
+
"required": false,
|
|
103
|
+
"description": "Duration quantiles, one panel each (default p50, p95 and p99)."
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"name": "datasource",
|
|
107
|
+
"type": "DatasourceInput<\"prometheus\">",
|
|
108
|
+
"required": true,
|
|
109
|
+
"description": "The Prometheus the metrics are queried from: a declared `Datasource`, or `{ type: \"prometheus\", uid }` for one declared elsewhere."
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"name": "title",
|
|
113
|
+
"type": "string",
|
|
114
|
+
"required": false
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"name": "uid",
|
|
118
|
+
"type": "string",
|
|
119
|
+
"required": false,
|
|
120
|
+
"description": "The dashboard uid."
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"name": "description",
|
|
124
|
+
"type": "string",
|
|
125
|
+
"required": false
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"name": "tags",
|
|
129
|
+
"type": "string[]",
|
|
130
|
+
"required": false
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"name": "folder",
|
|
134
|
+
"type": "string",
|
|
135
|
+
"required": false,
|
|
136
|
+
"description": "The Grafana folder to provision it into."
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"name": "time",
|
|
140
|
+
"type": "{ from: string; to: string }",
|
|
141
|
+
"required": false,
|
|
142
|
+
"description": "Initial time range."
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"name": "refresh",
|
|
146
|
+
"type": "string",
|
|
147
|
+
"required": false,
|
|
148
|
+
"description": "Auto-refresh interval, e.g. `30s`."
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"name": "links",
|
|
152
|
+
"type": "DashboardLinkInput[]",
|
|
153
|
+
"required": false
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"name": "SloDashboard",
|
|
159
|
+
"lexicon": "grafana",
|
|
160
|
+
"description": "A dashboard for one SLO: the SLI over its window against the objective, the error budget left, and each burn-rate alert's two windows with the rate it fires...",
|
|
161
|
+
"bundles": [
|
|
162
|
+
"Dashboard"
|
|
163
|
+
],
|
|
164
|
+
"params": [
|
|
165
|
+
{
|
|
166
|
+
"name": "slo",
|
|
167
|
+
"type": "SloInstance | RuleGroupEntity | SloMetrics",
|
|
168
|
+
"required": true,
|
|
169
|
+
"description": "The `Slo(...)` the dashboard reads, its rule group, or what `sloMetrics()` returned for it."
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
"name": "datasource",
|
|
173
|
+
"type": "DatasourceInput<\"prometheus\">",
|
|
174
|
+
"required": true,
|
|
175
|
+
"description": "The Prometheus the metrics are queried from: a declared `Datasource`, or `{ type: \"prometheus\", uid }` for one declared elsewhere."
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"name": "title",
|
|
179
|
+
"type": "string",
|
|
180
|
+
"required": false
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"name": "uid",
|
|
184
|
+
"type": "string",
|
|
185
|
+
"required": false,
|
|
186
|
+
"description": "The dashboard uid."
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"name": "description",
|
|
190
|
+
"type": "string",
|
|
191
|
+
"required": false
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"name": "tags",
|
|
195
|
+
"type": "string[]",
|
|
196
|
+
"required": false
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"name": "folder",
|
|
200
|
+
"type": "string",
|
|
201
|
+
"required": false,
|
|
202
|
+
"description": "The Grafana folder to provision it into."
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"name": "time",
|
|
206
|
+
"type": "{ from: string; to: string }",
|
|
207
|
+
"required": false,
|
|
208
|
+
"description": "Initial time range."
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"name": "refresh",
|
|
212
|
+
"type": "string",
|
|
213
|
+
"required": false,
|
|
214
|
+
"description": "Auto-refresh interval, e.g. `30s`."
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
"name": "links",
|
|
218
|
+
"type": "DashboardLinkInput[]",
|
|
219
|
+
"required": false
|
|
220
|
+
}
|
|
221
|
+
]
|
|
222
|
+
}
|
|
223
|
+
];
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The dashboard composites build from the declarations they read: renaming a
|
|
3
|
+
* metric or namespace at the source moves it in every panel query, the
|
|
4
|
+
* rendered dashboards pass every GRAF check (GRAF107 is the pinned schema),
|
|
5
|
+
* and every panel's PromQL parses.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, expect, test } from "vitest";
|
|
8
|
+
import type { Declarable } from "@intentius/chant/declarable";
|
|
9
|
+
import { PrometheusExporter, SpanMetricsConnector } from "@intentius/chant-lexicon-otel/components/index";
|
|
10
|
+
import { genAiComponents, genAiMetrics } from "@intentius/chant-lexicon-otel/genai";
|
|
11
|
+
import { spanMetricsNames } from "@intentius/chant-lexicon-otel/metric-names";
|
|
12
|
+
import { Slo, sloMetrics, type SloProps } from "@intentius/chant-lexicon-prometheus/composites/slo";
|
|
13
|
+
import { checkPromql } from "@intentius/chant-lexicon-prometheus/promql";
|
|
14
|
+
import { Datasource } from "../datasource";
|
|
15
|
+
import { buildGrafana, type DashboardJson } from "../build";
|
|
16
|
+
import { validateGrafanaOutput } from "../validate-output";
|
|
17
|
+
import { validateDashboardSchema } from "../schema-validate";
|
|
18
|
+
import { AgentDashboard, RedDashboard, SloDashboard } from "./index";
|
|
19
|
+
|
|
20
|
+
const prometheus = new Datasource({ name: "Prometheus", type: "prometheus", url: "http://prometheus:9090" });
|
|
21
|
+
|
|
22
|
+
type Json = Record<string, unknown>;
|
|
23
|
+
|
|
24
|
+
/** Build the dashboard with the datasource beside it, as one build root. */
|
|
25
|
+
function built(dashboard: Declarable, ...more: Declarable[]) {
|
|
26
|
+
const out = buildGrafana([prometheus, dashboard, ...more]);
|
|
27
|
+
expect(out.dashboards).toHaveLength(1);
|
|
28
|
+
return { out, json: out.dashboards[0].json };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Every panel, rows' children included. */
|
|
32
|
+
function panels(json: DashboardJson): Json[] {
|
|
33
|
+
const all: Json[] = [];
|
|
34
|
+
for (const p of json.panels as unknown as Json[]) {
|
|
35
|
+
all.push(p);
|
|
36
|
+
for (const c of (p.panels as Json[] | undefined) ?? []) all.push(c);
|
|
37
|
+
}
|
|
38
|
+
return all.filter((p) => p.type !== "row");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Every PromQL expression in the dashboard's panels. */
|
|
42
|
+
function exprs(json: DashboardJson): string[] {
|
|
43
|
+
return panels(json).flatMap((p) => ((p.targets as Json[] | undefined) ?? []).map((t) => t.expr as string));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Grafana's built-in variables as a parser would see them once Grafana fills them in. */
|
|
47
|
+
function asPromql(expr: string): string {
|
|
48
|
+
return expr.replaceAll("$__rate_interval", "5m").replaceAll("$__range", "1h");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function expectClean(json: DashboardJson, out: ReturnType<typeof buildGrafana>) {
|
|
52
|
+
expect(validateDashboardSchema(json as unknown as Json)).toEqual([]);
|
|
53
|
+
const issues = validateGrafanaOutput({
|
|
54
|
+
dashboards: out.dashboards.map((d) => ({ source: d.file, json: d.json as unknown as Json })),
|
|
55
|
+
datasources: out.datasources,
|
|
56
|
+
});
|
|
57
|
+
expect(issues).toEqual([]);
|
|
58
|
+
const all = exprs(json);
|
|
59
|
+
expect(all.length).toBeGreaterThan(0);
|
|
60
|
+
for (const e of all) {
|
|
61
|
+
const r = checkPromql(asPromql(e));
|
|
62
|
+
expect(r, e).toEqual({ ok: true });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function panelByTitle(json: DashboardJson, title: string): Json {
|
|
67
|
+
const p = panels(json).find((x) => x.title === title);
|
|
68
|
+
if (!p) throw new Error(`no panel "${title}" in ${panels(json).map((x) => x.title).join(", ")}`);
|
|
69
|
+
return p;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ── RED ─────────────────────────────────────────────────────────
|
|
73
|
+
|
|
74
|
+
describe("RedDashboard", () => {
|
|
75
|
+
test("rate, errors and p50/p95/p99 duration per service, from the connector's names", () => {
|
|
76
|
+
const spans = new SpanMetricsConnector({});
|
|
77
|
+
const { json, out } = built(RedDashboard({ spanMetrics: spans, datasource: prometheus }).dashboard);
|
|
78
|
+
expectClean(json, out);
|
|
79
|
+
expect(json.uid).toBe("red-traces-span-metrics");
|
|
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"');
|
|
85
|
+
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])))',
|
|
87
|
+
);
|
|
88
|
+
expect((panelByTitle(json, "Duration p95").fieldConfig as { defaults: Json }).defaults.unit).toBe("ms");
|
|
89
|
+
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)"]]);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("renaming the connector's namespace moves every query; its histogram unit moves the duration metric", () => {
|
|
94
|
+
const before = built(RedDashboard({ spanMetrics: new SpanMetricsConnector({ namespace: "shop" }), datasource: prometheus }).dashboard).json;
|
|
95
|
+
const after = built(
|
|
96
|
+
RedDashboard({ spanMetrics: new SpanMetricsConnector({ namespace: "store", histogram: { unit: "s" } }), datasource: prometheus }).dashboard,
|
|
97
|
+
);
|
|
98
|
+
expectClean(after.json, after.out);
|
|
99
|
+
for (const e of exprs(before)) expect(e).toMatch(/shop_(calls_total|duration_milliseconds_bucket)/);
|
|
100
|
+
for (const e of exprs(after.json)) {
|
|
101
|
+
expect(e).not.toContain("shop_");
|
|
102
|
+
expect(e).toMatch(/store_(calls_total|duration_seconds_bucket)/);
|
|
103
|
+
}
|
|
104
|
+
expect((panelByTitle(after.json, "Duration p99").fieldConfig as { defaults: Json }).defaults.unit).toBe("s");
|
|
105
|
+
expect(after.json.uid).toBe("red-store");
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test("the exporter's namespace, a names object, custom quantiles, and no histogram", () => {
|
|
109
|
+
const spans = new SpanMetricsConnector({ namespace: "spans", histogram: { disable: true } });
|
|
110
|
+
const exporter = new PrometheusExporter({ endpoint: "0.0.0.0:8889", namespace: "otel" });
|
|
111
|
+
const { json, out } = built(RedDashboard({ spanMetrics: spans, exporter, datasource: prometheus }).dashboard);
|
|
112
|
+
expectClean(json, out);
|
|
113
|
+
expect(panels(json).map((p) => p.title)).toEqual(["Rate", "Errors"]);
|
|
114
|
+
for (const e of exprs(json)) expect(e).toContain("otel_spans_calls_total");
|
|
115
|
+
|
|
116
|
+
const names = spanMetricsNames(new SpanMetricsConnector({ namespace: "x" }));
|
|
117
|
+
const q = built(RedDashboard({ spanMetrics: names, quantiles: [0.9], datasource: prometheus, uid: "mine" }).dashboard).json;
|
|
118
|
+
expect(panels(q).map((p) => p.title)).toEqual(["Rate", "Errors", "Duration p90"]);
|
|
119
|
+
expect(q.uid).toBe("mine");
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test("a { type, uid } ref to a Prometheus declared in another build root", () => {
|
|
123
|
+
const ref = { type: "prometheus" as const, uid: "shared-prom" };
|
|
124
|
+
const out = buildGrafana([RedDashboard({ spanMetrics: new SpanMetricsConnector({}), datasource: ref }).dashboard]);
|
|
125
|
+
const json = out.dashboards[0].json;
|
|
126
|
+
expect(validateDashboardSchema(json as unknown as Json)).toEqual([]);
|
|
127
|
+
expect(panels(json).every((p) => (p.datasource as Json).uid === "shared-prom")).toBe(true);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("refuses what it can't build", () => {
|
|
131
|
+
const spans = new SpanMetricsConnector({});
|
|
132
|
+
expect(() => RedDashboard({ spanMetrics: spans, datasource: undefined as never })).toThrow(/datasource is required/);
|
|
133
|
+
const tempo = new Datasource({ name: "Tempo", type: "tempo" });
|
|
134
|
+
expect(() => RedDashboard({ spanMetrics: spans, datasource: tempo as never })).toThrow(/Prometheus datasource/);
|
|
135
|
+
expect(() =>
|
|
136
|
+
RedDashboard({ spanMetrics: new SpanMetricsConnector({ exclude_dimensions: ["service.name"] }), datasource: prometheus }),
|
|
137
|
+
).toThrow(/service\.name/);
|
|
138
|
+
expect(() => RedDashboard({ spanMetrics: spans, quantiles: [95], datasource: prometheus })).toThrow(/between 0 and 1/);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// ── SLO ─────────────────────────────────────────────────────────
|
|
143
|
+
|
|
144
|
+
const sloProps = (over: Partial<SloProps> = {}): SloProps => ({
|
|
145
|
+
name: "checkout",
|
|
146
|
+
objective: 0.999,
|
|
147
|
+
window: "30d",
|
|
148
|
+
sli: {
|
|
149
|
+
errors: 'sum(rate(traces_span_metrics_calls_total{span_name="checkout",status_code="STATUS_CODE_ERROR"}[{{window}}]))',
|
|
150
|
+
total: 'sum(rate(traces_span_metrics_calls_total{span_name="checkout"}[{{window}}]))',
|
|
151
|
+
},
|
|
152
|
+
...over,
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
describe("SloDashboard", () => {
|
|
156
|
+
test("SLI, budget left, alerts firing, and one burn-rate panel per alert window with its threshold", () => {
|
|
157
|
+
const slo = Slo(sloProps());
|
|
158
|
+
const m = sloMetrics(slo);
|
|
159
|
+
const { json, out } = built(SloDashboard({ slo, datasource: prometheus }).dashboard);
|
|
160
|
+
expectClean(json, out);
|
|
161
|
+
expect(json.uid).toBe("slo-checkout");
|
|
162
|
+
expect(json.title).toBe("SLO: checkout");
|
|
163
|
+
expect((panelByTitle(json, "SLI over 30d").targets as Json[])[0].expr).toBe('1 - slo:sli_error:ratio_rate30d{slo="checkout"}');
|
|
164
|
+
expect((panelByTitle(json, "Error budget remaining").targets as Json[])[0].expr).toBe('slo:error_budget:remaining{slo="checkout"}');
|
|
165
|
+
expect((panelByTitle(json, "Burn-rate alerts firing").targets as Json[])[0].expr).toBe(
|
|
166
|
+
'sum(ALERTS{alertname="ErrorBudgetBurn", slo="checkout", alertstate="firing"}) or vector(0)',
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
const burn = panels(json).filter((p) => String(p.title).startsWith("Burn rate "));
|
|
170
|
+
expect(burn.map((p) => p.title)).toEqual([
|
|
171
|
+
"Burn rate 1h / 5m (page)",
|
|
172
|
+
"Burn rate 6h / 30m (page)",
|
|
173
|
+
"Burn rate 1d / 2h (ticket)",
|
|
174
|
+
"Burn rate 3d / 6h (ticket)",
|
|
175
|
+
]);
|
|
176
|
+
// The Workbook's factors on a 30-day window, drawn where the alert fires.
|
|
177
|
+
expect(m.burnRates.map((b) => b.factor)).toEqual([14.4, 6, 3, 1]);
|
|
178
|
+
burn.forEach((p, i) => {
|
|
179
|
+
const b = m.burnRates[i];
|
|
180
|
+
const defaults = (p.fieldConfig as { defaults: Json }).defaults as { thresholds: { steps: Json[] }; custom: Json };
|
|
181
|
+
expect(defaults.thresholds.steps).toEqual([
|
|
182
|
+
{ value: null, color: "green" },
|
|
183
|
+
{ value: b.factor, color: "red" },
|
|
184
|
+
]);
|
|
185
|
+
expect(defaults.custom.thresholdsStyle).toEqual({ mode: "dashed" });
|
|
186
|
+
expect((p.targets as Json[]).map((t) => t.expr)).toEqual([
|
|
187
|
+
`slo:sli_error:ratio_rate${b.long}{slo="checkout"} / 0.001`,
|
|
188
|
+
`slo:sli_error:ratio_rate${b.short}{slo="checkout"} / 0.001`,
|
|
189
|
+
]);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// The SLI's threshold is the objective.
|
|
193
|
+
const sliSteps = ((panelByTitle(json, "SLI over 30d").fieldConfig as { defaults: Json }).defaults as { thresholds: { steps: Json[] } }).thresholds.steps;
|
|
194
|
+
expect(sliSteps[1]).toEqual({ value: 0.999, color: "green" });
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
test("renaming the SLO, changing its window, objective or burn rates moves the panels and thresholds", () => {
|
|
198
|
+
const slo = Slo(
|
|
199
|
+
sloProps({
|
|
200
|
+
name: "order-ack",
|
|
201
|
+
objective: 0.995,
|
|
202
|
+
window: "28d",
|
|
203
|
+
alerting: { page: { burnRates: [{ long: "2h", short: "10m", factor: 10 }] }, ticket: false, alertName: "OrderAckBurn" },
|
|
204
|
+
}),
|
|
205
|
+
);
|
|
206
|
+
const { json, out } = built(SloDashboard({ slo, datasource: prometheus }).dashboard);
|
|
207
|
+
expectClean(json, out);
|
|
208
|
+
for (const e of exprs(json)) {
|
|
209
|
+
expect(e).not.toContain('slo="checkout"');
|
|
210
|
+
expect(e).toContain('"order-ack"');
|
|
211
|
+
}
|
|
212
|
+
expect(json.uid).toBe("slo-order-ack");
|
|
213
|
+
expect(panelByTitle(json, "SLI over 28d")).toBeDefined();
|
|
214
|
+
expect((panelByTitle(json, "Burn-rate alerts firing").targets as Json[])[0].expr).toContain('alertname="OrderAckBurn"');
|
|
215
|
+
const burn = panels(json).filter((p) => String(p.title).startsWith("Burn rate "));
|
|
216
|
+
expect(burn.map((p) => p.title)).toEqual(["Burn rate 2h / 10m (page)"]);
|
|
217
|
+
expect((burn[0].targets as Json[]).map((t) => t.expr)).toEqual([
|
|
218
|
+
'slo:sli_error:ratio_rate2h{slo="order-ack"} / 0.005',
|
|
219
|
+
'slo:sli_error:ratio_rate10m{slo="order-ack"} / 0.005',
|
|
220
|
+
]);
|
|
221
|
+
const steps = ((burn[0].fieldConfig as { defaults: Json }).defaults as { thresholds: { steps: Json[] } }).thresholds.steps;
|
|
222
|
+
expect(steps[1]).toEqual({ value: 10, color: "red" });
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
test("reads the rule group, or sloMetrics() output, the same as the Slo", () => {
|
|
226
|
+
const slo = Slo(sloProps());
|
|
227
|
+
const a = built(SloDashboard({ slo, datasource: prometheus }).dashboard).json;
|
|
228
|
+
const b = built(SloDashboard({ slo: slo.rules, datasource: prometheus }).dashboard).json;
|
|
229
|
+
const c = built(SloDashboard({ slo: sloMetrics(slo), datasource: prometheus }).dashboard).json;
|
|
230
|
+
expect(b).toEqual(a);
|
|
231
|
+
expect(c).toEqual(a);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test("no burn-rate row when alerting is off", () => {
|
|
235
|
+
const slo = Slo(sloProps({ alerting: { page: false, ticket: false } }));
|
|
236
|
+
const { json, out } = built(SloDashboard({ slo, datasource: prometheus }).dashboard);
|
|
237
|
+
expectClean(json, out);
|
|
238
|
+
expect(panels(json).some((p) => String(p.title).startsWith("Burn rate "))).toBe(false);
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// ── Agents ──────────────────────────────────────────────────────
|
|
243
|
+
|
|
244
|
+
describe("AgentDashboard", () => {
|
|
245
|
+
test("latency and errors per model and tool, errors by type, tokens per model", () => {
|
|
246
|
+
const { json, out } = built(AgentDashboard({ genAi: genAiMetrics(), datasource: prometheus }).dashboard);
|
|
247
|
+
expectClean(json, out);
|
|
248
|
+
expect(json.uid).toBe("genai-agents");
|
|
249
|
+
expect(panels(json).map((p) => p.title)).toEqual([
|
|
250
|
+
"Calls by model",
|
|
251
|
+
"Errors by model",
|
|
252
|
+
"Latency p95 by model",
|
|
253
|
+
"Tool calls",
|
|
254
|
+
"Errors by tool",
|
|
255
|
+
"Latency p95 by tool",
|
|
256
|
+
"Errors by type",
|
|
257
|
+
"Input tokens by model",
|
|
258
|
+
"Output tokens by model",
|
|
259
|
+
"Input tokens",
|
|
260
|
+
"Output tokens",
|
|
261
|
+
]);
|
|
262
|
+
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]))',
|
|
265
|
+
);
|
|
266
|
+
expect((panelByTitle(json, "Latency p95 by tool").targets as Json[])[0].expr).toBe(
|
|
267
|
+
'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
|
+
);
|
|
269
|
+
expect((panelByTitle(json, "Output tokens by model").targets as Json[])[0].expr).toBe(
|
|
270
|
+
'sum by (gen_ai_request_model) (rate(genai_tokens_output_total{gen_ai_request_model=~"$model"}[$__rate_interval]))',
|
|
271
|
+
);
|
|
272
|
+
expect((panelByTitle(json, "Errors by type").targets as Json[])[0].expr).toContain("sum by (error_type)");
|
|
273
|
+
const templating = json.templating as unknown as { list: Json[] };
|
|
274
|
+
expect(templating.list.map((v) => v.name)).toEqual(["service", "model"]);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
test("a preset with another namespace moves every query", () => {
|
|
278
|
+
const m = genAiMetrics({ namespace: "agents" });
|
|
279
|
+
const { json, out } = built(AgentDashboard({ genAi: m, datasource: prometheus }).dashboard);
|
|
280
|
+
expectClean(json, out);
|
|
281
|
+
const names = [m.calls.prometheus, `${m.duration.prometheus}_bucket`, m.inputTokens.prometheus, m.outputTokens.prometheus];
|
|
282
|
+
for (const e of exprs(json)) {
|
|
283
|
+
expect(e).not.toContain("genai_");
|
|
284
|
+
expect(names.some((n) => e.includes(n))).toBe(true);
|
|
285
|
+
}
|
|
286
|
+
expect(json.uid).toBe("agents-agents");
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
test("reads genAiComponents() the same as genAiMetrics()", () => {
|
|
290
|
+
const a = built(AgentDashboard({ genAi: genAiMetrics({ namespace: "ai" }), datasource: prometheus }).dashboard).json;
|
|
291
|
+
const b = built(AgentDashboard({ genAi: genAiComponents({ namespace: "ai" }), datasource: prometheus }).dashboard).json;
|
|
292
|
+
expect(b).toEqual(a);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
test("refuses metrics without the dimensions it breaks down by", () => {
|
|
296
|
+
const m = genAiMetrics();
|
|
297
|
+
const stripped = { ...m, calls: { ...m.calls, dimensions: m.calls.dimensions.filter((d) => d !== "gen_ai.tool.name") } };
|
|
298
|
+
expect(() => AgentDashboard({ genAi: stripped, datasource: prometheus })).toThrow(/gen_ai\.tool\.name/);
|
|
299
|
+
expect(() => AgentDashboard({ genAi: {} as never, datasource: prometheus })).toThrow(/genAiMetrics/);
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
describe("all three in one build root", () => {
|
|
304
|
+
test("distinct uids and a clean build", () => {
|
|
305
|
+
const out = buildGrafana([
|
|
306
|
+
prometheus,
|
|
307
|
+
RedDashboard({ spanMetrics: new SpanMetricsConnector({}), datasource: prometheus }).dashboard,
|
|
308
|
+
SloDashboard({ slo: Slo(sloProps()), datasource: prometheus }).dashboard,
|
|
309
|
+
AgentDashboard({ genAi: genAiMetrics(), datasource: prometheus }).dashboard,
|
|
310
|
+
]);
|
|
311
|
+
expect(out.dashboards.map((d) => d.uid)).toEqual(["red-traces-span-metrics", "slo-checkout", "genai-agents"]);
|
|
312
|
+
expect(validateGrafanaOutput({ dashboards: out.dashboards.map((d) => ({ json: d.json as unknown as Json })), datasources: out.datasources })).toEqual([]);
|
|
313
|
+
});
|
|
314
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grafana lexicon composites: dashboards built from the declarations they
|
|
3
|
+
* read, so renaming a metric at its source moves it in the panels.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { RedDashboard, redQueries } from "./red-dashboard";
|
|
7
|
+
export type { RedDashboardProps, RedDashboardMembers, RedDashboardInstance } from "./red-dashboard";
|
|
8
|
+
export { SloDashboard, sloQueries } from "./slo-dashboard";
|
|
9
|
+
export type { SloDashboardProps, SloDashboardMembers, SloDashboardInstance } from "./slo-dashboard";
|
|
10
|
+
export { AgentDashboard, agentQueries } from "./agent-dashboard";
|
|
11
|
+
export type { AgentDashboardProps, AgentDashboardMembers, AgentDashboardInstance } from "./agent-dashboard";
|
|
12
|
+
export type { DashboardOptions } from "./shared";
|