ααΆαα
αααΎαααααααΆαααααααααααΆαααααΆααααΆαααα½αααΆα ααα»α’αααΈααΆαααΆααΆα
αΆαααΆα
αααΎααααΈαααααΌααααααΆααααααΆααααα ααα αΆαα‘αΌααΈαααααααΆααααΊααααΌααααα
αααΆαααΆααααΏααααααΆααααααααααααααααΌαααΆα αααααΉαααΌαααααΉαα’αααΈαααααΆαααΆαα½ααα
αααα»ααα·αααααααα
αααα»ααααααΆααααααΆααααα½ααααααΆααα’ααα (αααα»ααα, Slack, Telegram)α αα
αααα»αααααΆααααααααααααΆααΆαααΆαα’ααΈαααΊαα·α
Kapacitor ααΊααΆααααααα½αααααα TICK αααα’αΆα
ααααΎαααΆαααααααααΈ InfluxDB α ααΆα’αΆα
ααααΆααααΆαααΆαααααααΆα
αααΎαααΆαα½αααααΆ (α
αΌααα½α) ααααΆα’αααΈαα½ααααααΆαααααααααααΈαα·αααααααααααα½αααΆα ααααααααααααααα‘αααα
InfluxDB ααααΎααΆαααΌαααααΉααα
Slack/Telegram/mailα
αααααΆααααΌαααΊαααααΆαααα·ααααα’α·α
float & int, ααα α»ααααα»αααΆαααααΆ
αααα αΆαααααααΆααα·αααααΆαα αααααααΆαααΆααααααα
var alert_float = 5.0
var alert_int = 10
data|eval(lambda: float("value") > alert_float OR float("value") < float("alert_int"))
ααααΎααααΆαααΎα()
ααααα·αααΎααααΆα/ααΆααα·αααααΌαααΆαααααα αααααα α»ααααα»αααΆαααααΆααΉαααΎαα‘αΎαα
|default()
.tag('status', 'empty')
.field('value', 0)
αααααααΆαα αΌααα½α (ααΆααααα»ααααααΉαααΆααααα )
ααΆαααααΆαααΎα ααΆαα
αΌααα½αααΉαααααααα
ααα»α
ααααα·αααΆααα·αααααα (ααΆααααα»α)α
ααΆαα½αααΉαααΆαααααα('null') ααΆαααααΆααααΆααααα
ααΉαααααΌαααΆαα’αα»αααα αααααΆααααΈαααα’αααααααΌαααααΎ default() α αΎααααααααααααααα
var data = res1
|join(res2)
.as('res1', 'res2)
.fill('null')
|default()
.field('res1.value', 0.0)
.field('res2.value', 100.0)
ααΆαα
ααααΆαααΆααα»ααααααααααΆαα
ααΈαααα αααα»αα§ααΆα αααααΆαααΎ ααααα·αααΎαααααΈααΆαα½α (res1 α¬ res2) ααα ααααααααΈαααααα (αα·αααααα) ααααΉαααααααα ααΆααααα»αααααΆα
αααΎαααΎαααααΆαααααααα
ααΎ Github (
ααΆαααααΎααααΆαααααααααααααα»αααΆαααααΆ (ααααα·αααΎαα αααα»α lambda)
|eval(lambda: if("value" > 0, true, false)
ααααΆαααΆααΈα α»ααααααααΈααααααααα αΌαααααααααααΆαααααααααααα
α§ααΆα ααα α’αααααααΌααααααααααααααααααααΆαααΆααΈα α»ααααααααΆαα½αααΉααααααΆα ααα»αα α’αααα’αΆα αααα·ααααααααΈαααΆααΆα αααΈαααΆα ααααα‘ααααΈααααΆ α¬ααΆαααααααααααα·ααααααααΈααααααααααΆααααα
|where(lambda: duration((unixNano(now()) - unixNano("time"))/1000, 1u) < 5m)
αααααΎααααααΆαα XNUMX ααΆααΈα α»ααααααααΊααααΌαααααΎ BarrierNode αααααΆααααααΆα ααα·αααααααα»ααααααααααΆααααααΆααα
|barrier()
.period(5m)
α§ααΆα αααααααΆαααααΎααααΆααααααΌ Go αα αααα»αααΆα
ααααΌααααΌαααααΆαα
ααΉαααααααααΈαααα
αα
ααααα·αβααΎβααΆαβαααααβααα
ααΎαβααΆααβα’αααΈαβααΆαβααααΆααβααααα α αΎαβαα·αβααααβα±ααβααα»αααβααΆαβα’αααααβααααβαααβααα
|alert()
...
.message(
'{{ if eq .Level "OK" }}It is ok now{{ else }}Chief, everything is broken{{end}}'
)
ααΈαααααααααααΆααααΈα ααα»α ααααΆααααα»αααΆα
ααΆααααααα’ααααααΆαα’αΆαααΆαα
|alert()
...
.message(
'now value is {{ index .Fields "value" | printf "%0.2f" }}'
)
ααΆααααααΈαα’ααααα αααα»αααΆα
ααΎααααα αΆαααααααΆααααααααα αααα»αααΆαααΎααααΈααααΎααααα½α "α ααα»α’αααΈααΆαααΆααΆααααα"?
var warnAlert = 10
|alert()
...
.message(
'Today value less then '+string(warnAlert)+'%'
)
ααααΏααααααΆααααΆαααΌαααααΉααα·ααα
αααααΆααΏαα αΆαααΆα ααα ααααααααΆααααα»αα αααΎαααΆααα½ααα αααα»ααα·αααααα ααΎαα·αααΌα ααααααααΆαααααΆαααΌαααααΉααα½αααα»αααααααΉαααααΌαααΆααααααΎαα
|alert()
...
.id('{{ index .Tags "myname" }}/{{ index .Tags "myfield" }}')
α’ααααααααααααααααΆαααααα½α
αααααΈααααααα’ααααααααααΆααα½αααΆα exec αααα’αα»ααααΆαα±ααα’αααααααα·ααααα·ααααααΈαααααα’αααααΆαα½αααΉααααΆαααΆαααααααααααΆαααααααΆαα (stdin) - ααΆαα αααααααα·ααα·αααααΆαα’αααΈααααα!
ααααααααααΆαααα½αααααααΎαααΊααααααΈα Python ααΌα
αα½ααααααΆααααααΎααΆαααΌαααααΉααα
slack α
ααααΌαβα‘αΎα ααΎαβα
ααβααααΎβααΌαααΆα Grafana αααβααΆαβααΆαβα’αα»ααααΆαβαααα»αβααΆαα αααααΆαααα ααααα ααααααα αα
αααα»ααααααααα‘αΆα αα
ααΆααααΆαααΌαααααΉαααΈαα»αααΈαααα»αααΌα
ααααΆ α αΎααα·ααααααΆααΆαααΆα
ααααα‘αααααααα ααααα·α
ααααααα - αααααααα
ααΆαααΌαααα α»αααΌαα
αααα»ααα
αααα»α X ααΆααΈα
α»ααααααα
αααααΆαααααΆα
ααααα‘αααα½αααΊααΆαααααΆαααααααΆααααααΆαα½αααααΆαααααααααααα αα·ααααααααΆαααΆαα½αααααααα½α
ααααΎααααααΆαααΌαααααΉα (αα»αααααΆααααΆααααα½ααα·αα·αααααααα’αααααααΎαααΆαααΆαααα’αααααααααΆαα)α
α§ααΆα αααααααΆααα·αααααΆα’αααΈα’ααααααααααΆα ααα 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("something")
ααΎα (cli): kapacitor -url
αααααΎαααΆαα½α httpOut
αααα αΆααα·αααααααα αααα»αααααααααα αΌααα αα α»ααααααα
|httpOut('something')
ααΎα (ααα½αααΆα):
αααααααΆαααααααα·ααααα·
- αα·α
αα
ααΆαααΈαα½αααααα‘αααααααΆαααααα·ααααα·αααααΆααααααΆααααααααααααα»ααααααα
ααααΆα ααα·α . - αααααα»ααα½αα
α ααα»α . - αα·αααααΆααααΆαα
αααα»ααααααα·ααΈααΎα
ααΈαααΆα .
ααΎα’αααα’αΆα ααα½αααΆααα»ααα½α αα α―ααΆ?
ααααΆαααααααΆαα αααα»α influxdb αα ααΎααΆααααααα‘αΎααα·α
α§ααΆα ααα ααΎααααα αααΆαααΌαααααΉααααααΆααααααΌαααααααΎαααα»ααα½ααααα (groupBy(1h)) α αΎαα αααααααααΆααΆαααΆααααΏααααααΆαααΎαα‘αΎααα αααα»α influxdb (ααΎααααΈαααα αΆααααΆαααα’αΆαααΌαααΆααα·ααααααα αΆαα ααΎααααΆα αααααα»α grafana)α
influxDBOut() ααΉαβαααααβαααααβαααααααΆβααΈβααΆαβααΌαβααααΉαβαα βααΆααβαααααααΆβ α’αΆαααααα ααα»ααα α ααα»α βαα ααΎβααααΌαααΆαβααΉαβααααΌαβααΆαβαααααβαα»α/αααααβααΆαβααΆαβααΌαβααααΉαβαααααα
αα ααααααααΆαααααΉαααααΌαααααΌαααΆαααΆαααΆαα ααΎααααααααΆααααα αΆααααααα α ααΌαααααααα α’ααααααααααΆαααααΆαααααα½α αααααΉαααααααα·αααααααα influxdb ααΆαα½αααΉαααααΆαααααααΆαα αα α»ααααααα
docker ααΆαααα αα·αααΆαααααααΆα
αα αααα αΆααααααΎα kapacitor α’αΆα αααα»αααΆααα·α αα ααααΌ αα·αα’ααααααααααΆαααΈαααααααΆααααααΆαααα αααα»αααΆαααααααα αααα»ααααα»α [αααα»α] α
ααΎααααΈβαααααΎαβαα·α αα ααΆαβααΆαβααααΉαααααΌα α’αααβααααΌαβααΆαβααααβααΌα βααΆαβαααααα
- αααααα―αααΆα - αααααΈααα ααΆααααααααΆααααααααΈα/ααααα
- αααααα - ααααααΈα / ααΆα α
- dbrp - ααΆααααααααΉαααΎααααΈαααα αΆαααΈααΌαααααΆααα·αααααα + αααααΆααααααααααααΈαααααΎαααΆα (dbrp "α’αααααααααααααα ""autogen")
ααααα·αααΎαα·α αα ααΆαααΆα ααα½αα ααα½ααα·αααΆααααααΆααααΆαα½α dbrp αααααααΆααααααΆααααΌαααΉαααα·ααααα·αα αΆααααααΎα α αΎαααΉααααααα’αααΈααΆααααααααααααααα αααα»ααααααα ααα»α
αα αααα»α chronograf αααα»ααα αα·α αααααΆααααααα·ααα½αααΆααα ααΆαα·αααααΌαααΆαααα½αααααΆααααα ααα»α αααααΆαα αα·ααααααΎαααα α»ααα½αα
Hack αα αααααΆαααααα»αααΊαααα Dockerfile α ααααΆαα½α -1 ααααα·αααΎααΆααααααΆααααΆαα½α //.+dbrp αααααΉαα’αα»ααααΆαα±ααα’ααααααααααΆααα’αααΈα ααα»αααααααΆααααΆααααΆααααα αααααα‘αΎαααΆαααααΆαααΆα
α αΌααα½αααΈαα½ααα α αααΎαα
α§ααΆα ααααα·α αα ααΆαα α’αααααααΌαααααΆαααααΈ 95 αααααααααΆααααα·ααααα·ααΆαααααααααΆαααααααααΆαααα½ααααααΆα α ααααααααααΆααααΆααΈαα 10 α α»ααααααααΆαα½αααΉαααααααααα
α’αααβαα·αβα’αΆα βααααΎβααΆαβα αΌαβαα½αβαα½αβαααβααΉαβα αααΎαβαα α α»αβααααα/ααααα/αααααβααΎβαααα»αβααβα ααα»α βααααβααααΆαβααααΆααβαα βααΆβααααααΈα ααα α»α "αα·αβα’αΆα βααααααβαααβαα·αβααααΌαβααααΆβααααβαα»ααΆαα ααΆα α -> ααααααΈα" ααΉαβααααΌαβααΆαβαααα‘ααβααβαα·αα
ααααααααααΆα ααα½α ααΆα’ααααα αααα»ααααααα lambda αααα·αααααΌαααΆααααα½ααααα
ααΆααααααΎααα½αααΎααααΈαααααΆαα»ααααα αΆαααΆα αααΈααΆα αααΈαα½ααα α―αααΆαααΆαααα udf α αΎααααα»αα―αααΆααααααΆαααα sideload α
ααΎααΎαααΆααααααααΆαα’αααΈααΆαα½αααΏαααα?
ααΎαβααΆαβα’αααβααααααααααβαααααΆααΆαβαααα αα 100 αααβαα½αααβααααΆαααβα’αΆα βααΆαβααΆαβαααααΆααβααααΆβααΆα αααΎαβαβ ααΌαβα α βααΆβααΆβααΆαααα ααΆααααααΆααααα αα 300 αααααααΆαααΆααααα ααΆαααααΈαα½ααα’αΆα ααααΆααα α»αα αααα»αα αααααααααΆαααααααΆααααααααΆααΆααα’αα ααΎαααΉααααα½ααα·αα·αααα’ααααΆααα α»α (ααααΎ αα·αααα α»α)α
α ααα»α’αααΈαα·α Grafana?
ααΆαααΌαααααΉαα’αααΈααα α»ααααααΆαααααααα ααΆαααααααααα αααα»α Grafana ααΆααα»ααα·ααααα·ααΆα αααΎαα αααααα·αααα αααααα·αααααααα α’αΆαααααααΎααααΆαααΆαα
Grafana αα·αααΉαααΈααααααααΆαααΆαααΆαααΆααααα + ααΆαααΌαααααΉααα ααα»ααααααΎαααααΌαααΆαα’ααααΆ (requests-errors)/requestsα
ααα α»αααΎααα α’αΆαααααα
αα·αβα’αΆαααααβαα·α
βαα
βαααβααΆαβααΎαβααΆβαα½αβααΉαβααααΎβαααβααα½αβααΆαβααααααβ:
αα·αα’αΈαα ααΎαα’αΆα
ααααΆα’ααααΆααΆαααααΆααααΆαα»ααα
αααα»αααααΆαααααα»α Grafana α αΎααααα»αααααΈααααααΆααΉαααααΎαααΆαα ααα»αααααα·αααααα
αααα»αααααααΎαααααααα ... αααααΆααααΆαααααΈαα½αα αααΆααΆαααααααΆαααααα½αααααααΆααααΌαααΆαα
αΆαααα»αααΆ "ααααααΆ" α αΎαααΆαααΌαααααΉαααααΎαααΆαααααααααΆαααααααα·αα·αααα (ααΎαααααΎααα½αααΆααααααααααααααΎα ααααΆααααααΌααα½αααΆααααα·αααΎααΆαααΆαααΌαααααΉαααΉαααΆαα)α
ααΆαααααααΊααΆα§ααΆα ααααα "ααααααΆ" αααααΆααααα»αααα·αααααααααααΆα
ααΎααα·αα’αΎααΎα
ααα»α
αα»α α αΎααααααααΆααΌαααΆα "ααααααΆ" ααΊααααααααααΆαααααΆααα’αααααααααααααααΆααα’ααα α₯α‘αΌααααα’αααΈααααααααΆαααΊααα’ α αΎαααΎαα’αΆα
ααα½αααΆααααααΆαααΆααααΏααα
αααα»α grafana?
ααΎαα’αΆα
ααααΎααΆα ααα»ααααααΎααα·αααΆαα·αα
αααα αααααααΎαααααΌαααααΎαααΎααααααΎααα½αα
α) αααααΎαααααΆα ααααΆα
αααΎααααααΆααααΆαααααΈαα½αααααα‘ααααΈααααΆ (α αΎαα’αααααΎααα½ααααααΆαααΊα
αΆαα)
α) αα»αααααΌαααΆααα½αααΆαα½ααααααΆαααΆααα’αα (αα·αααΆααααααα
αααα»ααααααΆααα
αααα»αααα αα·αααΆαααΌαααααΉαααΆααααα)
ααΎα’αααααααΎααΆαααααααααΆ?
ααΆβααααΈβααααβααα ααΆαβα§ααΆα αααβα
αΆααβααααΎαβααβααα’βαα½αβαα
βαααα»αβα―αααΆα (
α’αααΈαααααΎαααΆαααααΎαα ααΈαααα ααα
- α αΌααα½ααααααΈααΈααααα»αααααααααΈαααΈαααα αααααΆααααΆαααα»αααΆααααααΆαα
- ααααααααααΈααΆααααα»α ααααα·αααΎαα·αααΆααα·ααααααα
- αααααααααααααααΆααα 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) < todayPeriod)
|median('rate')
.as('median')
var prevRate = rates
|median('rate')
.as('median')
var joined = todayRate
|join(prevRate)
.as('today', 'prev')
|httpOut('join')
var trigger = joined
|alert()
.warn(lambda: ("prev.median" - "today.median") > 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=UTC%2B03%3A00'
)
.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 α¬α§ααααααααααααααα·ααααααααααααααΆααααΆααααα’αααααΆαααααα»αα
ααααα: www.habr.com