αž›αŸ’αž”αž·αž…αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž˜αŸ‰αŸ‚αžαŸ’αžšαž“αŸ…αž€αŸ’αž“αž»αž„ Kapacitor

αž—αžΆαž‚αž…αŸ’αžšαžΎαž“αž‘αŸ†αž“αž„αž‡αžΆαžαŸ’αž„αŸƒαž“αŸαŸ‡αž‚αŸ’αž˜αžΆαž“αž“αžšαžŽαžΆαž˜αŸ’αž“αžΆαž€αŸ‹αžŸαž½αžšαžαžΆαž αŸαžαž»αž’αŸ’αžœαžΈαž”αžΆαž“αž‡αžΆαžœαžΆαž…αžΆαŸ†αž”αžΆαž…αŸ‹αžŠαžΎαž˜αŸ’αž”αžΈαž”αŸ’αžšαž˜αžΌαž›αžšαž„αŸ’αžœαžΆαžŸαŸ‹αžŸαŸαžœαžΆαž€αž˜αŸ’αž˜αŸ” αž‡αŸ†αž αžΆαž“αž‘αžΌαž‡αžΈαžαž›αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž‚αžΊαžαŸ’αžšαžΌαžœαžšαŸ€αž”αž…αŸ†αž€αžΆαžšαžŠαžΆαžŸαŸ‹αžαžΏαž“αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž˜αŸ‰αŸ‚αžαŸ’αžšαžŠαŸ‚αž›αž”αŸ’αžšαž˜αžΌαž›αž”αžΆαž“ αžŠαŸ‚αž›αž“αžΉαž„αž‡αžΌαž“αžŠαŸ†αžŽαžΉαž„αž’αŸ†αž–αžΈαž‚αž˜αŸ’αž›αžΆαžαžŽαžΆαž˜αž½αž™αž“αŸ…αž€αŸ’αž“αž»αž„αž‘αž·αž“αŸ’αž“αž“αŸαž™αž“αŸ…αž€αŸ’αž“αž»αž„αž”αžŽαŸ’αžαžΆαž‰αžŠαŸ‚αž›αž„αžΆαž™αžŸαŸ’αžšαž½αž›αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž’αŸ’αž“αž€ (αžŸαŸ†αž”αž»αžαŸ’αžš, Slack, Telegram)αŸ” αž“αŸ…αž€αŸ’αž“αž»αž„αžŸαŸαžœαžΆαž€αž˜αŸ’αž˜αž€αž€αŸ‹αžŸαžŽαŸ’αž‹αžΆαž‚αžΆαžšαžαžΆαž˜αž’αŸŠαžΈαž“αž’αžΊαžŽαž·αž Ostrovok.ru αž˜αŸ‰αŸ‚αžαŸ’αžšαž‘αžΆαŸ†αž„αž’αžŸαŸ‹αž“αŸƒαžŸαŸαžœαžΆαž€αž˜αŸ’αž˜αžšαž”αžŸαŸ‹αž™αžΎαž„αžαŸ’αžšαžΌαžœαž”αžΆαž“αž…αžΆαž€αŸ‹αž…αžΌαž›αž‘αŸ…αž€αŸ’αž“αž»αž„ InfluxDB αž αžΎαž™αž”αž„αŸ’αž αžΆαž‰αž“αŸ…αž€αŸ’αž“αž»αž„ Grafana αž αžΎαž™αž€αžΆαžšαž‡αžΌαž“αžŠαŸ†αžŽαžΉαž„αž‡αžΆαž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž€αŸαžαŸ’αžšαžΌαžœαž”αžΆαž“αž€αŸ†αžŽαžαŸ‹αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αž“αŸ…αž‘αžΈαž“αŸ„αŸ‡αž•αž„αžŠαŸ‚αžšαŸ” αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αž·αž…αŸ’αž…αž€αžΆαžšαžŠαžΌαž…αž‡αžΆ "αž’αŸ’αž“αž€αžαŸ’αžšαžΌαžœαž‚αžŽαž“αžΆαž’αŸ’αžœαžΈαž˜αž½αž™ αž αžΎαž™αž”αŸ’αžšαŸ€αž”αž’αŸ€αž”αž‡αžΆαž˜αž½αž™αžœαžΆ" αž™αžΎαž„αž”αŸ’αžšαžΎ Kapacitor αŸ”

αž›αŸ’αž”αž·αž…αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž˜αŸ‰αŸ‚αžαŸ’αžšαž“αŸ…αž€αŸ’αž“αž»αž„ Kapacitor
Kapacitor αž‚αžΊαž‡αžΆαž•αŸ’αž“αŸ‚αž€αž˜αž½αž™αž“αŸƒαž‡αž„αŸ‹ TICK αžŠαŸ‚αž›αž’αžΆαž…αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž˜αŸ‰αŸ‚αžαŸ’αžšαž–αžΈ InfluxDB αŸ” αžœαžΆαž’αžΆαž…αž—αŸ’αž‡αžΆαž”αŸ‹αž€αžΆαžšαžœαžΆαžŸαŸ‹αžœαŸ‚αž„αž‡αžΆαž…αŸ’αžšαžΎαž“αž‡αžΆαž˜αž½αž™αž‚αŸ’αž“αžΆ (αž…αžΌαž›αžšαž½αž˜) αž‚αžŽαž“αžΆαž’αŸ’αžœαžΈαž˜αž½αž™αžŠαŸ‚αž›αž˜αžΆαž“αž”αŸ’αžšαž™αŸ„αž‡αž“αŸαž–αžΈαž‘αž·αž“αŸ’αž“αž“αŸαž™αžŠαŸ‚αž›αž‘αž‘αž½αž›αž”αžΆαž“ αžŸαžšαžŸαŸαžšαž›αž‘αŸ’αž’αž•αž›αžαŸ’αžšαž‘αž”αŸ‹αž‘αŸ… InfluxDB αž•αŸ’αž‰αžΎαž€αžΆαžšαž‡αžΌαž“αžŠαŸ†αžŽαžΉαž„αž‘αŸ… Slack/Telegram/mailαŸ”

αž‡αž„αŸ‹αž‘αžΆαŸ†αž„αž˜αžΌαž›αž‚αžΊαžαŸ’αžšαž‡αžΆαž€αŸ‹αž“αž·αž„αž›αž˜αŸ’αž’αž·αž αž―αž€αžŸαžΆαžšαž”αŸ‰αž»αž“αŸ’αžαŸ‚αžœαžΆαžαŸ‚αž„αžαŸ‚αž˜αžΆαž“αžšαž”αžŸαŸ‹αžŠαŸ‚αž›αž˜αžΆαž“αž”αŸ’αžšαž™αŸ„αž‡αž“αŸαžŠαŸ‚αž›αž˜αž·αž“αžαŸ’αžšαžΌαžœαž”αžΆαž“αž…αž„αŸ’αž’αž»αž›αž”αž„αŸ’αž αžΆαž‰αž™αŸ‰αžΆαž„αž…αŸ’αž”αžΆαžŸαŸ‹αž“αŸ…αž€αŸ’αž“αž»αž„αžŸαŸ€αžœαž—αŸ…αžŽαŸ‚αž“αžΆαŸ†αŸ” αž“αŸ…αž€αŸ’αž“αž»αž„αž’αžαŸ’αžαž”αž‘αž“αŸαŸ‡ αžαŸ’αž‰αž»αŸ†αž”αžΆαž“αžŸαž˜αŸ’αžšαŸαž…αž…αž·αžαŸ’αžαž”αŸ’αžšαž˜αžΌαž›αž“αžΌαžœαž‚αž“αŸ’αž›αžΉαŸ‡αžŠαŸαž˜αžΆαž“αž”αŸ’αžšαž™αŸ„αž‡αž“αŸ αž“αž·αž„αžŠαŸ‚αž›αž˜αž·αž“αž…αŸ’αž”αžΆαžŸαŸ‹αž›αžΆαžŸαŸ‹αž˜αž½αž™αž…αŸ†αž“αž½αž“ (αžœαžΆαž€αŸ’αž™αžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž“αŸƒ TICKscipt αžαŸ’αžšαžΌαžœαž”αžΆαž“αž–αž·αž–αžŽαŸŒαž“αžΆαŸ” αž“αŸ…αž‘αžΈαž“αŸαŸ‡) αž αžΎαž™αž”αž„αŸ’αž αžΆαž‰αž–αžΈαžšαž”αŸ€αž”αžŠαŸ‚αž›αž–αž½αž€αž‚αŸαž’αžΆαž…αžαŸ’αžšαžΌαžœαž”αžΆαž“αž’αž“αž»αžœαžαŸ’αžαžŠαŸ„αž™αž”αŸ’αžšαžΎαž§αž‘αžΆαž αžšαžŽαŸαž“αŸƒαž€αžΆαžšαžŠαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αž”αž‰αŸ’αž αžΆαž˜αž½αž™αžšαž”αžŸαŸ‹αž™αžΎαž„αŸ”

αžαŸ„αŸ‡αž‘αŸ…!

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 (1633, 1871, 6967) - αž™αžΎαž„αž€αŸ†αž–αž»αž„αžšαž„αŸ‹αž…αžΆαŸ†αž€αžΆαžšαž‡αž½αžŸαž‡αž»αž› αž“αž·αž„αžšαž„αž‘αž»αž€αŸ’αžαž”αž“αŸ’αžαž·αž…αž”αž“αŸ’αžαž½αž…αŸ”

αž€αžΆαžšαž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹αž›αž€αŸ’αžαžαžŽαŸ’αžŒαž€αŸ’αž“αž»αž„αž€αžΆαžšαž‚αžŽαž“αžΆ (αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž“αŸ…αž€αŸ’αž“αž»αž„ 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 host-or-ip: 9092 αž€αŸ†αžŽαžαŸ‹αž αŸαžαž» lvl=error

αž‡αž˜αŸ’αžšαžΎαžŸαž‡αžΆαž˜αž½αž™ httpOut

αž”αž„αŸ’αž αžΆαž‰αž‘αž·αž“αŸ’αž“αž“αŸαž™αž“αŸ…αž€αŸ’αž“αž»αž„αž”αŸ†αž–αž„αŸ‹αž”αž„αŸ’αž αžΌαžšαž”αž…αŸ’αž…αž»αž”αŸ’αž”αž“αŸ’αž“αŸ–

|httpOut('something')

αž˜αžΎαž› (αž‘αž‘αž½αž›αž”αžΆαž“): host-or-ipαŸ–9092/kapacitor/v1/tasks/task_name/αž’αŸ’αžœαžΈαž˜αž½αž™

αž‚αŸ’αžšαŸ„αž„αž€αžΆαžšαžŽαŸαž”αŸ’αžšαžαž·αž”αžαŸ’αžαž·

  • αž€αž·αž…αŸ’αž…αž€αžΆαžšαž“αžΈαž˜αž½αž™αŸ—αžαŸ’αžšαž‘αž”αŸ‹αž˜αŸ‚αž€αž’αžΆαž„αž”αŸ’αžšαžαž·αž”αžαŸ’αžαž·αžŠαŸ‚αž›αž˜αžΆαž“αž›αŸαžαž˜αžΆαž“αž”αŸ’αžšαž™αŸ„αž‡αž“αŸαž€αŸ’αž“αž»αž„αž‘αž˜αŸ’αžšαž„αŸ‹ αž€αŸ’αžšαžΆαž αŸ’αžœαž·αž….
  • αž™αž€αž”αŸ’αž›αž»αž€αž˜αž½αž™αŸ” αž…αŸ†αžŽαž»αž….
  • αž”αž·αž‘αž—αŸ’αž‡αžΆαž”αŸ‹αžœαžΆαž‘αŸ…αž€αŸ’αž“αž»αž„αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž˜αžΎαž› αžšαžΈαž€αžšαžΆαž™.

αžαžΎαž’αŸ’αž“αž€αž’αžΆαž…αž‘αž‘αž½αž›αž”αžΆαž“αžαž»αž„αžšαž½αž…αž“αŸ…αž―αžŽαžΆ?

αžαŸ’αžšαžΆαž–αŸαž›αžœαŸαž›αžΆαž“αŸ…αž€αŸ’αž“αž»αž„ influxdb αž“αŸ…αž›αžΎαž€αžΆαžšαžŸαžšαžŸαŸαžšαž‘αžΎαž„αžœαž·αž‰

αž§αž‘αžΆαž αžšαžŽαŸ αž™αžΎαž„αžšαŸ€αž”αž…αŸ†αž€αžΆαžšαž‡αžΌαž“αžŠαŸ†αžŽαžΉαž„αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž•αž›αž”αžΌαž€αž“αŸƒαžŸαŸ†αžŽαžΎαž€αŸ’αž“αž»αž„αž˜αž½αž™αž˜αŸ‰αŸ„αž„ (groupBy(1h)) αž αžΎαž™αž…αž„αŸ‹αž€αžαŸ‹αžαŸ’αžšαžΆαž€αžΆαžšαžŠαžΆαžŸαŸ‹αžαžΏαž“αžŠαŸ‚αž›αž”αžΆαž“αž€αžΎαžαž‘αžΎαž„αž“αŸ…αž€αŸ’αž“αž»αž„ influxdb (αžŠαžΎαž˜αŸ’αž”αžΈαž”αž„αŸ’αž αžΆαž‰αž™αŸ‰αžΆαž„αžŸαŸ’αž’αžΆαžαž“αžΌαžœαž€αžΆαžšαž–αž·αžαž“αŸƒαž”αž‰αŸ’αž αžΆαž“αŸ…αž›αžΎαž€αŸ’αžšαžΆαž αŸ’αžœαž€αŸ’αž“αž»αž„ grafana)αŸ”

influxDBOut() αž“αžΉαž„β€‹αžŸαžšαžŸαŸαžšβ€‹αžαž˜αŸ’αž›αŸƒβ€‹αž–αŸαž›αžœαŸαž›αžΆβ€‹αž–αžΈβ€‹αž€αžΆαžšβ€‹αž‡αžΌαž“β€‹αžŠαŸ†αžŽαžΉαž„β€‹αž‘αŸ…β€‹αž€αžΆαž“αŸ‹β€‹αž–αŸαž›αžœαŸαž›αžΆβ€‹ αž’αžΆαžŸαŸ’αžšαŸαž™αž αŸαžαž»αž“αŸαŸ‡ αž…αŸ†αžŽαž»αž…β€‹αž“αŸ…αž›αžΎβ€‹αž‚αŸ†αž“αžΌαžŸαžαžΆαž„β€‹αž“αžΉαž„β€‹αžαŸ’αžšαžΌαžœβ€‹αž”αžΆαž“β€‹αžŸαžšαžŸαŸαžšβ€‹αž˜αž»αž“/αž€αŸ’αžšαŸ„αž™β€‹αž‡αžΆαž„β€‹αž€αžΆαžšβ€‹αž‡αžΌαž“β€‹αžŠαŸ†αžŽαžΉαž„β€‹αž˜αž€αžŠαž›αŸ‹αŸ”

αž“αŸ…αž–αŸαž›αžŠαŸ‚αž›αž—αžΆαž–αžαŸ’αžšαžΉαž˜αžαŸ’αžšαžΌαžœαžαŸ’αžšαžΌαžœαž”αžΆαž“αž‘αžΆαž˜αž‘αžΆαžšαŸ– αž™αžΎαž„αžŠαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αž”αž‰αŸ’αž αžΆαž“αŸαŸ‡αžŠαŸ„αž™αž αŸ…αž‘αžΌαžšαžŸαŸαž–αŸ’αž‘αž‘αŸ…αž’αŸ’αž“αž€αžŠαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αž•αŸ’αž‘αžΆαž›αŸ‹αžαŸ’αž›αž½αž“ αžŠαŸ‚αž›αž“αžΉαž„αžŸαžšαžŸαŸαžšαž‘αž·αž“αŸ’αž“αž“αŸαž™αž‘αŸ… influxdb αž‡αžΆαž˜αž½αž™αž“αžΉαž„αžαŸ’αžšαžΆαž–αŸαž›αžœαŸαž›αžΆαž”αž…αŸ’αž…αž»αž”αŸ’αž”αž“αŸ’αž“αŸ”

docker αžŸαžΆαž„αžŸαž„αŸ‹ αž“αž·αž„αžŠαžΆαž€αŸ‹αž–αž„αŸ’αžšαžΆαž™

αž“αŸ…αž–αŸαž›αž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜ kapacitor αž’αžΆαž…αž•αŸ’αž‘αž»αž€αž—αžΆαžšαž€αž·αž…αŸ’αž… αž‚αŸ†αžšαžΌ αž“αž·αž„αž’αŸ’αž“αž€αžŠαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αž–αžΈαžαžαžŠαŸ‚αž›αž”αžΆαž“αž”αž‰αŸ’αž‡αžΆαž€αŸ‹αž“αŸ…αž€αŸ’αž“αž»αž„αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹αž“αŸ…αž€αŸ’αž“αž»αž„αž”αŸ’αž›αž»αž€ [αž•αŸ’αž‘αž»αž€] αŸ”

αžŠαžΎαž˜αŸ’αž”αžΈβ€‹αž”αž„αŸ’αž€αžΎαžβ€‹αž€αž·αž…αŸ’αž…αž€αžΆαžšβ€‹αž”αžΆαž“β€‹αžαŸ’αžšαžΉαž˜αžαŸ’αžšαžΌαžœ αž’αŸ’αž“αž€β€‹αžαŸ’αžšαžΌαžœβ€‹αž€αžΆαžšβ€‹αžšαž”αžŸαŸ‹β€‹αžŠαžΌαž…β€‹αžαžΆαž„β€‹αž€αŸ’αžšαŸ„αž˜αŸ–

  1. αžˆαŸ’αž˜αŸ„αŸ‡αž―αž€αžŸαžΆαžš - αž–αž„αŸ’αžšαžΈαž€αž‘αŸ…αž‡αžΆαž›αŸαžαžŸαž˜αŸ’αž‚αžΆαž›αŸ‹αžŸαŸ’αž‚αŸ’αžšαžΈαž”/αžˆαŸ’αž˜αŸ„αŸ‡
  2. αž”αŸ’αžšαž—αŸαž‘ - αžŸαŸ’αž‘αŸ’αžšαžΈαž˜ / αž”αžΆαž…αŸ‹
  3. dbrp - αž–αžΆαž€αŸ’αž™αž‚αž“αŸ’αž›αžΉαŸ‡αžŠαžΎαž˜αŸ’αž”αžΈαž”αž„αŸ’αž αžΆαž‰αž–αžΈαž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™ + αž‚αŸ„αž›αž€αžΆαžšαžŽαŸαžŠαŸ‚αž›αžŸαŸ’αž‚αŸ’αžšαžΈαž”αžŠαŸ†αžŽαžΎαžšαž€αžΆαžš (dbrp "αž’αŸ’αž“αž€αž•αŸ’αž‚αžαŸ‹αž•αŸ’αž‚αž„αŸ‹αŸ” ""autogen")

αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž€αž·αž…αŸ’αž…αž€αžΆαžšαž”αžΆαž…αŸ‹αž˜αž½αž™αž…αŸ†αž“αž½αž“αž˜αž·αž“αž˜αžΆαž“αž”αž“αŸ’αž‘αžΆαžαŸ‹αž‡αžΆαž˜αž½αž™ dbrp αž“αŸ„αŸ‡αžŸαŸαžœαžΆαž€αž˜αŸ’αž˜αž‘αžΆαŸ†αž„αž˜αžΌαž›αž“αžΉαž„αž”αžŠαž·αžŸαŸαž’αž˜αž·αž“αž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜ αž αžΎαž™αž“αžΉαž„αžŸαžšαžŸαŸαžšαž’αŸ†αž–αžΈαžœαžΆαžŠαŸ„αž™αžŸαŸ’αž˜αŸ„αŸ‡αžαŸ’αžšαž„αŸ‹αž“αŸ…αž€αŸ’αž“αž»αž„αž€αŸ†αžŽαžαŸ‹αž αŸαžαž»αŸ”

αž“αŸ…αž€αŸ’αž“αž»αž„ chronograf αž•αŸ’αž‘αž»αž™αž‘αŸ…αžœαž·αž‰ αž”αž“αŸ’αž‘αžΆαžαŸ‹αž“αŸαŸ‡αž˜αž·αž“αž‚αž½αžšαž˜αžΆαž“αž‘αŸ αžœαžΆαž˜αž·αž“αžαŸ’αžšαžΌαžœαž”αžΆαž“αž‘αž‘αž½αž›αž™αž€αžαžΆαž˜αžšαž™αŸˆαž…αŸ†αžŽαž»αž…αž”αŸ’αžšαž‘αžΆαž€αŸ‹ αž“αž·αž„αž”αž„αŸ’αž€αžΎαžαž€αŸ†αž αž»αžŸαž˜αž½αž™αŸ”

Hack αž“αŸ…αž–αŸαž›αžŸαžΆαž„αžŸαž„αŸ‹αž€αž»αž„αžαžΊαž“αŸαžšαŸ– Dockerfile αž…αŸαž‰αž‡αžΆαž˜αž½αž™ -1 αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž˜αžΆαž“αž”αž“αŸ’αž‘αžΆαžαŸ‹αž‡αžΆαž˜αž½αž™ //.+dbrp αžŠαŸ‚αž›αž“αžΉαž„αž’αž“αž»αž‰αŸ’αž‰αžΆαžαž±αŸ’αž™αž’αŸ’αž“αž€αž™αž›αŸ‹αž—αŸ’αž›αžΆαž˜αŸ—αž’αŸ†αž–αžΈαž αŸαžαž»αž•αž›αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž”αžšαžΆαž‡αŸαž™αž“αŸ…αž–αŸαž›αžŠαŸ†αž‘αžΎαž„αž€αžΆαžšαžŸαŸ’αžαžΆαž”αž“αžΆαŸ”

αž…αžΌαž›αžšαž½αž˜αž–αžΈαž˜αž½αž™αž‘αŸ…αž…αŸ’αžšαžΎαž“αŸ”

αž§αž‘αžΆαž αžšαžŽαŸαž€αž·αž…αŸ’αž…αž€αžΆαžšαŸ– αž’αŸ’αž“αž€αžαŸ’αžšαžΌαžœαž™αž€αž—αžΆαž‚αžšαž™αž‘αžΈ 95 αž“αŸƒαž–αŸαž›αžœαŸαž›αžΆαž”αŸ’αžšαžαž·αž”αžαŸ’αžαž·αž€αžΆαžšαžšαž”αžŸαŸ‹αžŸαŸαžœαžΆαž€αž˜αŸ’αž˜αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž˜αž½αž™αžŸαž”αŸ’αžαžΆαž αŸ αž”αŸ’αžšαŸ€αž”αž’αŸ€αž”αžšαžΆαž›αŸ‹αž“αžΆαž‘αžΈαž“αŸƒ 10 αž…αž»αž„αž€αŸ’αžšαŸ„αž™αž‡αžΆαž˜αž½αž™αž“αžΉαž„αžαž˜αŸ’αž›αŸƒαž“αŸαŸ‡αŸ”

αž’αŸ’αž“αž€β€‹αž˜αž·αž“β€‹αž’αžΆαž…β€‹αž’αŸ’αžœαžΎβ€‹αž€αžΆαžšβ€‹αž…αžΌαž›β€‹αžšαž½αž˜β€‹αž˜αž½αž™β€‹αž‘αž›αŸ‹β€‹αž“αžΉαž„β€‹αž…αŸ’αžšαžΎαž“β€‹αž‘αŸ αž…αž»αž„β€‹αž€αŸ’αžšαŸ„αž™/αž˜αž’αŸ’αž™αž˜/αž˜αž’αŸ’αž™αž˜β€‹αž›αžΎβ€‹αž€αŸ’αžšαž»αž˜β€‹αž“αŸƒβ€‹αž…αŸ†αžŽαž»αž…β€‹αž”αŸ’αžšαŸ‚β€‹αž€αŸ’αž›αžΆαž™β€‹αžαŸ’αž“αžΆαŸ†αž„β€‹αž‘αŸ…β€‹αž‡αžΆβ€‹αžŸαŸ’αž‘αŸ’αžšαžΈαž˜ αž€αŸ†αž αž»αžŸ "αž˜αž·αž“β€‹αž’αžΆαž…β€‹αž”αž“αŸ’αžαŸ‚αž˜β€‹αž‚αŸ‚αž˜β€‹αž˜αž·αž“β€‹αžαŸ’αžšαžΌαžœβ€‹αž‚αŸ’αž“αžΆβ€‹αžšαž”αžŸαŸ‹β€‹αž€αž»αž˜αžΆαžšαŸ– αž”αžΆαž…αŸ‹ -> αžŸαŸ’αž‘αŸ’αžšαžΈαž˜" αž“αžΉαž„β€‹αžαŸ’αžšαžΌαžœβ€‹αž”αžΆαž“β€‹αžαŸ’αžšαž‘αž”αŸ‹β€‹αž˜αž€β€‹αžœαž·αž‰αŸ”

αž›αž‘αŸ’αž’αž•αž›αž“αŸƒαž”αžΆαž…αŸ‹αž˜αž½αž™ αž‡αžΆαž’αžαŸαžšαž“αŸ…αž€αŸ’αž“αž»αž„αž€αž“αŸ’αžŸαŸ„αž˜ lambda αž€αŸαž˜αž·αž“αžαŸ’αžšαžΌαžœαž”αžΆαž“αž‡αŸ†αž“αž½αžŸαžŠαŸ‚αžšαŸ”

αž˜αžΆαž“αž‡αž˜αŸ’αžšαžΎαžŸαž˜αž½αž™αžŠαžΎαž˜αŸ’αž”αžΈαžšαž€αŸ’αžŸαžΆαž‘αž»αž€αž›αŸαžαž…αžΆαŸ†αž”αžΆαž…αŸ‹αž–αžΈαž”αžΆαž…αŸ‹αž‘αžΈαž˜αž½αž™αž‘αŸ…αž―αž€αžŸαžΆαžšαžαžΆαž˜αžšαž™αŸˆ udf αž αžΎαž™αž•αŸ’αž‘αž»αž€αž―αž€αžŸαžΆαžšαž“αŸαŸ‡αžαžΆαž˜αžšαž™αŸˆ sideload αŸ”

αžαžΎαž™αžΎαž„αž”αžΆαž“αžŠαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αž’αŸ’αžœαžΈαž‡αžΆαž˜αž½αž™αžšαžΏαž„αž“αŸαŸ‡?

αž™αžΎαž„β€‹αž˜αžΆαž“β€‹αž’αŸ’αž“αž€β€‹αž•αŸ’αž‚αžαŸ‹αž•αŸ’αž‚αž„αŸ‹β€‹αžŸαžŽαŸ’αž‹αžΆαž‚αžΆαžšβ€‹αž”αŸ’αžšαž αŸ‚αž› 100 αžŠαŸ‚αž›β€‹αž–αž½αž€αž‚αŸβ€‹αž˜αŸ’αž“αžΆαž€αŸ‹αŸ—β€‹αž’αžΆαž…β€‹αž˜αžΆαž“β€‹αž€αžΆαžšβ€‹αžαž—αŸ’αž‡αžΆαž”αŸ‹β€‹αž‚αŸ’αž“αžΆβ€‹αž‡αžΆαž…αŸ’αžšαžΎαž“β€‹αŸ”β€‹ αžŸαžΌαž˜β€‹αž αŸ…β€‹αžœαžΆβ€‹αžαžΆβ€‹αž†αžΆαž“αŸ‚αž›αŸ” αž˜αžΆαž“αž”αžŽαŸ’αžαžΆαž‰αž”αŸ’αžšαž αŸ‚αž› 300 αž“αŸƒαž”αžŽαŸ’αžαžΆαž‰αž‘αžΆαŸ†αž„αž“αŸαŸ‡ αž†αžΆαž“αŸ‚αž›αž“αžΈαž˜αž½αž™αŸ—αž’αžΆαž…αž’αŸ’αž›αžΆαž€αŸ‹αž…αž»αŸ‡αŸ” αž€αŸ’αž“αž»αž„αž…αŸ†αžŽαŸ„αž˜αžšαž„αŸ’αžœαžΆαžŸαŸ‹αžŠαŸ‚αž›αž”αžΆαž“αž€αžαŸ‹αžαŸ’αžšαžΆαž‘αžΆαŸ†αž„αž’αžŸαŸ‹ αž™αžΎαž„αž“αžΉαž„αžαŸ’αžšαž½αžαž–αž·αž“αž·αžαŸ’αž™αž’αžαŸ’αžšαžΆαž€αŸ†αž αž»αžŸ (αžŸαŸ†αžŽαžΎ αž“αž·αž„αž€αŸ†αž αž»αžŸ)αŸ”

αž αŸαžαž»αž’αŸ’αžœαžΈαž˜αž·αž“ Grafana?

αž€αžΆαžšαž‡αžΌαž“αžŠαŸ†αžŽαžΉαž„αž’αŸ†αž–αžΈαž€αŸ†αž αž»αžŸαžŠαŸ‚αž›αž”αžΆαž“αž€αŸ†αžŽαžαŸ‹αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αž“αŸ…αž€αŸ’αž“αž»αž„ Grafana αž˜αžΆαž“αž‚αž»αžŽαžœαž·αž”αžαŸ’αžαž·αž‡αžΆαž…αŸ’αžšαžΎαž“αŸ” αžαŸ’αž›αŸ‡αžšαž·αŸ‡αž‚αž“αŸ‹ αžαŸ’αž›αŸ‡αž”αž·αž‘αž—αŸ’αž“αŸ‚αž€αž‘αŸ… αž’αžΆαžŸαŸ’αžšαŸαž™αž›αžΎαžŸαŸ’αžαžΆαž“αž—αžΆαž–αŸ”

Grafana αž˜αž·αž“αžŠαžΉαž„αž–αžΈαžšαž”αŸ€αž”αž‚αžŽαž“αžΆαžšαžœαžΆαž„αž€αžΆαžšαžœαžΆαžŸαŸ‹αžœαŸ‚αž„ + αž€αžΆαžšαž‡αžΌαž“αžŠαŸ†αžŽαžΉαž„αž‘αŸ αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž™αžΎαž„αžαŸ’αžšαžΌαžœαž€αžΆαžšαž’αžαŸ’αžšαžΆ (requests-errors)/requestsαŸ”

αž€αŸ†αž αž»αžŸαž˜αžΎαž›αž‘αŸ…αž’αžΆαž€αŸ’αžšαž€αŸ‹αŸ–

αž›αŸ’αž”αž·αž…αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž˜αŸ‰αŸ‚αžαŸ’αžšαž“αŸ…αž€αŸ’αž“αž»αž„ Kapacitor

αž“αž·αž„β€‹αž’αžΆαž€αŸ’αžšαž€αŸ‹β€‹αžαž·αž…β€‹αž“αŸ…β€‹αž–αŸαž›β€‹αž”αžΆαž“β€‹αž˜αžΎαž›β€‹αž‡αžΆβ€‹αž˜αž½αž™β€‹αž“αžΉαž„β€‹αžŸαŸ†αžŽαžΎβ€‹αžŠαŸ‚αž›β€‹αž‘αž‘αž½αž›β€‹αž”αžΆαž“β€‹αž‡αŸ„αž‚αž‡αŸαž™β€‹:

αž›αŸ’αž”αž·αž…αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž˜αŸ‰αŸ‚αžαŸ’αžšαž“αŸ…αž€αŸ’αž“αž»αž„ Kapacitor

αž˜αž·αž“αž’αžΈαž‘αŸ αž™αžΎαž„αž’αžΆαž…αž‚αžŽαž“αžΆαž’αžαŸ’αžšαžΆαž€αžΆαžšαž”αŸ’αžšαžΆαž€αŸ‹αž‡αžΆαž˜αž»αž“αž“αŸ…αž€αŸ’αž“αž»αž„αžŸαŸαžœαžΆαž€αž˜αŸ’αž˜αž˜αž»αž“ Grafana αž αžΎαž™αž€αŸ’αž“αž»αž„αž€αžšαžŽαžΈαžαŸ’αž›αŸ‡αžœαžΆαž“αžΉαž„αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαŸ” αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž˜αž·αž“αž˜αŸ‚αž“αž“αŸ…αž€αŸ’αž“αž»αž„αžšαž”αžŸαŸ‹αž™αžΎαž„αž‘αŸαž–αŸ’αžšαŸ„αŸ‡ ... αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž†αžΆαž“αŸ‚αž›αž“αžΈαž˜αž½αž™αŸ— αžŸαž˜αžΆαž˜αžΆαžαŸ’αžšαž•αŸ’αž‘αžΆαž›αŸ‹αžαŸ’αž›αž½αž“αžšαž”αžŸαŸ‹αžœαžΆαžαŸ’αžšαžΌαžœαž”αžΆαž“αž…αžΆαžαŸ‹αž‘αž»αž€αžαžΆ "αž’αž˜αŸ’αž˜αžαžΆ" αž αžΎαž™αž€αžΆαžšαž‡αžΌαž“αžŠαŸ†αžŽαžΉαž„αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαžŠαŸ„αž™αž™αŸ„αž„αžαžΆαž˜αžαž˜αŸ’αž›αŸƒαž‹αž·αžαž·αžœαž“αŸ’αž (αž™αžΎαž„αžšαž€αž˜αžΎαž›αž–αž½αž€αžœαžΆαžŠαŸ„αž™αž—αŸ’αž“αŸ‚αž€αžšαž”αžŸαŸ‹αž™αžΎαž„ αž•αŸ’αž›αžΆαžŸαŸ‹αž”αŸ’αžαžΌαžšαž–αž½αž€αžœαžΆαž”αŸ’αžšαžŸαž·αž“αž”αžΎαž˜αžΆαž“αž€αžΆαžšαž‡αžΌαž“αžŠαŸ†αžŽαžΉαž„αž‰αžΉαž€αž‰αžΆαž”αŸ‹)αŸ”

αž‘αžΆαŸ†αž„αž“αŸαŸ‡αž‚αžΊαž‡αžΆαž§αž‘αžΆαž αžšαžŽαŸαž“αŸƒ "αž’αž˜αŸ’αž˜αžαžΆ" αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž”αŸ‰αž»αžŸαŸ’αžαž·αŸαž•αŸ’αžŸαŸαž„αŸ—αž‚αŸ’αž“αžΆαŸ–

αž›αŸ’αž”αž·αž…αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž˜αŸ‰αŸ‚αžαŸ’αžšαž“αŸ…αž€αŸ’αž“αž»αž„ Kapacitor

αž›αŸ’αž”αž·αž…αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž˜αŸ‰αŸ‚αžαŸ’αžšαž“αŸ…αž€αŸ’αž“αž»αž„ Kapacitor

αž™αžΎαž„αž˜αž·αž“αž’αžΎαž–αžΎαž…αŸ†αžŽαž»αž…αž˜αž»αž“ αž αžΎαž™αžŸαž“αŸ’αž˜αžαžαžΆαžšαžΌαž”αž—αžΆαž– "αž’αž˜αŸ’αž˜αžαžΆ" αž‚αžΊαžŸαŸ’αžšαžŠαŸ€αž„αž‚αŸ’αž“αžΆαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž’αŸ’αž“αž€αž•αŸ’αž‚αžαŸ‹αž•αŸ’αž‚αž„αŸ‹αž‘αžΆαŸ†αž„αž’αžŸαŸ‹αŸ” αž₯αž‘αžΌαžœαž“αŸαŸ‡αž’αŸ’αžœαžΈαž‚αŸ’αžšαž”αŸ‹αž™αŸ‰αžΆαž„αž‚αžΊαž›αŸ’αž’ αž αžΎαž™αž™αžΎαž„αž’αžΆαž…αž‘αž‘αž½αž›αž”αžΆαž“αžŠαŸ„αž™αž€αžΆαžšαžŠαžΆαžŸαŸ‹αžαžΏαž“αž“αŸ…αž€αŸ’αž“αž»αž„ grafana?
αž™αžΎαž„αž’αžΆαž…αž’αŸ’αžœαžΎαž”αžΆαž“ αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž™αžΎαž„αž–αž·αžαž‡αžΆαž˜αž·αž“αž…αž„αŸ‹αž‘αŸ αž–αŸ’αžšαŸ„αŸ‡αž™αžΎαž„αžαŸ’αžšαžΌαžœαž‡αŸ’αžšαžΎαžŸαžšαžΎαžŸαž‡αž˜αŸ’αžšαžΎαžŸαž˜αž½αž™αŸ–
αž€) αž”αž„αŸ’αž€αžΎαžαž€αŸ’αžšαžΆαž αŸ’αžœαž‡αžΆαž…αŸ’αžšαžΎαž“αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž†αžΆαž“αŸ‚αž›αž“αžΈαž˜αž½αž™αŸ—αžŠαŸ„αž™αž‘αŸ‚αž€αž–αžΈαž‚αŸ’αž“αžΆ (αž αžΎαž™αž’αž˜αžŠαŸ†αžŽαžΎαžšαž–αž½αž€αž‚αŸαž™αŸ‰αžΆαž„αžˆαžΊαž…αžΆαž”αŸ‹)
ខ) αž‘αž»αž€αž‚αŸ†αž“αžΌαžŸαžαžΆαž„αž˜αž½αž™αž‡αžΆαž˜αž½αž™αž”αžŽαŸ’αžαžΆαž‰αž‘αžΆαŸ†αž„αž’αžŸαŸ‹ (αž“αž·αž„αž”αžΆαžαŸ‹αž”αž„αŸ‹αž“αŸ…αž€αŸ’αž“αž»αž„αž”αž“αŸ’αž‘αžΆαžαŸ‹αž…αž˜αŸ’αžšαž»αŸ‡αž–αžŽαŸŒ αž“αž·αž„αž€αžΆαžšαž‡αžΌαž“αžŠαŸ†αžŽαžΉαž„αžαžΆαž˜αž”αŸ†αžŽαž„)

αž›αŸ’αž”αž·αž…αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž˜αŸ‰αŸ‚αžαŸ’αžšαž“αŸ…αž€αŸ’αž“αž»αž„ Kapacitor

αžαžΎαž’αŸ’αž“αž€αž’αŸ’αžœαžΎαžœαžΆαžŠαŸ„αž™αžšαž”αŸ€αž”αžŽαžΆ?

αž‡αžΆβ€‹αžαŸ’αž˜αžΈβ€‹αž˜αŸ’αžαž„β€‹αž‘αŸ€αž αž˜αžΆαž“β€‹αž§αž‘αžΆαž αžšαžŽαŸβ€‹αž…αžΆαž”αŸ‹β€‹αž•αŸ’αžαžΎαž˜β€‹αžŠαŸβ€‹αž›αŸ’αž’β€‹αž˜αž½αž™β€‹αž“αŸ…β€‹αž€αŸ’αž“αž»αž„β€‹αž―αž€αžŸαžΆαžš (αž€αžΆαžšαž‚αžŽαž“αžΆαž’αžαŸ’αžšαžΆαž“αŸ…αž‘αžΌαž‘αžΆαŸ†αž„αžŸαŸŠαŸαžšαžΈαžŠαŸ‚αž›αž”αžΆαž“αž…αžΌαž›αžšαž½αž˜) αž’αžΆαž…αžαŸ’αžšαžΌαžœαž”αžΆαž“αž˜αžΎαž› αž¬αž™αž€αž‡αžΆαž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž€αŸ’αž“αž»αž„αž”αž‰αŸ’αž αžΆαžŸαŸ’αžšαžŠαŸ€αž„αž‚αŸ’αž“αžΆαŸ”

αž’αŸ’αžœαžΈαžŠαŸ‚αž›αž™αžΎαž„αž”αžΆαž“αž’αŸ’αžœαžΎαž“αŸ…αž‘αžΈαž”αž‰αŸ’αž…αž”αŸ‹αŸ–

  • αž…αžΌαž›αžšαž½αž˜αžŸαŸŠαŸαžšαžΈαž–αžΈαžšαž€αŸ’αž“αž»αž„αžšαž™αŸˆαž–αŸαž›αž–αžΈαžšαž”αžΈαž˜αŸ‰αŸ„αž„ αžŠαŸ„αž™αžŠαžΆαž€αŸ‹αž‡αžΆαž€αŸ’αžšαž»αž˜αžαžΆαž˜αž”αžŽαŸ’αžαžΆαž‰αŸ”
  • αž”αŸ†αž–αŸαž‰αžŸαŸŠαŸαžšαžΈαžαžΆαž˜αž€αŸ’αžšαž»αž˜ αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž˜αž·αž“αž˜αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™αŸ”
  • αž”αŸ’αžšαŸ€αž”αž’αŸ€αž”αž˜αž’αŸ’αž™αž˜αž—αžΆαž‚αž“αŸƒ 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

αž”αž“αŸ’αžαŸ‚αž˜αž˜αžαž·αž™αŸ„αž”αž›αŸ‹