Π’Ρ€ΡŽΠΊΠΈ для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΌΠ΅Ρ‚Ρ€ΠΈΠΊ Π² Kapacitor

Π‘ΠΊΠΎΡ€Π΅Π΅ всСго, сСгодня ΡƒΠΆΠ΅ Π½ΠΈ Ρƒ ΠΊΠΎΠ³ΠΎ Π½Π΅ Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ‚ вопрос, Π·Π°Ρ‡Π΅ΠΌ Π½ΡƒΠΆΠ½ΠΎ ΡΠΎΠ±ΠΈΡ€Π°Ρ‚ΡŒ ΠΌΠ΅Ρ‚Ρ€ΠΈΠΊΠΈ сСрвисов. Π‘Π»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ Π»ΠΎΠ³ΠΈΡ‡Π½Ρ‹ΠΉ шаг – Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ Π°Π»Π΅Ρ€Ρ‚ΠΈΠ½Π³ Π½Π° собираСмыС ΠΌΠ΅Ρ‚Ρ€ΠΈΠΊΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΠΏΠΎΠ²Π΅Ρ‰Π°Ρ‚ΡŒ ΠΎ Π»ΡŽΠ±Ρ‹Ρ… отклонСниях Π² Π΄Π°Π½Π½Ρ‹Ρ… Π² ΡƒΠ΄ΠΎΠ±Π½Ρ‹Π΅ Π²Π°ΠΌ ΠΊΠ°Π½Π°Π»Ρ‹ (ΠΏΠΎΡ‡Ρ‚Ρƒ, Slack, Telegram). Π’ сСрвисС ΠΎΠ½Π»Π°ΠΉΠ½-бронирования ΠΎΡ‚Π΅Π»Π΅ΠΉ Ostrovok.ru всС ΠΌΠ΅Ρ‚Ρ€ΠΈΠΊΠΈ Π½Π°ΡˆΠΈΡ… сСрвисов Π»ΡŒΡŽΡ‚ΡΡ Π² InfluxDB ΠΈ ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°ΡŽΡ‚ΡΡ Π² Grafana, Ρ‚Π°ΠΌ ΠΆΠ΅ настроСн Π±Π°Π·ΠΎΠ²Ρ‹ΠΉ Π°Π»Π΅Ρ€Ρ‚ΠΈΠ½Π³. Для Π·Π°Π΄Π°Ρ‡ Ρ‚ΠΈΠΏΠ° Β«Π½ΡƒΠΆΠ½ΠΎ ΠΏΠΎΡΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ ΠΈ ΡΡ€Π°Π²Π½ΠΈΡ‚ΡŒ с этим» ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Kapacitor.

Π’Ρ€ΡŽΠΊΠΈ для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΌΠ΅Ρ‚Ρ€ΠΈΠΊ Π² Kapacitor
Kapacitor – Ρ‡Π°ΡΡ‚ΡŒ TICK-стСка, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΡƒΠΌΠ΅Π΅Ρ‚ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ ΠΌΠ΅Ρ‚Ρ€ΠΈΠΊΠΈ ΠΈΠ· InfluxDB. Он ΠΌΠΎΠΆΠ΅Ρ‚ ΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒ нСсколько ΠΈΠ·ΠΌΠ΅Ρ€Π΅Π½ΠΈΠΉ ΠΌΠ΅ΠΆΠ΄Ρƒ собой (join), ΠΈΠ· ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½Ρ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ… Π²Ρ‹Ρ‡ΠΈΡΠ»ΠΈΡ‚ΡŒ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ ΠΏΠΎΠ»Π΅Π·Π½ΠΎΠ΅, Π·Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ Π² InfluxDB, ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ Π°Π»Π΅Ρ€Ρ‚ Π² Slack/Telegram/ΠΏΠΎΡ‡Ρ‚Ρƒ.

Π’Π΅ΡΡŒ стСк ΠΈΠΌΠ΅Π΅Ρ‚ ΠΊΡ€ΡƒΡ‚ΡƒΡŽ ΠΈ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΡƒΡŽ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡŽ, Π½ΠΎ всСгда найдутся ΠΏΠΎΠ»Π΅Π·Π½Ρ‹Π΅ ΡˆΡ‚ΡƒΠΊΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π² явном Π²ΠΈΠ΄Π΅ Π² ΠΌΠ°Π½ΡƒΠ°Π»Π°Ρ… Π½Π΅ ΡƒΠΊΠ°Π·Π°Π½Ρ‹. Π’ этой ΡΡ‚Π°Ρ‚ΡŒΠ΅ я Ρ€Π΅ΡˆΠΈΠ» ΡΠΎΠ±Ρ€Π°Ρ‚ΡŒ ряд Ρ‚Π°ΠΊΠΈΡ… ΠΏΠΎΠ»Π΅Π·Π½Ρ‹Ρ… Π½Π΅ΠΎΡ‡Π΅Π²ΠΈΠ΄Π½Ρ‹Ρ… совСтов (основный синтаксис 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()

Если Ρ‚Π΅Π³/ΠΏΠΎΠ»Π΅ Π½Π΅ Π·Π°ΠΏΠΎΠ»Π½Π΅Π½ΠΎ, Π²ΠΎΠ·Π½ΠΈΠΊΠ½ΡƒΡ‚ ошибки Π² вычислСниях:

|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) Ρ‚Π°ΠΊΠΆΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ пустой. На эту Ρ‚Π΅ΠΌΡƒ Π΅ΡΡ‚ΡŒ нСсколько Ρ‚ΠΈΠΊΠ΅Ρ‚ΠΎΠ² Π½Π° Π³ΠΈΡ‚Ρ…Π°Π±Π΅ (1633, 1871, 6967) – ΠΆΠ΄Π΅ΠΌ фиксов ΠΈ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ страдаСм.

ИспользованиС условий Π² вычислСниях (if Π² lambda)

|eval(lambda: if("value" > 0, true, false)

ПослСдниС ΠΏΡΡ‚ΡŒ ΠΌΠΈΠ½ΡƒΡ‚ ΠΈΠ· ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½Π° Π·Π° ΠΏΠ΅Ρ€ΠΈΠΎΠ΄

НапримСр, Π²Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ ΡΡ€Π°Π²Π½ΠΈΡ‚ΡŒ значСния послСдних пяти ΠΌΠΈΠ½ΡƒΡ‚ с ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅ΠΉ Π½Π΅Π΄Π΅Π»Π΅ΠΉ. МоТно Π²Π·ΡΡ‚ΡŒ Π΄Π²Π΅ ΠΏΠ°Ρ‡ΠΊΠΈ Π΄Π°Π½Π½Ρ‹Ρ… двумя ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΌΠΈ batch’ами ΠΈΠ»ΠΈ Π²Ρ‹Ρ‚Π°Ρ‰ΠΈΡ‚ΡŒ Ρ‡Π°ΡΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈΠ· большСго ΠΏΠ΅Ρ€ΠΈΠΎΠ΄Π°:

 |where(lambda: duration((unixNano(now()) - unixNano("time"))/1000, 1u) < 5m)

ΠΠ»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²ΠΎΠΉ для послСдних пяти ΠΌΠΈΠ½ΡƒΡ‚ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ использованиС Π½ΠΎΠ΄Ρ‹ BarrierNode, которая отсСкаСт Π΄Π°Π½Π½Ρ‹Π΅ Ρ€Π°Π½ΡŒΡˆΠ΅ ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠ³ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ:

|barrier()
        .period(5m)

ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ использования Goβ€™ΡˆΠ½Ρ‹Ρ… шаблонов Π² message

Π¨Π°Π±Π»ΠΎΠ½Ρ‹ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‚ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Ρƒ ΠΈΠ· ΠΏΠ°ΠΊΠ΅Ρ‚Π° text.template, Π½ΠΈΠΆΠ΅ нСсколько часто Π²ΡΡ‚Ρ€Π΅Ρ‡Π°ΡŽΡ‰ΠΈΡ…ΡΡ Π·Π°Π΄Π°Ρ‡Π΅ΠΊ.

if-else

Наводим порядок, Π½Π΅ Ρ‚Ρ€ΠΈΠ³Π³Π΅Ρ€ΠΈΠΌ людСй тСкстом лишний Ρ€Π°Π·:

|alert()
    ...
    .message(
        '{{ if eq .Level "OK" }}It is ok now{{ else }}Chief, everything is broken{{end}}'
    )

Π”Π²Π΅ Ρ†ΠΈΡ„Ρ€Ρ‹ послС запятой Π² message

Π£Π»ΡƒΡ‡ΡˆΠ°Π΅ΠΌ Ρ‡ΠΈΡ‚Π°Π±Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ сообщСния:

|alert()
    ...
    .message(
        'now value is {{ index .Fields "value" | printf "%0.2f" }}'
    )

Π Π°Π·Π²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π½ΠΈΠ΅ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… Π² message

Π’Ρ‹Π²ΠΎΠ΄ΠΈΠΌ Π² сообщСниС большС ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ для ΠΎΡ‚Π²Π΅Ρ‚Π° Π½Π° вопрос Β«ΠŸΠΎΡ‡Π΅ΠΌΡƒ ΠΎΡ€Π΅Ρ‚-Ρ‚ΠΎΒ»?

var warnAlert = 10
  |alert()
    ...
    .message(
       'Today value less then '+string(warnAlert)+'%'
    )

Π£Π½ΠΈΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΉ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ Π°Π»Π΅Ρ€Ρ‚Π°

НуТная ΡˆΡ‚ΡƒΠΊΠ°, ΠΊΠΎΠ³Π΄Π° Π² Π΄Π°Π½Π½Ρ‹Ρ… большС ΠΎΠ΄Π½ΠΎΠΉ Π³Ρ€ΡƒΠΏΠΏΡ‹, ΠΈΠ½Π°Ρ‡Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒΡΡ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ΄ΠΈΠ½ Π°Π»Π΅Ρ€Ρ‚:

|alert()
      ...
      .id('{{ index .Tags "myname" }}/{{ index .Tags "myfield" }}')

ΠšΠ°ΡΡ‚ΠΎΠΌΠ½Ρ‹Π΅ handler’s

Π’ большом спискС Ρ…Π΅Π½Π΄Π»Π΅Ρ€ΠΎΠ² Π΅ΡΡ‚ΡŒ exec, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ позволяСт Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ свой скрипт с ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹ΠΌΠΈ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π°ΠΌΠΈ (stdin) – творчСство Π΄Π° ΠΈ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ!

Один ΠΈΠ· Π½Π°ΡˆΠΈΡ… кастомов – это нСбольшой питонячий скрипт для ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠΈ ΡƒΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠΉ Π² слак.
Π‘Π½Π°Ρ‡Π°Π»Π° Π½Π°ΠΌ Π·Π°Ρ…ΠΎΡ‚Π΅Π»ΠΎΡΡŒ ΠΎΡ‚ΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ Π² сообщСнии ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΡƒ ΠΈΠ· Π³Ρ€Π°Ρ„Π°Π½Ρ‹, Π·Π°Ρ‰ΠΈΡ‰Π΅Π½Π½ΠΎΠΉ Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠ΅ΠΉ. ПослС – ΠΏΠΈΡΠ°Ρ‚ΡŒ 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("something")

Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ (cli): kapacitor -url host-or-ip:9092 logs lvl=error

Π’Π°Ρ€ΠΈΠ°Π½Ρ‚ с httpOut

ΠŸΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ Π΄Π°Π½Π½Ρ‹Π΅ Π² Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΌ ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½Π΅:

|httpOut('something')

Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ (get): host-or-ip:9092/kapacitor/v1/tasks/task_name/something

Π‘Ρ…Π΅ΠΌΠ° выполнСния

  • КаТдая таска Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Π΄Π΅Ρ€Π΅Π²ΠΎ выполнСния с ΠΏΠΎΠ»Π΅Π·Π½Ρ‹ΠΌΠΈ Ρ†ΠΈΡ„Ρ€Π°ΠΌΠΈ Π² Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π΅ graphviz.
  • Π‘Π΅Ρ€Π΅ΠΌ Π±Π»ΠΎΠΊ dot.
  • ВставляСм Π² viewer, наслаТдаСмся.

Π“Π΄Π΅ Π΅Ρ‰Ρ‘ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ граблями

timestamp Π² influxdb ΠΏΡ€ΠΈ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠΉ записи

НапримСр, ΠΌΡ‹ настраиваСм Π°Π»Π΅Ρ€Ρ‚ Π½Π° сумму запросов Π·Π° час (groupBy(1h)) ΠΈ Ρ…ΠΎΡ‚ΠΈΠΌ Π·Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ ΡΠ»ΡƒΡ‡ΠΈΠ²ΡˆΠΈΠΉΡΡ Π°Π»Π΅Ρ€Ρ‚ Π² influxdb (Ρ‡Ρ‚ΠΎΠ±Ρ‹ красиво ΠΏΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ Ρ„Π°ΠΊΡ‚ наличия ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ Π½Π° Π³Ρ€Π°Ρ„ΠΈΠΊΠ΅ Π² grafana).

influxDBOut() Π·Π°ΠΏΠΈΡˆΠ΅Ρ‚ Π² timestamp Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ time ΠΈΠ· Π°Π»Π΅Ρ€Ρ‚Π°, соотвСтствСнно, Ρ‚ΠΎΡ‡ΠΊΠ° Π½Π° Π³Ρ€Π°Ρ„ΠΈΠΊΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ записана Ρ€Π°Π½ΡŒΡˆΠ΅/ΠΏΠΎΠ·ΠΆΠ΅, Ρ‡Π΅ΠΌ ΠΏΡ€ΠΈΡˆΠ΅Π» Π°Π»Π΅Ρ€Ρ‚.

Когда трСбуСтся Ρ‚ΠΎΡ‡Π½ΠΎΡΡ‚ΡŒ: ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌ эту ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ Ρ‡Π΅Ρ€Π΅Π· Π²Ρ‹Π·ΠΎΠ² кастомного handler’Π°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π·Π°ΠΏΠΈΡˆΠ΅Ρ‚ Π΄Π°Π½Π½Ρ‹Π΅ Π² influxdb с Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΌ timestamp’ΠΎΠΌ.

docker, сборка ΠΈ Π΄Π΅ΠΏΠ»ΠΎΠΉ

ΠŸΡ€ΠΈ стартС kapacitor ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΠ΄Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ таски, ΡˆΠ°Π±Π»ΠΎΠ½Ρ‹ ΠΈ Ρ…Π΅Π½Π΄Π»Π΅Ρ€Ρ‹ ΠΈΠ· Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ, прописанной Π² ΠΊΠΎΠ½Ρ„ΠΈΠ³Π΅, Π² Π±Π»ΠΎΠΊΠ΅ [load].

Для ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½ΠΎΠ³ΠΎ создания таски Π½ΡƒΠΆΠ½Ρ‹ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ Π²Π΅Ρ‰ΠΈ:

  1. НазваниС Ρ„Π°ΠΉΠ»Π° – разворачиваСтся Π² id/Π½Π°Π·Π²Π°Π½ΠΈΠ΅ скрипта
  2. Π’ΠΈΠΏ – stream/batch
  3. 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-Π²Ρ‹Ρ€Π°ΠΆΠ΅Π½ΠΈΠΈ, Ρ‚ΠΎΠΆΠ΅ Π½Π΅ подставляСтся.

Π•ΡΡ‚ΡŒ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ ΡΠΎΡ…Ρ€Π°Π½ΡΡ‚ΡŒ Π½ΡƒΠΆΠ½Ρ‹Π΅ Ρ†ΠΈΡ„Ρ€Ρ‹ ΠΈΠ· ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ Π±Π°Ρ‚Ρ‡Π° Π² Ρ„Π°ΠΉΠ» Ρ‡Π΅Ρ€Π΅Π· udf ΠΈ Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ этот Ρ„Π°ΠΉΠ» Ρ‡Π΅Ρ€Π΅Π· sideload.

Π§Ρ‚ΠΎ ΠΌΡ‹ этим Ρ€Π΅ΡˆΠ°Π»ΠΈ?

Π£ нас Π΅ΡΡ‚ΡŒ ΠΎΠΊΠΎΠ»ΠΎ 100 поставщиков ΠΎΡ‚Π΅Π»Π΅ΠΉ, ΠΊ ΠΊΠ°ΠΆΠ΄ΠΎΠΌΡƒ ΠΈΠ· Π½ΠΈΡ… ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ нСсколько ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ, Π½Π°Π·ΠΎΠ²Π΅ΠΌ это ΠΊΠ°Π½Π°Π»ΠΎΠΌ. Π­Ρ‚ΠΈΡ… ΠΊΠ°Π½Π°Π»ΠΎΠ² ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ 300, ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΈΠ· ΠΊΠ°Π½Π°Π»ΠΎΠ² ΠΌΠΎΠΆΠ΅Ρ‚ ΠΎΡ‚Π²Π°Π»ΠΈΡ‚ΡŒΡΡ. Из всСх записываСмых ΠΌΠ΅Ρ‚Ρ€ΠΈΠΊ Π±ΡƒΠ΄Π΅ΠΌ ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ΠΈΡ‚ΡŒ Ρ€Π΅ΠΉΡ‚ ошибок (requests ΠΈ errors).

ΠŸΠΎΡ‡Π΅ΠΌΡƒ Π½Π΅ Π³Ρ€Π°Ρ„Π°Π½Π°?

АлСрты ΠΏΠΎ ошибкам, настроСнныС Π² Π³Ρ€Π°Ρ„Π°Π½Π΅, ΠΈΠΌΠ΅ΡŽΡ‚ нСсколько минусов. КакиС-Ρ‚ΠΎ ΠΊΡ€ΠΈΡ‚ΠΈΡ‡Π½Ρ‹Π΅, Π½Π° ΠΊΠ°ΠΊΠΈΠ΅-Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ Π·Π°ΠΊΡ€Ρ‹Ρ‚ΡŒ Π³Π»Π°Π·Π°, Π² зависимости ΠΎΡ‚ ситуации.

Π“Ρ€Π°Ρ„Π°Π½Π° Π½Π΅ ΡƒΠΌΠ΅Π΅Ρ‚ вычислСния ΠΌΠ΅ΠΆΠ΄Ρƒ измСрСниями + Π°Π»Π΅Ρ€Ρ‚ΠΈΠ½Π³, Π° Π½Π°ΠΌ ΠΆΠ΅ Π½ΡƒΠΆΠ΅Π½ Ρ€Π΅ΠΉΡ‚ (requests-errors)/requests.

Ошибки выглядят Π·Π»ΠΎΠ±Π½ΠΎ:

Π’Ρ€ΡŽΠΊΠΈ для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΌΠ΅Ρ‚Ρ€ΠΈΠΊ Π² Kapacitor

И ΠΌΠ΅Π½Π΅Π΅ Π·Π»ΠΎΠ±Π½ΠΎ, Ссли ΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ с ΡƒΡΠΏΠ΅ΡˆΠ½Ρ‹ΠΌΠΈ запросами:

Π’Ρ€ΡŽΠΊΠΈ для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΌΠ΅Ρ‚Ρ€ΠΈΠΊ Π² Kapacitor

ОкСй, ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ΠΏΠΎΡΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ Ρ€Π΅ΠΉΡ‚ Π² сСрвисС Π΄ΠΎ Π³Ρ€Π°Ρ„Π°Π½Ρ‹, ΠΈ Π² ΠΊΠ°ΠΊΠΈΡ…-Ρ‚ΠΎ случаях это ΠΏΠΎΠ΄ΠΎΠΉΠ΄Π΅Ρ‚. Но Π½Π΅ Π² нашСм, Ρ‚.ΠΊ. для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΊΠ°Π½Π°Π»Π° своС ΡΠΎΠΎΡ‚Π½ΠΎΡˆΠ΅Π½ΠΈΠ΅ считаСтся Β«Π½ΠΎΡ€ΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΌΒ», Π° Π°Π»Π΅Ρ€Ρ‚Ρ‹ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ ΠΏΠΎ статичным значСниям (ΠΈΡ‰Π΅ΠΌ Π³Π»Π°Π·ΠΊΠ°ΠΌΠΈ, мСняСм, Ссли часто Π°Π»Π΅Ρ€Ρ‚ΠΈΡ‚).

Π­Ρ‚ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ Β«Π½ΠΎΡ€ΠΌΠ°Π»ΡŒΠ½ΠΎΒ» для Ρ€Π°Π·Π½Ρ‹Ρ… ΠΊΠ°Π½Π°Π»ΠΎΠ²:

Π’Ρ€ΡŽΠΊΠΈ для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΌΠ΅Ρ‚Ρ€ΠΈΠΊ Π² Kapacitor

Π’Ρ€ΡŽΠΊΠΈ для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΌΠ΅Ρ‚Ρ€ΠΈΠΊ Π² Kapacitor

ΠŸΡ€Π΅Π½Π΅Π±Ρ€Π΅Π³Π°Π΅ΠΌ ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΠΌ ΠΏΡƒΠ½ΠΊΡ‚ΠΎΠΌ ΠΈ ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»ΠΎΠΆΠΈΠΌ, Ρ‡Ρ‚ΠΎ Ρƒ всСх поставщиков Β«Π½ΠΎΡ€ΠΌΠ°Π»ΡŒΠ½Π°ΡΒ» ΠΊΠ°Ρ€Ρ‚ΠΈΠ½Π° ΠΏΠΎΡ…ΠΎΠΆΠ°. Π’Π΅ΠΏΠ΅Ρ€ΡŒ-Ρ‚ΠΎ всС Ρ…ΠΎΡ€ΠΎΡˆΠΎ, ΠΈ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΎΠ±ΠΎΠΉΡ‚ΠΈΡΡŒ Π°Π»Π΅Ρ€Ρ‚Π°ΠΌΠΈ Π² grafana?
МоТСм, Π½ΠΎ ΠΎΡ‡Π΅Π½ΡŒ Π½Π΅ хочСтся, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ Π½Π°Π΄ΠΎ Π²Ρ‹Π±ΠΈΡ€Π°Ρ‚ΡŒ ΠΎΠ΄ΠΈΠ½ ΠΈΠ· Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ΠΎΠ²:
Π°) ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ мноТСство Π³Ρ€Π°Ρ„ΠΈΠΊΠΎΠ² ΠΏΠΎΠ΄ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΊΠ°Π½Π°Π» ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎ (ΠΈ ΠΌΡƒΡ‡ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ΠΈΡ… ΡΠΎΠΏΡ€ΠΎΠ²ΠΎΠΆΠ΄Π°Ρ‚ΡŒ)
Π±) ΠΎΡΡ‚Π°Π²ΠΈΡ‚ΡŒ ΠΎΠ΄ΠΈΠ½ Π³Ρ€Π°Ρ„ΠΈΠΊ со всСми ΠΊΠ°Π½Π°Π»Π°ΠΌΠΈ (ΠΈ ΠΏΠΎΡ‚Π΅Ρ€ΡΡ‚ΡŒΡΡ Π² цвСтастых линиях ΠΈ настроСнных Π°Π»Π΅Ρ€Ρ‚Π°Ρ…)

Π’Ρ€ΡŽΠΊΠΈ для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΌΠ΅Ρ‚Ρ€ΠΈΠΊ Π² Kapacitor

Как сдСлали?

ΠžΠΏΡΡ‚ΡŒ ΠΆΠ΅, Π² Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ Π΅ΡΡ‚ΡŒ Ρ…ΠΎΡ€ΠΎΡˆΠΈΠΉ стартовый ΠΏΡ€ΠΈΠΌΠ΅Ρ€ (Calculating rates across joined series), ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠ΄Π³Π»ΡΠ΄Π΅Ρ‚ΡŒ ΠΈΠ»ΠΈ Π²Π·ΡΡ‚ΡŒ Π·Π° основу Π² Π°Π½Π°Π»ΠΎΠ³ΠΈΡ‡Π½Ρ‹Ρ… Π·Π°Π΄Π°Ρ‡Π°Ρ….

Π§Ρ‚ΠΎ сдСлали Π² ΠΈΡ‚ΠΎΠ³Π΅:

  • join Π΄Π²ΡƒΡ… сСрий Π·Π° нСсколько часов, Π³Ρ€ΡƒΠΏΠΏΠΈΡ€ΠΎΠ²ΠΊΠ° ΠΏΠΎ ΠΊΠ°Π½Π°Π»Π°ΠΌ;
  • заполняСм сСрии ΠΏΠΎ Π³Ρ€ΡƒΠΏΠΏΠ°ΠΌ, Ссли Π΄Π°Π½Π½Ρ‹Ρ… Π½Π΅ Π±Ρ‹Π»ΠΎ;
  • сравниваСм ΠΌΠ΅Π΄ΠΈΠ°Π½Ρƒ послСдних 10 ΠΌΠΈΠ½ΡƒΡ‚ с ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΠΌΠΈ Π΄Π°Π½Π½Ρ‹ΠΌΠΈ;
  • ΠΊΡ€ΠΈΡ‡ΠΈΠΌ, Ссли Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ ΠΎΠ±Π½Π°Ρ€ΡƒΠΆΠΈΠ»ΠΈ;
  • пишСм посчитанныС Ρ€Π΅ΠΉΡ‚Ρ‹ ΠΈ ΡΠ»ΡƒΡ‡ΠΈΠ²ΡˆΠΈΠ΅ΡΡ Π°Π»Π΅Ρ€Ρ‚Ρ‹ Π² influxdb;
  • отправляСм ΠΏΠΎΠ»Π΅Π·Π½ΠΎΠ΅ сообщСниС Π² slack.

На ΠΌΠΎΠΉ взгляд, Π½Π°ΠΌ максимально красиво ΡƒΠ΄Π°Π»ΠΎΡΡŒ всё, Ρ‡Ρ‚ΠΎ Ρ…ΠΎΡ‚Π΅Π»ΠΈ Π±Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ Π½Π° Π²Ρ‹Ρ…ΠΎΠ΄Π΅ (ΠΈ Π΄Π°ΠΆΠ΅ Ρ‡ΡƒΡ‚ΡŒ большС с кастомными хэндлСрами).

На github.com ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΊΠΎΠ΄Π° ΠΈ ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡŒΠ½ΡƒΡŽ схСму (graphviz) ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½ΠΎΠ³ΠΎ скрипта.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ²ΡˆΠ΅Π³ΠΎΡΡ ΠΊΠΎΠ΄Π°:

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).

ΠŸΠΎΡ€ΠΎΠ³ вхоТдСния Π½Π΅ ΠΎΡ‡Π΅Π½ΡŒ высокий – ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ Π΅Π³ΠΎ, Ссли Π³Ρ€Π°Ρ„Π°Π½Π° ΠΈΠ»ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ инструмСнты Π½Π΅ Π΄ΠΎ ΠΊΠΎΠ½Ρ†Π° ΡƒΠ΄ΠΎΠ²Π»Π΅Ρ‚Π²ΠΎΡ€ΡΡŽΡ‚ ваши Ρ…ΠΎΡ‚Π΅Π»ΠΊΠΈ.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com