@intentius/chant-lexicon-prometheus 0.124.30 → 0.124.32

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 (114) hide show
  1. package/dist/alertmanager.js +61 -0
  2. package/dist/api/alertmanager.js +98 -0
  3. package/dist/api/apply.js +306 -0
  4. package/dist/api/bind.js +66 -0
  5. package/dist/api/client.js +110 -0
  6. package/dist/api/evaluated.js +86 -0
  7. package/dist/api/fake-servers.js +165 -0
  8. package/dist/api/index.js +17 -0
  9. package/dist/api/ruler.js +122 -0
  10. package/dist/build.js +240 -0
  11. package/dist/catalog.js +66 -0
  12. package/dist/codegen/docs-cli.js +3 -0
  13. package/dist/codegen/docs.js +105 -0
  14. package/dist/codegen/generate-cli.js +7 -0
  15. package/dist/codegen/generate.js +42 -0
  16. package/dist/codegen/package.js +28 -0
  17. package/dist/collector-metrics.js +225 -0
  18. package/dist/composites/alert-routing.js +210 -0
  19. package/dist/composites/catalog.js +344 -0
  20. package/dist/composites/genai.js +454 -0
  21. package/dist/composites/index.js +8 -0
  22. package/dist/composites/red-alerts.js +135 -0
  23. package/dist/composites/slo.js +353 -0
  24. package/dist/composites/watchdog.js +110 -0
  25. package/dist/config-model.js +52 -0
  26. package/dist/config.js +225 -0
  27. package/dist/describe-resources.js +299 -0
  28. package/dist/detect.js +12 -0
  29. package/dist/duration.js +54 -0
  30. package/dist/export-resources.js +163 -0
  31. package/dist/import/alertmanager-live.js +309 -0
  32. package/dist/import/embedded.js +100 -0
  33. package/dist/import/generator.js +683 -0
  34. package/dist/import/parser.js +428 -0
  35. package/dist/import/slo.js +207 -0
  36. package/dist/index.js +33 -0
  37. package/dist/init-templates.js +119 -0
  38. package/dist/integrations.js +33 -0
  39. package/dist/integrity.json +2 -2
  40. package/dist/lint/audit-catalog.js +60 -0
  41. package/dist/lint/audit-lineage.js +42 -0
  42. package/dist/lint/post-synth/index.js +68 -0
  43. package/dist/lint/post-synth/prom-helpers.js +157 -0
  44. package/dist/lint/post-synth/prom101.js +13 -0
  45. package/dist/lint/post-synth/prom102.js +13 -0
  46. package/dist/lint/post-synth/prom103.js +13 -0
  47. package/dist/lint/post-synth/prom104.js +13 -0
  48. package/dist/lint/post-synth/prom105.js +13 -0
  49. package/dist/lint/post-synth/prom106.js +13 -0
  50. package/dist/lint/post-synth/prom107.js +13 -0
  51. package/dist/lint/post-synth/prom201.js +13 -0
  52. package/dist/lint/post-synth/prom202.js +13 -0
  53. package/dist/lint/post-synth/prom203.js +13 -0
  54. package/dist/lint/post-synth/prom204.js +13 -0
  55. package/dist/lint/post-synth/prom205.js +13 -0
  56. package/dist/lint/post-synth/prom206.js +13 -0
  57. package/dist/lint/post-synth/prom207.js +13 -0
  58. package/dist/lint/post-synth/prom208.js +13 -0
  59. package/dist/lint/post-synth/prom209.js +13 -0
  60. package/dist/lint/post-synth/prom210.js +13 -0
  61. package/dist/lint/post-synth/prom211.js +17 -0
  62. package/dist/lint/post-synth/prom212.js +14 -0
  63. package/dist/lint/post-synth/prom213.js +16 -0
  64. package/dist/lint/post-synth/prom214.js +14 -0
  65. package/dist/lint/post-synth/prom215.js +14 -0
  66. package/dist/lint/post-synth/prom216.js +15 -0
  67. package/dist/lint/post-synth/prom217.js +14 -0
  68. package/dist/lint/post-synth/prom218.js +15 -0
  69. package/dist/lint/post-synth/prom219.js +14 -0
  70. package/dist/lint/post-synth/prom220.js +14 -0
  71. package/dist/lint/post-synth/prom221.js +15 -0
  72. package/dist/lint/post-synth/prom222.js +14 -0
  73. package/dist/lint/post-synth/prom223.js +15 -0
  74. package/dist/lint/post-synth/prom224.js +14 -0
  75. package/dist/lint/post-synth/prom225.js +15 -0
  76. package/dist/lint/post-synth/prom301.js +19 -0
  77. package/dist/lint/rules/index.js +8 -0
  78. package/dist/lint/rules/literal-credential.js +127 -0
  79. package/dist/lint/rules/prom-ast.js +65 -0
  80. package/dist/lint/rules/promql-literal.js +65 -0
  81. package/dist/lint/rules/slo-literal.js +79 -0
  82. package/dist/lsp/completions.js +11 -0
  83. package/dist/lsp/hover.js +21 -0
  84. package/dist/manifest.json +1 -1
  85. package/dist/matchers.js +131 -0
  86. package/dist/model.js +108 -0
  87. package/dist/op/activities/index.js +20 -0
  88. package/dist/op/activities/promtool.js +87 -0
  89. package/dist/op/activities/rule-audit.js +128 -0
  90. package/dist/op/activities/rules-loaded.js +73 -0
  91. package/dist/op/activities/silence.js +123 -0
  92. package/dist/op/activity-contracts.js +51 -0
  93. package/dist/op/audit-op.js +28 -0
  94. package/dist/op/builders.js +57 -0
  95. package/dist/op/slo-rule-tests.js +148 -0
  96. package/dist/package-cli.js +14 -0
  97. package/dist/pin.js +13 -0
  98. package/dist/plugin.js +143 -0
  99. package/dist/prometheus-config.js +38 -0
  100. package/dist/promql-analysis.js +343 -0
  101. package/dist/promql.js +44 -0
  102. package/dist/rule-eval.js +466 -0
  103. package/dist/rules.js +97 -0
  104. package/dist/serializer.js +59 -0
  105. package/dist/skill-defs.js +41 -0
  106. package/dist/tools.js +85 -0
  107. package/dist/validate-cli.js +7 -0
  108. package/dist/validate-config.js +556 -0
  109. package/dist/validate-integrations.js +388 -0
  110. package/dist/validate-relabel.js +52 -0
  111. package/dist/validate-security.js +135 -0
  112. package/dist/validate.js +69 -0
  113. package/package.json +10 -10
  114. package/src/codegen/package.ts +2 -2
@@ -0,0 +1,210 @@
1
+ /**
2
+ * `AlertRouting`: an Alertmanager routing tree by team and severity, the
3
+ * inhibit rules between severity levels, and the receivers.
4
+ *
5
+ * The root route sends to `receiver` (default: a `default` receiver with no
6
+ * integrations, which drops what reaches it). Below it, in order:
7
+ *
8
+ * 1. `routes`: child routes of your own, first, such as `Watchdog`'s.
9
+ * 2. One route per team, matched on the team label (`team` by default),
10
+ * sending to the team's receiver; a team can send a severity level to
11
+ * another receiver of its own (a pager for `critical`).
12
+ * 3. One route per severity level, for every alert no team route took.
13
+ *
14
+ * The default levels are the severities the lexicon's composites write:
15
+ * `critical` (with `Slo`'s `page`), `warning` (with `Slo`'s `ticket`, and
16
+ * `GenAiRules`' and `RedAlerts`' default `warning`) and `info`. Each level
17
+ * sends to the root receiver unless it names one, so a project routes
18
+ * `critical` to a pager and leaves the rest, and PROM202 finds every
19
+ * severity routed.
20
+ *
21
+ * While an alert of one level fires, the same alert at every lower level is
22
+ * held back (an inhibit rule per pair). "The same alert" is equal values of
23
+ * `inhibitEqual`, by default `alertname` and the labels the lexicon's
24
+ * composites tell their alerts apart by (`slo`, `service_name`) plus the team
25
+ * label: one SLO's page holds back that SLO's ticket, not another's.
26
+ */
27
+ import { Composite } from "@intentius/chant/composite";
28
+ import { InhibitRule, Receiver, Route, isReceiver, isRoute, } from "../alertmanager.js";
29
+ import { isValidDuration } from "../duration.js";
30
+ /** The default levels: the severities `Slo`, `GenAiRules` and `RedAlerts` write, most severe first. */
31
+ export const ALERT_ROUTING_LEVELS = Object.freeze([
32
+ { name: "critical", severities: ["critical", "page"] },
33
+ { name: "warning", severities: ["warning", "ticket"] },
34
+ { name: "info", severities: ["info"] },
35
+ ]);
36
+ const LEVEL_NAME = /^[A-Za-z][A-Za-z0-9_]*$/;
37
+ const LABEL = /^[A-Za-z_][A-Za-z0-9_]*$/;
38
+ function fail(message) {
39
+ throw new Error(`AlertRouting: ${message}`);
40
+ }
41
+ /** `severity="a"` for one value, `severity=~"a|b"` for several. */
42
+ function severityMatcher(values) {
43
+ const escaped = values.map((v) => v.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
44
+ return values.length === 1 ? `severity=${JSON.stringify(values[0])}` : `severity=~${JSON.stringify(escaped.join("|"))}`;
45
+ }
46
+ function timing(t, at) {
47
+ const out = {};
48
+ for (const [key, field] of [
49
+ ["groupWait", "group_wait"],
50
+ ["groupInterval", "group_interval"],
51
+ ["repeatInterval", "repeat_interval"],
52
+ ]) {
53
+ const v = t[key];
54
+ if (v === undefined)
55
+ continue;
56
+ if (!isValidDuration(v))
57
+ fail(`${at}.${key} "${v}" is not a duration`);
58
+ out[field] = v;
59
+ }
60
+ return out;
61
+ }
62
+ /**
63
+ * A routing tree by team and severity, with inhibit rules between levels.
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * import { AlertRouting, Watchdog } from "@intentius/chant-lexicon-prometheus";
68
+ *
69
+ * const pager = { name: "pager", pagerduty_configs: [{ routing_key_file: "/etc/alertmanager/secrets/pagerduty" }] };
70
+ * const chat = { name: "chat", slack_configs: [{ api_url_file: "/etc/alertmanager/secrets/slack", channel: "#alerts" }] };
71
+ * export const watchdog = Watchdog({});
72
+ * export const routing = AlertRouting({
73
+ * receiver: chat,
74
+ * levels: [{ name: "critical", severities: ["critical", "page"], receiver: pager }, { name: "warning", severities: ["warning", "ticket"] }],
75
+ * routes: [watchdog.route],
76
+ * });
77
+ * ```
78
+ */
79
+ export const AlertRouting = Composite((input) => {
80
+ const props = input ?? {};
81
+ const members = {};
82
+ const declared = new Map();
83
+ const external = new Map();
84
+ const receiverRef = (r, at) => {
85
+ if (typeof r === "string") {
86
+ if (r === "")
87
+ fail(`${at} must name a receiver`);
88
+ return r;
89
+ }
90
+ if (isReceiver(r)) {
91
+ const name = r.props.name;
92
+ const seen = declared.get(name)?.entity ?? external.get(name);
93
+ if (seen && seen !== r)
94
+ fail(`${at}: two receivers are named "${name}"`);
95
+ external.set(name, r);
96
+ return r;
97
+ }
98
+ if (!r || typeof r !== "object" || typeof r.name !== "string" || r.name === "")
99
+ fail(`${at}.name is required`);
100
+ const before = declared.get(r.name);
101
+ if (before) {
102
+ if (before.props !== r)
103
+ fail(`${at}: two receivers are named "${r.name}"; declare it once and pass the same object`);
104
+ return before.entity;
105
+ }
106
+ if (external.has(r.name))
107
+ fail(`${at}: two receivers are named "${r.name}"`);
108
+ const entity = new Receiver(r);
109
+ declared.set(r.name, { props: r, entity });
110
+ members[`receiver_${r.name.replace(/[^A-Za-z0-9_]/g, "_")}`] = entity;
111
+ return entity;
112
+ };
113
+ const teamLabel = props.teamLabel ?? "team";
114
+ if (!LABEL.test(teamLabel))
115
+ fail(`teamLabel "${teamLabel}" is not a label name`);
116
+ const groupBy = props.groupBy ?? ["alertname"];
117
+ for (const l of groupBy)
118
+ if (l !== "..." && !LABEL.test(l))
119
+ fail(`groupBy label "${l}" is not a label name`);
120
+ const equal = props.inhibitEqual ?? ["alertname", "slo", "service_name", teamLabel];
121
+ for (const l of equal)
122
+ if (!LABEL.test(l))
123
+ fail(`inhibitEqual label "${l}" is not a label name`);
124
+ const root = receiverRef(props.receiver ?? { name: "default" }, "receiver");
125
+ const levels = props.levels ?? ALERT_ROUTING_LEVELS;
126
+ if (!Array.isArray(levels))
127
+ fail("levels must be a list");
128
+ const levelNames = new Set();
129
+ const severities = new Map();
130
+ levels.forEach((l, i) => {
131
+ const at = `levels[${i}]`;
132
+ if (!l || typeof l.name !== "string" || !LEVEL_NAME.test(l.name))
133
+ fail(`${at}.name must be letters, digits and '_', starting with a letter`);
134
+ if (levelNames.has(l.name))
135
+ fail(`${at}: a second level is named "${l.name}"`);
136
+ levelNames.add(l.name);
137
+ if (!Array.isArray(l.severities) || l.severities.length === 0)
138
+ fail(`${at}.severities must name at least one severity`);
139
+ for (const s of l.severities) {
140
+ if (typeof s !== "string" || s === "")
141
+ fail(`${at}.severities must be non-empty strings`);
142
+ const other = severities.get(s);
143
+ if (other !== undefined)
144
+ fail(`${at}: severity "${s}" is already in level "${other}"`);
145
+ severities.set(s, l.name);
146
+ }
147
+ });
148
+ const children = [];
149
+ (props.routes ?? []).forEach((r, i) => {
150
+ if (!isRoute(r) && (typeof r !== "object" || r === null))
151
+ fail(`routes[${i}] must be a Route or route props`);
152
+ children.push(r);
153
+ });
154
+ const teams = props.teams ?? [];
155
+ const teamNames = new Set();
156
+ teams.forEach((t, i) => {
157
+ const at = `teams[${i}]`;
158
+ if (!t || typeof t.team !== "string" || t.team === "")
159
+ fail(`${at}.team is required`);
160
+ if (teamNames.has(t.team))
161
+ fail(`${at}: team "${t.team}" is listed twice`);
162
+ teamNames.add(t.team);
163
+ if (t.receiver === undefined)
164
+ fail(`${at}.receiver is required`);
165
+ const routes = [];
166
+ for (const [levelName, r] of Object.entries(t.levels ?? {})) {
167
+ const level = levels.find((l) => l.name === levelName);
168
+ if (!level)
169
+ fail(`${at}.levels names "${levelName}", which is not a level (${[...levelNames].join(", ")})`);
170
+ routes.push({ matchers: [severityMatcher(level.severities)], receiver: receiverRef(r, `${at}.levels.${levelName}`) });
171
+ }
172
+ children.push({
173
+ matchers: [`${teamLabel}=${JSON.stringify(t.team)}`],
174
+ receiver: receiverRef(t.receiver, `${at}.receiver`),
175
+ ...timing(t, at),
176
+ ...(routes.length > 0 ? { routes } : {}),
177
+ });
178
+ });
179
+ levels.forEach((l, i) => {
180
+ children.push({
181
+ matchers: [severityMatcher(l.severities)],
182
+ receiver: l.receiver !== undefined ? receiverRef(l.receiver, `levels[${i}].receiver`) : root,
183
+ ...timing(l, `levels[${i}]`),
184
+ });
185
+ });
186
+ const route = new Route({
187
+ receiver: root,
188
+ group_by: [...groupBy],
189
+ group_wait: "30s",
190
+ group_interval: "5m",
191
+ repeat_interval: "4h",
192
+ ...timing(props, "props"),
193
+ routes: children,
194
+ });
195
+ if (props.inhibit !== false) {
196
+ for (let hi = 0; hi < levels.length; hi++) {
197
+ for (let lo = hi + 1; lo < levels.length; lo++) {
198
+ const a = levels[hi];
199
+ const b = levels[lo];
200
+ members[`inhibit_${a.name}_${b.name}`] = new InhibitRule({
201
+ name: `${a.name} holds back ${b.name}`,
202
+ source_matchers: [severityMatcher(a.severities)],
203
+ target_matchers: [severityMatcher(b.severities)],
204
+ equal: [...equal],
205
+ });
206
+ }
207
+ }
208
+ }
209
+ return { route, ...members };
210
+ }, "AlertRouting");
@@ -0,0 +1,344 @@
1
+ export const compositeCatalog = [
2
+ {
3
+ "name": "AlertRouting",
4
+ "lexicon": "prometheus",
5
+ "description": "A routing tree by team and severity, with inhibit rules between levels.",
6
+ "bundles": [
7
+ "InhibitRule",
8
+ "Receiver",
9
+ "Route"
10
+ ],
11
+ "params": [
12
+ {
13
+ "name": "receiver",
14
+ "type": "AlertRoutingReceiver",
15
+ "required": false,
16
+ "description": "The root route's receiver, for what no child route takes (default: a `default` receiver with no integrations)."
17
+ },
18
+ {
19
+ "name": "levels",
20
+ "type": "AlertRoutingLevel[]",
21
+ "required": false,
22
+ "description": "Severity levels, most severe first (default `critical`, `warning`, `info`; see `ALERT_ROUTING_LEVELS`)."
23
+ },
24
+ {
25
+ "name": "teams",
26
+ "type": "AlertRoutingTeam[]",
27
+ "required": false,
28
+ "description": "Team routes, tried before the severity levels (default: none)."
29
+ },
30
+ {
31
+ "name": "teamLabel",
32
+ "type": "string",
33
+ "required": false,
34
+ "description": "The label team routes match on (default `team`)."
35
+ },
36
+ {
37
+ "name": "routes",
38
+ "type": "Array<RouteEntity | RouteProps>",
39
+ "required": false,
40
+ "description": "Child routes of your own, tried first, e.g. `[watchdog.route]`."
41
+ },
42
+ {
43
+ "name": "groupBy",
44
+ "type": "string[]",
45
+ "required": false,
46
+ "description": "Labels alerts are grouped by into one notification (default `[\"alertname\"]`)."
47
+ },
48
+ {
49
+ "name": "inhibit",
50
+ "type": "boolean",
51
+ "required": false,
52
+ "description": "Inhibit lower levels while a higher one fires (default: on)."
53
+ },
54
+ {
55
+ "name": "inhibitEqual",
56
+ "type": "string[]",
57
+ "required": false,
58
+ "description": "The labels that must match for one alert to hold back another (default `alertname`, `slo`, `service_name` and the team label)."
59
+ },
60
+ {
61
+ "name": "groupWait",
62
+ "type": "string",
63
+ "required": false,
64
+ "description": "How long to wait before the first notification of a new group."
65
+ },
66
+ {
67
+ "name": "groupInterval",
68
+ "type": "string",
69
+ "required": false,
70
+ "description": "How long to wait before notifying about new alerts in a group already notified."
71
+ },
72
+ {
73
+ "name": "repeatInterval",
74
+ "type": "string",
75
+ "required": false,
76
+ "description": "How long to wait before sending a notification again."
77
+ }
78
+ ]
79
+ },
80
+ {
81
+ "name": "GenAiRules",
82
+ "lexicon": "prometheus",
83
+ "description": "Recording rules and opt-in alerts for GenAI calls, from the otel preset's metrics.",
84
+ "bundles": [
85
+ "RuleGroup"
86
+ ],
87
+ "params": [
88
+ {
89
+ "name": "genAi",
90
+ "type": "GenAiMetrics | { metrics: GenAiMetrics }",
91
+ "required": true,
92
+ "description": "The preset's metrics: `genAiMetrics(options)` with the options the collector was built with, or `genAiComponents(options)`."
93
+ },
94
+ {
95
+ "name": "source",
96
+ "type": "\"client\" | \"spans\"",
97
+ "required": false,
98
+ "description": "Which metrics the model rules read (default `client` when the metrics include the conventions' client metrics, else `spans`)."
99
+ },
100
+ {
101
+ "name": "prices",
102
+ "type": "GenAiPrice[]",
103
+ "required": false,
104
+ "description": "Prices per provider and model."
105
+ },
106
+ {
107
+ "name": "alerts",
108
+ "type": "GenAiAlerting",
109
+ "required": false,
110
+ "description": "Opt-in alerts (default: none)."
111
+ },
112
+ {
113
+ "name": "name",
114
+ "type": "string",
115
+ "required": false,
116
+ "description": "The rule group's name (default `genai`)."
117
+ },
118
+ {
119
+ "name": "prefix",
120
+ "type": "string",
121
+ "required": false,
122
+ "description": "The first part of every recorded series name (default `gen_ai`)."
123
+ },
124
+ {
125
+ "name": "rateWindow",
126
+ "type": "string",
127
+ "required": false,
128
+ "description": "The range every `rate` reads (default `5m`)."
129
+ },
130
+ {
131
+ "name": "groupBy",
132
+ "type": "string[]",
133
+ "required": false,
134
+ "description": "More Prometheus labels every rule keeps, e.g. `job` or `service_name`."
135
+ },
136
+ {
137
+ "name": "labels",
138
+ "type": "LabelSet",
139
+ "required": false,
140
+ "description": "Labels added to every rule, e.g. `team`."
141
+ },
142
+ {
143
+ "name": "interval",
144
+ "type": "string",
145
+ "required": false,
146
+ "description": "Evaluation interval of the group (default: Prometheus's `evaluation_interval`)."
147
+ }
148
+ ]
149
+ },
150
+ {
151
+ "name": "RedAlerts",
152
+ "lexicon": "prometheus",
153
+ "description": "Error-ratio and latency alerts per service, from a `spanmetrics` connector.",
154
+ "bundles": [
155
+ "RuleGroup"
156
+ ],
157
+ "params": [
158
+ {
159
+ "name": "spanMetrics",
160
+ "type": "OTelComponent<\"connector\", \"spanmetrics\", SpanMetricsConnectorConfig> | SpanMetricsNames",
161
+ "required": true,
162
+ "description": "The `spanmetrics` connector the metrics come from (the otel lexicon's `RedMetrics` has it as `spanMetrics`), or the names `spanMetricsNames()` returned for it."
163
+ },
164
+ {
165
+ "name": "exporter",
166
+ "type": "OTelComponent<\"exporter\", \"prometheus\", PrometheusExporterConfig> | PrometheusNaming",
167
+ "required": false,
168
+ "description": "The `prometheus` exporter that serves them, when its `namespace` or `add_metric_suffixes` changes the names."
169
+ },
170
+ {
171
+ "name": "errorRatio",
172
+ "type": "boolean | RedErrorRatioAlert",
173
+ "required": false,
174
+ "description": "Error ratio per service (default: on, above 0.05)."
175
+ },
176
+ {
177
+ "name": "latency",
178
+ "type": "boolean | RedLatencyAlert",
179
+ "required": false,
180
+ "description": "A duration quantile per service (default: on, p95 above 1s, when the connector has a histogram)."
181
+ },
182
+ {
183
+ "name": "spanKinds",
184
+ "type": "SpanMetricsKind[]",
185
+ "required": false,
186
+ "description": "The span kinds counted (default server and consumer spans); `[]` counts every kind."
187
+ },
188
+ {
189
+ "name": "rateWindow",
190
+ "type": "string",
191
+ "required": false,
192
+ "description": "The range every `rate` reads (default `5m`)."
193
+ },
194
+ {
195
+ "name": "minRate",
196
+ "type": "number",
197
+ "required": false,
198
+ "description": "Spans per second a service must see for its alerts to fire, so a handful of calls can't page (default: no floor)."
199
+ },
200
+ {
201
+ "name": "groupBy",
202
+ "type": "string[]",
203
+ "required": false,
204
+ "description": "More Prometheus labels the alerts are split by besides the service, e.g. `deployment_environment`."
205
+ },
206
+ {
207
+ "name": "name",
208
+ "type": "string",
209
+ "required": false,
210
+ "description": "The rule group's name (default `red`)."
211
+ },
212
+ {
213
+ "name": "labels",
214
+ "type": "LabelSet",
215
+ "required": false,
216
+ "description": "Labels added to every rule, e.g. `team`."
217
+ },
218
+ {
219
+ "name": "interval",
220
+ "type": "string",
221
+ "required": false,
222
+ "description": "Evaluation interval of the group (default: Prometheus's `evaluation_interval`)."
223
+ }
224
+ ]
225
+ },
226
+ {
227
+ "name": "Slo",
228
+ "lexicon": "prometheus",
229
+ "description": "An SLO, built to recording rules and multiwindow multi-burn-rate alerts.",
230
+ "bundles": [
231
+ "RuleGroup"
232
+ ],
233
+ "params": [
234
+ {
235
+ "name": "name",
236
+ "type": "string",
237
+ "required": true,
238
+ "description": "The SLO's name, the `slo` label on every series and alert it builds and part of its group names."
239
+ },
240
+ {
241
+ "name": "objective",
242
+ "type": "number",
243
+ "required": true,
244
+ "description": "The target share of good events, strictly between 0 and 1, e.g. `0.995`."
245
+ },
246
+ {
247
+ "name": "window",
248
+ "type": "string",
249
+ "required": true,
250
+ "description": "The rolling window the objective holds over, a Prometheus duration, e.g. `28d` or `30d`."
251
+ },
252
+ {
253
+ "name": "sli",
254
+ "type": "SloSli",
255
+ "required": true,
256
+ "description": "The SLI: good (or error) events over total events, with `{{window}}` for the range."
257
+ },
258
+ {
259
+ "name": "description",
260
+ "type": "string",
261
+ "required": false,
262
+ "description": "A sentence for the alerts' description, e.g. what the SLO measures."
263
+ },
264
+ {
265
+ "name": "alerting",
266
+ "type": "SloAlerting",
267
+ "required": false,
268
+ "description": "Burn-rate alerts (default: both tiers with the Workbook's windows)."
269
+ },
270
+ {
271
+ "name": "labels",
272
+ "type": "LabelSet",
273
+ "required": false,
274
+ "description": "Labels added to every rule, e.g. `team` or `service`."
275
+ },
276
+ {
277
+ "name": "interval",
278
+ "type": "string",
279
+ "required": false,
280
+ "description": "Evaluation interval of the group (default: Prometheus's `evaluation_interval`)."
281
+ }
282
+ ]
283
+ },
284
+ {
285
+ "name": "Watchdog",
286
+ "lexicon": "prometheus",
287
+ "description": "An always-firing alert and the route that sends it to a heartbeat receiver.",
288
+ "bundles": [
289
+ "Receiver",
290
+ "Route",
291
+ "RuleGroup"
292
+ ],
293
+ "params": [
294
+ {
295
+ "name": "receiver",
296
+ "type": "ReceiverEntity | ReceiverProps | string",
297
+ "required": false,
298
+ "description": "Where the heartbeat goes: a declared `Receiver`, a receiver's props (the composite declares it), or the name of one declared elsewhere."
299
+ },
300
+ {
301
+ "name": "urlFile",
302
+ "type": "string",
303
+ "required": false,
304
+ "description": "The file the default receiver's webhook reads its URL from (default `/etc/alertmanager/secrets/heartbeat-url`)."
305
+ },
306
+ {
307
+ "name": "alert",
308
+ "type": "string",
309
+ "required": false,
310
+ "description": "The alert's name (default `Watchdog`)."
311
+ },
312
+ {
313
+ "name": "severity",
314
+ "type": "string",
315
+ "required": false,
316
+ "description": "The alert's `severity` label (default `none`): no severity route takes it."
317
+ },
318
+ {
319
+ "name": "repeatInterval",
320
+ "type": "string",
321
+ "required": false,
322
+ "description": "How often the heartbeat is sent again while the alert fires (default `1m`)."
323
+ },
324
+ {
325
+ "name": "group",
326
+ "type": "string",
327
+ "required": false,
328
+ "description": "The rule group's name (default `watchdog`)."
329
+ },
330
+ {
331
+ "name": "labels",
332
+ "type": "LabelSet",
333
+ "required": false,
334
+ "description": "More labels on the alert."
335
+ },
336
+ {
337
+ "name": "annotations",
338
+ "type": "LabelSet",
339
+ "required": false,
340
+ "description": "More annotations on the alert."
341
+ }
342
+ ]
343
+ }
344
+ ];