@@ -9,146 +9,267 @@ Trigger allows you to define evaluation rules with SQL.
99GreptimeDB evaluates these rules periodically; once the condition is met, a
1010notification 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