Режим ассертов: полный справочник по проверке ответа
Режим ассертов заменяет фиксированные поля прохождения/провала монитора списком правил, которые вы пишете сами, и каждое правило называет ровно то, что должно быть истинно в ответе. Большинство мониторов аптайма судят о проверке по горстке фиксированных полей: код состояния, который считается "недоступностью", список статусов, которые нужно игнорировать, возможно, ключевое слово, которое должно где-то встретиться в теле. Этих полей не хватает, чтобы выразить API, которое на законных основаниях отвечает 404 для отсутствующего ресурса, страницу, которая возвращает 200 с пустой оболочкой из-за таймаута базы данных, или цепочку редиректов, которая вдруг начинает вести через чужой домен.
Режим ассертов HostTracker заменяет эти фиксированные поля небольшим языком правил, который вы пишете сами, правило за правилом, прямо в редакторе монитора. Каждое правило говорит ровно, что должно быть истинно в ответе: статус, часть тела, заголовок, сколько времени это заняло, куда в итоге привел редирект. Проверка проваливается только тогда, когда проваливается одно из ваших правил. Это один и тот же язык для сайта, REST API, запроса к базе данных, TCP-порта, цели Ping, счетчика SNMP или обычной проверки Counter: один набор субъектов, один набор предикатов, переиспользуемый везде, где появляется этот режим. Это руководство разбирает каждый субъект, оператор, редьюсер, сахарную конструкцию и синтаксическую форму, которые реализует движок.
Что заменяет режим ассертов
Классические поля проверки ответа никуда не деваются, пока режим ассертов выключен: ожидаемый диапазон статуса, список игнорируемых статусов, ключевое слово, которое должно (или не должно) встретиться. Режим - это переключатель, меняющий этот фиксированный набор на список правил, который вы строите сами, а выключение режима обратно перед сохранением возвращает классические поля как были. Ни один монитор не привязан к одному режиму навсегда.
Один язык вместо кучи разрозненных штучек под каждый тип складывается воедино. Проверка "должен быть JSON и содержать поле", проверка "должна по-прежнему говорить Add to cart" и проверка "не должно стать медленнее" - это три правила на одном и том же синтаксисе, в одном списке, каждое проходит или проваливается само по себе.
Как включить
Режим ассертов находится внутри раздела Проверка ответа редактора монитора, для мониторов HTTP (сайт) и API. Переключите тумблер, и классические поля сменятся пронумерованным списком правил с кнопкой "Add rule" и живым счетчиком, показывающим, сколько правил вы использовали относительно лимита вашего тарифа.

Каждое правило проверяется по мере построения: незавершенное правило несет отдельное состояние "не завершено", а правило, которое редактор способен вычислить, помечается как готовое. У каждого правила также есть небольшая кнопка </>, открывающая его форму в виде обычного текста, так что вы можете прочитать или скопировать точное выражение, а не только смотреть на него по полям.
Мысленная модель: субъект, предикат, значение
У каждого правила одна и та же форма: субъект (код состояния, тело, заголовок, время отклика), предикат (равно, содержит, существует, меньше чем) и, для большинства предикатов, значение для сравнения. status eq 200 - это субъект, предикат и значение; body.json exists - субъект и предикат без значения, потому что "exists" больше ничего не требует.
Построение правила в редакторе начинается с выбора того, что проверять, затем условия, затем значения:

Правила в списке объединяются через AND: проверка проваливается, если провалилось хотя бы одно правило, и проходит, только если прошли все. Оператора OR пока нет, поэтому чтобы принять один из нескольких статусов или строк, выразите это внутри одного правила (status in [200, 301, 302], body containsAny ["In stock", "Pre-order"]). Провалившееся правило называет себя в оповещении, поэтому давайте каждому короткую метку там, где можете, - и оповещение скажет, какое именно ожидание не оправдалось.
Что можно проверять
Селектор группирует субъекты по документу самого ответа (тело, заголовки) и по его транспорту (статус, время, редиректы, TLS). Несколько самых важных субъектов, с полным списком в справочнике ниже:
| Субъект | Что это | Пример |
|---|---|---|
status | Код состояния HTTP итогового ответа, после прохождения редиректов | status isOk |
body | Тело ответа как обычный текст | body contains "Add to cart" |
body.json / body.xml / body.html / body.yaml | Тело, но только когда оно действительно разбирается в этот формат - иначе субъект просто отсутствует | body.json exists |
body.json.path("$.a") | Запрос JSONPath к телу JSON (тот же язык запросов работает и над YAML, поскольку YAML разбирается в ту же модель объекта) | body.json.path("$.status") eq "ok" |
body.size / body.hash | Размер ответа в байтах и отпечаток содержимого тела | body.size gt 1kb |
header("Name") | Один заголовок ответа, по имени | header("Content-Type") isJson |
time и time.connect / time.tls / time.dns / time.head | Общее время отклика и его фазы: сеть, TLS-рукопожатие, DNS и время раздумий сервера | time lt 2s |
redirects / requests | Пройденные проверкой переходы и вся цепочка (включая итоговый ответ) | redirects.count eq 0 |
url и его части (.host, .scheme, .path...) | Итоговый URL, на котором проверка остановилась | url.scheme eq "https" |
cert.days.left | Дней до истечения TLS-сертификата | cert.days.left gt 14 |
Числа принимают суффиксы единиц измерения, чтобы вам никогда не пришлось переводить их вручную: 2s означает 2000 миллисекунд, 1kb означает 1024 байта. Сравнение текста чувствительно к регистру, если не добавить в правило nocase.
Полный справочник
Дальше идет каждый субъект, оператор, редьюсер, сахарная конструкция, фильтр и синтаксическая форма, которые движок ассертов регистрирует для проверок HTTP и API, взятые прямо из собственного реестра движка (те же данные, что питают селекторы редактора правил и его документацию). Записи, которые пока не полностью доступны, несут пометку в скобках: зарезервированные поля, которые движок еще не начал заполнять, кандидаты, еще выкатывающиеся на агенты, и семейство с состоянием, требующее конкретного тарифа. Все, что без такой пометки, работает уже сегодня на любом тарифе с режимом ассертов.
Справочник следует собственной группировке движка: сначала поля ответа, затем способы заглянуть внутрь тела, затем время, сеть и TLS, затем операторы, редьюсеры и сокращения, работающие со всеми ними, а затем виды проверок помимо HTTP, говорящие на том же самом языке.
Ответ
Субъекты, описывающие сам ответ: его статус, его сырое тело, его заголовки, URL, с которого он на самом деле ответил, и цепочку запросов, которая до него довела.
| Имя | Что это | Тип/значения | Пример |
|---|---|---|---|
body | Тело ответа как декодированный текст. | string | body contains "Welcome" |
header | Один заголовок итогового ответа, по имени. | string | header("Content-Type") isJson |
redirects | Пройденные переходы редиректа - цепочка запросов без ее последнего элемента. | collection | redirects.count eq 0 |
status | Код состояния HTTP итогового ответа, после прохождения редиректов. | number | status isOk |
body.size | Размер скачанного тела, в байтах. | number | body.size lt 500000 |
url | URL, который на самом деле ответил, после всех редиректов. url: сравнивайте его как текст либо читайте его части (url.host, .port, .path, .query, .scheme). | url | url.host eq "www.example.com" |
requests | Каждый запрос, сделанный этой проверкой, по порядку - переходы редиректа, а затем итоговый запрос. | collection | requests.count le 2 |
url.host | Часть URL с хостом. | string | url.host eq "example.com" |
url.path | Часть URL с путем. | string | url.path startsWith "/api" |
url.port | Часть URL с портом. | number | url.port eq 443 |
url.query | Строка запроса URL. | string | url.query contains "token" |
url.scheme | Схема URL (http или https). | string | url.scheme eq "https" |
body.hash | Дайджест тела ответа - сравните с previous.body.hash, чтобы обнаружить изменение содержимого. | string | body.hash eq previous.body.hash |
httpVersion (зарезервировано - пока не заполняется) | Согласованная версия HTTP. | string | httpVersion eq "HTTP/2" |
setCookie | Значения Set-Cookie итогового ответа, по одному элементу на cookie - сопоставляйте одно через contains или matches, считайте через .count. | collection | setCookie exists |
steps (пока недоступно) | Шаги многошаговой проверки. Пока недоступно. | collection | steps.count le 1 |
url.original | URL, с которым была настроена проверка, до какого-либо редиректа. url вроде самого url: те же части (url.original.host, .port, .path, .query, .scheme). | url | url.original.scheme eq "http" |
url.original.host | Часть URL с хостом. | string | url.original.host eq "example.com" |
url.original.path | Часть URL с путем. | string | url.original.path startsWith "/start" |
url.original.port | Часть URL с портом. | number | url.original.port eq 80 |
url.original.query | Строка запроса URL. | string | url.original.query contains "utm_" |
url.original.scheme | Схема URL (http или https). | string | url.original.scheme eq "http" |
Два псевдонима: redirectCount - сокращение для redirects.count - redirectCount eq 0 читается чуть естественнее эквивалентной длинной формы, когда вы имеете в виду "проверка ответила напрямую, без редиректов". А setCookie на верхнем уровне - это список cookie итогового ответа; то же имя повторяется на уровне каждого перехода внутри requests/redirects (см. субъекты перехода ниже), храня cookie именно этого запроса.
Извлечение значений из тела
Эти субъекты разрешаются только тогда, когда тело - это именно тот формат, который они называют: пространство имен JSON на HTML-странице просто отсутствует, а не является типизированной ошибкой. Именно поэтому exists - стандартный способ проверить формат, а body.json exists спрашивает, разобралось ли тело как JSON. Каждое из четырех пространств имен форматов несет соответствующую функцию запроса .path(...) (JSONPath для json/yaml, XPath для xml, CSS-селекторы для html) и соответствующий .regex(...), а также не зависящий от формата body.regex(...), читающий сырой текст независимо от формата. body.html.a, body.html.script и body.html.link - это готовые коллекции всех ссылок, скриптов и элементов <link> на странице; см. области элементов ниже про доступные для каждого поля.
| Имя | Что это | Тип/значения | Пример |
|---|---|---|---|
body.json | Тело ответа, но только когда это действительно JSON. | string | body.json exists |
body.json.path | Запрос к телу JSON выражением JSONPath. | json | body.json.path("$.status") eq "ok" |
body.html | Тело ответа, но только когда это действительно HTML. | string | body.html exists |
body.html.path | Выбор элементов страницы CSS-селектором. | collection | body.html.path("h1").first contains "Welcome" |
body.regex | Сопоставление текста регулярным выражением и взятие того, что оно захватило. | string | body.regex("order-(?<id>\\d+)") exists |
body.xml | Тело ответа, но только когда это действительно XML. | string | body.xml exists |
body.xml.path | Запрос к телу XML выражением XPath. | string | body.xml.path("//item/@id") exists |
body.html.a | Каждая ссылка на странице. | collection | body.html.a.count gt 0 |
body.html.link | Каждый элемент <link>, объявленный на странице. Голое упоминание означает цели ссылок. | collection | body.html.link.count gt 0 |
body.html.script | Каждый скрипт, загружаемый страницей. Голое упоминание означает источники скриптов. | collection | body.html.script.count gt 0 |
body.yaml | Тело ответа, но только когда это действительно YAML. | string | body.yaml exists |
body.yaml.path | Запрос к телу YAML выражением JSONPath. | json | body.yaml.path("$.services.web.image") contains ":1." |
body.html.regex | Сопоставление текста регулярным выражением и взятие того, что оно захватило. | string | body.regex("order-(?<id>\\d+)") exists |
body.json.regex | Сопоставление текста регулярным выражением и взятие того, что оно захватило. | string | body.regex("order-(?<id>\\d+)") exists |
body.xml.regex | Сопоставление текста регулярным выражением и взятие того, что оно захватило. | string | body.regex("order-(?<id>\\d+)") exists |
body.yaml.regex | Сопоставление текста регулярным выражением и взятие того, что оно захватило. | string | body.regex("order-(?<id>\\d+)") exists |
Деталь про семейство регулярных выражений, о которой стоит упомянуть отдельно: именованные группы захвата ((?<id>...)) внутри правила .regex(...) записываются в пространство имен привязок, действующее в рамках проверки, а более позднее правило может прочитать их обратно через bind("id") или по позиции через bind[0] - см. захваченные значения ниже.
Захваченные значения
Один субъект живет в собственной группе реестра, потому что он не читает ответ напрямую - он читает то, что захватило более раннее правило.
| Имя | Что это | Тип/значения | Пример |
|---|---|---|---|
bind | Значение, захваченное более ранним правилом regex, по имени захвата или по позиции. | string | bind("id") gt 1000 |
Сочетайте с правилом regex выше по списку: правило вроде body.regex("order-(?<id>\d+)") exists захватывает id заказа в имя id, а более позднее правило может проверить его через bind("id") gt 1000 либо, для позиционного (безымянного) захвата, через bind[0].
Время
Один общий показатель плюс разбивка по фазам, так что оповещение "стало медленнее" может заодно сказать, какая часть стала медленнее.
| Имя | Что это | Тип/значения | Пример |
|---|---|---|---|
time | Общее время отклика: соединение + TLS + ожидание + скачивание. Разрешение DNS не входит. | number | time lt 2000 |
ttfb (зарезервировано - пока не заполняется) | Время до первого байта. | number | ttfb lt 200 |
time.connect | Время установления TCP-соединения. | number | time.connect lt 500 |
time.data | Время скачивания тела ответа. | number | time.data lt 1000 |
time.dns | Время разрешения доменного имени. Не входит в голый субъект time. | number | time.dns lt 200 |
time.head | Время ожидания заголовков ответа. | number | time.head lt 500 |
time.tls | Время TLS-рукопожатия. | number | time.tls lt 300 |
Голый субъект time - это соединение + TLS + ожидание заголовков + скачивание тела. Разрешение DNS исключено и живет только в соседнем time.dns, потому что DNS часто кэшируется, и иначе один и тот же эндпоинт выглядел бы то быстрым, то медленным от проверки к проверке без всякой причины.
Сеть: DNS и соединение
dns и conn - чистые пространства имен в реестре: группа без собственного значения, поэтому правило никогда не может остановиться на голом имени (и редактор, и движок отклоняют цепочку, заканчивающуюся просто на dns или conn, указывая на настоящие поля ниже).
| Имя | Что это | Тип/значения | Пример |
|---|---|---|---|
conn | Сетевое соединение, установленное проверкой - адрес, отдавший ответ, и любые сбои соединения. | string | - |
conn.failed | Сколько из разрешенных адресов не удалось подключить. | number | conn.failed eq 0 |
conn.failedIps (кандидат - выкатывается на агенты) | Разрешенные адреса, к которым не удалось подключиться. | collection | conn.failedIps.count eq 0 |
conn.ip | IP-адрес, который на самом деле отдал ответ. | string | conn.ip eq "203.0.113.10" |
conn.ip.family (кандидат - выкатывается на агенты) | Отдан ли ответ по IPv4 или IPv6. | string | conn.ip.family eq "IPv4" |
dns | Разрешение DNS отслеживаемого имени - в какие адреса оно разрешилось и какой сервер ответил. | string | - |
dns.ips | Все IP-адреса, в которые разрешилось доменное имя во время этой проверки. | collection | dns.ips contains "1.2.3.4" |
dns.server | DNS-сервер, ответивший на разрешение. | string | dns.server eq "8.8.8.8" |
TLS и сертификат
Как и dns и conn, tls и cert - чистые пространства имен: факты о сертификате/рукопожатии живут на уровень ниже.
| Имя | Что это | Тип/значения | Пример |
|---|---|---|---|
cert.days.left | Дней до истечения сертификата сайта. | number | cert.days.left gt 14 |
cert | Сертификат, предъявленный сервером - дни до истечения, издатель и поля идентификации. | string | - |
cert.days | Дней с момента выпуска сертификата. | number | cert.days gt 0 |
cert.issuer | Удостоверяющий центр, выпустивший сертификат сайта. | string | cert.issuer contains "Let's Encrypt" |
cert.san | Доменные имена, для которых действителен сертификат. | collection | cert.san contains "www.example.com" |
cert.serial | Серийный номер сертификата. | string | cert.serial exists |
cert.subject (зарезервировано - пока не заполняется) | Субъект сертификата. Пока не собирается - появится с будущей версией агента. | string | cert.subject contains "example.com" |
tls | TLS-рукопожатие защищенного соединения - согласованная версия протокола и шифр. | string | - |
tls.cipher | Согласованный набор шифров. | string | tls.cipher contains "AES" |
tls.protocol | Согласованная версия TLS. | string | tls.protocol eq "Tls13" |
cert.subject приведен здесь для полноты, но пока не заполняется - см. раздел о честности ниже про то, что на практике означает "зарезервировано". Повседневное правило для сертификата - cert.days.left gt 14, разобранное в разделе с готовыми правилами.
Субъекты перехода: поля внутри requests и redirects
requests и redirects - это коллекции, и каждый элемент - полная запись запроса/ответа со своим сокращенным набором полей. Не каждый субъект верхнего уровня имеет смысл на уровне одного перехода (у перехода нет собственного сертификата), а одно поле существует только на уровне перехода: hstsHeader, заголовок Strict-Transport-Security этого запроса в цепочке.
| Имя | Что это | Тип/значения | Пример |
|---|---|---|---|
status | Код состояния этого запроса в цепочке. | number | status eq 200 |
url | URL, на который был сделан этот запрос. | url | url startsWith "https://" |
header | Заголовок ответа этого запроса. Переход хранит сокращенную запись заголовка с одним значением - списочные предикаты (containsAny, containsAll, unique) применимы только к заголовку итогового ответа. | string | header("Content-Type") contains "json" |
hstsHeader | Заголовок Strict-Transport-Security этого запроса. | string | requests[0].hstsHeader exists |
setCookie | Значения заголовка Set-Cookie этого запроса. | collection | setCookie exists |
url.original | URL, с которым была настроена проверка, до какого-либо редиректа. url вроде самого url: те же части (url.original.host, .port, .path, .query, .scheme). | url | url.original.scheme eq "http" |
url.host | Часть URL с хостом. | string | url.host eq "example.com" |
url.port | Часть URL с портом. | number | url.port eq 443 |
url.path | Часть URL с путем. | string | url.path startsWith "/api" |
url.query | Строка запроса URL. | string | url.query contains "token" |
url.scheme | Схема URL (http или https). | string | url.scheme eq "https" |
url.original.host | Часть URL с хостом. | string | url.original.host eq "example.com" |
url.original.port | Часть URL с портом. | number | url.original.port eq 80 |
url.original.path | Часть URL с путем. | string | url.original.path startsWith "/start" |
url.original.query | Строка запроса URL. | string | url.original.query contains "utm_" |
url.original.scheme | Схема URL (http или https). | string | url.original.scheme eq "http" |
Значение header(...) для одного перехода хранит сокращенную запись с одним значением: списочные предикаты вроде containsAny или unique имеют смысл только для полной карты заголовков итогового ответа, поэтому применяются только там, а не для каждого перехода. Две коллекции означают разное. requests - это вся цепочка, включая итоговый ответ, который в итоге ответил, поэтому она никогда не пуста даже для прямого 200, а redirects - только переходы, пройденные по пути, и пуста, если редиректов не было вовсе.
Области элементов: поля внутри одного элемента коллекции
Область элемента - это набор полей, доступных для ОДНОГО элемента коллекции - после индексации в него (requests[0]) или при фильтрации через where(current. ...) (см. следующий раздел). Шесть коллекций несут собственную область элемента: четыре коллекции элементов HTML имеют одну общую форму, а requests/redirects используют форму субъектов перехода, описанную чуть выше.
| Область элемента | Как выглядит один элемент |
|---|---|
body.html.path | Один элемент, найденный CSS-запросом body.html.path("selector"). |
body.html.a | Один элемент <a> из body.html.a. |
body.html.script | Один элемент <script> из body.html.script. |
body.html.link | Один элемент <link> из body.html.link. |
requests | Один запрос в полной цепочке (см. таблицу субъектов перехода выше). |
redirects | Один пройденный переход редиректа (те же поля, что и у requests, см. выше). |
Общая форма для body.html.path(...), body.html.a, body.html.script и body.html.link - по одной строке на ссылку, тег скрипта или элемент <link>:
| Имя | Что это | Тип/значения | Пример |
|---|---|---|---|
url | Цель ссылки ровно так, как ее записывает разметка. | string | body.html.a.url contains "/checkout" |
text | Видимый текст элемента. | string | body.html.a.text contains "Sign in" |
absolute | Цель ссылки, разрешенная относительно URL страницы в абсолютный адрес - список url, с частями url, доступными для каждого элемента (.host, .path, .port, .query, .scheme). | url | body.html.a.absolute.scheme in ["https"] |
rel | Атрибут rel элемента. | string | body.html.a.where(current.rel eq "nofollow").count eq 0 |
absolute.host | Часть URL с хостом. | string | body.html.a.absolute.host.unique.count le 3 |
absolute.port | Часть URL с портом. | number | body.html.a.absolute.port in [443] |
absolute.path | Часть URL с путем. | string | body.html.a.absolute.path startsWith "/" |
absolute.query | Строка запроса URL. | string | body.html.a.absolute.query not contains "session" |
absolute.scheme | Схема URL (http или https). | string | body.html.a.absolute.scheme in ["https"] |
Прежде чем писать правило против этих коллекций, действуют два умолчания. Голое упоминание body.html.a (или .script/.link) означает его проекцию .url, поэтому body.html.a.count gt 0 считает href-ы, а сохраненное правило перечитывается со спелленной формой .url, потому что сохраненное правило всегда говорит ровно, что оно вычисляет. И .url - это сырой атрибут href ровно так, как его написала разметка, так что относительная ссылка остается относительной; .absolute - та же ссылка, разрешенная относительно собственного URL страницы, что и нужно при проверке схемы или хоста исходящих ссылок (body.html.a.absolute.scheme in ["https"]).
Операторы
Предикатная половина каждого правила: какую проверку выполнить над субъектом. Все 15 общие для любого вида проверки, а какие из них подходят конкретному субъекту, зависит от его типа (код состояния принимает lt/gt, тело принимает contains, коллекция принимает exists/unique/in).
| Имя | Что это | Применяется к | Пример |
|---|---|---|---|
eq | Равно. Против литерала json("…") / xml("…") / yaml("…") - это ТОЧНОЕ структурное совпадение: те же ключи (в любом порядке), массивы по порядку, те же значения. | любой тип | body.json eq json("{\"ok\": true}") |
lt | Меньше чем. | числа | time lt 2000 |
le | Меньше или равно. | числа | cert.days.left le 30 |
gt | Больше чем. | числа | body.size gt 0 |
ge | Больше или равно. | числа | status ge 500 |
contains | Содержит текст - для списка проходит, когда значение ЯВЛЯЕТСЯ одним из элементов (точное совпадение; используйте matches для поиска внутри элементов). Против литерала json("…") / xml("…") / yaml("…") - это СТРУКТУРНОЕ включение: все, что указано в литерале, должно присутствовать и совпадать; в ответе может быть больше. | текст или список | body.json contains json("{\"status\": \"ok\"}") |
startsWith | Начинается с текста - для списка, когда это верно для ЛЮБОГО элемента. | текст | url.path startsWith "/api" |
endsWith | Заканчивается текстом - для списка, когда это верно для ЛЮБОГО элемента. | текст | url.path endsWith ".json" |
matches | Совпадает с регулярным выражением где-либо в тексте - для списка, когда это верно для ЛЮБОГО элемента. | текст | body matches "order-\\d+" |
containsAny | Содержит хотя бы одно из перечисленных значений (для списка: какой-то элемент РАВЕН одному из них). | список | body containsAny ["In stock", "Pre-order"] |
containsAll | Содержит каждое из перечисленных значений (для списка: каждое значение равно какому-то элементу - подтверждающие элементы могут различаться). | список | body.html.a.text containsAll ["Home", "Contact"] |
in | Является одним из перечисленных значений или диапазонов - для списка, верно для каждого элемента. | значение(я) или диапазон | status in [200, 301, 302] |
exists | Субъект присутствует. | любой субъект | header("ETag") exists |
isNumber | Значение читается как число. | текст или любой тип | bind("id") isNumber |
unique | В списке нет дубликатов. | список | dns.ips unique |
Два оператора значат нечто более узкое, чем кажется на слух. contains для списка - это точное членство: значение должно быть равно целому элементу, а не встречаться как подстрока внутри одного из них, поэтому для поведения "подстрока" внутри элементов коллекции используйте matches. А eq против литерала json(...)/xml(...)/yaml(...) - это полное структурное совпадение (те же ключи, массивы в том же порядке, те же значения), тогда как contains против такого же литерала - структурное включение: все, что указывает литерал, должно присутствовать, но реальный ответ может нести больше.
Редьюсеры
Редьюсер сворачивает коллекцию в одно значение и может стоять только в конце цепочки. Примеры ниже используют requests.status, естественно числовую коллекцию из субъектов HTTP, для иллюстрации; те же восемь редьюсеров работают над любой числовой коллекцией в любом виде проверки (времена кругового пути проверки Ping, отфильтрованный набор строк базы данных).
| Имя | Что сворачивает | Применяется к | Пример |
|---|---|---|---|
count | Сколько элементов в списке. | любая коллекция | requests.count le 2 |
min | Наименьшее число в списке. | числовая коллекция | requests.status.min ge 200 |
max | Наибольшее число в списке. | числовая коллекция | requests.status.max lt 500 |
sum | Сумма чисел в списке. | числовая коллекция | requests.status.sum gt 0 |
avg | Среднее чисел в списке. | числовая коллекция | requests.status.avg lt 300 |
first | Первый элемент списка. | любая коллекция | redirects.status.first eq 301 |
last | Последний элемент списка. | любая коллекция | requests.status.last eq status |
unique | Список без дубликатов. | любая коллекция | dns.ips.unique.count le 3 |
unique перегружен, и написание отличает эти два значения друг от друга. В форме оператора без точки (x unique) это предикат: "в этой коллекции нет дубликатов" - и он проваливается, называя повтор. В форме редьюсера с точкой (x.unique) это преобразование, сама дедуплицированная коллекция, за которой все еще что-то нужно (x.unique.count eq 1). Висящий x.unique без чего-либо после него - синтаксическая ошибка, потому что движок не может угадать, какой из двух вариантов вы имели в виду.
Сахар
Сахарные предикаты - это сокращения, которые движок разворачивает в обычные базовые предикаты еще до того, как правило вообще отправляется агенту - добавление сахарного предиката ничего не стоит дополнительно (не нужен бандл агента, не нужен порог версии), потому что к моменту попадания на провод он уже выглядит как обычное правило. Предпочитайте сахар везде, где он есть: он читается лучше и полностью эквивалентен написанию длинной формы вручную.
| Имя | Что это значит | Применяется к | Пример |
|---|---|---|---|
isOk | Статус - код успеха (200-299). | status | - |
isRedirect | Статус - код редиректа (300-399). | status | status isRedirect |
isClientError | Статус - ошибка клиента (400-499). | status | status isClientError |
isServerError | Статус - ошибка сервера (500-599). | status | status isServerError |
isJson | Содержимое действительно JSON. | документ или текст медиатипа | header("Content-Type") isJson |
isXml | Содержимое действительно XML - тело разбирается как XML либо заголовок называет медиатип XML. | документ или текст медиатипа | body isXml |
isHtml | Содержимое действительно HTML - тело разбирается как HTML либо заголовок называет медиатип HTML. | документ или текст медиатипа | body isHtml |
isForm | Медиатип называет форматом кодировки формы: application/x-www-form-urlencoded или multipart/form-data. В отличие от isJson/isXml/isHtml, здесь нет соответствующего пространства имен тела, так что применимо только к значению медиатипа, например к заголовку Content-Type. | только текст медиатипа | header("Content-Type") isForm |
isEmpty | Ничего нет: пустой текст, нулевой размер или пустой список. | текст, размер или список | body isEmpty |
isNull | Значение равно null. | любое значение | body.json.path("$.deletedAt") isNull |
absent | Субъект вообще отсутствует. | любой субъект | header("X-Debug") absent |
between | Число в пределах включительного диапазона. | числа (2 операнда) | body.size between 50 and 500kb |
isJson/isXml/isHtml намеренно зависят от контекста, и то, на чем вы их пишете, определяет применяемое значение. Написанные на самом документе (body isJson) они значат "разбирается ли это как данный формат" - то же самое, что body.json exists. Написанные на текстовом значении, называющем медиатип, например на заголовке (header("Content-Type") isJson), они значат "называет ли это семейство MIME данного формата"; см. семейства MIME ниже про то, какие медиатипы подходят. У isForm есть только второе значение, поскольку пространства имен body.form для разбора не существует, поэтому body isForm - статическая ошибка, а не правило, которое просто никогда не может быть истинным.
Фильтр where(...)
Оставить только подходящие элементы и продолжить работу с ними. Это единственная фильтрующая конструкция в языке, и у нее ровно одна форма: where(current.<field> <condition> <value>).
Фильтрация отличается от проекции: requests.url contains "cart" спрашивает, существует ли такой переход вообще в цепочке, а requests.where(current.url contains "cart").status спрашивает, что вернул именно этот переход. Фильтрация не сворачивает список, поэтому завершайте выражение через .first, проверку in [...] или .count. Она идет только на один уровень и принимает ровно одно условие.
| Часть | Что называет | Заметки |
|---|---|---|
current.<field> | Поле каждого фильтруемого элемента, записанное после current. | Это та половина, в которой чаще всего ошибаются: current.url - это URL отдельного перехода, а не итогового ответа. После current. могут идти только собственные поля элемента. |
| условие | Любой обычный предикат, включая not и nocase | Любое условие, работающее на верхнем уровне правила, работает и здесь. |
| значение | С чем сравнивается поле каждого элемента | Обычно простое значение. Субъект, написанный здесь, читается из ВНЕШНЕГО ответа, а не из элемента - where(current.url eq url.original) сравнивает каждый переход с URL, с которым была настроена проверка, поэтому сторона элемента должна явно говорить current.. |
Пример: requests.where(current.url contains "cart").status.first eq 301 - оставить только переходы, чей URL содержит "cart", затем посмотреть статус первого из подошедших.
Еще два ограничения, оба проверяются парсером с собственным сообщением: where нельзя вложить внутрь другого where, а его аргумент - ровно одно условие, без and/or внутри. Он применим только к коллекции, элементы которой несут именованные поля (requests, body.html.a), а не к простому спроецированному списку вроде dns.ips, где для current. просто нечего называть.
Справочник по синтаксису
Все остальное, что определяет грамматика: как назвать правило, как писать диапазоны и списки, что значит голый субъект, и небольшие пунктуационные формы, встречающиеся во многих правилах.
| Форма | Что делает | Вид | Пример |
|---|---|---|---|
where | Оставить только подходящие элементы и продолжить работу с ними. | фильтр коллекции | requests.where(current.url contains "cart").status.first eq 301 |
not | Инвертирует следующее за ним условие. | флаг | body not contains "error" |
nocase | Сравнивает текст без учета регистра. | флаг | body contains "welcome" nocase |
current | Внутри where(…) называет один фильтруемый элемент. | ссылка на элемент (внутри where) | requests.where(current.status eq 301) |
range | Диапазон чисел, ОБА конца ВКЛЮЧЕНЫ. | числовой диапазон | status in [200..299] |
list | Список значений для сравнения. | список значений | status in [200, 301, 302] |
docLiteral | Типизированное значение документа для структурного сравнения: текст в кавычках разбирается как JSON, XML или YAML при сохранении правила. | текст json/xml/yaml | body.json contains json("{\"user\": {\"active\": true}}") |
implicitExists | Правило, называющее только субъект, проверяет его присутствие: запись просто body.json сохраняется как body.json exists. | строка с голым субъектом | body.json |
index | Выбирает ОДИН элемент списка по позиции, считая от 0. | 0-based целое | requests[0].status |
label | Необязательное имя правила, записанное перед двоеточием. | имя перед двоеточием | "json ok": body.json exists |
comment | Все после # - заметка для себя; на проверку не влияет. | текст после # в конце строки | status isOk # the happy path |
Несколько пунктов стоит объяснить обычным языком. label дает правилу имя, которое отображается в оповещении вместо отрисованного выражения; пишите его перед двоеточием, как в "json ok": body.json exists. implicitExists означает, что строка, называющая только субъект без предиката, - это сокращение для exists: запись body.json сохраняется как body.json exists, и при повторном открытии правила видна развернутая форма. range и list - это две формы, которые может принимать значение после in: диапазон ([200..299], оба конца включены) или явный список ([200, 301, 302]), и значение может быть открытым с любой стороны ([400..]). docLiteral - это обертка json(...)/xml(...)/yaml(...), используемая для структурного сравнения с телом (разобрана в разделе "Операторы" выше и в готовых правилах ниже). index выбирает один элемент из коллекции по позиции, с отсчетом от 0, так же как bind[0] читает позиционный захват. current имеет смысл только внутри фильтра where(...), разобранного в собственном разделе выше.
Обертки: previous, delta и delta2
Три формы, которые смотрят назад, а не только на текущий ответ - каждая доступна на тарифах с ассертами с состоянием, и каждая подробно объяснена в разделе "Сравнение с предыдущей проверкой" ниже.
| Имя | Что это | Тип/значения | Пример |
|---|---|---|---|
delta (требует тариф с ассертами с состоянием) | Насколько изменилось числовое значение с предыдущей проверки - опционально как скорость за мс/с/мин/ч. | number | delta(body.size, h) lt 1mb |
delta2 (требует тариф с ассертами с состоянием) | Изменение изменения - ускоряется ли значение? | number | delta2(time) gt 0 |
previous (требует тариф с ассертами с состоянием) | Значение этого субъекта на предыдущей проверке. | any | status eq previous.status |
Флаги: not и nocase
Два модификатора, которые присоединяются к правилу, а не выступают самостоятельными субъектами или предикатами.
| Флаг | Что делает | Вид | Пример |
|---|---|---|---|
not | Инвертирует следующее за ним условие. | флаг (присоединяется к правилу) | body not contains "error" |
nocase | Сравнивает текст без учета регистра. | флаг (присоединяется к правилу) | body contains "welcome" nocase |
not сочетается со следующим за ним предикатом, а не отрицает все правило целиком - x not != y читается как x eq y, а не как двойное отрицание. Когда субъект может вовсе отсутствовать, предпочитайте сахар absent вместо not exists: оба значат ровно одно и то же, но absent говорит об этом прямо. nocase меняет что-либо только при действительно текстовом сравнении; редактор (и этот справочник) все равно позволяют написать его где угодно, но на числовой проверке вроде status eq 200 nocase он молча ничего не значит.
Семейства MIME
Таблицы соответствий за isJson, isXml, isHtml и isForm, когда они применяются к значению медиатипа, например к заголовку. Каждое семейство соответствует очевидному медиатипу верхнего уровня плюс, для JSON и XML, любому типу, оканчивающемуся на соответствующий суффикс структурированного синтаксиса - именно это заставляет header("Content-Type") isJson корректно срабатывать на application/problem+json или application/vnd.api+json, а не только на чистый application/json.
| Семейство | Соответствует | Парный сахар | Пример |
|---|---|---|---|
json | application/json, text/json или любой медиатип, оканчивающийся на +json (application/problem+json, application/vnd.api+json, application/ld+json, ...). | сахар: isJson | header("Content-Type") isJson |
xml | application/xml, text/xml или любой медиатип, оканчивающийся на +xml (image/svg+xml, application/atom+xml, ...). | сахар: isXml | header("Content-Type") isXml |
html | text/html или application/xhtml+xml. | сахар: isHtml | header("Content-Type") isHtml |
form | application/x-www-form-urlencoded или multipart/form-data. | сахар: isForm | header("Content-Type") isForm |
Сопоставление игнорирует все, начиная с первого ; (так что application/json; charset=utf-8 все равно совпадает), и нечувствительно к регистру.
Субъекты для проверок базы данных, счетчика, SNMP, порта и ping
Каждый оператор, редьюсер, сахарная конструкция и синтаксическая форма выше идентичны для этих пяти видов проверок: движок регистрирует одни и те же 15 операторов, 8 редьюсеров, 12 сахарных предикатов и 11 синтаксических форм для всех шести видов без исключения. Различается по видам список субъектов. Каждый вид предоставляет небольшой набор субъектов, уникальных для того, что он измеряет, плюс подмножество уже описанных выше субъектов сети/времени/TLS, чей смысл подстраивается под вид (у проверки Database субъект time - это соединение-плюс-запрос, а не соединение-плюс-TLS-плюс-скачивание, поскольку HTTP-ответа для скачивания там нет).
Проверки базы данных
Делит time, time.connect и time.dns с субъектами, описанными выше (переосмысленными для соединения с базой данных: соединение-плюс-запрос, разрешение DNS хоста базы данных). Уникальны для проверок базы данных:
| Имя | Что это | Тип/значения | Пример |
|---|---|---|---|
scalar | Единственное значение, которое вернул запрос (режим Scalar). | any | - |
rows | Строки, затронутые или возвращенные запросом (режим NonQuery). | collection | - |
time.query | Время, которое занял сам запрос. | number | - |
Разобранный пример - в следующем разделе: используйте rows.count, чтобы проверить, сколько строк затронул или вернул запрос, и scalar, чтобы проверить напрямую одно возвращенное значение.
Проверки Counter
Делит time с субъектами, описанными выше - как поле в статусе "кандидат" именно для проверок Counter (время кругового пути запроса счетчика; см. раздел о честности про то, что означает "кандидат"). Уникально для проверок Counter:
| Имя | Что это | Тип/значения | Пример |
|---|---|---|---|
value | Измеренное значение счетчика. | number | - |
Проверки SNMP
Делит time и time.dns с субъектами, описанными выше (разрешение имени хоста плюс сам запрос SNMP). Уникально для проверок SNMP:
| Имя | Что это | Тип/значения | Пример |
|---|---|---|---|
time.request | Время, которое занял запрос SNMP. | number | - |
value | Значение, которое вернул OID. | any | - |
value.type (кандидат - выкатывается на агенты) | Имя типа данных SNMP для возвращенного значения. | string | - |
value.type в статусе "кандидат"; см. раздел о честности. Примечание о доступности: переключатель проверки ответа в режиме ассертов пока не добрался до редактора монитора SNMP. Он показывает панель "Coming soon", называющую эти два субъекта, а не работающий список правил. Сами субъекты и вычислитель под ними уже зарегистрированы; ожидает своей очереди только интерфейс редактора SNMP.
Проверки портов
Самый большой общий список среди всех видов, кроме HTTP. Проверка TCP-порта несет практически тот же набор субъектов соединения, DNS, TLS и сертификата, что и HTTP-проверка, поскольку проверка порта тоже может согласовывать TLS: bind, cert и его шесть подполей, conn и его четыре подполя, dns и его два подполя, time/time.connect/time.dns/time.tls, а также tls/tls.cipher/tls.protocol - все описаны в разделах выше, с теми же значениями. Уникально для проверок портов:
| Имя | Что это | Тип/значения | Пример |
|---|---|---|---|
banner | Данные, прочитанные из сокета после подключения. | string | - |
banner.hash (кандидат - выкатывается на агенты) | Дайджест баннера - сравните с previous.banner.hash, чтобы обнаружить изменение сервиса. | string | - |
banner.regex | Сопоставление текста регулярным выражением и взятие того, что оно захватило. | string | body.regex("order-(?<id>\\d+)") exists |
banner.size (кандидат - выкатывается на агенты) | Размер баннера, в байтах. | number | - |
banner.hash и banner.size в статусе "кандидат" - см. раздел о честности. banner.regex уже работает сегодня и действует точно так же, как body.regex(...) в HTTP-проверке: именованные захваты питают то же пространство имен bind(...).
Проверки Ping
Делит субъекты соединения и DNS с разделами выше: conn, conn.failed, conn.failedIps, conn.ip, conn.ip.family, dns, dns.ips, dns.server, time (здесь - среднее время кругового пути успешных ответов) и time.dns. Уникально для проверок Ping:
| Имя | Что это | Тип/значения | Пример |
|---|---|---|---|
loss | Процент эхо-запросов, оставшихся без ответа. | number | loss eq 0 |
reply | Успешные эхо-ответы. | collection | - |
sentCount (кандидат - выкатывается на агенты) | Сколько эхо-запросов было отправлено. | number | - |
time.max | Время кругового пути самого медленного ответа. | number | - |
time.min | Время кругового пути самого быстрого ответа. | number | - |
ttl | TTL первого успешного ответа - сравните с previous.ttl, чтобы заметить смену маршрута. | number | - |
sentCount в статусе "кандидат" - см. раздел о честности. О ttl стоит знать даже вне строгого правила прохождения/провала: сочетание с previous.ttl (см. обертки выше) сигнализирует о смене маршрута между проверками, поскольку время жизни пакета к моменту прибытия отражает, сколько переходов он прошел.
Правила, которые люди действительно хотят писать
Страница работает и действительно говорит то, что нужно
Один код состояния не может сказать вам, что страница отрисовалась правильно - ответ 200 с пустой оболочкой - классический тихий сбой, который проверка только по статусу пропускает.
status isOk
body contains "Add to cart"
API отвечает JSON и нужным полем
Проверьте, что эндпоинт по-прежнему говорит на JSON, затем загляните внутрь. Первая строка ловит HTML-страницу ошибки, отданную там, где должен быть JSON, - частая форма сбоя за прокси; вторая проверяет собственное сообщаемое здоровье API, а не только статус транспорта.
body isJson
body.json.path("$.status") eq "ok"
Ответ стал медленнее, чем должен
Разбейте на части, когда нужно знать, что чинить, а не просто то, что что-то медленно - time.connect, time.tls, time.dns и time.head разделяют время сети, рукопожатия, резолвера и приложения.
time lt 2s
Редирект увел посетителей с вашего собственного домена
Сравнивает, куда в итоге пришла проверка, с URL, который вы настроили - проваливается в тот момент, когда цепочка редиректов, взломанная, неверно настроенная или просто измененная деплоем, приводит не туда, куда вы рассчитывали.
url.host eq url.original.host
Страница изменилась с последней проверки
Полезно для содержимого, которое должно быть стабильным между проверками - цены, условия, опубликованная политика, - а заодно служит базовым сигналом дефейса.
previous.body.hash eq body.hash
Число в диапазоне, записанное коротким способом
Ловит и урезанную страницу, и разросшуюся одним и тем же правилом, без явного написания диапазона.
body.size between 50 and 500kb
Сертификат, который вот-вот истечет
Самая частая проверка TLS, и она же - та, что простой монитор вверх/вниз вообще не способен выразить: сертификат, который сегодня еще проходит проверку, но истекает на следующей неделе, не дает никакого другого предупреждающего сигнала. Сочетайте с cert.issuer, если хотите заодно поймать сертификат, тихо выпущенный не тем удостоверяющим центром.
cert.days.left gt 14
Запрос к базе данных возвращает не то число строк
В проверке Database rows - это коллекция, затронутая или возвращенная запросом - подсчет ловит запрос, который должен возвращать ровно одну запись об аккаунте, но начал незаметно возвращать ноль (удалена, либо сломался join) или больше одной (дубликат, которого не должно существовать).
rows.count eq 1
Значение SNMP уходит за пределы диапазона
Устройство SNMP, которое вообще отвечает, - это не то же самое, что здоровое устройство: отслеживаемый OID (использование диска, глубина очереди, температура) может подняться далеко за безопасный порог, пока само устройство остается прекрасно доступным. Сравнение опрошенного value с диапазоном ловит то, что не способна поймать простая проверка доступности.
value lt 90
Служба TCP отвечает не тем баннером
Порт, принимающий соединения, - это не то же самое, что нужная служба, слушающая на нем: зависший процесс, неверно настроенный прокси или подмененная/устаревшая служба - все они по-прежнему способны завершить TCP-рукопожатие. Чтение приветственного текста, который служба отправляет сразу после подключения (баннер SMTP, FTP или похожий), ловит то, что не способна поймать голая проверка "порт открыт".
banner contains "220"
Сравнение с предыдущей проверкой
Горстка субъектов смотрит назад, а не только на текущий ответ: поставьте previous. перед субъектом, чтобы прочитать, каким он был на прошлой проверке, либо оберните его в delta(...), чтобы получить разницу между тогда и сейчас, либо в delta2(...), чтобы получить изменение этого изменения - полезно, чтобы заметить значение, которое ускоряется, а не просто дрейфует (время отклика, растущее все быстрее с каждой проверкой). previous.body.hash eq body.hash выше - это ровно оно: "совпадает ли отпечаток тела с тем, каким он был в прошлый раз". delta(body.size, h) читает изменение как скорость в час вместо сырой разницы - для значений, которые вы ожидаете расти постепенно, а не скачками.
В первый раз, когда такое правило выполняется, ему не с чем сравнивать, поэтому оно пропускается, а не проваливается: проверка помечается как "прогревается", а не как сломанная, и добавление такого правила не поднимает ложного оповещения. Прогрев применяется только тогда, когда текущее чтение исправно, а базового значения нет. Если само текущее чтение проваливается (скажем, тело в этот раз не валидный JSON), правило проваливается точно так же, как провалилась бы его обычная версия без previous.. Такому правилу также нужно, чтобы значение менялось между проверками, из-за чего оно бессмысленно для метода проверки, который никогда не продвигает состояние, например для запроса HEAD.
Сравнение с предыдущей проверкой требует тарифа более высокого уровня; без него эти субъекты отображаются в редакторе серыми, с объяснением.
Лимиты и то, чего здесь намеренно нет
Сколько правил можно добавить, зависит от вашего тарифа, показано живым счетчиком рядом с "Add rule". Движок также применяет абсолютный потолок для любой проверки независимо от тарифа - это защита от злоупотреблений, а не ограничение обычного использования: проверка с числом правил, приближающимся к этому потолку, уже была бы необычно большой.
Нет способа написать для правила собственный JavaScript, и не будет никогда. Каждое правило строится из фиксированного, именованного словаря субъектов и предикатов, а не из открытой песочницы для скриптов, что делает правило читаемым с первого взгляда и безопасным для выполнения на каждом агенте мониторинга по всему миру.
Не каждое правило работает везде в момент написания: некоторым более новым условиям нужна свежая версия агента мониторинга, выполняющего вашу проверку, поэтому новой возможности требуется время, чтобы дойти до каждой проверки на вашем аккаунте по мере фонового обновления агентов. Правила, построенные на стабильном ядре языка, этого не касаются.
Горстка записей в этом справочнике пока не полностью доступна, и каждая помечена в своей таблице выше:
- Зарезервировано (объявлено, но пока не заполняется ни одним агентом):
ttfb,httpVersion,cert.subject. - Кандидат (уже выкатывается, но пока не на каждом агенте):
conn.ip.familyиconn.failedIpsв проверках HTTP, Port и Ping,value.typeв проверках SNMP,banner.hashиbanner.sizeв проверках Port,sentCountв проверках Ping, и собственныйtimeпроверки Counter. - Пока недоступно:
steps, зарезервировано для будущего многошагового вида проверки. - Требует тариф с ассертами с состоянием: все семейство оберток
previous/delta/delta2, для любого вида проверки.
Все остальное в этом справочнике работает уже сегодня на любом тарифе с режимом ассертов.
Где режим ассертов работает уже сегодня
Переключатель проверки ответа для режима ассертов появляется на мониторах HTTP (сайт) и API, которые используют один и тот же редактор правил и синтаксис. Тот же язык и тот же вычислитель уже работают на уровне протокола под проверками Database, Counter, Port, Ping и SNMP: реестр выше обслуживает все шесть видов проверок, и правило, сохраненное для одного из них, читается так же, если режим позже доберется до редактора другого типа.
SNMP показывает самый ясный предпросмотр: в его редакторе уже есть панель правил ассертов, называющая value и value.type, с пометкой "Coming soon", но пока без работающего списка правил за ней. Проверки Database, Counter и Ping вообще не показывают панель режима ассертов, хотя их субъекты в движке под капотом точно так же живы.
Настройка настоящей проверки
Если вы проверяете REST API, а не простую веб-страницу, начните с проверки ответов API, которая охватывает аптайм, время отклика и тело вашего собственного API вместе. Для страницы или сайта, которые должны оставаться доступными и отвечать правильно отовсюду, где находятся ваши пользователи, глобальный мониторинг аптайма из 300+ локаций - более широкая картина, в которую встраивается режим ассертов. Чтобы задавать правила через код, а не через панель, собственный API v2 HostTracker создает и обновляет правила ассертов монитора точно так же, как это делает редактор. Про правило истечения сертификата выше и все, что касается TLS, читайте в мониторинге домена и TLS-сертификата, который охватывает тип проверки, на котором живут cert.days.left и другие субъекты TLS. Чтобы прямо сейчас увидеть, как одно правило вычисляется для настоящего URL, без аккаунта, используйте бесплатный инструмент HTTP-проверки. Про коды состояния, с которыми сравнивает субъект status, начните с 200 OK, а руководства по мониторингу расскажут о настройке каждого вида проверки, под которым работает этот язык.
Часто задаваемые вопросы
Что происходит с моими старыми настройками кода состояния и ключевого слова, если я включу режим ассертов?
Пока режим включен, их заменяет список правил. Выключение режима обратно перед сохранением восстанавливает классические поля точно такими, какими они были: ничего не удаляется, просто оба режима не могут быть активны одновременно.
Можно ли объединить несколько условий в одном мониторе?
Да: каждое правило в списке должно пройти. Оператора "OR" между отдельными правилами пока нет, поэтому чтобы принять одно из нескольких значений, используйте одно правило с in [...] или containsAny [...].
Позволит ли режим ассертов когда-нибудь написать собственный скрипт?
Нет. Каждое правило составляется из фиксированного набора субъектов и предикатов языка. Никакого собственного JavaScript, и это осознанное решение.
Что происходит при первом добавлении правила, сравнивающего с предыдущей проверкой?
Сравнивать пока не с чем, поэтому оно помечается как прогревающееся и пропускается, а не проваливается. Добавление правила "изменилось ли это" само по себе никогда не поднимает ложное оповещение.
Нужен ли для режима ассертов конкретный тариф?
Сам режим и повседневные правила (статус, тело, заголовки, время, редиректы) широко доступны; сколько правил можно добавить одновременно, зависит от вашего тарифа и отображается живьем прямо в редакторе. Правилам, сравнивающим с предыдущей проверкой (previous, delta, delta2), нужен тариф более высокого уровня, и они отображаются серыми с объяснением.
Работает ли режим ассертов на мониторах API так же, как на мониторах сайта?
Да. Мониторы HTTP и API используют один и тот же редактор правил, субъекты и предикаты, и правило, написанное для одного из них, читается идентично на другом.
Что на самом деле делает where(...), и когда он нужен?
Он отфильтровывает коллекцию до элементов, подходящих под условие, прежде чем вы читаете поле результата. Используйте его, когда простой проекции вроде requests.status недостаточно конкретно и вам нужен один конкретный переход, ссылка или элемент, а не вся коллекция целиком (см. раздел выше).
Можно ли уже сегодня написать правило для запроса к базе данных, значения SNMP, баннера порта или результата ping?
Язык и вычислитель поддерживают все это, и таблицы субъектов выше охватывают каждый из них. Редактор правил - нет: переключатель проверки ответа сегодня показывают только мониторы HTTP и API. SNMP показывает предпросмотр "Coming soon" для своих двух субъектов, а проверки Database, Counter и Ping вообще не показывают панель режима ассертов.
Почему некоторые субъекты в этом справочнике помечены как "зарезервировано" или "кандидат", а не просто перечислены как обычно?
"Зарезервировано" значит, что поле объявлено в реестре, но пока ни один агент его не заполняет; "кандидат" значит, что оно уже выкатывается на агенты, но пока не дошло до всех. Оба случая отмечены везде, где встречаются в этом справочнике, и в сводном списке в разделе "Лимиты" выше.