рдмрд╣реБрдзрд╛, рдЖрдЬ рдХреЛрдгреАрд╣реА рд╡рд┐рдЪрд╛рд░рдд рдирд╛рд╣реА рдХреА рд╕реЗрд╡рд╛ рдореЗрдЯреНрд░рд┐рдХреНрд╕ рдЧреЛрд│рд╛ рдХрд░рдгреЗ рдХрд╛ рдЖрд╡рд╢реНрдпрдХ рдЖрд╣реЗ. рдкреБрдвреАрд▓ рддрд╛рд░реНрдХрд┐рдХ рдкрд╛рдпрд░реА рдореНрд╣рдгрдЬреЗ рдЧреЛрд│рд╛ рдХреЗрд▓реЗрд▓реНрдпрд╛ рдореЗрдЯреНрд░рд┐рдХреНрд╕рд╕рд╛рдареА рдЕрд▓рд░реНрдЯ рд╕реЗрдЯ рдХрд░рдгреЗ, рдЬреЗ рддреБрдордЪреНрдпрд╛рд╕рд╛рдареА (рдореЗрд▓, рд╕реНрд▓реЕрдХ, рдЯреЗрд▓рд┐рдЧреНрд░рд╛рдо) рд╕реЛрдпреАрд╕реНрдХрд░ рдЪреЕрдиреЗрд▓рдордзреАрд▓ рдбреЗрдЯрд╛рдордзреАрд▓ рдХреЛрдгрддреНрдпрд╛рд╣реА рд╡рд┐рдЪрд▓рдирд╛рдмрджреНрджрд▓ рд╕реВрдЪрд┐рдд рдХрд░реЗрд▓. рдСрдирд▓рд╛рдЗрди рд╣реЙрдЯреЗрд▓ рдмреБрдХрд┐рдВрдЧ рд╕реЗрд╡реЗрдордзреНрдпреЗ
рдХрдкреЕрд╕рд┐рдЯрд░ рд╣рд╛ TICK рд╕реНрдЯреЕрдХрдЪрд╛ рднрд╛рдЧ рдЖрд╣реЗ рдЬреЛ InfluxDB рд╡рд░реВрди рдореЗрдЯреНрд░рд┐рдХреНрд╕рд╡рд░ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХрд░реВ рд╢рдХрддреЛ. рд╣реЗ рдЕрдиреЗрдХ рдореЛрдЬрдорд╛рдк рдПрдХрддреНрд░ рдЬреЛрдбреВ рд╢рдХрддреЗ (рд╕рд╛рдореАрд▓ рд╣реЛрдК рд╢рдХрддреЗ), рдкреНрд░рд╛рдкреНрдд рдбреЗрдЯрд╛рдордзреВрди рдХрд╛рд╣реАрддрд░реА рдЙрдкрдпреБрдХреНрдд рдЧрдгрдирд╛ рдХрд░реВ рд╢рдХрддреЗ, рдкрд░рд┐рдгрд╛рдо рдкрд░рдд InfluxDB рд╡рд░ рд▓рд┐рд╣реВ рд╢рдХрддреЗ, Slack/Telegram/mail рд╡рд░ рдЕрд▓рд░реНрдЯ рдкрд╛рдард╡реВ рд╢рдХрддреЗ.
рд╕рдВрдкреВрд░реНрдг рд╕реНрдЯреЕрдХ рдЫрд╛рди рдЖрдгрд┐ рддрдкрд╢реАрд▓рд╡рд╛рд░ рдЖрд╣реЗ
рдлреНрд▓реЛрдЯ рдЖрдгрд┐ рдЗрдВрдЯ, рдЧрдгрдирд╛ рддреНрд░реБрдЯреА
рдЬрд╛рддреАрдВрджреНрд╡рд╛рд░реЗ рд╕реЛрдбрд╡рд▓реЗрд▓реА рдПрдХ рдкреВрд░реНрдгрдкрдгреЗ рдорд╛рдирдХ рд╕рдорд╕реНрдпрд╛:
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)
рдЬреЙрдИрди рднрд░рд╛ (рдЖрддреАрд▓ рд╡рд┐рд░реБрджреНрдз рдмрд╛рд╣реНрдп)
рдбреАрдлреЙрд▓реНрдЯрдиреБрд╕рд╛рд░, рдЬреЙрдЗрди рдмрд┐рдВрджреВ рдЯрд╛рдХреВрди рджреЗрдИрд▓ рдЬреЗрдереЗ рдбреЗрдЯрд╛ рдирд╛рд╣реА (рдЖрддреАрд▓).
fill('null') рд╕рд╣, рдПрдХ рдмрд╛рд╣реНрдп рдЬреЛрдбрдгреА рдХреЗрд▓реА рдЬрд╛рдИрд▓, рддреНрдпрд╛рдирдВрддрд░ рддреБрдореНрд╣рд╛рд▓рд╛ рдбреАрдлреЙрд▓реНрдЯ() рдХрд░рд╛рд╡реЗ рд▓рд╛рдЧреЗрд▓ рдЖрдгрд┐ рд░рд┐рдХреНрдд рдореВрд▓реНрдпреЗ рднрд░рд╛:
var data = res1
|join(res2)
.as('res1', 'res2)
.fill('null')
|default()
.field('res1.value', 0.0)
.field('res2.value', 100.0)
рдпреЗрдереЗ рдЕрдЬреВрдирд╣реА рдПрдХ рд╕реВрдХреНрд╖реНрдорддрд╛ рдЖрд╣реЗ. рд╡рд░реАрд▓ рдЙрджрд╛рд╣рд░рдгрд╛рдд, рдорд╛рд▓рд┐рдХреЗрдкреИрдХреА рдПрдХ (res1 рдХрд┐рдВрд╡рд╛ res2) рд░рд┐рдХрд╛рдореА рдЕрд╕рд▓реНрдпрд╛рд╕, рдкрд░рд┐рдгрд╛рдореА рдорд╛рд▓рд┐рдХрд╛ (рдбреЗрдЯрд╛) рджреЗрдЦреАрд▓ рд░рд┐рдХреНрдд рдЕрд╕реЗрд▓. Github рд╡рд░ рдпрд╛ рд╡рд┐рд╖рдпрд╛рд╡рд░ рдЕрдиреЗрдХ рддрд┐рдХрд┐рдЯреЗ рдЖрд╣реЗрдд (
рдЧрдгрдирд╛рдордзреНрдпреЗ рдкрд░рд┐рд╕реНрдерд┐рддреА рд╡рд╛рдкрд░рдгреЗ (рд▓реЕрдореНрдмрдбрд╛рдордзреНрдпреЗ рдЕрд╕рд▓реНрдпрд╛рд╕)
|eval(lambda: if("value" > 0, true, false)
рдХрд╛рд▓рд╛рд╡рдзреАрд╕рд╛рдареА рдкрд╛рдЗрдкрд▓рд╛рдЗрдирдкрд╛рд╕реВрди рд╢реЗрд╡рдЯрдЪреА рдкрд╛рдЪ рдорд┐рдирд┐рдЯреЗ
рдЙрджрд╛рд╣рд░рдгрд╛рд░реНрде, рддреБрдореНрд╣рд╛рд▓рд╛ рд╢реЗрд╡рдЯрдЪреНрдпрд╛ рдкрд╛рдЪ рдорд┐рдирд┐рдЯрд╛рдВрдЪреНрдпрд╛ рдореВрд▓реНрдпрд╛рдВрдЪреА рдорд╛рдЧреАрд▓ рдЖрдард╡рдбреНрдпрд╛рд╢реА рддреБрд▓рдирд╛ рдХрд░рдгреЗ рдЖрд╡рд╢реНрдпрдХ рдЖрд╣реЗ. рддреБрдореНрд╣реА рджреЛрди рд╕реНрд╡рддрдВрддреНрд░ рдмреЕрдЪрдордзреНрдпреЗ рдбреЗрдЯрд╛рдЪреНрдпрд╛ рджреЛрди рдмреЕрдЪ рдШреЗрдК рд╢рдХрддрд╛ рдХрд┐рдВрд╡рд╛ рдореЛрдареНрдпрд╛ рдХрд╛рд▓рд╛рд╡рдзреАрддреАрд▓ рдбреЗрдЯрд╛рдЪрд╛ рдХрд╛рд╣реА рднрд╛рдЧ рдХрд╛рдвреВ рд╢рдХрддрд╛:
|where(lambda: duration((unixNano(now()) - unixNano("time"))/1000, 1u) < 5m)
рд╢реЗрд╡рдЯрдЪреНрдпрд╛ рдкрд╛рдЪ рдорд┐рдирд┐рдЯрд╛рдВрд╕рд╛рдареА рдПрдХ рдкрд░реНрдпрд╛рдп рдореНрд╣рдгрдЬреЗ рдмреЕрд░рд┐рдпрд░рдиреЛрдб рд╡рд╛рдкрд░рдгреЗ, рдЬреЗ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╡реЗрд│реЗрдкреВрд░реНрд╡реА рдбреЗрдЯрд╛ рдХрд╛рдкреВрди рдЯрд╛рдХрддреЗ:
|barrier()
.period(5m)
рд╕рдВрджреЗрд╢рд╛рдд рдЧреЛ рдЯреЗрдореНрдкрд▓реЗрдЯреНрд╕ рд╡рд╛рдкрд░рдгреНрдпрд╛рдЪреА рдЙрджрд╛рд╣рд░рдгреЗ
рдЯреЗрдореНрдкрд▓реЗрдЯреНрд╕ рдкреЕрдХреЗрдЬрдордзреАрд▓ рд╕реНрд╡рд░реВрдкрд╛рд╢реА рд╕рдВрдмрдВрдзрд┐рдд рдЖрд╣реЗрдд
if-other
рдЖрдореНрд╣реА рдЧреЛрд╖реНрдЯреА рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдареЗрд╡рддреЛ рдЖрдгрд┐ рд▓реЛрдХрд╛рдВрдирд╛ рдкреБрдиреНрд╣рд╛ рдПрдХрджрд╛ рдордЬрдХреВрд░ рджреЗрдКрди рдЯреНрд░рд┐рдЧрд░ рдХрд░рдд рдирд╛рд╣реА:
|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) - рд╕рд░реНрдЬрдирд╢реАрд▓рддрд╛ рдЖрдгрд┐ рдЖрдгрдЦреА рдХрд╛рд╣реА рдирд╛рд╣реА!
рдЖрдордЪреНрдпрд╛ рд░реАрддрд┐рд░рд┐рд╡рд╛рдЬрд╛рдВрдкреИрдХреА рдПрдХ рдореНрд╣рдгрдЬреЗ рд╕реНрд▓реЕрдХрд▓рд╛ рд╕реВрдЪрдирд╛ рдкрд╛рдард╡рдгреНрдпрд╛рд╕рд╛рдареА рдПрдХ рд▓рд╣рд╛рди рдкрд╛рдпрдерди рд╕реНрдХреНрд░рд┐рдкреНрдЯ.
рд╕реБрд░реБрд╡рд╛рддреАрд▓рд╛, рдЖрдореНрд╣рд╛рд▓рд╛ рд╕рдВрджреЗрд╢рд╛рдд рдЕрдзрд┐рдХреГрддрддрд╛-рд╕рдВрд░рдХреНрд╖рд┐рдд рдЧреНрд░рд╛рдлрдирд╛ рдЪрд┐рддреНрд░ рдкрд╛рдард╡рд╛рдпрдЪреЗ рд╣реЛрддреЗ. рддреНрдпрд╛рдирдВрддрд░, рдереНрд░реЗрдбрдордзреНрдпреЗ рд╕рдорд╛рди рдЧрдЯрд╛рддреАрд▓ рдорд╛рдЧреАрд▓ рд╕реВрдЪрдирд╛рдВрд╡рд░ рдУрдХреЗ рд▓рд┐рд╣рд╛, рдЖрдгрд┐ рд╕реНрд╡рддрдВрддреНрд░ рд╕рдВрджреЗрд╢ рдореНрд╣рдгреВрди рдирд╛рд╣реА. рдереЛрдбреНрдпрд╛ рд╡реЗрд│рд╛рдиреЗ - рд╢реЗрд╡рдЯрдЪреНрдпрд╛ 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 рдордзреНрдпреЗ рдЖрд▓реЗрд▓рд╛ рдЗрд╢рд╛рд░рд╛ рд░реЗрдХреЙрд░реНрдб рдХрд░реВ рдЗрдЪреНрдЫрд┐рддреЛ (рдЧреНрд░рд╛рдлрдирд╛рдордзреАрд▓ рдЖрд▓реЗрдЦрд╛рд╡рд░ рд╕рдорд╕реНрдпреЗрдЪреА рд╡рд╕реНрддреБрд╕реНрдерд┐рддреА рд╕реБрдВрджрд░рдкрдгреЗ рджрд░реНрд╢рд╡рдгреНрдпрд╛рд╕рд╛рдареА).
influxDBOut() рдЪреЗрддрд╛рд╡рдгреАрдкрд╛рд╕реВрди рдЯрд╛рдЗрдорд╕реНрдЯреЕрдореНрдкрд╡рд░ рд╡реЗрд│ рдореВрд▓реНрдп рд▓рд┐рд╣реЗрд▓; рддреНрдпрд╛рдиреБрд╕рд╛рд░, рдЪрд╛рд░реНрдЯрд╡рд░реАрд▓ рдмрд┐рдВрджреВ рдЕрд▓рд░реНрдЯ рдЖрд▓реНрдпрд╛рдЪреНрдпрд╛ рдЖрдзреА/рдирдВрддрд░ рд▓рд┐рд╣рд┐рд▓рд╛ рдЬрд╛рдИрд▓.
рдЬреЗрд╡реНрд╣рд╛ рдЕрдЪреВрдХрддрд╛ рдЖрд╡рд╢реНрдпрдХ рдЕрд╕рддреЗ: рдЖрдореНрд╣реА рдХрд╕реНрдЯрдо рд╣рдБрдбрд▓рд░рд▓рд╛ рдХреЙрд▓ рдХрд░реВрди рдпрд╛ рд╕рдорд╕реНрдпреЗрд╡рд░ рдХрд╛рдо рдХрд░рддреЛ, рдЬреЛ рд╡рд░реНрддрдорд╛рди рдЯрд╛рдЗрдорд╕реНрдЯреЕрдореНрдкрд╕рд╣ influxdb рд╡рд░ рдбреЗрдЯрд╛ рд▓рд┐рд╣рд┐рддреЛ.
рдбреЙрдХрд░, рдмрд┐рд▓реНрдб рдЖрдгрд┐ рдбрд┐рдкреНрд▓реЙрдпрдореЗрдВрдЯ
рд╕реНрдЯрд╛рд░реНрдЯрдЕрдкрд╡рд░, рдХреЕрдкреЗрд╕рд┐рдЯрд░ [рд▓реЛрдб] рдмреНрд▓реЙрдХрдордзреАрд▓ рдХреЙрдиреНрдлрд┐рдЧрд░реЗрд╢рдирдордзреНрдпреЗ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХреЗрд▓реЗрд▓реНрдпрд╛ рдирд┐рд░реНрджреЗрд╢рд┐рдХреЗрддреВрди рдХрд╛рд░реНрдпреЗ, рдЯреЗрдореНрдкрд▓реЗрдЯреНрд╕ рдЖрдгрд┐ рд╣рдБрдбрд▓рд░ рд▓реЛрдб рдХрд░реВ рд╢рдХрддреЛ.
рдХрд╛рд░реНрдп рдпреЛрдЧреНрдпрд░рд┐рддреНрдпрд╛ рддрдпрд╛рд░ рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА, рдЖрдкрд▓реНрдпрд╛рд▓рд╛ рдЦрд╛рд▓реАрд▓ рдЧреЛрд╖реНрдЯреАрдВрдЪреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдЖрд╣реЗ:
- рдлрд╛рдЗрд▓ рдирд╛рд╡ - рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдЖрдпрдбреА/рдирд╛рд╡рд╛рдордзреНрдпреЗ рд╡рд┐рд╕реНрддрд╛рд░рд┐рдд
- рдкреНрд░рдХрд╛рд░ - рдкреНрд░рд╡рд╛рд╣/рдмреЕрдЪ
- dbrp тАУ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЛрдгрддреНрдпрд╛ рдбреЗрдЯрд╛рдмреЗрд╕ + рдкреЙрд▓рд┐рд╕реАрдордзреНрдпреЗ рдЪрд╛рд▓рддреЗ рд╣реЗ рд╕реВрдЪрд┐рдд рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рдХреАрд╡рд░реНрдб (dbrp тАЬрдкреБрд░рд╡рдард╛рджрд╛рд░.тАЭ тАЬрдСрдЯреЛрдЬреЗрдитАЭ)
рдЬрд░ рдХрд╛рд╣реА рдмреЕрдЪ рдЯрд╛рд╕реНрдХрдордзреНрдпреЗ dbrp рд╕рд╣ рдУрд│ рдирд╕реЗрд▓, рддрд░ рд╕рдВрдкреВрд░реНрдг рд╕реЗрд╡рд╛ рд╕реБрд░реВ рд╣реЛрдгреНрдпрд╛рд╕ рдирдХрд╛рд░ рджреЗрдИрд▓ рдЖрдгрд┐ рд▓реЙрдЧрдордзреНрдпреЗ рддреНрдпрд╛рдмрджреНрджрд▓ рдкреНрд░рд╛рдорд╛рдгрд┐рдХрдкрдгреЗ рд▓рд┐рд╣реЗрд▓.
рдХреНрд░реЛрдиреЛрдЧреНрд░рд╛рдлрдордзреНрдпреЗ, рдпрд╛рдЙрд▓рдЯ, рд╣реА рдУрд│ рдЕрд╕реНрддрд┐рддреНрд╡рд╛рдд рдирд╕рд╛рд╡реА; рддреА рдЗрдВрдЯрд░рдлреЗрд╕рджреНрд╡рд╛рд░реЗ рд╕реНрд╡реАрдХрд╛рд░рд▓реА рдЬрд╛рдд рдирд╛рд╣реА рдЖрдгрд┐ рддреНрд░реБрдЯреА рдирд┐рд░реНрдорд╛рдг рдХрд░рддреЗ.
рдХрдВрдЯреЗрдирд░ рддрдпрд╛рд░ рдХрд░рддрд╛рдирд╛ рд╣реЕрдХ: рдбреЙрдХрд░рдлрд╛рдЗрд▓ //.+dbrp рд╕рд╣ рдУрд│реА рдЕрд╕рд▓реНрдпрд╛рд╕ -1 рд╕рд╣ рдмрд╛рд╣реЗрд░ рдкрдбрддреЗ, рдЬреНрдпрд╛рдореБрд│реЗ рдмрд┐рд▓реНрдб рдЕрд╕реЗрдВрдмрд▓ рдХрд░рддрд╛рдирд╛ рдмрд┐рдШрд╛рдбрд╛рдЪреЗ рдХрд╛рд░рдг рддреНрд╡рд░рд┐рдд рд╕рдордЬреВ рд╢рдХреЗрд▓.
рдПрдХ рддреЗ рдЕрдиреЗрдХ рд╕рд╛рдореАрд▓ рд╡реНрд╣рд╛
рдЙрджрд╛рд╣рд░рдг рдХрд╛рд░реНрдп: рддреБрдореНрд╣рд╛рд▓рд╛ рдПрдХрд╛ рдЖрдард╡рдбреНрдпрд╛рд╕рд╛рдареА рд╕реЗрд╡реЗрдЪреНрдпрд╛ рдСрдкрд░реЗрдЯрд┐рдВрдЧ рд╡реЗрд│реЗрдЪрд╛ 95 рд╡рд╛ рдкрд░реНрд╕реЗрдВрдЯрд╛рдЗрд▓ рдШреЗрдгреЗ рдЖрд╡рд╢реНрдпрдХ рдЖрд╣реЗ, рд╢реЗрд╡рдЯрдЪреНрдпрд╛ 10 рдЪреНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХ рдорд┐рдирд┐рдЯрд╛рдЪреА рдпрд╛ рдореВрд▓реНрдпрд╛рд╢реА рддреБрд▓рдирд╛ рдХрд░рд╛.
рддреБрдореНрд╣реА рдПрдХ-рддреЗ-рдЕрдиреЗрдХ рд╕рд╛рдореАрд▓ рд╣реЛрдК рд╢рдХрдд рдирд╛рд╣реА, рдкреЙрдЗрдВрдЯреНрд╕рдЪреНрдпрд╛ рдЧрдЯрд╛рд╡рд░ рд╢реЗрд╡рдЯрдЪреЗ/рдордзреНрдп/рдордзреНрдпрдо рдиреЛрдбрд▓рд╛ рдкреНрд░рд╡рд╛рд╣рд╛рдд рдмрджрд▓рддреЗ, рддреНрд░реБрдЯреА "рдЪрд╛рдЗрд▓реНрдб рди рдЬреБрд│рд▓реЗрд▓реНрдпрд╛ рдХрдбрд╛ рдЬреЛрдбреВ рд╢рдХрдд рдирд╛рд╣реА: рдмреЕрдЪ -> рдкреНрд░рд╡рд╛рд╣" рдкрд░рдд рдХреЗрд▓реА рдЬрд╛рдИрд▓.
рдмреЕрдЪрдЪрд╛ рдкрд░рд┐рдгрд╛рдо, рд▓реЕрдореНрдмрдбрд╛ рдЕрднрд┐рд╡реНрдпрдХреНрддреАрдордзреНрдпреЗ рд╡реНрд╣реЗрд░рд┐рдПрдмрд▓ рдореНрд╣рдгреВрди, рджреЗрдЦреАрд▓ рдмрджрд▓рд▓рд╛ рдЬрд╛рдд рдирд╛рд╣реА.
рдкрд╣рд┐рд▓реНрдпрд╛ рдмреЕрдЪрдордзреАрд▓ рдЖрд╡рд╢реНрдпрдХ рд╕рдВрдЦреНрдпрд╛ udf рджреНрд╡рд╛рд░реЗ рдлрд╛рдЗрд▓рдордзреНрдпреЗ рд╕реЗрд╡реНрд╣ рдХрд░рдгреНрдпрд╛рдЪрд╛ рдЖрдгрд┐ рд╣реА рдлрд╛рдЗрд▓ рд╕рд╛рдЗрдбрд▓реЛрдбрджреНрд╡рд╛рд░реЗ рд▓реЛрдб рдХрд░рдгреНрдпрд╛рдЪрд╛ рдкрд░реНрдпрд╛рдп рдЖрд╣реЗ.
рд╣реЗ рдЖрдореНрд╣реА рдХрд╛рдп рд╕реЛрдбрд╡рд▓реЗ?
рдЖрдордЪреНрдпрд╛рдХрдбреЗ рд╕реБрдорд╛рд░реЗ 100 рд╣реЙрдЯреЗрд▓ рдкреБрд░рд╡рдард╛рджрд╛рд░ рдЖрд╣реЗрдд, рддреНрдпрд╛рдВрдЪреНрдпрд╛рдкреИрдХреА рдкреНрд░рддреНрдпреЗрдХрд╛рдЪреЗ рдЕрдиреЗрдХ рдХрдиреЗрдХреНрд╢рди рдЕрд╕реВ рд╢рдХрддрд╛рдд, рдЪрд▓рд╛ рдпрд╛рд▓рд╛ рдЪреЕрдиреЗрд▓ рдореНрд╣рдгреВрдпрд╛. рдпрд╛рдкреИрдХреА рдЕрдВрджрд╛рдЬреЗ 300 рдЪреЕрдиреЗрд▓ рдЖрд╣реЗрдд, рдкреНрд░рддреНрдпреЗрдХ рдЪреЕрдиреЗрд▓ рдмрдВрдж рдкрдбреВ рд╢рдХрддрд╛рдд. рд╕рд░реНрд╡ рд░реЗрдХреЙрд░реНрдб рдХреЗрд▓реЗрд▓реНрдпрд╛ рдореЗрдЯреНрд░рд┐рдХреНрд╕рдкреИрдХреА, рдЖрдореНрд╣реА рддреНрд░реБрдЯреА рджрд░ (рд╡рд┐рдирдВрддреНрдпрд╛ рдЖрдгрд┐ рддреНрд░реБрдЯреА) рдЪреЗ рдирд┐рд░реАрдХреНрд╖рдг рдХрд░реВ.
рдЧреНрд░рд╛рдлрдирд╛ рдХрд╛ рдирд╛рд╣реА?
Grafana рдордзреНрдпреЗ рдХреЙрдиреНрдлрд┐рдЧрд░ рдХреЗрд▓реЗрд▓реНрдпрд╛ рддреНрд░реБрдЯреА рд╕реВрдЪрдирд╛рдВрдЪреЗ рдЕрдиреЗрдХ рддреЛрдЯреЗ рдЖрд╣реЗрдд. рдХрд╛рд╣реА рдЧрдВрднреАрд░ рдЖрд╣реЗрдд, рдХрд╛рд╣реА рдкрд░рд┐рд╕реНрдерд┐рддреАрдиреБрд╕рд╛рд░ рддреБрдореНрд╣реА рдбреЛрд│реЗ рдмрдВрдж рдХрд░реВ рд╢рдХрддрд╛.
рдЧреНрд░рд╛рдлрд╛рдирд╛рд▓рд╛ рдореЛрдЬрдорд╛рдк + рдЕрд▓рд░реНрдЯрд┐рдВрдЧ рджрд░рдореНрдпрд╛рди рдЧрдгрдирд╛ рдХрд╢реА рдХрд░рд╛рдпрдЪреА рд╣реЗ рдорд╛рд╣рд┐рдд рдирд╛рд╣реА, рдкрд░рдВрддреБ рдЖрдореНрд╣рд╛рд▓рд╛ рджрд░ (рд╡рд┐рдирдВрддреНрдпрд╛-рддреНрд░реБрдЯреА)/рд╡рд┐рдирдВрддреА рдЖрд╡рд╢реНрдпрдХ рдЖрд╣реЗрдд.
рддреНрд░реБрдЯреА рд╡рд╛рдИрдЯ рджрд┐рд╕рддрд╛рдд:
рдЖрдгрд┐ рдпрд╢рд╕реНрд╡реА рд╡рд┐рдирдВрддреНрдпрд╛рдВрд╕рд╣ рдкрд╛рд╣рд┐рд▓реНрдпрд╛рд╕ рдХрдореА рд╡рд╛рдИрдЯ:
рдареАрдХ рдЖрд╣реЗ, рдЖрдореНрд╣реА рдЧреНрд░рд╛рдлрдирд╛рдкреВрд░реНрд╡реА рд╕реЗрд╡реЗрддреАрд▓ рджрд░рд╛рдЪреА рдкреВрд░реНрд╡-рдЧрдгрдирд╛ рдХрд░реВ рд╢рдХрддреЛ рдЖрдгрд┐ рдХрд╛рд╣реА рдкреНрд░рдХрд░рдгрд╛рдВрдордзреНрдпреЗ рд╣реЗ рдХрд╛рд░реНрдп рдХрд░реЗрд▓. рдкрдг рдЖрдкрд▓реНрдпрд╛рдд рдирд╛рд╣реА, рдХрд╛рд░рдг... рдкреНрд░рддреНрдпреЗрдХ рдЪреЕрдиреЗрд▓рд╕рд╛рдареА рддреНрдпрд╛рдЪреЗ рд╕реНрд╡рддрдГрдЪреЗ рдЧреБрдгреЛрддреНрддрд░ "рд╕рд╛рдорд╛рдиреНрдп" рдорд╛рдирд▓реЗ рдЬрд╛рддреЗ рдЖрдгрд┐ рдЕреЕрд▓рд░реНрдЯ рд╕реНрдерд┐рд░ рдореВрд▓реНрдпрд╛рдВрдиреБрд╕рд╛рд░ рдХрд╛рд░реНрдп рдХрд░рддрд╛рдд (рдЖрдореНрд╣реА рддреЗ рдЖрдордЪреНрдпрд╛ рдбреЛрд│реНрдпрд╛рдВрдиреА рд╢реЛрдзрддреЛ, рд╡рд╛рд░рдВрд╡рд╛рд░ рдЕрд▓рд░реНрдЯ рдЕрд╕рд▓реНрдпрд╛рд╕ рддреЗ рдмрджрд▓реВ).
рд╣реА рднрд┐рдиреНрди рдЪреЕрдиреЗрд▓рд╕рд╛рдареА "рд╕рд╛рдорд╛рдиреНрдп" рдЪреА рдЙрджрд╛рд╣рд░рдгреЗ рдЖрд╣реЗрдд:
рдЖрдореНрд╣реА рдорд╛рдЧреАрд▓ рдореБрджреНрджреНрдпрд╛рдХрдбреЗ рджреБрд░реНрд▓рдХреНрд╖ рдХрд░рддреЛ рдЖрдгрд┐ рдЕрд╕реЗ рдЧреГрд╣реАрдд рдзрд░рддреЛ рдХреА рд╕рд░реНрд╡ рдкреБрд░рд╡рдард╛рджрд╛рд░рд╛рдВрд╕рд╛рдареА "рд╕рд╛рдорд╛рдиреНрдп" рдЪрд┐рддреНрд░ рд╕рдорд╛рди рдЖрд╣реЗ. рдЖрддрд╛ рд╕рд░реНрд╡ рдХрд╛рд╣реА рдареАрдХ рдЖрд╣реЗ, рдЖрдгрд┐ рдЖрдореНрд╣реА рдЧреНрд░рд╛рдлрдирд╛рдордзреНрдпреЗ рдЕрд▓рд░реНрдЯрд╕рд╣ рдорд┐рд│рд╡реВ рд╢рдХрддреЛ?
рдЖрдореНрд╣реА рдХрд░реВ рд╢рдХрддреЛ, рдкрд░рдВрддреБ рдЖрдореНрд╣рд╛рд▓рд╛ рдЦрд░реЛрдЦрд░ рдХрд░рд╛рдпрдЪреЗ рдирд╛рд╣реА, рдХрд╛рд░рдг рдЖрдореНрд╣рд╛рд▓рд╛ рдкрд░реНрдпрд╛рдпрд╛рдВрдкреИрдХреА рдПрдХ рдирд┐рд╡рдбрд╛рд╡рд╛ рд▓рд╛рдЧреЗрд▓:
рдЕ) рдкреНрд░рддреНрдпреЗрдХ рдЪреЕрдиреЗрд▓рд╕рд╛рдареА рд╕реНрд╡рддрдВрддреНрд░рдкрдгреЗ рдмрд░реЗрдЪ рдЖрд▓реЗрдЦ рдмрдирд╡рд╛ (рдЖрдгрд┐ рд╡реЗрджрдирд╛рджрд╛рдпрдХрдкрдгреЗ рддреНрдпрд╛рдВрдЪреНрдпрд╛рд╕реЛрдмрдд)
b) рд╕рд░реНрд╡ рдЪреЕрдиреЗрд▓рд╕рд╣ рдПрдХ рдЪрд╛рд░реНрдЯ рд╕реЛрдбрд╛ (рдЖрдгрд┐ рд░рдВрдЧреАрдмреЗрд░рдВрдЧреА рдУрд│реА рдЖрдгрд┐ рд╕рд╛рдиреБрдХреВрд▓рд┐рдд рд╕реВрдЪрдирд╛рдВрдордзреНрдпреЗ рд╣рд░рд╡реВрди рдЬрд╛)
рдЖрдкрдг рддреЗ рдХрд╕реЗ рдХреЗрд▓реЗ?
рдкреБрдиреНрд╣рд╛, рджрд╕реНрддрдРрд╡рдЬреАрдХрд░рдгрд╛рдд рдПрдХ рдЪрд╛рдВрдЧрд▓реЗ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдЙрджрд╛рд╣рд░рдг рдЖрд╣реЗ (
рдЖрдореНрд╣реА рд╢реЗрд╡рдЯреА рдХрд╛рдп рдХреЗрд▓реЗ:
- рдХрд╛рд╣реА рддрд╛рд╕рд╛рдВрдд рджреЛрди рдорд╛рд▓рд┐рдХрд╛ рд╕рд╛рдореАрд▓ рд╡реНрд╣рд╛, рдЪреЕрдиреЗрд▓рджреНрд╡рд╛рд░реЗ рдЧрдЯрдмрджреНрдз рдХрд░рд╛;
- рдбреЗрдЯрд╛ рдирд╕рд▓реНрдпрд╛рд╕ рдЧрдЯрд╛рдиреБрд╕рд╛рд░ рдорд╛рд▓рд┐рдХрд╛ рднрд░рд╛;
- рдорд╛рдЧреАрд▓ рдбреЗрдЯрд╛рд╕рд╣ рд╢реЗрд╡рдЯрдЪреНрдпрд╛ 10 рдорд┐рдирд┐рдЯрд╛рдВрдЪреНрдпрд╛ рдордзреНрдпрд╛рдЪреА рддреБрд▓рдирд╛ рдХрд░рд╛;
- рдЖрдореНрд╣рд╛рд▓рд╛ рдХрд╛рд╣реА рд╕рд╛рдкрдбрд▓реЗ рддрд░ рдЖрдореНрд╣реА рдУрд░рдбрддреЛ;
- рдЖрдореНрд╣реА influxdb рдордзреНрдпреЗ рдЖрд▓реЗрд▓реЗ рдЧрдгрдирд╛ рдХреЗрд▓реЗрд▓реЗ рджрд░ рдЖрдгрд┐ рд╕реВрдЪрдирд╛ рд▓рд┐рд╣рд┐рддреЛ;
- рд╕реНрд▓реЕрдХрд▓рд╛ рдЙрдкрдпреБрдХреНрдд рд╕рдВрджреЗрд╢ рдкрд╛рдард╡рд╛.
рдорд╛рдЭреНрдпрд╛ рдорддреЗ, рдЖрдореНрд╣рд╛рд▓рд╛ рдЬреЗ рдХрд╛рд╣реА рдорд┐рд│рд╡рд╛рдпрдЪреЗ рд╣реЛрддреЗ рддреЗ рд╕рд░реНрд╡ (рдЖрдгрд┐ рд╕рд╛рдиреБрдХреВрд▓ рд╣рдБрдбрд▓рд░реНрд╕рд╕рд╣ рдереЛрдбреЗ рдЕрдзрд┐рдХ) рд╢рдХреНрдп рддрд┐рддрдХреНрдпрд╛ рд╕реБрдВрджрд░рдкрдгреЗ рдЖрдореНрд╣реА рд╕рд╛рдзреНрдп рдХреЗрд▓реЗ.
рддреБрдореНрд╣реА 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)
рдирд┐рд╖реНрдХрд░реНрд╖ рдХрд╛рдп рдЖрд╣реЗ?
рдХреЕрдкреЗрд╕рд┐рдЯрд░ рдЕрдиреЗрдХ рдЧрдЯрд╛рдВрд╕рд╣ рдореЙрдирд┐рдЯрд░рд┐рдВрдЧ-рдЕреЕрд▓рд░реНрдЯреНрд╕ рдХрд░рдгреЗ, рдЖрдзреАрдЪ рд░реЗрдХреЙрд░реНрдб рдХреЗрд▓реЗрд▓реНрдпрд╛ рдореЗрдЯреНрд░рд┐рдХреНрд╕рд╡рд░ рдЖрдзрд╛рд░рд┐рдд рдЕрддрд┐рд░рд┐рдХреНрдд рдЧрдгрдирд╛ рдХрд░рдгреЗ, рд╕рд╛рдиреБрдХреВрд▓ рдХреНрд░рд┐рдпрд╛ рдХрд░рдгреЗ рдЖрдгрд┐ рд╕реНрдХреНрд░рд┐рдкреНрдЯреНрд╕ (udf) рдЪрд╛рд▓рд╡рдгреЗ рдпрд╛рд╕рд╛рдареА рдЙрддреНрдХреГрд╖реНрдЯ рдЖрд╣реЗ.
рдкреНрд░рд╡реЗрд╢рд╛рдЪрд╛ рдЕрдбрдерд│рд╛ рдлрд╛рд░ рдЬрд╛рд╕реНрдд рдирд╛рд╣реА - рдЬрд░ рдЧреНрд░рд╛рдлрдирд╛ рдХрд┐рдВрд╡рд╛ рдЗрддрд░ рд╕рд╛рдзрдиреЗ рддреБрдордЪреНрдпрд╛ рдЗрдЪреНрдЫрд╛ рдкреВрд░реНрдг рдХрд░рдд рдирд╛рд╣реАрдд рддрд░ рддреЗ рд╡рд╛рдкрд░реВрди рдкрд╣рд╛.
рд╕реНрддреНрд░реЛрдд: www.habr.com