ΠΠ΅ΡΠΎΡΡΠ½ΠΎ, Π΄Π½Π΅Ρ Π²Π΅ΡΠ΅ Π½ΠΈΠΊΠΎΠΉ Π½Π΅ ΠΏΠΎΡΡΠ°Π²Ρ ΠΏΠΎΠ΄ Π²ΡΠΏΡΠΎΡ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎΡΡΡΠ° ΠΎΡ ΡΡΠ±ΠΈΡΠ°Π½Π΅ Π½Π° ΠΌΠ΅ΡΡΠΈΠΊΠΈ Π½Π° ΡΡΠ»ΡΠ³ΠΈΡΠ΅. Π‘Π»Π΅Π΄Π²Π°ΡΠ°ΡΠ° Π»ΠΎΠ³ΠΈΡΠ½Π° ΡΡΡΠΏΠΊΠ° Π΅ Π΄Π° Π½Π°ΡΡΡΠΎΠΈΡΠ΅ ΠΎΠΏΠΎΠ²Π΅ΡΡΡΠ²Π°Π½Π΅ Π·Π° ΡΡΠ±ΡΠ°Π½ΠΈΡΠ΅ ΠΌΠ΅ΡΡΠΈΠΊΠΈ, ΠΊΠΎΠ΅ΡΠΎ ΡΠ΅ ΡΠ²Π΅Π΄ΠΎΠΌΡΠ²Π° Π·Π° Π²ΡΡΠΊΠΎ ΠΎΡΠΊΠ»ΠΎΠ½Π΅Π½ΠΈΠ΅ Π² Π΄Π°Π½Π½ΠΈΡΠ΅ ΠΏΠΎ ΡΠ΄ΠΎΠ±Π½ΠΈ Π·Π° Π²Π°Ρ ΠΊΠ°Π½Π°Π»ΠΈ (ΠΈΠΌΠ΅ΠΉΠ», Slack, Telegram). Π ΡΡΠ»ΡΠ³Π°ΡΠ° Π·Π° ΠΎΠ½Π»Π°ΠΉΠ½ ΡΠ΅Π·Π΅ΡΠ²Π°ΡΠΈΡ Π½Π° Ρ ΠΎΡΠ΅Π»ΠΈ Π²ΡΠΈΡΠΊΠΈ ΠΌΠ΅ΡΡΠΈΠΊΠΈ Π½Π° Π½Π°ΡΠΈΡΠ΅ ΡΡΠ»ΡΠ³ΠΈ ΡΠ΅ ΡΡΠ±ΠΈΡΠ°Ρ Π² InfluxDB ΠΈ ΡΠ΅ ΠΏΠΎΠΊΠ°Π·Π²Π°Ρ Π² Grafana, ΡΠ°ΠΌ ΡΡΡΠΎ Π΅ Π½Π°ΡΡΡΠΎΠ΅Π½ΠΎ ΠΎΡΠ½ΠΎΠ²Π½ΠΎ ΠΎΠΏΠΎΠ²Π΅ΡΡΡΠ²Π°Π½Π΅. ΠΠ° Π·Π°Π΄Π°ΡΠΈ ΠΊΠ°ΡΠΎ βΡΡΠ΅Π±Π° Π΄Π° ΡΠ΅ ΠΈΠ·ΡΠΈΡΠ»ΠΈ Π½Π΅ΡΠΎ ΠΈ Π΄Π° ΡΠ΅ ΡΡΠ°Π²Π½ΠΈ Ρ ΡΠΎΠ²Π°β ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ Kapacitor.

Kapacitor Π΅ ΡΠ°ΡΡ ΠΎΡ TICK ΡΡΠ΅ΠΊΠ°, ΠΊΠΎΠΉΡΠΎ ΠΌΠΎΠΆΠ΅ Π΄Π° ΠΎΠ±ΡΠ°Π±ΠΎΡΠ²Π° ΠΌΠ΅ΡΡΠΈΠΊΠΈ ΠΎΡ InfluxDB. Π’ΠΎΠΉ ΠΌΠΎΠΆΠ΅ Π΄Π° ΡΠ²ΡΡΠΆΠ΅ Π½ΡΠΊΠΎΠ»ΠΊΠΎ ΠΈΠ·ΠΌΠ΅ΡΠ΅Π½ΠΈΡ ΠΏΠΎΠΌΠ΅ΠΆΠ΄Ρ ΡΠΈ (join), Π΄Π° ΠΈΠ·ΡΠΈΡΠ»ΠΈ Π½Π΅ΡΠΎ ΠΏΠΎΠ»Π΅Π·Π½ΠΎ ΠΎΡ ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΡΠ΅ Π΄Π°Π½Π½ΠΈ, Π΄Π° Π·Π°ΠΏΠΈΡΠ΅ ΡΠ΅Π·ΡΠ»ΡΠ°ΡΠ° ΠΎΠ±ΡΠ°ΡΠ½ΠΎ Π² InfluxDB, Π΄Π° ΠΈΠ·ΠΏΡΠ°ΡΠΈ ΠΎΠΏΠΎΠ²Π΅ΡΡΡΠ²Π°Π½Π΅ Π² Slack/Twitter/ΠΈΠΌΠ΅ΠΉΠ».
Π¦Π΅Π»ΠΈΡΡ ΡΡΠ΅ΠΊ ΠΈΠΌΠ° Π²ΠΏΠ΅ΡΠ°ΡΠ»ΡΠ²Π°ΡΠ° ΠΈ ΠΏΠΎΠ΄ΡΠΎΠ±Π½Π° , Π½ΠΎ Π²ΠΈΠ½Π°Π³ΠΈ ΠΈΠΌΠ° ΠΏΠΎΠ»Π΅Π·Π½ΠΈ Π½Π΅ΡΠ°, ΠΊΠΎΠΈΡΠΎ Π½Π΅ ΡΠ° ΡΡΠ½ΠΎ ΡΠΊΠ°Π·Π°Π½ΠΈ Π² ΡΡΠΊΠΎΠ²ΠΎΠ΄ΡΡΠ²Π°ΡΠ°. Π ΡΠ°Π·ΠΈ ΡΡΠ°ΡΠΈΡ ΡΠ΅ΡΠΈΡ Π΄Π° ΡΡΠ±Π΅ΡΠ° ΡΠ΅ΡΠΈΡ ΠΎΡ ΠΏΠΎΠ»Π΅Π·Π½ΠΈ ΠΈ Π½Π΅ΠΎΡΠ΅Π²ΠΈΠ΄Π½ΠΈ ΡΡΠ²Π΅ΡΠΈ (ΠΎΡΠ½ΠΎΠ²Π½ΠΈΡΡ ΡΠΈΠ½ΡΠ°ΠΊΡΠΈΡ Π½Π° TICKscipt Π΅ ΠΎΠΏΠΈΡΠ°Π½ ) ΠΈ Π΄Π° ΠΏΠΎΠΊΠ°ΠΆΠ° ΠΊΠ°ΠΊ ΠΌΠΎΠ³Π°Ρ Π΄Π° ΡΠ΅ ΠΏΡΠΈΠ»Π°Π³Π°Ρ, Π½Π° ΠΏΡΠΈΠΌΠ΅ΡΠ° Π½Π° ΡΠ΅ΡΠ°Π²Π°Π½Π΅ Π½Π° Π΅Π΄Π½Π° ΠΎΡ Π½Π°ΡΠΈΡΠ΅ Π·Π°Π΄Π°ΡΠΈ.
Π₯Π°ΠΉΠ΄Π΅ Π΄Π° Π·Π°ΠΏΠΎΡΠ²Π°ΠΌΠ΅!
float & int, Π³ΡΠ΅ΡΠΊΠΈ Π² ΠΈΠ·ΡΠΈΡΠ»Π΅Π½ΠΈΡΡΠ°
ΠΠ±ΡΠΎΠ»ΡΡΠ½ΠΎ ΡΡΠ°Π½Π΄Π°ΡΡΠ΅Π½ ΠΏΡΠΎΠ±Π»Π΅ΠΌ, ΡΠ΅ΡΠ°Π²Π° ΡΠ΅ ΡΡΠ΅Π· cast:
var alert_float = 5.0
var alert_int = 10
data|eval(lambda: float("value") > alert_float OR float("value") < float("alert_int"))
ΠΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ Π½Π° default()
ΠΠΊΠΎ ΡΠ°Π³/ΠΏΠΎΠ»Π΅ Π½Π΅ Π΅ ΠΏΠΎΠΏΡΠ»Π½Π΅Π½ΠΎ, ΡΠ΅ Π²ΡΠ·Π½ΠΈΠΊΠ½Π°Ρ Π³ΡΠ΅ΡΠΊΠΈ Π² ΠΈΠ·ΡΠΈΡΠ»Π΅Π½ΠΈΡΡΠ°:
|default()
.tag('status', 'empty')
.field('value', 0)
fill Π² join (inner vs outer)
ΠΠΎ ΠΏΠΎΠ΄ΡΠ°Π·Π±ΠΈΡΠ°Π½Π΅ join ΠΎΡΡ
Π²ΡΡΠ»Ρ ΡΠΎΡΠΊΠΈΡΠ΅, ΠΊΡΠ΄Π΅ΡΠΎ Π½ΡΠΌΠ° Π΄Π°Π½Π½ΠΈ (inner).
ΠΡΠΈ fill(βnullβ) ΡΠ΅ Π±ΡΠ΄Π΅ ΠΈΠ·ΠΏΡΠ»Π½Π΅Π½ outer join, ΡΠ»Π΅Π΄ ΠΊΠΎΠ΅ΡΠΎ Π΅ Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΎ Π΄Π° ΡΠ΅ Π½Π°ΠΏΡΠ°Π²ΠΈ default() ΠΈ Π΄Π° ΡΠ΅ Π·Π°ΠΏΡΠ»Π½ΡΡ ΠΏΡΠ°Π·Π½ΠΈΡΠ΅ ΡΡΠΎΠΉΠ½ΠΎΡΡΠΈ:
var data = res1
|join(res2)
.as('res1', 'res2)
.fill('null')
|default()
.field('res1.value', 0.0)
.field('res2.value', 100.0)
Π’ΡΠΊ Π²ΡΠ΅ ΠΏΠ°ΠΊ ΠΈΠΌΠ° Π½ΡΠ°Π½Ρ. ΠΠΊΠΎ Π² ΠΏΡΠΈΠΌΠ΅ΡΠ° ΠΏΠΎ-Π³ΠΎΡΠ΅ Π΅Π΄Π½Π° ΠΎΡ ΡΠ΅ΡΠΈΠΈΡΠ΅ (res1 ΠΈΠ»ΠΈ res2) Π΅ ΠΏΡΠ°Π·Π½Π°, ΠΊΡΠ°ΠΉΠ½Π°ΡΠ° ΡΠ΅ΡΠΈΡ (data) ΡΡΡΠΎ ΡΠ΅ Π±ΡΠ΄Π΅ ΠΏΡΠ°Π·Π½Π°. ΠΠΌΠ° Π½ΡΠΊΠΎΠ»ΠΊΠΎ ΡΠΈΠΊΠ°Π΅ΡΠ° Π½Π° GitHub ΠΏΠΎ ΡΠ°Π·ΠΈ ΡΠ΅ΠΌΠ° (, , ) β ΡΠ°ΠΊΠ°ΠΌΠ΅ ΠΏΠΎΠΏΡΠ°Π²ΠΊΠΈ ΠΈ ΠΌΠ°Π»ΠΊΠΎ ΡΡΡΠ°Π΄Π°ΠΌΠ΅.
ΠΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ Π½Π° ΡΡΠ»ΠΎΠ²ΠΈΡ Π² ΠΈΠ·ΡΠΈΡΠ»Π΅Π½ΠΈΡΡΠ° (if Π² lambda)
|eval(lambda: if("value" > 0, true, false)
ΠΠΎΡΠ»Π΅Π΄Π½ΠΈΡΠ΅ ΠΏΠ΅Ρ ΠΌΠΈΠ½ΡΡΠΈ ΠΎΡ ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½Π° Π·Π° ΠΏΠ΅ΡΠΈΠΎΠ΄
ΠΠ°ΠΏΡΠΈΠΌΠ΅Ρ, Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ Π΅ Π΄Π° ΡΡΠ°Π²Π½ΠΈΡΠ΅ ΡΡΠΎΠΉΠ½ΠΎΡΡΠΈΡΠ΅ Π½Π° ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΈΡΠ΅ ΠΏΠ΅Ρ ΠΌΠΈΠ½ΡΡΠΈ Ρ ΠΏΡΠ΅Π΄Ρ ΠΎΠ΄Π½Π°ΡΠ° ΡΠ΅Π΄ΠΌΠΈΡΠ°. ΠΠΎΠΆΠ΅ΡΠ΅ Π΄Π° Π²Π·Π΅ΠΌΠ΅ΡΠ΅ Π΄Π²Π΅ ΠΏΠ°ΡΡΠΈΠ΄ΠΈ Π΄Π°Π½Π½ΠΈ Π² Π΄Π²Π΅ ΠΎΡΠ΄Π΅Π»Π½ΠΈ ΠΏΠ°ΡΡΠΈΠ΄ΠΈ ΠΈΠ»ΠΈ Π΄Π° ΠΈΠ·Π²Π»Π΅ΡΠ΅ΡΠ΅ ΡΠ°ΡΡ ΠΎΡ Π΄Π°Π½Π½ΠΈΡΠ΅ ΠΎΡ ΠΏΠΎ-Π³ΠΎΠ»ΡΠΌ ΠΏΠ΅ΡΠΈΠΎΠ΄:
|where(lambda: duration((unixNano(now()) - unixNano("time"))/1000, 1u) < 5m)
ΠΠ»ΡΠ΅ΡΠ½Π°ΡΠΈΠ²Π° Π·Π° ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΈΡΠ΅ ΠΏΠ΅Ρ ΠΌΠΈΠ½ΡΡΠΈ ΠΌΠΎΠΆΠ΅ Π΄Π° Π±ΡΠ΄Π΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ΡΠΎ Π½Π° BarrierNode, ΠΊΠΎΠΉΡΠΎ ΠΎΡΡΡΠ·Π²Π° Π΄Π°Π½Π½ΠΈ ΠΏΠΎ-ΡΠ°Π½ΠΎ ΠΎΡ Π·Π°Π΄Π°Π΄Π΅Π½ΠΎΡΠΎ Π²ΡΠ΅ΠΌΠ΅:
|barrier()
.period(5m)
ΠΡΠΈΠΌΠ΅ΡΠΈ Π·Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ Π½Π° Go ΡΠ°Π±Π»ΠΎΠ½ΠΈ Π² ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΠ΅
Π¨Π°Π±Π»ΠΎΠ½ΠΈΡΠ΅ ΠΎΡΠ³ΠΎΠ²Π°ΡΡΡ Π½Π° ΡΠΎΡΠΌΠ°ΡΠ° ΠΎΡ ΠΏΠ°ΠΊΠ΅ΡΠ° , ΠΏΠΎ-Π΄ΠΎΠ»Ρ Π½ΡΠΊΠΎΠ»ΠΊΠΎ ΡΠ΅ΡΡΠΎ ΡΡΠ΅ΡΠ°Π½ΠΈ Π·Π°Π΄Π°ΡΠΈ.
if-else
Π‘Π»Π°Π³Π°ΠΌΠ΅ ΡΠ΅Π΄, Π±Π΅Π· Π΄Π° ΠΏΡΠ΅Π΄ΠΈΠ·Π²ΠΈΠΊΠ²Π°ΠΌΠ΅ Ρ ΠΎΡΠ°ΡΠ° Ρ Π½Π΅Π½ΡΠΆΠ΅Π½ ΡΠ΅ΠΊΡΡ:
|alert()
...
.message(
'{{ if eq .Level "OK" }}Π‘Π΅Π³Π° Π΅ ΠΎΠΊ{{ else }}Π¨Π΅ΡΠ΅, Π²ΡΠΈΡΠΊΠΎ Π΅ ΡΡΡΠΏΠ΅Π½ΠΎ{{end}}'
)
ΠΠ²Π΅ ΡΠΈΡΡΠΈ ΡΠ»Π΅Π΄ Π·Π°ΠΏΠ΅ΡΠ°ΡΡΠ° Π² ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ΡΠΎ
ΠΠΎΠ΄ΠΎΠ±ΡΡΠ²Π°ΠΌΠ΅ ΡΠ΅ΡΠΈΠ²Π½ΠΎΡΡΡΠ° Π½Π° ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ΡΠΎ:
|alert()
...
.message(
'ΡΠ΅Π³Π° ΡΡΠΎΠΉΠ½ΠΎΡΡΡΠ° Π΅ {{ index .Fields "value" | printf "%0.2f" }}'
)
Π Π°Π·Π³ΡΡΡΠ°Π½Π΅ Π½Π° ΠΏΡΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π² ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ΡΠΎ
ΠΠ·Π²Π΅ΠΆΠ΄Π°ΠΌΠ΅ ΠΏΠΎΠ²Π΅ΡΠ΅ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ Π² ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ΡΠΎ Π·Π° ΠΎΡΠ³ΠΎΠ²ΠΎΡΠ° Π½Π° Π²ΡΠΏΡΠΎΡΠ° "ΠΠ°ΡΠΎ Π²ΠΈΠΊΠ°?"
var warnAlert = 10
|alert()
...
.message(
'ΠΠ½Π΅ΡΠ½Π°ΡΠ° ΡΡΠΎΠΉΠ½ΠΎΡΡ Π΅ ΠΏΠΎ-ΠΌΠ°Π»ΠΊΠ° ΠΎΡ ' + string(warnAlert) + '%'
)
Π£Π½ΠΈΠΊΠ°Π»Π΅Π½ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡ Π½Π° Π°Π»Π΅ΡΡΠ°
ΠΠ΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ Π΅, ΠΊΠΎΠ³Π°ΡΠΎ Π² Π΄Π°Π½Π½ΠΈΡΠ΅ ΠΈΠΌΠ° ΠΏΠΎΠ²Π΅ΡΠ΅ ΠΎΡ Π΅Π΄Π½Π° Π³ΡΡΠΏΠ°, ΠΈΠ½Π°ΡΠ΅ ΡΠ΅ ΡΠ΅ Π³Π΅Π½Π΅ΡΠΈΡΠ° ΡΠ°ΠΌΠΎ Π΅Π΄ΠΈΠ½ Π°Π»Π΅ΡΡ:
|alert()
...
.id('{{ index .Tags "myname" }}\/{{ index .Tags "myfield" }}')
ΠΠ΅ΡΡΠΎΠ½Π°Π»ΠΈΠ·ΠΈΡΠ°Π½ΠΈ ΠΎΠ±ΡΠ°Π±ΠΎΡΡΠΈΡΠΈ
Π Π³ΠΎΠ»ΡΠΌ ΡΠΏΠΈΡΡΠΊ ΠΎΡ ΠΎΠ±ΡΠ°Π±ΠΎΡΡΠΈΡΠΈ ΠΈΠΌΠ° exec, ΠΊΠΎΠΉΡΠΎ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ²Π° ΠΈΠ·ΠΏΡΠ»Π½Π΅Π½ΠΈΠ΅ΡΠΎ Π½Π° ΡΠΎΠ±ΡΡΠ²Π΅Π½ ΡΠΊΡΠΈΠΏΡ Ρ ΠΏΡΠ΅Π΄Π°Π΄Π΅Π½ΠΈΡΠ΅ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΈ (stdin) β ΡΠ°ΠΌΠΎ ΡΠ²ΠΎΡΡΠ΅ΡΡΠ²ΠΎ!
ΠΠ΄ΠΈΠ½ ΠΎΡ Π½Π°ΡΠΈΡΠ΅ ΠΏΠ΅ΡΡΠΎΠ½Π°Π»ΠΈΠ·ΠΈΡΠ°Π½ΠΈ Π΅ ΠΌΠ°Π»ΡΠΊ python ΡΠΊΡΠΈΠΏΡ Π·Π° ΠΈΠ·ΠΏΡΠ°ΡΠ°Π½Π΅ Π½Π° ΠΈΠ·Π²Π΅ΡΡΠΈΡ Π² Slack.
ΠΡΡΠ²ΠΎΠ½Π°ΡΠ°Π»Π½ΠΎ ΠΈΡΠΊΠ°Ρ
ΠΌΠ΅ Π΄Π° ΠΈΠ·ΠΏΡΠ°ΡΠΈΠΌ Π² ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ΡΠΎ ΠΊΠ°ΡΡΠΈΠ½ΠΊΠ° ΠΎΡ Grafana Ρ Π°Π²ΡΠΎΡΠΈΠ·Π°ΡΠΈΡ. Π‘Π»Π΅Π΄ ΡΠΎΠ²Π° β Π΄Π° ΠΏΠΈΡΠ΅ΠΌ OK Π² ΡΡΠ΅Π΄Π° Π½Π° ΠΏΡΠ΅Π΄ΠΈΡΠ½ΠΈΡ Π°Π»Π΅ΡΡ ΠΎΡ ΡΡΡΠ°ΡΠ° Π³ΡΡΠΏΠ°, Π° Π½Π΅ ΠΊΠ°ΡΠΎ ΠΎΡΠ΄Π΅Π»Π½ΠΎ ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΠ΅. ΠΠ°Π»ΠΊΠΎ ΠΏΠΎ-ΠΊΡΡΠ½ΠΎ β Π΄Π° Π΄ΠΎΠ±Π°Π²ΡΠΌΠ΅ Π² ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ΡΠΎ Π½Π°ΠΉ-ΡΠ΅ΡΡΠ°ΡΠ° Π³ΡΠ΅ΡΠΊΠ° Π·Π° ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΈΡΠ΅ Π₯ ΠΌΠΈΠ½ΡΡΠΈ.
ΠΡΠ΄Π΅Π»Π½Π° ΡΠ΅ΠΌΠ° Π΅ ΡΠ²ΡΡΠ·Π°Π½ΠΎΡΡΡΠ° Ρ Π΄ΡΡΠ³ΠΈ ΡΡΠ»ΡΠ³ΠΈ ΠΈ ΠΊΠ°ΠΊΠ²ΠΈΡΠΎ ΠΈ Π΄Π° Π΅ Π΄Π΅ΠΉΡΡΠ²ΠΈΡ, ΠΈΠ½ΠΈΡΠΈΠΈΡΠ°Π½ΠΈ ΠΎΡ Π°Π»Π΅ΡΡΠ° (ΡΠ°ΠΌΠΎ Π°ΠΊΠΎ Π²Π°ΡΠΈΡΡ ΠΌΠΎΠ½ΠΈΡΠΎΡΠΈΠ½Π³ ΡΠ°Π±ΠΎΡΠΈ Π΄ΠΎΡΡΠ°ΡΡΡΠ½ΠΎ Π΄ΠΎΠ±ΡΠ΅).
ΠΡΠΈΠΌΠ΅Ρ Π·Π° ΠΎΠΏΠΈΡΠ°Π½ΠΈΠ΅ Π½Π° ΠΎΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊΠ°, ΠΊΡΠ΄Π΅ΡΠΎ slack_handler.py β Π½Π°ΡΠΈΡΡ ΡΠ°ΠΌΠΎΠΏΠΈΡΠ°Π½ ΡΠΊΡΠΈΠΏΡ:
topic: slack_graph
id: slack_graph.alert
match: level() != INFO AND changed() == TRUE
kind: exec
options:
prog: \/sbin\/slack_handler.py
args: ["-c", "CHANNELID", "--graph", "--search"]
ΠΠ°ΠΊ Π΄Π° Π΄Π΅Π±ΡΠ³Π²Π°ΠΌΠ΅?
ΠΠ°ΡΠΈΠ°Π½Ρ Ρ ΠΈΠ·Ρ ΠΎΠ΄ Π² Π»ΠΎΠ³
|log()
.level("error")
.prefix("Π½Π΅ΡΠΎ")
ΠΠ»Π΅Π΄Π°ΠΉΡΠ΅ (cli): kapacitor -url :9092 logs lvl=error
ΠΠ°ΡΠΈΠ°Π½Ρ Ρ httpOut
ΠΠΎΠΊΠ°Π·Π²Π° Π΄Π°Π½Π½ΠΈ Π² ΡΠ΅ΠΊΡΡΠΈΡ ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½:
|httpOut('Π½Π΅ΡΠΎ')
ΠΠ»Π΅Π΄Π°ΠΉΡΠ΅ (get): :9092\/kapacitor\/v1\/tasks\/task_name\/something
Π‘Ρ Π΅ΠΌΠ° Π½Π° ΠΈΠ·ΠΏΡΠ»Π½Π΅Π½ΠΈΠ΅
- ΠΡΡΠΊΠ° Π·Π°Π΄Π°ΡΠ° Π²ΡΡΡΠ° Π΄ΡΡΠ²ΠΎ Π½Π° ΠΈΠ·ΠΏΡΠ»Π½Π΅Π½ΠΈΠ΅ Ρ ΠΏΠΎΠ»Π΅Π·Π½ΠΈ ΡΠΈΡΡΠΈ Π²ΡΠ² ΡΠΎΡΠΌΠ°Ρ .
- ΠΠ·ΠΈΠΌΠ°ΠΌΠ΅ Π±Π»ΠΎΠΊΠ° .
- ΠΠΌΡΠΊΠ²Π°ΠΌΠ΅ Π² viewer, .
ΠΡΠ΄Π΅ ΠΎΡΠ΅ ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° ΠΏΠΎΠ»ΡΡΠΈΠΌ Π³ΡΠ°Π±Π»ΠΈ
timestamp Π² influxdb ΠΏΡΠΈ ΠΎΠ±ΡΠ°ΡΠ½ΠΎ Π·Π°ΠΏΠΈΡΠ²Π°Π½Π΅
ΠΠ°ΠΏΡΠΈΠΌΠ΅Ρ, Π½ΠΈΠ΅ Π½Π°ΡΡΡΠΎΠΉΠ²Π°ΠΌΠ΅ Π°Π»Π°ΡΠΌΠ° Π·Π° Π±ΡΠΎΡ Π½Π° Π·Π°ΡΠ²ΠΊΠΈΡΠ΅ Π½Π° ΡΠ°Ρ (groupBy(1h)) ΠΈ ΠΈΡΠΊΠ°ΠΌΠ΅ Π΄Π° Π·Π°ΠΏΠΈΡΠ΅ΠΌ Π½Π°ΡΡΡΠΏΠΈΠ»Π°ΡΠ° Π°Π»Π°ΡΠΌΠ° Π² influxdb (Π·Π° Π΄Π° ΠΏΠΎΠΊΠ°ΠΆΠ΅ΠΌ ΠΊΡΠ°ΡΠΈΠ²ΠΎ ΡΠ°ΠΊΡΠ° Π·Π° Π½Π°Π»ΠΈΡΠΈΠ΅ Π½Π° ΠΏΡΠΎΠ±Π»Π΅ΠΌ Π½Π° Π³ΡΠ°ΡΠΈΠΊΠ° Π² grafana).
influxDBOut() ΡΠ΅ Π·Π°ΠΏΠΈΡΠ΅ Π² timestamp ΡΡΠΎΠΉΠ½ΠΎΡΡΡΠ° time ΠΎΡ Π°Π»Π°ΡΠΌΠ°ΡΠ°, ΡΡΠΎΡΠ²Π΅ΡΠ½ΠΎ, ΡΠΎΡΠΊΠ°ΡΠ° Π½Π° Π³ΡΠ°ΡΠΈΠΊΠ° ΡΠ΅ Π±ΡΠ΄Π΅ Π·Π°ΠΏΠΈΡΠ°Π½Π° ΠΏΠΎ-ΡΠ°Π½ΠΎ/ΠΏΠΎ-ΠΊΡΡΠ½ΠΎ ΠΎΡ ΠΏΠΎΠ»ΡΡΠ΅Π½Π°ΡΠ° Π°Π»Π°ΡΠΌΠ°.
ΠΠΎΠ³Π°ΡΠΎ Π΅ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠ° ΠΏΡΠ΅ΡΠΈΠ·Π½ΠΎΡΡ: Π·Π°ΠΎΠ±ΠΈΠΊΠ°Π»ΡΠΌΠ΅ ΡΠΎΠ·ΠΈ ΠΏΡΠΎΠ±Π»Π΅ΠΌ ΡΡΠ΅Π· ΠΈΠ·Π²ΠΈΠΊΠ²Π°Π½Π΅ Π½Π° ΠΏΠ΅ΡΡΠΎΠ½Π°Π»ΠΈΠ·ΠΈΡΠ°Π½ handler, ΠΊΠΎΠΉΡΠΎ ΡΠ΅ Π·Π°ΠΏΠΈΡΠ΅ Π΄Π°Π½Π½ΠΈΡΠ΅ Π² influxdb Ρ ΡΠ΅ΠΊΡΡΠΈΡ timestamp.
docker, ΡΠ±ΠΎΡΠΊΠ° ΠΈ Π΄Π΅ΠΏΠ»ΠΎΠΉ
ΠΡΠΈ ΡΡΠ°ΡΡΠΈΡΠ°Π½Π΅ Π½Π° kapacitor, ΡΠΎΠΉ ΠΌΠΎΠΆΠ΅ Π΄Π° Π·Π°ΡΠ΅ΠΆΠ΄Π° Π·Π°Π΄Π°ΡΠΈ, ΡΠ°Π±Π»ΠΎΠ½ΠΈ ΠΈ Ρ Π΅Π½Π΄Π»Π΅ΡΠΈ ΠΎΡ Π΄ΠΈΡΠ΅ΠΊΡΠΎΡΠΈΡΡΠ°, Π·Π°Π΄Π°Π΄Π΅Π½Π° Π² ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡΡΠ°, Π² Π±Π»ΠΎΠΊΠ° [load].
ΠΠ° ΠΊΠΎΡΠ΅ΠΊΡΠ½ΠΎ ΡΡΠ·Π΄Π°Π²Π°Π½Π΅ Π½Π° Π·Π°Π΄Π°ΡΠ° ΡΠ° Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΈ ΡΠ»Π΅Π΄Π½ΠΈΡΠ΅ Π½Π΅ΡΠ°:
- ΠΠΌΠ΅ Π½Π° ΡΠ°ΠΉΠ»Π° β ΡΠ°Π·ΡΠΈΡΡΠ²Π° ΡΠ΅ Π² id/ΠΈΠΌΠ΅ Π½Π° ΡΠΊΡΠΈΠΏΡΠ°
- Π’ΠΈΠΏ β stream/batch
- dbrp β ΠΊΠ»ΡΡΠΎΠ²Π° Π΄ΡΠΌΠ° Π·Π° ΡΠΊΠ°Π·Π²Π°Π½Π΅ Π² ΠΊΠΎΡ Π±Π°Π·Π° + ΠΏΠΎΠ»ΠΈΡΠΈΠΊΠ° ΡΠ°Π±ΠΎΡΠΈ ΡΠΊΡΠΈΠΏΡΠ° (dbrp Β«supplierΒ».Β«autogenΒ»)
ΠΠΊΠΎ Π² Π½ΡΠΊΠ°ΠΊΠ²Π° batch-Π·Π°Π΄Π°ΡΠ° Π½ΡΠΌΠ° ΡΠ΅Π΄ Ρ dbrp, ΡΡΠ»Π°ΡΠ° ΡΡΠ»ΡΠ³Π° ΡΠ΅ ΠΎΡΠΊΠ°ΠΆΠ΅ Π΄Π° ΡΡΠ°ΡΡΠΈΡΠ° ΠΈ ΡΠ΅ΡΡΠ½ΠΎ ΡΠ΅ Π½Π°ΠΏΠΈΡΠ΅ Π·Π° ΡΠΎΠ²Π° Π² Π»ΠΎΠ³ΠΎΠ²Π΅ΡΠ΅.
Π chronograf ΠΎΠ±Π°ΡΠ΅, ΠΏΡΠΎΡΠΈΠ²Π½ΠΎ Π½Π° ΡΠΎΠ²Π°, ΡΠΎΠ·ΠΈ ΡΠ΅Π΄ Π½Π΅ ΡΡΡΠ±Π²Π° Π΄Π° ΠΏΡΠΈΡΡΡΡΠ²Π°, ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΡΡ Π½Π΅ Π³ΠΎ ΠΏΡΠΈΠ΅ΠΌΠ° ΠΈ ΠΈΠ·Π΄Π°Π²Π° Π³ΡΠ΅ΡΠΊΠ°.
Π₯Π°ΠΊ ΠΏΡΠΈ ΡΠ±ΠΎΡΠΊΠ° Π½Π° ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅ΡΠ°: Dockerfile ΠΈΠ·Π»ΠΈΠ·Π° Ρ -1, Π°ΠΊΠΎ ΠΈΠΌΠ° ΡΠ΅Π΄ΠΎΠ²Π΅ Ρ /.+dbrp, ΠΊΠΎΠ΅ΡΠΎ ΡΠ΅ ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈ Π²Π΅Π΄Π½Π°Π³Π° Π΄Π° ΡΠ΅ ΡΠ°Π·Π±Π΅ΡΠ΅ ΠΏΡΠΈΡΠΈΠ½Π°ΡΠ° Π·Π° Π½Π΅ΡΡΠΏΠ΅Ρ Π° ΠΏΡΠΈ ΡΠ±ΠΎΡΠΊΠ° Π½Π° Π±ΠΈΠ»Π΄Π°.
join Π΅Π΄ΠΈΠ½ ΠΊΡΠΌ ΠΌΠ½ΠΎΠ³ΠΎ
ΠΠ°Π΄Π°ΡΠ°-ΠΏΡΠΈΠΌΠ΅Ρ: ΡΡΡΠ±Π²Π° Π΄Π° Π²Π·Π΅ΠΌΠ΅ΠΌ 95-ΡΠΈ ΠΏΠ΅ΡΡΠ΅Π½ΡΠΈΠ» Π½Π° Π²ΡΠ΅ΠΌΠ΅ΡΠΎ Π·Π° ΡΠ°Π±ΠΎΡΠ° Π½Π° ΡΡΠ»ΡΠ³Π°ΡΠ° Π·Π° ΡΠ΅Π΄ΠΌΠΈΡΠ°, Π΄Π° ΡΡΠ°Π²Π½ΠΈΠΌ Π²ΡΡΠΊΠ° ΠΌΠΈΠ½ΡΡΠ° ΠΎΡ ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΈΡΠ΅ 10 Ρ ΡΠ°Π·ΠΈ ΡΡΠΎΠΉΠ½ΠΎΡΡ.
ΠΠ΅ ΠΌΠΎΠΆΠ΅ Π΄Π° ΡΠ΅ Π½Π°ΠΏΡΠ°Π²ΠΈ join Π΅Π΄ΠΈΠ½ ΠΊΡΠΌ ΠΌΠ½ΠΎΠ³ΠΎ, last/mean/median ΠΏΠΎ Π³ΡΡΠΏΠ° ΡΠΎΡΠΊΠΈ ΠΏΡΠ΅Π²ΡΡΡΠ°Ρ Π½ΠΎΠ΄Π° Π² stream, ΡΠ΅ ΡΠ΅ Π²ΡΡΠ½Π΅ Π³ΡΠ΅ΡΠΊΠ° Β«cannot add child mismatched edges: batch -> streamΒ».
Π Π΅Π·ΡΠ»ΡΠ°ΡΡΡ ΠΎΡ batch-Π°, ΠΊΠ°ΡΠΎ ΠΏΡΠΎΠΌΠ΅Π½Π»ΠΈΠ²Π° Π² lambda-ΠΈΠ·ΡΠ°Π·, ΡΡΡΠΎ Π½Π΅ ΡΠ΅ ΠΏΠΎΠ΄ΡΡΠ°Π²Ρ.
ΠΠΌΠ° Π²Π°ΡΠΈΠ°Π½Ρ Π΄Π° ΡΠ΅ ΡΡΡ ΡΠ°Π½ΡΡ Π½ΡΠΆΠ½ΠΈΡΠ΅ ΡΠΈΡΡΠΈ ΠΎΡ ΠΏΡΡΠ²ΠΈΡ batch Π² ΡΠ°ΠΉΠ» ΡΡΠ΅Π· udf ΠΈ Π΄Π° ΡΠ΅ Π·Π°ΡΠ΅Π΄ΠΈ ΡΠΎΠ·ΠΈ ΡΠ°ΠΉΠ» ΡΡΠ΅Π· sideload.
ΠΠ°ΠΊΠ²ΠΎ ΡΠ΅ΡΠ°Π²Π°Ρ ΠΌΠ΅ Ρ ΡΠΎΠ²Π°?
ΠΠΌΠ°ΠΌΠ΅ ΠΎΠΊΠΎΠ»ΠΎ 100 Π΄ΠΎΡΡΠ°Π²ΡΠΈΡΠΈ Π½Π° Ρ ΠΎΡΠ΅Π»ΠΈ, ΠΊΡΠΌ Π²ΡΠ΅ΠΊΠΈ ΠΎΡ ΡΡΡ ΠΌΠΎΠΆΠ΅ Π΄Π° ΠΈΠΌΠ° Π½ΡΠΊΠΎΠ»ΠΊΠΎ ΡΠ²ΡΡΠ·Π²Π°Π½ΠΈΡ, Π½Π°ΡΠ΅ΡΠ΅Π½ΠΈ ΠΊΠ°Π½Π°Π»ΠΈ. Π’Π΅Ρ Π½ΠΈΡΠ΅ ΠΊΠ°Π½Π°Π»ΠΈ ΡΠ° ΠΎΠΊΠΎΠ»ΠΎ 300, Π²ΡΠ΅ΠΊΠΈ ΠΎΡ ΠΊΠ°Π½Π°Π»ΠΈΡΠ΅ ΠΌΠΎΠΆΠ΅ Π΄Π° ΠΎΡΠΏΠ°Π΄Π½Π΅. ΠΡ Π²ΡΠΈΡΠΊΠΈ Π·Π°ΠΏΠΈΡΠ²Π°Π½ΠΈ ΠΌΠ΅ΡΡΠΈΠΊΠΈ ΡΠ΅ Π½Π°Π±Π»ΡΠ΄Π°Π²Π°ΠΌΠ΅ ΠΏΡΠΎΡΠ΅Π½ΡΠ° Π½Π° Π³ΡΠ΅ΡΠΊΠΈ (requests ΠΈ errors).
ΠΠ°ΡΠΎ Π½Π΅ Π³ΡΠ°ΡΠ°Π½Π°?
ΠΠ»Π°ΡΠΌΠΈΡΠ΅ Π·Π° Π³ΡΠ΅ΡΠΊΠΈ, Π½Π°ΡΡΡΠΎΠ΅Π½ΠΈ Π² Π³ΡΠ°ΡΠ°Π½Π°, ΠΈΠΌΠ°Ρ Π½ΡΠΊΠΎΠ»ΠΊΠΎ Π½Π΅Π΄ΠΎΡΡΠ°ΡΡΠΊΠ°. ΠΡΠΊΠΎΠΈ ΠΎΡ ΡΡΡ ΡΠ° ΠΊΡΠΈΡΠΈΡΠ½ΠΈ, Π½Π° Π½ΡΠΊΠΎΠΈ ΠΌΠΎΠΆΠ΅ Π΄Π° ΡΠ΅ Π·Π°ΡΠ²ΠΎΡΡΡ ΠΎΡΠΈ, Π² Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡ ΠΎΡ ΡΠΈΡΡΠ°ΡΠΈΡΡΠ°.
ΠΡΠ°ΡΠ°Π½Π° Π½Π΅ ΡΠΌΠ΅Π΅ Π΄Π° ΠΏΡΠ°Π²ΠΈ ΠΈΠ·ΡΠΈΡΠ»Π΅Π½ΠΈΡ ΠΌΠ΅ΠΆΠ΄Ρ ΠΈΠ·ΠΌΠ΅ΡΠ²Π°Π½ΠΈΡ + Π°Π»Π°ΡΠΌΠΈΡΠ°Π½Π΅, Π° Π½ΠΈΠ΅ ΡΠ΅ Π½ΡΠΆΠ΄Π°Π΅ΠΌ ΠΎΡ ΠΏΡΠΎΡΠ΅Π½ΡΠ° (requests-errors)/requests.
ΠΡΠ΅ΡΠΊΠΈΡΠ΅ ΠΈΠ·Π³Π»Π΅ΠΆΠ΄Π°Ρ Π·Π»ΠΎΠ±Π½ΠΎ:

Π ΠΏΠΎ-ΠΌΠ°Π»ΠΊΠΎ Π·Π»ΠΎΠ±Π½ΠΎ, Π°ΠΊΠΎ ΡΠ΅ Π³Π»Π΅Π΄Π° Ρ ΡΡΠΏΠ΅ΡΠ½ΠΈΡΠ΅ Π·Π°ΡΠ²ΠΊΠΈ:

ΠΠΎΠ±ΡΠ΅, ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΡΠ΅Π΄Π²Π°ΡΠΈΡΠ΅Π»Π½ΠΎ Π΄Π° ΠΈΠ·ΡΠΈΡΠ»ΠΈΠΌ ΡΠ΅ΠΉΡ Π² ΡΡΠ»ΡΠ³Π°ΡΠ° ΠΏΡΠ΅Π΄ΠΈ Π³ΡΠ°ΡΠ°Π½Π°ΡΠ°, ΠΈ Π² Π½ΡΠΊΠΎΠΈ ΡΠ»ΡΡΠ°ΠΈ ΡΠΎΠ²Π° Π±ΠΈ Π±ΠΈΠ»ΠΎ ΠΏΠΎΠ΄Ρ
ΠΎΠ΄ΡΡΠΎ. ΠΠΎ Π½Π΅ Π² Π½Π°ΡΠΈΡ ΡΠ»ΡΡΠ°ΠΉ, ΡΡΠΉ ΠΊΠ°ΡΠΎ Π·Π° Π²ΡΠ΅ΠΊΠΈ ΠΊΠ°Π½Π°Π» ΡΠ΅ ΠΈΠ·ΡΠΈΡΠ»ΡΠ²Π° βΠ½ΠΎΡΠΌΠ°Π»Π½ΠΎβ ΡΠΎΠΎΡΠ½ΠΎΡΠ΅Π½ΠΈΠ΅, Π° Π°Π»Π°ΡΠΌΠΈΡΠ΅ ΡΠ°Π±ΠΎΡΡΡ ΠΏΠΎ ΡΡΠ°ΡΠΈΡΠ½ΠΈ ΡΡΠΎΠΉΠ½ΠΎΡΡΠΈ (ΡΡΡΡΠΈΠΌ Π½Π° ΠΎΠΊΠΎ, ΠΏΡΠΎΠΌΠ΅Π½ΡΠΌΠ΅, Π°ΠΊΠΎ Π°Π»Π°ΡΠΌΠΈΡΠ° ΡΠ΅ΡΡΠΎ).
Π’ΠΎΠ²Π° ΡΠ° ΠΏΡΠΈΠΌΠ΅ΡΠΈ Π·Π° βΠ½ΠΎΡΠΌΠ°Π»Π½ΠΎβ Π·Π° ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ ΠΊΠ°Π½Π°Π»ΠΈ:


ΠΡΠ΅Π½Π΅Π±ΡΠ΅Π³Π²Π°ΠΌΠ΅ ΠΏΡΠ΅Π΄ΠΈΡΠ½Π°ΡΠ° ΡΠΎΡΠΊΠ° ΠΈ ΠΏΡΠΈΠ΅ΠΌΠ°ΠΌΠ΅, ΡΠ΅ ΠΏΡΠΈ Π²ΡΠΈΡΠΊΠΈ Π΄ΠΎΡΡΠ°Π²ΡΠΈΡΠΈ ΠΊΠ°ΡΡΠΈΠ½Π°ΡΠ° Π΅ βΠ½ΠΎΡΠΌΠ°Π»Π½Π°β. Π‘Π΅Π³Π° Π²ΡΠΈΡΠΊΠΎ Π΅ Π½Π°ΡΠ΅Π΄, ΠΈ ΠΌΠΎΠΆΠ΅ΠΌ Π»ΠΈ Π΄Π° ΡΠ΅ ΡΠΏΡΠ°Π²ΠΈΠΌ Ρ Π°Π»Π°ΡΠΌΠΈΡΠ΅ Π² Π³ΡΠ°ΡΠ°Π½Π°ΡΠ°?
ΠΠΎΠΆΠ΅ΠΌ, Π½ΠΎ Π½Π΅ ΠΌΠΈ ΡΠ΅ ΠΈΡΠΊΠ°, Π·Π°ΡΠΎΡΠΎ ΡΡΡΠ±Π²Π° Π΄Π° ΠΈΠ·Π±Π΅ΡΠ΅ΠΌ Π΅Π΄ΠΈΠ½ ΠΎΡ Π²Π°ΡΠΈΠ°Π½ΡΠΈΡΠ΅:
Π°) Π΄Π° Π½Π°ΠΏΡΠ°Π²ΠΈΠΌ ΠΌΠ½ΠΎΠΆΠ΅ΡΡΠ²ΠΎ Π³ΡΠ°ΡΠΈΠΊΠΈ Π·Π° Π²ΡΠ΅ΠΊΠΈ ΠΊΠ°Π½Π°Π» ΠΏΠΎΠΎΡΠ΄Π΅Π»Π½ΠΎ (ΠΈ ΠΌΡΡΠΈΡΠ΅Π»Π½ΠΎ Π΄Π° Π³ΠΈ ΠΏΠΎΠ΄Π΄ΡΡΠΆΠ°ΠΌΠ΅)
Π±) Π΄Π° ΠΎΡΡΠ°Π²ΠΈΠΌ Π΅Π΄Π½Π° Π³ΡΠ°ΡΠΈΠΊΠ° Ρ Π²ΡΠΈΡΠΊΠΈ ΠΊΠ°Π½Π°Π»ΠΈ (ΠΈ Π΄Π° ΡΠ΅ Π·Π°Π³ΡΠ±ΠΈΠΌ Π² ΡΠ²Π΅ΡΠ½ΠΈ Π»ΠΈΠ½ΠΈΠΈ ΠΈ Π½Π°ΡΡΡΠΎΠ΅Π½ΠΈ Π°Π»Π°ΡΠΌΠΈ)

ΠΠ°ΠΊΠ²ΠΎ Π½Π°ΠΏΡΠ°Π²ΠΈΡ ΠΌΠ΅?
ΠΡΠ½ΠΎΠ²ΠΎ, Π² Π΄ΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΡΡΠ° ΠΈΠΌΠ° Π΄ΠΎΠ±ΡΡ ΡΡΠ°ΡΡΠΎΠ² ΠΏΡΠΈΠΌΠ΅Ρ (), ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° Π½Π°Π΄Π½ΠΈΠΊΠ½Π΅ΠΌ ΠΈΠ»ΠΈ Π΄Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ Π·Π° ΠΎΡΠ½ΠΎΠ²Π° Π² Π°Π½Π°Π»ΠΎΠ³ΠΈΡΠ½ΠΈ Π·Π°Π΄Π°ΡΠΈ.
ΠΠ°ΠΊΠ²ΠΎ Π½Π°ΠΏΡΠ°Π²ΠΈΡ ΠΌΠ΅ Π² ΠΊΡΠ°ΠΉΠ½Π° ΡΠΌΠ΅ΡΠΊΠ°:
- ΠΎΠ±Π΅Π΄ΠΈΠ½Π΅Π½ΠΈΠ΅ Π½Π° Π΄Π²Π΅ ΡΠ΅ΡΠΈΠΈ Π·Π° Π½ΡΠΊΠΎΠ»ΠΊΠΎ ΡΠ°ΡΠ°, Π³ΡΡΠΏΠΈΡΠ°Π½Π΅ ΠΏΠΎ ΠΊΠ°Π½Π°Π»ΠΈ;
- ΠΏΠΎΠΏΡΠ»Π²Π°ΠΌΠ΅ ΡΠ΅ΡΠΈΠΈΡΠ΅ ΠΏΠΎ Π³ΡΡΠΏΠΈ, Π°ΠΊΠΎ Π½ΡΠΌΠ° Π΄Π°Π½Π½ΠΈ;
- ΡΡΠ°Π²Π½ΡΠ²Π°ΠΌΠ΅ ΠΌΠ΅Π΄ΠΈΠ°Π½Π°ΡΠ° Π½Π° ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΈΡΠ΅ 10 ΠΌΠΈΠ½ΡΡΠΈ Ρ ΠΏΡΠ΅Π΄ΠΈΡΠ½ΠΈΡΠ΅ Π΄Π°Π½Π½ΠΈ;
- Π²ΠΈΠΊΠΎΠ²Π΅, Π°ΠΊΠΎ ΠΎΡΠΊΡΠΈΠ΅ΠΌ Π½Π΅ΡΠΎ;
- ΠΏΠΈΡΠ΅ΠΌ ΠΈΠ·ΡΠΈΡΠ»Π΅Π½ΠΈΡΠ΅ ΡΠ΅ΠΉΡΠΎΠ²Π΅ ΠΈ ΡΠ»ΡΡΠΈΠ»ΠΈΡΠ΅ ΡΠ΅ Π°Π»Π°ΡΠΌΠΈ Π² influxdb;
- ΠΈΠ·ΠΏΡΠ°ΡΠ°ΠΌΠ΅ ΠΏΠΎΠ»Π΅Π·Π½ΠΎ ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ Π² slack.
ΠΠΎ ΠΌΠΎΠ΅ ΠΌΠ½Π΅Π½ΠΈΠ΅, ΡΡΠΏΡΡ ΠΌΠ΅ Π΄Π° ΠΏΠΎΡΡΠΈΠ³Π½Π΅ΠΌ ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»Π½ΠΎ ΠΏΡΠΈΡΡΠ½ΠΎ Π²ΡΠΈΡΠΊΠΎ, ΠΊΠΎΠ΅ΡΠΎ ΠΈΡΠΊΠ°Ρ ΠΌΠ΅ Π΄Π° ΠΏΠΎΠ»ΡΡΠΈΠΌ Π½Π° ΠΈΠ·Ρ ΠΎΠ΄Π° (ΠΈ Π΄ΠΎΡΠΈ ΠΌΠ°Π»ΠΊΠΎ ΠΏΠΎΠ²Π΅ΡΠ΅ Ρ ΠΏΠ΅ΡΡΠΎΠ½Π°Π»ΠΈΠ·ΠΈΡΠ°Π½ΠΈ Ρ Π΅Π½Π΄Π»Π΅ΡΠΈ).
ΠΠ° github.com ΠΌΠΎΠΆΠ΅ΡΠ΅ Π΄Π° Π²ΠΈΠ΄ΠΈΡΠ΅ ΠΈ Π½Π° ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΡ ΡΠΊΡΠΈΠΏΡ.
ΠΡΠΈΠΌΠ΅Ρ Π·Π° ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΡ ΠΊΠΎΠ΄:
dbrp "supplier"."autogen"
var name = 'requests.rate'
var grafana_dash = 'pczpmYZWU/mydashboard'
var grafana_panel = '26'
var period = 8h
var todayPeriod = 10m
var every = 1m
var warnAlert = 15
var warnReset = 5
var reqQuery = 'SELECT sum("count") AS value FROM "supplier"."autogen"."requests"'
var errQuery = 'SELECT sum("count") AS value FROM "supplier"."autogen"."errors"'
var prevErr = batch
|query(errQuery)
.period(period)
.every(every)
.groupBy(1m, 'channel', 'supplier')
var prevReq = batch
|query(reqQuery)
.period(period)
.every(every)
.groupBy(1m, 'channel', 'supplier')
var rates = prevReq
|join(prevErr)
.as('req', 'err')
.tolerance(1m)
.fill('null')
// Π·Π°ΠΏΠΎΠ»Π½ΡΠ΅ΠΌ Π·Π½Π°ΡΠ΅Π½ΠΈΡ Π½ΡΠ»ΡΠΌΠΈ, Π΅ΡΠ»ΠΈ ΠΈΡ
Π½Π΅ Π±ΡΠ»ΠΎ
|default()
.field('err.value', 0.0)
.field('req.value', 0.0)
// if Π² lambda: ΡΡΠΈΡΠ°Π΅ΠΌ ΡΠ΅ΠΉΡ, ΡΠΎΠ»ΡΠΊΠΎ Π΅ΡΠ»ΠΈ ΠΎΡΠΈΠ±ΠΊΠΈ Π±ΡΠ»ΠΈ
|eval(lambda: if("err.value" > 0, 100.0 * (float("req.value") - float("err.value")) / float("req.value"), 100.0))
.as('rate')
// Π·Π°ΠΏΠΈΡΡΠ²Π°Π΅ΠΌ ΠΏΠΎΡΡΠΈΡΠ°Π½Π½ΡΠ΅ Π·Π½Π°ΡΠ΅Π½ΠΈΡ Π² ΠΈΠ½ΡΠ»ΡΠΊΡ
rates
|influxDBOut()
.quiet()
.create()
.database('kapacitor')
.retentionPolicy('autogen')
.measurement('rates')
// Π²ΡΠ±ΠΈΡΠ°Π΅ΠΌ Π΄Π°Π½Π½ΡΠ΅ Π·Π° ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΈΠ΅ 10 ΠΌΠΈΠ½ΡΡ, ΡΡΠΈΡΠ°Π΅ΠΌ ΠΌΠ΅Π΄ΠΈΠ°Π½Ρ
var todayRate = rates
|where(lambda: duration((unixNano(now()) - unixNano("time")) / 1000, 1u) warnAlert)
.warnReset(lambda: ("prev.median" - "today.median") < warnReset)
.flapping(0.25, 0.5)
.stateChangesOnly()
// ΡΠΎΠ±ΠΈΡΠ°Π΅ΠΌ Π² message ΡΡΡΠ»ΠΊΡ Π½Π° Π³ΡΠ°ΡΠΈΠΊ Π΄Π°ΡΠ±ΠΎΡΠ΄Π° Π³ΡΠ°ΡΠ°Π½Ρ
.message(
'{{ .Level }}: {{ index .Tags "channel" }} err/req ratio ({{ index .Tags "supplier" }})
{{ if eq .Level "OK" }}It is ok now{{ else }}
'+string(todayPeriod)+' median is {{ index .Fields "today.median" | printf "%0.2f" }}%, by previous '+string(period)+' is {{ index .Fields "prev.median" | printf "%0.2f" }}%{{ end }}
http://grafana.ostrovok.in/d/'+string(grafana_dash)+'
?var-supplier={{ index .Tags "supplier" }}&var-channel={{ index .Tags "channel" }}&panelId='+string(grafana_panel)+'&fullscreen&tz=UTC0300'
)
.id('{{ index .Tags "name" }}\/{{ index .Tags "channel" }}')
.levelTag('level')
.messageField('message')
.durationField('duration')
.topic('slack_graph')
// "today.median" Π΄ΡΠ±Π»ΠΈΡΡΠ΅ΠΌ ΠΊΠ°ΠΊ "value", ΡΠ°ΠΊΠΆΠ΅ ΠΏΠΈΡΠ΅ΠΌ Π² ΠΈΠ½ΡΠ»ΡΠΊΡ ΠΎΡΡΠ°Π»ΡΠ½ΡΠ΅ ΡΠΈΠ»Π΄Ρ Π°Π»Π΅ΡΡΠ° (keep)
trigger
|eval(lambda: "today.median")
.as('value')
.keep()
|influxDBOut()
.quiet()
.create()
.database('kapacitor')
.retentionPolicy('autogen')
.measurement('alerts')
.tag('alertName', name)
ΠΠ°ΠΊΡΠ² ΡΠ΅ Π±ΡΠ΄Π΅ ΠΈΠ·Ρ ΠΎΠ΄ΡΡ?
Kapacitor ΠΏΡΠ΅ΠΊΡΠ°ΡΠ½ΠΎ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ²Π° ΠΌΠΎΠ½ΠΈΡΠΎΡΠΈΠ½Π³ ΠΈ Π°Π»Π΅ΡΡΠΈΡΠ°Π½Π΅ Ρ ΠΌΠ½ΠΎΠΆΠ΅ΡΡΠ²ΠΎ Π³ΡΡΠΏΠΈΡΠΎΠ²ΠΊΠΈ, ΠΈΠ·Π²ΡΡΡΠ²Π° Π΄ΠΎΠΏΡΠ»Π½ΠΈΡΠ΅Π»Π½ΠΈ ΠΈΠ·ΡΠΈΡΠ»Π΅Π½ΠΈΡ Π½Π° Π²Π΅ΡΠ΅ Π·Π°ΠΏΠΈΡΠ°Π½ΠΈ ΠΌΠ΅ΡΡΠΈΠΊΠΈ, ΠΏΡΠ΅Π΄Π»Π°Π³Π° ΠΏΠ΅ΡΡΠΎΠ½Π°Π»ΠΈΠ·ΠΈΡΠ°Π½ΠΈ Π΄Π΅ΠΉΡΡΠ²ΠΈΡ ΠΈ ΡΡΠ°ΡΡΠΈΡΠ° ΡΠΊΡΠΈΠΏΡΠΎΠ²Π΅ (udf).
ΠΡΠ°Π³ΡΡ Π·Π° Π²ΠΊΠ»ΡΡΠ²Π°Π½Π΅ Π½Π΅ Π΅ ΠΌΠ½ΠΎΠ³ΠΎ Π²ΠΈΡΠΎΠΊ β ΠΎΠΏΠΈΡΠ°ΠΉΡΠ΅ Π³ΠΎ, Π°ΠΊΠΎ Grafana ΠΈΠ»ΠΈ Π΄ΡΡΠ³ΠΈ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΈ Π½Π΅ ΡΠ΄ΠΎΠ²Π»Π΅ΡΠ²ΠΎΡΡΠ²Π°Ρ ΠΈΠ·ΡΡΠ»ΠΎ Π²Π°ΡΠΈΡΠ΅ ΠΈΠ·ΠΈΡΠΊΠ²Π°Π½ΠΈΡ.
ΠΠ·ΡΠΎΡΠ½ΠΈΠΊ: habr.com
