Skip to content

Commit 6e1b24f

Browse files
authored
docs: enhance trigger (#2286)
1 parent 16fc459 commit 6e1b24f

File tree

2 files changed

+427
-186
lines changed

2 files changed

+427
-186
lines changed

docs/enterprise/trigger.md

Lines changed: 217 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -9,146 +9,267 @@ Trigger allows you to define evaluation rules with SQL.
99
GreptimeDB evaluates these rules periodically; once the condition is met, a
1010
notification is sent out.
1111

12-
The following content is a quick start example that sets up a Trigger to monitor system load and raise alerts step by step.
13-
For details on how to write a Trigger,
14-
please refer to the [Syntax](/reference/sql/trigger-syntax.md) documentation.
12+
## Key Features
13+
14+
- **SQL-native**: Define trigger rules in SQL, reusing GreptimeDB's built-in
15+
functions without a learning curve
16+
- **Multi-stage state management**: Built-in pending / firing / inactive state
17+
machine prevents flapping and duplicate notifications
18+
- **Rich context**: Custom labels and annotations with automatic injection of
19+
query result fields to pinpoint root causes
20+
- **Ecosystem-friendly**: Alert payload fully compatible with Prometheus
21+
Alertmanager—use its grouping, inhibition, silencing, and routing without
22+
adapters
1523

1624
## Quick Start Example
1725

18-
This section walks through an end-to-end example that uses Trigger to monitor
19-
system load and raise an alert.
26+
This section walks through an end-to-end alerting scenario: monitor system load
27+
(`load1`) and fire alerts when load exceeds a threshold.
2028

21-
The diagram illustrates the complete end-to-end workflow of the example.
29+
In this quick start, you will:
2230

23-
![Trigger demo architecture](/trigger-demo-architecture.png)
31+
- Create a `load1` table to store host load metrics
32+
- Define a Trigger with conditions, labels, annotations, and notifications
33+
- Simulate data ingestion with normal and abnormal values
34+
- Watch alerts transition through pending → firing → inactive
2435

25-
1. Vector continuously scrapes host metrics and writes them to GreptimeDB.
26-
2. A Trigger in GreptimeDB evaluates a rule every minute; whenever the condition
27-
is met, it sends a notification to Alertmanager.
28-
3. Alertmanager applies its own policies and finally delivers the alert to Slack.
36+
### 1. Create the Data Table
2937

30-
### Use Vector to Scrape Host Metrics
38+
Connect to GreptimeDB with a MySQL client and create the `load1` table:
3139

32-
Use Vector to scrape host metrics and write it to GreptimeDB. Below is a Vector
33-
configuration example:
40+
```sql
41+
CREATE TABLE `load1` (
42+
host STRING,
43+
load1 FLOAT32,
44+
ts TIMESTAMP TIME INDEX
45+
) WITH ('append_mode'='true');
46+
```
47+
48+
### 2. Create Trigger
49+
50+
Connect to GreptimeDB with MySQL client and create the `load1_monitor` trigger:
51+
52+
```sql
53+
CREATE TRIGGER IF NOT EXISTS `load1_monitor`
54+
ON (
55+
SELECT
56+
host AS label_host,
57+
avg(load1) AS avg_load1,
58+
max(ts) AS ts
59+
FROM public.load1
60+
WHERE ts >= NOW() - '1 minutes'::INTERVAL
61+
GROUP BY host
62+
HAVING avg(load1) > 10
63+
) EVERY '1 minutes'::INTERVAL
64+
FOR '3 minutes'::INTERVAL
65+
KEEP FIRING FOR '3 minutes'::INTERVAL
66+
LABELS (severity=warning)
67+
ANNOTATIONS (comment='Your computer is smoking, should take a break.')
68+
NOTIFY(
69+
WEBHOOK alert_manager URL 'http://localhost:9093' WITH (timeout='1m')
70+
);
71+
```
72+
73+
This Trigger runs every minute, computes average load per host over the last
74+
60 seconds, and produces an alert instance for each host where `avg(load1) > 10`.
75+
76+
Key parameters:
77+
78+
- **FOR**: Specifies how long the condition must continuously hold before an
79+
alert instance enters firing state.
80+
- **KEEP FIRING FOR**: Specifies how long an alert instance stays in the firing
81+
state after the condition no longer holds.
82+
83+
See the [trigger syntax](/reference/sql/trigger-syntax.md) for more detail.
84+
85+
### 3. Check Trigger Status
86+
87+
#### List all Triggers
88+
89+
```sql
90+
SHOW TRIGGERS;
91+
```
3492

35-
```toml
36-
[sources.in]
37-
type = "host_metrics"
38-
scrape_interval_secs = 15
93+
Output:
3994

40-
[sinks.out]
41-
inputs = ["in"]
42-
type = "greptimedb"
43-
endpoint = "localhost:4001"
95+
```text
96+
+---------------+
97+
| Triggers |
98+
+---------------+
99+
| load1_monitor |
100+
+---------------+
44101
```
45102

46-
GreptimeDB auto-creates tables on the first write. The `host_load1` table stores
47-
the system load averaged over the last minute. It is a key performance indicator
48-
for measuring system activity. We can create a monitoring rule to track values
49-
in this table. The schema of this table is shown below:
103+
#### View the creation statement
50104

51105
```sql
52-
+-----------+----------------------+------+------+---------+---------------+
53-
| Column | Type | Key | Null | Default | Semantic Type |
54-
+-----------+----------------------+------+------+---------+---------------+
55-
| ts | TimestampMillisecond | PRI | NO | | TIMESTAMP |
56-
| collector | String | PRI | YES | | TAG |
57-
| host | String | PRI | YES | | TAG |
58-
| val | Float64 | | YES | | FIELD |
59-
+-----------+----------------------+------+------+---------+---------------+
106+
SHOW CREATE TRIGGER `load1_monitor`\G
60107
```
61108

62-
### Set up Alertmanager with a Slack Receiver
109+
Output:
63110

64-
The payload of GreptimeDB Trigger's Webhook is compatible with [Prometheus
65-
Alertmanager](https://prometheus.io/docs/alerting/latest/alertmanager/), so we
66-
can reuse Alertmanager’s grouping, inhibition, silencing and routing features
67-
without any extra glue code.
111+
```text
112+
*************************** 1. row ***************************
113+
Trigger: load1_monitor
114+
Create Trigger: CREATE TRIGGER IF NOT EXISTS `load1_monitor`
115+
ON (SELECT host AS label_host, avg(load1) AS avg_load1 ...) EVERY '1 minutes'::INTERVAL
116+
FOR '3 minutes'::INTERVAL
117+
KEEP FIRING FOR '3 minutes'::INTERVAL
118+
LABELS (severity = 'warning')
119+
ANNOTATIONS (comment = 'Your computer is smoking, should take a break.')
120+
NOTIFY(
121+
WEBHOOK `alert_manager` URL `http://localhost:9093` WITH (timeout = '1m'),
122+
)
123+
```
68124

69-
You can refer to the [official documentation](https://prometheus.io/docs/alerting/latest/configuration/)
70-
to configure Prometheus Alertmanager. Below is a minimal message template you
71-
can use:
125+
#### View Trigger details
126+
127+
```sql
128+
SELECT * FROM information_schema.triggers\G
129+
```
130+
131+
Output:
72132

73133
```text
74-
{{ define "slack.text" }}
75-
{{ range .Alerts }}
134+
*************************** 1. row ***************************
135+
trigger_name: load1_monitor
136+
trigger_id: 1024
137+
raw_sql: (SELECT host AS label_host, avg(load1) AS avg_load1, ...)
138+
interval: 60
139+
labels: {"severity":"warning"}
140+
annotations: {"comment":"Your computer is smoking, should take a break."}
141+
for: 180
142+
keep_firing_for: 180
143+
channels: [{"channel_type":{"Webhook":{"opts":{"timeout":"1m"}, ...}]
144+
flownode_id: 0
145+
```
76146

77-
Labels:
78-
{{- range .Labels.SortedPairs }}
79-
- {{ .Name }}: {{ .Value }}
80-
{{ end }}
147+
See the [Triggers](/reference/sql/information-schema/triggers) for more details.
81148

82-
Annotations:
83-
{{- range .Annotations.SortedPairs }}
84-
- {{ .Name }}: {{ .Value }}
85-
{{ end }}
149+
#### View alert instances
86150

87-
{{ end }}
88-
{{ end }}
151+
```sql
152+
SELECT * FROM information_schema.alerts;
89153
```
90154

91-
Generating a Slack message using the above template will iterate over all alerts
92-
and display the labels and annotations for each alert.
155+
With no data written yet, this returns an empty set.
156+
157+
See the [Alerts](/reference/sql/information-schema/alerts) for more details.
93158

94-
Start Alertmanager once the configuration is ready.
159+
### 4. Write Data and Observe Alert States
95160

96-
### Create Trigger
161+
This script simulates data ingestion: normal values for the first minute, high
162+
values for 6 minutes to trigger alerts, then back to normal.
163+
164+
```bash
165+
#!/usr/bin/env bash
97166

98-
Connect to GreptimeDB with MySQL client and run the following SQL:
167+
MYSQL="mysql -h 127.0.0.1 -P 4002"
168+
169+
insert_normal() {
170+
$MYSQL -e "INSERT INTO load1 (host, load1, ts) VALUES
171+
('newyork1', 1.2, now()),
172+
('newyork2', 1.1, now()),
173+
('newyork3', 1.3, now());"
174+
}
175+
176+
insert_high() {
177+
$MYSQL -e "INSERT INTO load1 (host, load1, ts) VALUES
178+
('newyork1', 1.2, now()),
179+
('newyork2', 12.1, now()),
180+
('newyork3', 11.5, now());"
181+
}
182+
183+
# First minute: normal data
184+
for i in {1..4}; do insert_normal; sleep 15; done
185+
186+
# Next 6 minutes: high values
187+
for i in {1..24}; do insert_high; sleep 15; done
188+
189+
# After: back to normal
190+
while true; do insert_normal; sleep 15; done
191+
```
192+
193+
#### State Transitions
194+
195+
In another terminal, query alert status:
196+
197+
**Phase 1: No alerts**
99198

100199
```sql
101-
CREATE TRIGGER IF NOT EXISTS load1_monitor
102-
ON (
103-
SELECT collector AS label_collector,
104-
host as label_host,
105-
val
106-
FROM host_load1 WHERE val > 10 and ts >= now() - '1 minutes'::INTERVAL
107-
) EVERY '1 minute'::INTERVAL
108-
LABELS (severity=warning)
109-
ANNOTATIONS (comment='Your computer is smoking, should take a break.')
110-
NOTIFY(
111-
WEBHOOK alert_manager URL 'http://localhost:9093' WITH (timeout="1m")
112-
);
113-
```
114-
115-
The above SQL will create a trigger named `load1_monitor` that runs every minute.
116-
It evaluates the last 60 seconds of data in `host_load1`; if any load1 value
117-
exceeds 10, the `WEBHOOK` option in the `NOTIFY` syntax specifies that this
118-
trigger will send a notification to Alertmanager which running on localhost with
119-
port 9093.
120-
121-
You can execute `SHOW TRIGGERS` to view the list of created Triggers.
200+
SELECT * FROM information_schema.alerts\G
201+
```
202+
203+
Output:
204+
205+
```
206+
Empty set
207+
```
208+
209+
**Phase 2: pending** (condition met, `FOR` duration not reached)
122210

123211
```sql
124-
SHOW TRIGGERS;
212+
SELECT trigger_id, labels, active_at, fired_at, resolved_at FROM information_schema.alerts;
125213
```
126214

127-
The output should look like this:
215+
```text
216+
+------------+-----------------------------------------------------------------------+----------------------------+----------+-------------+
217+
| trigger_id | labels | active_at | fired_at | resolved_at |
218+
+------------+-----------------------------------------------------------------------+----------------------------+----------+-------------+
219+
| 1024 | {"alert_name":"load1_monitor","host":"newyork3","severity":"warning"} | 2025-12-29 11:58:20.992670 | NULL | NULL |
220+
| 1024 | {"alert_name":"load1_monitor","host":"newyork2","severity":"warning"} | 2025-12-29 11:58:20.992670 | NULL | NULL |
221+
+------------+-----------------------------------------------------------------------+----------------------------+----------+-------------+
222+
```
223+
224+
**Phase 3: firing** (`FOR` satisfied, notifications sent)
225+
226+
```sql
227+
SELECT trigger_id, labels, active_at, fired_at, resolved_at FROM information_schema.alerts;
228+
```
128229

129230
```text
130-
+---------------+
131-
| Triggers |
132-
+---------------+
133-
| load1_monitor |
134-
+---------------+
231+
+------------+-----------------------------------------------------------------------+----------------------------+----------------------------+-------------+
232+
| trigger_id | labels | active_at | fired_at | resolved_at |
233+
+------------+-----------------------------------------------------------------------+----------------------------+----------------------------+-------------+
234+
| 1024 | {"alert_name":"load1_monitor","host":"newyork3","severity":"warning"} | 2025-12-29 11:58:20.992670 | 2025-12-29 12:02:20.991713 | NULL |
235+
| 1024 | {"alert_name":"load1_monitor","host":"newyork2","severity":"warning"} | 2025-12-29 11:58:20.992670 | 2025-12-29 12:02:20.991713 | NULL |
236+
+------------+-----------------------------------------------------------------------+----------------------------+----------------------------+-------------+
135237
```
136238

137-
### Test Trigger
239+
**Phase 4: inactive** (condition cleared + `KEEP FIRING FOR` expired)
138240

139-
Use [stress-ng](https://github.com/ColinIanKing/stress-ng) to simulate high CPU
140-
load for 60s:
241+
```sql
242+
SELECT trigger_id, labels, active_at, fired_at, resolved_at FROM information_schema.alerts;
243+
```
141244

142-
```bash
143-
stress-ng --cpu 100 --cpu-load 10 --timeout 60
245+
```text
246+
+------------+-----------------------------------------------------------------------+----------------------------+----------------------------+----------------------------+
247+
| trigger_id | labels | active_at | fired_at | resolved_at |
248+
+------------+-----------------------------------------------------------------------+----------------------------+----------------------------+----------------------------+
249+
| 1024 | {"alert_name":"load1_monitor","host":"newyork3","severity":"warning"} | 2025-12-29 11:58:20.992670 | 2025-12-29 12:02:20.991713 | 2025-12-29 12:05:20.991750 |
250+
| 1024 | {"alert_name":"load1_monitor","host":"newyork2","severity":"warning"} | 2025-12-29 11:58:20.992670 | 2025-12-29 12:02:20.991713 | 2025-12-29 12:05:20.991750 |
251+
+------------+-----------------------------------------------------------------------+----------------------------+----------------------------+----------------------------+
144252
```
145253

146-
The load1 will rise quickly, the Trigger notification will fire, and within a
147-
minute Slack channel will receive an alert like:
254+
### 5. Alertmanager Integration (Optional)
255+
256+
If you have Prometheus Alertmanager deployed, GreptimeDB automatically pushes
257+
firing and inactive alerts to it.
258+
259+
After each evaluation, the Trigger injects fields from the query results into
260+
labels and annotations. In this example, `host` is included as a label and
261+
`avg_load1` is included as an annotation. These fields are propagated to
262+
Alertmanager and can be referenced in notification templates.
148263

149-
![Trigger slack alert](/trigger-slack-alert.png)
264+
Since the payload is Alertmanager-compatible, you can use grouping, inhibition,
265+
silencing, and routing without adapters.
150266

151267
## Reference
152268

153-
- [Syntax](/reference/sql/trigger-syntax.md): The syntax for SQL statements related to `TRIGGER`.
269+
- [Trigger Syntax](/reference/sql/trigger-syntax.md): The syntax for SQL statements
270+
related to `TRIGGER`
271+
- [INFORMATION_SCHEMA.TRIGGERS](/reference/sql/information-schema/triggers):
272+
View for trigger metadata
273+
- [INFORMATION_SCHEMA.ALERTS](/reference/sql/information-schema/alerts):
274+
View for alert instance metadata
154275

0 commit comments

Comments
 (0)