Modalità assert: referenza completa alla validazione della risposta
La modalità assert sostituisce i campi fissi di successo/fallimento di un monitor con un elenco di regole che scrivi tu stesso, ciascuna delle quali nomina esattamente cosa deve essere vero della risposta. La maggior parte dei monitor di uptime giudica un controllo con una manciata di campi fissi: un codice di stato che conta come "down", un elenco di stati da ignorare, forse una parola chiave che deve comparire da qualche parte nel corpo. Questi campi non possono esprimere un'API che risponde legittimamente 404 per una risorsa mancante, una pagina che restituisce 200 con un guscio vuoto perché il database è andato in timeout, o una catena di redirect che inizia a instradare verso il dominio di qualcun altro.
La modalità assert di HostTracker sostituisce quei campi fissi con un piccolo linguaggio di regole che scrivi tu stesso, regola per regola, dentro l'editor del monitor. Ogni regola dice esattamente cosa deve essere vero della risposta: lo stato, un pezzo del corpo, un'intestazione, quanto tempo ci ha messo, dove è finito un redirect. Un controllo fallisce solo quando una delle tue regole fallisce. È lo stesso linguaggio per un sito web, un'API REST, una query di database, una porta TCP, un target Ping, un contatore SNMP o un controllo Counter generico: un unico insieme di soggetti, un unico insieme di predicati, riusati ovunque compaia la modalità. Questa guida copre ogni soggetto, operatore, riduttore, scorciatoia di zucchero sintattico e forma di sintassi che il motore implementa.
Cosa sostituisce la modalità assert
I classici campi di Response Validation sono ancora lì quando la modalità assert è spenta: un intervallo di stato atteso, un elenco di stati da ignorare, una parola chiave che deve (o non deve) comparire. La modalità è un interruttore che scambia quell'insieme fisso con un elenco di regole che costruisci tu, e disattivarlo di nuovo prima di salvare riporta esattamente i campi classici. Nessun monitor resta bloccato in una modalità in modo permanente.
Un unico linguaggio invece di un mucchio di aggeggi specifici per tipo si compone. Un controllo "deve essere JSON e contenere un campo", un controllo "deve ancora dire Add to cart" e un controllo "non deve essere diventato più lento" sono tre regole nella stessa sintassi, nello stesso elenco, ciascuna passa o fallisce per conto proprio.
Attivarla
La modalità assert vive dentro la sezione Response Validation dell'editor del monitor, per i monitor HTTP (sito web) e API. Attiva l'interruttore, e i campi classici vengono sostituiti da un elenco numerato di regole con un pulsante "Add rule" e un contatore in tempo reale che mostra quante regole hai usato rispetto al limite del tuo piano.

Ogni regola viene convalidata mentre la costruisci: una regola non ancora finita porta uno stato distinto di "non finita", e una regola che l'editor riesce a valutare viene contrassegnata come completa. Ogni regola ha anche un piccolo pulsante </> che apre la sua forma sorgente in testo semplice, così puoi leggere o copiare l'espressione esatta invece della sola vista a caselle.
Il modello mentale: soggetto, predicato, valore
Ogni regola ha la stessa forma: un soggetto (il codice di stato, il corpo, un'intestazione, il tempo di risposta), un predicato (uguale a, contiene, esiste, è minore di) e, per la maggior parte dei predicati, un valore con cui confrontare. status eq 200 è soggetto, predicato e valore; body.json exists è un soggetto e un predicato senza valore, perché "exists" non ha bisogno di altro.
Costruire una regola nell'editor inizia scegliendo cosa controllare, poi la condizione, poi il valore:

Le regole nell'elenco sono combinate con AND: un controllo fallisce quando una singola regola fallisce e passa solo quando ogni regola passa. Non c'è ancora un OR, quindi per accettare uno tra diversi stati o stringhe, esprimilo dentro un'unica regola (status in [200, 301, 302], body containsAny ["In stock", "Pre-order"]). Una regola che fallisce si nomina da sola nell'avviso, quindi dai a ciascuna un'etichetta breve dove puoi e l'avviso dirà quale aspettativa si è rotta.
Cosa puoi controllare
Il selettore raggruppa i soggetti nel documento proprio della risposta (il corpo, le intestazioni) e nel suo trasporto (stato, timing, redirect, TLS). Alcuni dei soggetti più importanti, con l'elenco completo nella referenza che segue:
| Soggetto | Cos'è | Esempio |
|---|---|---|
status | Il codice di stato HTTP della risposta finale, dopo aver seguito i redirect | status isOk |
body | Il corpo della risposta come testo semplice | body contains "Add to cart" |
body.json / body.xml / body.html / body.yaml | Il corpo, ma solo quando viene effettivamente interpretato come quel formato, altrimenti il soggetto è semplicemente assente | body.json exists |
body.json.path("$.a") | Una query JSONPath dentro un corpo JSON (lo stesso linguaggio di query funziona anche su YAML, dato che YAML viene interpretato nello stesso modello a oggetti) | body.json.path("$.status") eq "ok" |
body.size / body.hash | La dimensione della risposta in byte, e un'impronta del contenuto del corpo | body.size gt 1kb |
header("Name") | Un'intestazione della risposta, cercata per nome | header("Content-Type") isJson |
time e time.connect / time.tls / time.dns / time.head | Tempo di risposta totale, e le sue fasi di rete, handshake TLS, DNS e tempo di elaborazione del server | time lt 2s |
redirects / requests | I salti che un controllo ha seguito, e la catena completa (inclusa la risposta finale) | redirects.count eq 0 |
url e le sue parti (.host, .scheme, .path...) | L'URL finale su cui è atterrato il controllo | url.scheme eq "https" |
cert.days.left | Giorni rimanenti prima che il certificato TLS scada | cert.days.left gt 14 |
I numeri accettano suffissi di unità così non devi mai convertire a mano: 2s significa 2000 millisecondi, 1kb significa 1024 byte. I confronti di testo distinguono maiuscole e minuscole a meno che tu non aggiunga nocase alla regola.
La referenza completa
Quello che segue è ogni soggetto, operatore, riduttore, scorciatoia di zucchero sintattico, filtro e forma di sintassi che il motore di assert registra per i controlli HTTP e API, preso direttamente dal registro del motore stesso (gli stessi dati che alimentano i selettori dell'editor delle regole e la sua documentazione). Le voci non ancora generalmente disponibili portano una nota tra parentesi: campi riservati che nessun agente ha ancora iniziato a popolare, candidati ancora in fase di distribuzione agli agenti, e la famiglia con stato che richiede un piano specifico. Tutto ciò che non ha una tale nota è live oggi su ogni piano che ha la modalità assert.
La referenza segue il raggruppamento proprio del motore: campi della risposta, poi i modi per accedere a un corpo, poi timing, rete e TLS, poi gli operatori, i riduttori e le scorciatoie che funzionano su tutti loro, poi i tipi di controllo oltre HTTP che parlano lo stesso linguaggio.
Risposta
I soggetti che descrivono la risposta stessa: il suo stato, il suo corpo grezzo, le sue intestazioni, l'URL da cui ha effettivamente risposto, e la catena di richieste che ce l'ha portata.
| Nome | Cos'è | Tipo/valori | Esempio |
|---|---|---|---|
body | Il corpo della risposta come testo decodificato. | string | body contains "Welcome" |
header | Un'intestazione della risposta finale, per nome. | string | header("Content-Type") isJson |
redirects | I salti di redirect che sono stati seguiti, la catena di richieste senza il suo elemento finale. | collection | redirects.count eq 0 |
status | Il codice di stato HTTP della risposta finale, dopo aver seguito i redirect. | number | status isOk |
body.size | La dimensione del corpo scaricato, in byte. | number | body.size lt 500000 |
url | L'URL che ha effettivamente risposto, dopo tutti i redirect. Un url: confrontalo come testo, o leggi le sue parti (url.host, .port, .path, .query, .scheme). | url | url.host eq "www.example.com" |
requests | Ogni richiesta fatta da questo controllo, in ordine: i salti di redirect e poi la richiesta finale. | collection | requests.count le 2 |
url.host | La parte host dell'URL. | string | url.host eq "example.com" |
url.path | La parte percorso dell'URL. | string | url.path startsWith "/api" |
url.port | La parte porta dell'URL. | number | url.port eq 443 |
url.query | La stringa di query dell'URL. | string | url.query contains "token" |
url.scheme | Lo schema dell'URL (http o https). | string | url.scheme eq "https" |
body.hash | Un digest del corpo della risposta, confrontalo con previous.body.hash per rilevare cambi di contenuto. | string | body.hash eq previous.body.hash |
httpVersion (riservato, non ancora popolato) | La versione HTTP negoziata. | string | httpVersion eq "HTTP/2" |
setCookie | I valori Set-Cookie della risposta finale, un elemento per cookie, confrontane uno con contains o matches, contali con .count. | collection | setCookie exists |
steps (non ancora disponibile) | I passi di un controllo multi-step. Non ancora disponibile. | collection | steps.count le 1 |
url.original | L'URL con cui il controllo era configurato, prima di ogni redirect. Un url come url stesso: ha le stesse parti (url.original.host, .port, .path, .query, .scheme). | url | url.original.scheme eq "http" |
url.original.host | La parte host dell'URL. | string | url.original.host eq "example.com" |
url.original.path | La parte percorso dell'URL. | string | url.original.path startsWith "/start" |
url.original.port | La parte porta dell'URL. | number | url.original.port eq 80 |
url.original.query | La stringa di query dell'URL. | string | url.original.query contains "utm_" |
url.original.scheme | Lo schema dell'URL (http o https). | string | url.original.scheme eq "http" |
Due alias: redirectCount è la forma breve di redirects.count, redirectCount eq 0 si legge in modo leggermente più naturale della forma lunga equivalente quando intendi "il controllo ha risposto direttamente, senza redirect." E setCookie al livello superiore è l'elenco cookie della risposta finale; lo stesso nome ricompare per ogni salto dentro requests/redirects (vedi Soggetti dei salti sotto), contenendo solo i cookie di quella singola richiesta.
Estrarre valori dal corpo
Questi soggetti si risolvono solo quando il corpo è nel formato che nominano: uno spazio dei nomi JSON su una pagina HTML è semplicemente assente, non un errore tipizzato. Questo rende exists il modo standard per sondare il formato, e body.json exists chiede se il corpo è stato interpretato come JSON. I quattro spazi dei nomi di formato portano ciascuno una funzione di query .path(...) corrispondente (JSONPath per json/yaml, XPath per xml, selettori CSS per html) e un .regex(...) corrispondente, più un body.regex(...) indipendente dal formato che legge il testo grezzo indipendentemente dal formato. body.html.a, body.html.script e body.html.link sono collezioni già pronte di ogni link, script ed elemento <link> nella pagina; vedi Ambiti di elemento sotto per i campi disponibili su ciascuno.
| Nome | Cos'è | Tipo/valori | Esempio |
|---|---|---|---|
body.json | Il corpo della risposta, ma solo quando è davvero JSON. | string | body.json exists |
body.json.path | Interroga il corpo JSON con un'espressione JSONPath. | json | body.json.path("$.status") eq "ok" |
body.html | Il corpo della risposta, ma solo quando è davvero HTML. | string | body.html exists |
body.html.path | Seleziona elementi della pagina con un selettore CSS. | collection | body.html.path("h1").first contains "Welcome" |
body.regex | Fai corrispondere il testo con un'espressione regolare e prendi ciò che ha catturato. | string | body.regex("order-(?<id>\\d+)") exists |
body.xml | Il corpo della risposta, ma solo quando è davvero XML. | string | body.xml exists |
body.xml.path | Interroga il corpo XML con un'espressione XPath. | string | body.xml.path("//item/@id") exists |
body.html.a | Ogni link nella pagina. | collection | body.html.a.count gt 0 |
body.html.link | Ogni <link> dichiarato dalla pagina. Una menzione nuda significa i target del link. | collection | body.html.link.count gt 0 |
body.html.script | Ogni script caricato dalla pagina. Una menzione nuda significa le sorgenti dello script. | collection | body.html.script.count gt 0 |
body.yaml | Il corpo della risposta, ma solo quando è davvero YAML. | string | body.yaml exists |
body.yaml.path | Interroga il corpo YAML con un'espressione JSONPath. | json | body.yaml.path("$.services.web.image") contains ":1." |
body.html.regex | Fai corrispondere il testo con un'espressione regolare e prendi ciò che ha catturato. | string | body.regex("order-(?<id>\\d+)") exists |
body.json.regex | Fai corrispondere il testo con un'espressione regolare e prendi ciò che ha catturato. | string | body.regex("order-(?<id>\\d+)") exists |
body.xml.regex | Fai corrispondere il testo con un'espressione regolare e prendi ciò che ha catturato. | string | body.regex("order-(?<id>\\d+)") exists |
body.yaml.regex | Fai corrispondere il testo con un'espressione regolare e prendi ciò che ha catturato. | string | body.regex("order-(?<id>\\d+)") exists |
Un dettaglio della famiglia regex che vale la pena segnalare: i gruppi di cattura con nome ((?<id>...)) dentro una regola .regex(...) scrivono in uno spazio dei nomi di binding limitato al controllo che una regola successiva può rileggere con bind("id") o bind[0] per posizione, vedi Valori catturati sotto.
Valori catturati
Un soggetto vive nel proprio gruppo del registro perché non legge direttamente la risposta, legge ciò che una regola precedente ha catturato da essa.
| Nome | Cos'è | Tipo/valori | Esempio |
|---|---|---|---|
bind | Un valore catturato da una regola regex precedente, per nome di cattura o per posizione. | string | bind("id") gt 1000 |
Abbinalo a una regola regex precedente nell'elenco: una regola come body.regex("order-(?<id>\d+)") exists cattura l'id dell'ordine nel nome id, e una regola successiva può testarlo con bind("id") gt 1000 oppure, per una cattura posizionale (senza nome), bind[0].
Timing
Un totale più una scomposizione per fase, così un avviso "è diventato più lento" può anche dire quale parte è diventata più lenta.
| Nome | Cos'è | Tipo/valori | Esempio |
|---|---|---|---|
time | Tempo di risposta totale: connessione + TLS + attesa + download. La risoluzione DNS non è inclusa. | number | time lt 2000 |
ttfb (riservato, non ancora popolato) | Tempo al primo byte. | number | ttfb lt 200 |
time.connect | Tempo impiegato per stabilire la connessione TCP. | number | time.connect lt 500 |
time.data | Tempo impiegato per scaricare il corpo della risposta. | number | time.data lt 1000 |
time.dns | Tempo impiegato per risolvere il nome di dominio. Non incluso nel soggetto time nudo. | number | time.dns lt 200 |
time.head | Tempo di attesa per le intestazioni della risposta. | number | time.head lt 500 |
time.tls | Tempo impiegato per l'handshake TLS. | number | time.tls lt 300 |
Il soggetto time nudo è connessione + TLS + attesa delle intestazioni + download del corpo. La risoluzione DNS è esclusa e vive solo nel soggetto fratello time.dns, perché il DNS è spesso in cache e altrimenti farebbe apparire lo stesso endpoint incoerentemente veloce o lento tra un controllo e l'altro.
Rete: DNS e connessione
dns e conn sono puri spazi dei nomi nel registro, un gruppo senza un proprio valore, quindi una regola non può mai fermarsi sul nome nudo (sia l'editor sia il motore rifiutano una catena che finisce solo su dns o conn, indirizzandoti ai campi reali sotto).
| Nome | Cos'è | Tipo/valori | Esempio |
|---|---|---|---|
conn | La connessione di rete fatta dal controllo, l'indirizzo che ha servito la risposta e gli eventuali fallimenti di connessione. | string | - |
conn.failed | Quanti degli indirizzi risolti non sono riusciti a connettersi. | number | conn.failed eq 0 |
conn.failedIps (candidato, in fase di distribuzione agli agenti) | Gli indirizzi risolti che non sono riusciti a connettersi. | collection | conn.failedIps.count eq 0 |
conn.ip | L'indirizzo IP che ha effettivamente servito la risposta. | string | conn.ip eq "203.0.113.10" |
conn.ip.family (candidato, in fase di distribuzione agli agenti) | Se la risposta è stata servita su IPv4 o IPv6. | string | conn.ip.family eq "IPv4" |
dns | La risoluzione DNS del nome monitorato, a quali indirizzi si è risolto e quale server ha risposto. | string | - |
dns.ips | Tutti gli indirizzi IP a cui si è risolto il nome di dominio durante questo controllo. | collection | dns.ips contains "1.2.3.4" |
dns.server | Il server DNS che ha risposto alla risoluzione. | string | dns.server eq "8.8.8.8" |
TLS e certificato
Come dns e conn, tls e cert sono puri spazi dei nomi, i fatti su certificato/handshake vivono un livello sotto.
| Nome | Cos'è | Tipo/valori | Esempio |
|---|---|---|---|
cert.days.left | Giorni rimanenti prima che il certificato del sito scada. | number | cert.days.left gt 14 |
cert | Il certificato presentato dal server, giorni alla scadenza, emittente e campi di identità. | string | - |
cert.days | Giorni trascorsi dall'emissione del certificato. | number | cert.days gt 0 |
cert.issuer | L'autorità di certificazione che ha emesso il certificato del sito. | string | cert.issuer contains "Let's Encrypt" |
cert.san | I nomi di dominio per cui il certificato è valido. | collection | cert.san contains "www.example.com" |
cert.serial | Il numero di serie del certificato. | string | cert.serial exists |
cert.subject (riservato, non ancora popolato) | Il soggetto del certificato. Non ancora catturato, in arrivo con una futura versione dell'agente. | string | cert.subject contains "example.com" |
tls | L'handshake TLS della connessione protetta, versione del protocollo e cifrario negoziati. | string | - |
tls.cipher | La suite di cifratura negoziata. | string | tls.cipher contains "AES" |
tls.protocol | La versione TLS negoziata. | string | tls.protocol eq "Tls13" |
cert.subject è elencato qui per completezza ma non è ancora popolato, vedi la sezione Trasparenza sotto per cosa significa "riservato" in pratica. La regola quotidiana sul certificato è cert.days.left gt 14, trattata nella sezione delle regole pratiche.
Soggetti dei salti: campi dentro requests e redirects
requests e redirects sono collezioni, e ogni elemento è un record completo di richiesta/risposta con il proprio insieme ridotto di campi. Non ogni soggetto di primo livello ha senso per singolo salto (un salto non ha un proprio certificato), e un campo esiste solo per salto: hstsHeader, l'intestazione Strict-Transport-Security di quella richiesta nella catena.
| Nome | Cos'è | Tipo/valori | Esempio |
|---|---|---|---|
status | Il codice di stato di questa richiesta nella catena. | number | status eq 200 |
url | L'URL a cui è stata fatta questa richiesta. | url | url startsWith "https://" |
header | Un'intestazione della risposta di questa richiesta. Un salto mantiene un record di intestazione ridotto a un solo valore, i predicati per liste (containsAny, containsAll, unique) si applicano solo sull'intestazione della risposta finale. | string | header("Content-Type") contains "json" |
hstsHeader | L'intestazione Strict-Transport-Security di questa richiesta. | string | requests[0].hstsHeader exists |
setCookie | I valori dell'intestazione Set-Cookie di questa richiesta. | collection | setCookie exists |
url.original | L'URL con cui il controllo era configurato, prima di ogni redirect. Un url come url stesso: ha le stesse parti (url.original.host, .port, .path, .query, .scheme). | url | url.original.scheme eq "http" |
url.host | La parte host dell'URL. | string | url.host eq "example.com" |
url.port | La parte porta dell'URL. | number | url.port eq 443 |
url.path | La parte percorso dell'URL. | string | url.path startsWith "/api" |
url.query | La stringa di query dell'URL. | string | url.query contains "token" |
url.scheme | Lo schema dell'URL (http o https). | string | url.scheme eq "https" |
url.original.host | La parte host dell'URL. | string | url.original.host eq "example.com" |
url.original.port | La parte porta dell'URL. | number | url.original.port eq 80 |
url.original.path | La parte percorso dell'URL. | string | url.original.path startsWith "/start" |
url.original.query | La stringa di query dell'URL. | string | url.original.query contains "utm_" |
url.original.scheme | Lo schema dell'URL (http o https). | string | url.original.scheme eq "http" |
Il header(...) per singolo salto mantiene un record ridotto a un solo valore: predicati a forma di lista come containsAny o unique hanno senso solo sulla mappa completa delle intestazioni della risposta finale, quindi si applicano lì e non per salto. Le due collezioni significano cose diverse. requests è l'intera catena inclusa la risposta finale che ha risposto, quindi non è mai vuota nemmeno per un 200 diretto, mentre redirects sono solo i salti seguiti lungo il percorso, vuota quando nulla ha effettuato redirect.
Ambiti di elemento: campi dentro un elemento della collezione
Un ambito di elemento è l'insieme di campi disponibile su UN elemento di una collezione, dopo aver indicizzato al suo interno (requests[0]) o mentre la filtri con where(current. ...) (vedi la sezione successiva). Sei collezioni portano un proprio ambito di elemento: le quattro collezioni di elementi HTML condividono una forma, e requests/redirects condividono la forma dei soggetti dei salti documentata subito sopra.
| Ambito di elemento | Come appare un elemento |
|---|---|
body.html.path | Un elemento trovato da una query CSS body.html.path("selector"). |
body.html.a | Un elemento link <a> da body.html.a. |
body.html.script | Un elemento <script> da body.html.script. |
body.html.link | Un elemento <link> da body.html.link. |
requests | Una richiesta nella catena completa (vedi la tabella dei soggetti dei salti sopra). |
redirects | Un salto di redirect seguito (gli stessi campi di requests, vedi sopra). |
La forma condivisa per body.html.path(...), body.html.a, body.html.script e body.html.link, una riga per link, tag script o elemento <link>:
| Nome | Cos'è | Tipo/valori | Esempio |
|---|---|---|---|
url | Il target del link esattamente come lo scrive il markup. | string | body.html.a.url contains "/checkout" |
text | Il testo visibile dell'elemento. | string | body.html.a.text contains "Sign in" |
absolute | Il target del link risolto rispetto all'URL della pagina in un indirizzo assoluto, un elenco di url, con le parti dell'url disponibili per elemento (.host, .path, .port, .query, .scheme). | url | body.html.a.absolute.scheme in ["https"] |
rel | L'attributo rel dell'elemento. | string | body.html.a.where(current.rel eq "nofollow").count eq 0 |
absolute.host | La parte host dell'URL. | string | body.html.a.absolute.host.unique.count le 3 |
absolute.port | La parte porta dell'URL. | number | body.html.a.absolute.port in [443] |
absolute.path | La parte percorso dell'URL. | string | body.html.a.absolute.path startsWith "/" |
absolute.query | La stringa di query dell'URL. | string | body.html.a.absolute.query not contains "session" |
absolute.scheme | Lo schema dell'URL (http o https). | string | body.html.a.absolute.scheme in ["https"] |
Due valori predefiniti si applicano prima di scrivere una regola su queste collezioni. Una menzione nuda di body.html.a (o .script/.link) significa la sua proiezione .url, quindi body.html.a.count gt 0 conta gli href, e una regola salvata si rilegge con .url scritto per esteso, perché una regola memorizzata dice sempre esattamente cosa valuta. E .url è l'attributo href grezzo esattamente come lo ha scritto il markup, quindi un link relativo resta relativo; .absolute è lo stesso link risolto rispetto all'URL proprio della pagina, che è ciò che vuoi quando controlli lo schema o l'host dei link in uscita (body.html.a.absolute.scheme in ["https"]).
Operatori
La metà predicato di ogni regola: quale test eseguire sul soggetto. Tutti e 15 sono condivisi tra ogni tipo di controllo, e quali si adattano a un dato soggetto dipende dal suo tipo (un codice di stato accetta lt/gt, un corpo accetta contains, una collezione accetta exists/unique/in).
| Nome | Cos'è | Si applica a | Esempio |
|---|---|---|---|
eq | Uguale a. Contro un letterale json("…") / xml("…") / yaml("…") è una corrispondenza strutturale ESATTA: stesse chiavi (in qualsiasi ordine), array nello stesso ordine, stessi valori. | qualsiasi tipo | body.json eq json("{\"ok\": true}") |
lt | Minore di. | numbers | time lt 2000 |
le | Minore o uguale a. | numbers | cert.days.left le 30 |
gt | Maggiore di. | numbers | body.size gt 0 |
ge | Maggiore o uguale a. | numbers | status ge 500 |
contains | Contiene il testo, su una lista, passa quando il valore È uno degli elementi (corrispondenza esatta; usa matches per cercare dentro gli elementi). Contro un letterale json("…") / xml("…") / yaml("…") è contenimento STRUTTURALE: tutto ciò che il letterale dichiara deve essere presente e corrispondere; la risposta può averne di più. | text or list | body.json contains json("{\"status\": \"ok\"}") |
startsWith | Inizia con il testo, su una lista, quando un QUALSIASI elemento lo fa. | text | url.path startsWith "/api" |
endsWith | Finisce con il testo, su una lista, quando un QUALSIASI elemento lo fa. | text | url.path endsWith ".json" |
matches | Corrisponde all'espressione regolare in qualsiasi punto del testo, su una lista, quando un QUALSIASI elemento lo fa. | text | body matches "order-\\d+" |
containsAny | Contiene almeno uno dei valori elencati (su una lista: qualche elemento È UGUALE a uno di essi). | list | body containsAny ["In stock", "Pre-order"] |
containsAll | Contiene ognuno dei valori elencati (su una lista: ogni valore è uguale a qualche elemento, i testimoni possono differire). | list | body.html.a.text containsAll ["Home", "Contact"] |
in | È uno dei valori o intervalli elencati, su una lista, ogni elemento lo è. | value(s) or range | status in [200, 301, 302] |
exists | Il soggetto è presente. | any subject | header("ETag") exists |
isNumber | Il valore si legge come un numero. | text or any | bind("id") isNumber |
unique | La lista non ha duplicati. | list | dns.ips unique |
Due operatori significano qualcosa di più stretto di quanto sembri. contains su una lista è appartenenza esatta: il valore deve essere uguale a un intero elemento, non comparire come sottostringa dentro uno di essi, quindi usa matches quando vuoi un comportamento a sottostringa tra gli elementi di una collezione. E eq contro un letterale json(...)/xml(...)/yaml(...) è una corrispondenza strutturale completa (stesse chiavi, array nello stesso ordine, stessi valori), mentre contains contro lo stesso tipo di letterale è contenimento strutturale: tutto ciò che il letterale dichiara deve essere presente, ma la risposta reale può portarne di più.
Riduttori
Un riduttore riduce una collezione a un unico valore e può comparire solo alla fine di una catena. Gli esempi sotto usano requests.status, la collezione naturalmente numerica che i soggetti HTTP formano, come illustrazione; gli stessi otto riduttori funzionano su qualsiasi collezione numerica in qualsiasi tipo di controllo (i tempi di andata e ritorno di un controllo Ping, un insieme filtrato di righe di database).
| Nome | Cosa riduce | Si applica a | Esempio |
|---|---|---|---|
count | Quanti elementi ha la lista. | any collection | requests.count le 2 |
min | Il numero più piccolo nella lista. | numeric collection | requests.status.min ge 200 |
max | Il numero più grande nella lista. | numeric collection | requests.status.max lt 500 |
sum | La somma dei numeri nella lista. | numeric collection | requests.status.sum gt 0 |
avg | La media dei numeri nella lista. | numeric collection | requests.status.avg lt 300 |
first | Il primo elemento della lista. | any collection | redirects.status.first eq 301 |
last | L'ultimo elemento della lista. | any collection | requests.status.last eq status |
unique | La lista con i duplicati rimossi. | any collection | dns.ips.unique.count le 3 |
unique è sovraccaricato, e la grafia distingue i due significati. Scritto come operatore senza punto (x unique) è un predicato, "questa collezione non ha duplicati," e fallisce nominando la ripetizione. Scritto come riduttore con un punto (x.unique) è una trasformazione, la collezione deduplicata stessa, che ha ancora bisogno di qualcosa dopo (x.unique.count eq 1). Un x.unique penzolante senza nulla dopo è un errore di sintassi, perché il motore non può indovinare quale dei due intendevi.
Zucchero sintattico
I predicati di zucchero sono forme brevi che il motore espande in predicati core ordinari prima ancora che la regola venga inviata a un agente, un predicato di zucchero non costa nulla in più da aggiungere (nessun bundle dell'agente, nessuna soglia di versione) perché nel momento in cui arriva sulla linea appare già come una regola ordinaria. Preferisci lo zucchero ogni volta che esiste: si legge meglio, ed è esattamente equivalente a scrivere la forma lunga a mano.
| Nome | Cosa significa | Si applica a | Esempio |
|---|---|---|---|
isOk | Lo stato è un codice di successo (200-299). | status | - |
isRedirect | Lo stato è un codice di redirect (300-399). | status | status isRedirect |
isClientError | Lo stato è un errore client (400-499). | status | status isClientError |
isServerError | Lo stato è un errore server (500-599). | status | status isServerError |
isJson | Il contenuto è davvero JSON. | document or media-type text | header("Content-Type") isJson |
isXml | Il contenuto è davvero XML, il corpo viene interpretato come XML, oppure un'intestazione nomina un media type XML. | document or media-type text | body isXml |
isHtml | Il contenuto è davvero HTML, il corpo viene interpretato come HTML, oppure un'intestazione nomina un media type HTML. | document or media-type text | body isHtml |
isForm | Un media type nomina una codifica di modulo: application/x-www-form-urlencoded o multipart/form-data. A differenza di isJson/isXml/isHtml non esiste uno spazio dei nomi del corpo corrispondente, quindi questo si applica solo a un valore di media type come un'intestazione Content-Type. | media-type text only | header("Content-Type") isForm |
isEmpty | Non c'è nulla: un testo vuoto, una dimensione zero o una lista vuota. | text, size or list | body isEmpty |
isNull | Il valore è null. | any value | body.json.path("$.deletedAt") isNull |
absent | Il soggetto non è presente affatto. | any subject | header("X-Debug") absent |
between | Un numero dentro un intervallo inclusivo. | numbers (2-operand) | body.size between 50 and 500kb |
isJson/isXml/isHtml sono sensibili al contesto di proposito, e ciò su cui li scrivi decide quale significato si applica. Scritti sul documento stesso (body isJson) significano "questo viene interpretato come quel formato," lo stesso di body.json exists. Scritti su un valore testuale che nomina un media type, come un'intestazione (header("Content-Type") isJson), significano "questo nomina la famiglia MIME di quel formato"; vedi Famiglie MIME sotto per quali media type qualificano. isForm ha solo il secondo significato, dato che non esiste uno spazio dei nomi body.form in cui interpretare, quindi body isForm è un errore statico invece che una regola che non potrebbe mai essere vera.
Il filtro where(...)
Mantieni solo gli elementi che corrispondono, poi prosegui da lì. È l'unico costrutto di filtraggio nel linguaggio, e ha esattamente una forma: where(current.<field> <condition> <value>).
Filtrare è diverso dal proiettare: requests.url contains "cart" chiede se un tale salto esiste da qualche parte nella catena, mentre requests.where(current.url contains "cart").status chiede cosa ha restituito quel salto. Il filtraggio non riduce la lista, quindi concludi con .first, un controllo in [...], o .count. Va un solo livello, e prende esattamente una condizione.
| Parte | Cosa nomina | Note |
|---|---|---|
current.<field> | Un campo di ciascun elemento in fase di filtraggio, scritto dopo current. | Questa è la metà su cui le persone sbagliano: current.url è l'URL del singolo salto, non quello della risposta finale. Solo i campi propri dell'elemento possono seguire current. |
| la condizione | Qualsiasi predicato ordinario, incluso not e nocase | Qualsiasi condizione che funziona al livello superiore di una regola funziona anche qui. |
| il valore | Con cosa viene confrontato il campo di ciascun elemento | Di solito un valore semplice. Un soggetto scritto qui viene letto dalla risposta ESTERNA, non dall'elemento, where(current.url eq url.original) confronta ogni salto con l'URL con cui il controllo era configurato, motivo per cui il lato elemento deve dire current. esplicitamente. |
Esempio: requests.where(current.url contains "cart").status.first eq 301, mantieni solo i salti il cui URL contiene "cart", poi guarda lo stato del primo che corrisponde.
Altri due limiti, entrambi imposti dal parser con un proprio messaggio: where non può essere annidato dentro un altro where, e il suo argomento è esattamente una condizione, senza and/or all'interno. Si applica solo a una collezione i cui elementi portano campi con nome (requests, body.html.a), non a una semplice lista proiettata come dns.ips, dove non c'è nulla che current. possa nominare.
Referenza di sintassi
Tutto il resto che la grammatica definisce: come nominare una regola, come scrivere intervalli e liste, cosa significa un soggetto nudo, e le piccole forme di punteggiatura che compaiono in molte regole.
| Forma | Cosa fa | Tipo | Esempio |
|---|---|---|---|
where | Mantieni solo gli elementi che corrispondono, poi prosegui da lì. | collection filter | requests.where(current.url contains "cart").status.first eq 301 |
not | Inverte la condizione che segue. | flag | body not contains "error" |
nocase | Confronta il testo senza distinguere maiuscole e minuscole. | flag | body contains "welcome" nocase |
current | Dentro where(…), nomina l'unico elemento in fase di filtraggio. | element reference (inside where) | requests.where(current.status eq 301) |
range | Un intervallo di numeri, entrambi gli estremi INCLUSI. | number range | status in [200..299] |
list | Una lista di valori con cui confrontare. | value list | status in [200, 301, 302] |
docLiteral | Un valore documento tipizzato per confronto strutturale: il testo tra virgolette viene interpretato come JSON, XML o YAML quando la regola viene salvata. | json/xml/yaml text | body.json contains json("{\"user\": {\"active\": true}}") |
implicitExists | Una regola che nomina solo un soggetto controlla che sia presente: scrivere solo body.json si salva come body.json exists. | bare subject line | body.json |
index | Sceglie UN elemento di una lista per posizione, contando da 0. | 0-based integer | requests[0].status |
label | Un nome facoltativo per la regola, scritto prima di due punti. | name before a colon | "json ok": body.json exists |
comment | Tutto ciò che segue # è una nota per te stesso; non influisce sul controllo. | trailing # text | status isOk # the happy path |
Alcuni meritano un passaggio in prosa semplice. label dà a una regola un nome che compare nell'avviso invece dell'espressione resa; scrivilo prima di due punti, come in "json ok": body.json exists. implicitExists significa che una riga che nomina solo un soggetto e nessun predicato è la forma breve di exists: scrivere body.json si salva come body.json exists, e riaprire la regola mostra la forma scritta per esteso. range e list sono le due forme che un valore può assumere dopo in: un intervallo ([200..299], entrambi gli estremi inclusi) o una lista esplicita ([200, 301, 302]), e un valore può essere aperto su entrambi i lati ([400..]). docLiteral è il wrapper json(...)/xml(...)/yaml(...) usato per il confronto strutturale contro il corpo (trattato sotto Operatori sopra e nelle regole pratiche sotto). index sceglie un elemento da una collezione per posizione, a partire da 0, allo stesso modo in cui bind[0] legge una cattura posizionale. current ha significato solo dentro un filtro where(...), trattato nella propria sezione sopra.
Wrapper: previous, delta e delta2
Tre forme che guardano indietro invece di guardare solo la risposta attuale, ciascuna limitata ai piani con asserzioni con stato, e ciascuna spiegata per intero in "Confrontare con il controllo precedente" sotto.
| Nome | Cos'è | Tipo/valori | Esempio |
|---|---|---|---|
delta (richiede un piano con asserzioni con stato) | Di quanto è cambiato un valore numerico dal controllo precedente, facoltativamente come tasso per ms/s/m/h. | number | delta(body.size, h) lt 1mb |
delta2 (richiede un piano con asserzioni con stato) | Il cambiamento del cambiamento: un valore sta accelerando? | number | delta2(time) gt 0 |
previous (richiede un piano con asserzioni con stato) | Il valore che questo soggetto aveva al controllo precedente. | any | status eq previous.status |
Flag: not e nocase
Due modificatori che si attaccano a una regola invece di essere soggetti o predicati a sé.
| Flag | Cosa fa | Tipo | Esempio |
|---|---|---|---|
not | Inverte la condizione che segue. | flag (attaches to a rule) | body not contains "error" |
nocase | Confronta il testo senza distinguere maiuscole e minuscole. | flag (attaches to a rule) | body contains "welcome" nocase |
not si compone con il predicato che segue invece di negare l'intera regola come unità, x not != y si legge come x eq y, non come una doppia negazione. Quando un soggetto potrebbe essere del tutto assente, preferisci lo zucchero absent a not exists: i due significano esattamente la stessa cosa, ma absent lo dice direttamente. nocase cambia qualcosa solo su un confronto genuinamente testuale; l'editor (e questa referenza) ti lasciano comunque scriverlo ovunque, ma è silenziosamente privo di significato su un test numerico come status eq 200 nocase.
Famiglie MIME
Le tabelle di lookup dietro isJson, isXml, isHtml e isForm quando vengono applicati a un valore di media type come un'intestazione. Ogni famiglia corrisponde al media type di primo livello ovvio più, per JSON e XML, qualsiasi tipo che termina nel suffisso di sintassi strutturata corrispondente, il che è ciò che fa passare correttamente header("Content-Type") isJson su application/problem+json o application/vnd.api+json e non solo sul semplice application/json.
| Famiglia | Corrisponde a | Zucchero abbinato | Esempio |
|---|---|---|---|
json | application/json, text/json, o qualsiasi media type che termina in +json (application/problem+json, application/vnd.api+json, application/ld+json, ...). | sugar: isJson | header("Content-Type") isJson |
xml | application/xml, text/xml, o qualsiasi media type che termina in +xml (image/svg+xml, application/atom+xml, ...). | sugar: isXml | header("Content-Type") isXml |
html | text/html o application/xhtml+xml. | sugar: isHtml | header("Content-Type") isHtml |
form | application/x-www-form-urlencoded o multipart/form-data. | sugar: isForm | header("Content-Type") isForm |
La corrispondenza ignora tutto a partire dal primo ; in poi (così application/json; charset=utf-8 corrisponde comunque) e non distingue maiuscole e minuscole.
Soggetti per controlli database, counter, SNMP, porta e ping
Ogni operatore, riduttore, scorciatoia di zucchero sintattico e forma di sintassi sopra è identico per questi cinque tipi di controllo: il motore registra gli stessi 15 operatori, 8 riduttori, 12 predicati di zucchero e 11 forme di sintassi per tutti e sei i tipi senza eccezioni. Ciò che cambia per tipo è l'elenco dei soggetti. Ogni tipo espone un piccolo insieme di soggetti propri di ciò che misura, più un sottoinsieme dei soggetti di rete/timing/TLS già documentati sopra, con il significato che si adatta al tipo (il time di un controllo Database è connessione-più-query invece di connessione-più-TLS-più-download, dato che non c'è una risposta HTTP da scaricare).
Controlli database
Condivide time, time.connect e time.dns con i soggetti documentati sopra (ridefiniti su una connessione database: connessione-più-query, risoluzione DNS dell'host del database). Propri dei controlli database:
| Nome | Cos'è | Tipo/valori | Esempio |
|---|---|---|---|
scalar | Il singolo valore restituito dalla query (modalità Scalar). | any | - |
rows | Le righe che la query ha interessato o restituito (modalità NonQuery). | collection | - |
time.query | Il tempo impiegato dalla query stessa. | number | - |
Un esempio pratico è nella sezione successiva: usa rows.count per verificare quante righe una query ha interessato o restituito, e scalar per controllare direttamente un singolo valore restituito.
Controlli counter
Condivide time con i soggetti documentati sopra, come campo in stato candidato specificamente per i controlli Counter (tempo di andata e ritorno della richiesta del counter; vedi la sezione Trasparenza per cosa significa "candidato"). Propri dei controlli counter:
| Nome | Cos'è | Tipo/valori | Esempio |
|---|---|---|---|
value | Il valore misurato del counter. | number | - |
Controlli SNMP
Condivide time e time.dns con i soggetti documentati sopra (risoluzione del nome host più la richiesta SNMP stessa). Propri dei controlli SNMP:
| Nome | Cos'è | Tipo/valori | Esempio |
|---|---|---|---|
time.request | Il tempo impiegato dalla richiesta SNMP. | number | - |
value | Il valore restituito dall'OID. | any | - |
value.type (candidato, in fase di distribuzione agli agenti) | Il nome del tipo di dato SNMP del valore restituito. | string | - |
value.type è in stato candidato; vedi la sezione Trasparenza. Nota sulla disponibilità: l'interruttore di Response Validation della modalità assert non è ancora arrivato all'editor del monitor SNMP. Mostra un pannello "Coming soon" che nomina questi due soggetti invece di un elenco di regole funzionante. I soggetti e il motore di valutazione sottostante sono già registrati; è in sospeso solo l'interfaccia dell'editor SNMP.
Controlli porta
L'elenco condiviso più ampio di qualsiasi tipo non-HTTP. Un controllo di porta TCP porta essenzialmente gli stessi soggetti di connessione, DNS, TLS e certificato di un controllo HTTP, dato che un controllo di porta può negoziare TLS a sua volta: bind, cert e i suoi sei sottocampi, conn e i suoi quattro sottocampi, dns e i suoi due sottocampi, time/time.connect/time.dns/time.tls, e tls/tls.cipher/tls.protocol, tutti documentati nelle sezioni sopra, con gli stessi significati. Propri dei controlli porta:
| Nome | Cos'è | Tipo/valori | Esempio |
|---|---|---|---|
banner | I dati letti dal socket dopo la connessione. | string | - |
banner.hash (candidato, in fase di distribuzione agli agenti) | Un digest del banner, confrontalo con previous.banner.hash per rilevare cambi del servizio. | string | - |
banner.regex | Fai corrispondere il testo con un'espressione regolare e prendi ciò che ha catturato. | string | body.regex("order-(?<id>\\d+)") exists |
banner.size (candidato, in fase di distribuzione agli agenti) | La dimensione del banner, in byte. | number | - |
banner.hash e banner.size sono in stato candidato, vedi la sezione Trasparenza. banner.regex è live oggi e funziona esattamente come body.regex(...) su un controllo HTTP: le catture con nome alimentano lo stesso spazio dei nomi bind(...).
Controlli ping
Condivide i soggetti di connessione e DNS con le sezioni sopra: conn, conn.failed, conn.failedIps, conn.ip, conn.ip.family, dns, dns.ips, dns.server, time (qui, il tempo medio di andata e ritorno delle risposte riuscite) e time.dns. Propri dei controlli ping:
| Nome | Cos'è | Tipo/valori | Esempio |
|---|---|---|---|
loss | La percentuale di richieste echo che non hanno ricevuto risposta. | number | loss eq 0 |
reply | Le risposte echo riuscite. | collection | - |
sentCount (candidato, in fase di distribuzione agli agenti) | Quante richieste echo sono state inviate. | number | - |
time.max | Il tempo di andata e ritorno della risposta più lenta. | number | - |
time.min | Il tempo di andata e ritorno della risposta più veloce. | number | - |
ttl | Il TTL della prima risposta riuscita, confrontalo con previous.ttl per individuare cambi di rotta. | number | - |
sentCount è in stato candidato, vedi la sezione Trasparenza. ttl vale la pena conoscerlo anche fuori da una rigida regola di successo/fallimento: abbinarlo a previous.ttl (vedi Wrapper sopra) segnala un cambio di rotta tra un controllo e l'altro, dato che il time-to-live di un pacchetto all'arrivo riflette quanti salti ha attraversato.
Le regole che le persone vogliono davvero scrivere
La pagina è raggiungibile e dice davvero la cosa giusta
Un codice di stato da solo non può dirti che una pagina si è renderizzata correttamente, una risposta 200-con-guscio-vuoto è il classico fallimento silenzioso che un controllo basato solo sullo stato non vede.
status isOk
body contains "Add to cart"
Un'API risponde con JSON e il campo che ti aspetti
Controlla che l'endpoint stia ancora parlando JSON, poi accedi al suo interno. La prima riga intercetta una pagina di errore HTML servita dove dovrebbe esserci JSON, una forma comune di interruzione dietro un proxy; la seconda controlla lo stato di salute dichiarato dall'API stessa, non solo il suo stato di trasporto.
body isJson
body.json.path("$.status") eq "ok"
La risposta è diventata più lenta di quanto dovrebbe
Scomponila quando hai bisogno di sapere cosa correggere invece di sapere solo che qualcosa è lento, time.connect, time.tls, time.dns e time.head separano tempo di rete, handshake, resolver e tempo dell'applicazione.
time lt 2s
Un redirect ha mandato i visitatori fuori dal tuo stesso dominio
Confronta dove è finito il controllo con l'URL che hai configurato, fallisce nel momento in cui una catena di redirect, dirottata, mal configurata, o semplicemente cambiata da un deploy, atterra da qualche parte che non intendevi.
url.host eq url.original.host
La pagina è cambiata dall'ultimo controllo
Utile su contenuti che dovrebbero restare stabili tra un controllo e l'altro, come prezzi, termini, una policy pubblicata, e funge anche da segnale base di defacement.
previous.body.hash eq body.hash
Un numero dentro un intervallo, scritto in modo breve
Intercetta sia una pagina ridotta all'osso sia una fuori controllo in un'unica regola, senza scrivere per esteso un intervallo esplicito.
body.size between 50 and 500kb
Un certificato in scadenza
Il singolo controllo TLS più comune, e uno che un monitor semplice su/giù non può esprimere affatto, un certificato ancora valido oggi ma che scade la prossima settimana non dà nessun altro segno di avvertimento. Abbinalo a cert.issuer se vuoi intercettare anche un certificato emesso silenziosamente dall'autorità sbagliata.
cert.days.left gt 14
Una query di database che restituisce il numero sbagliato di righe
Su un controllo Database, rows è la collezione che una query ha interessato o restituito, contarla intercetta una query che dovrebbe restituire esattamente un record account e inizia silenziosamente a restituirne zero (eliminato, o un join rotto) oppure più di uno (un duplicato che non dovrebbe esistere).
rows.count eq 1
Un valore SNMP che esce dall'intervallo
Un dispositivo SNMP che risponde comunque non è lo stesso di uno sano, un OID monitorato (uso disco, profondità di coda, temperatura) può salire ben oltre una soglia sicura mentre il dispositivo stesso resta perfettamente raggiungibile. Confrontare il value interrogato con un intervallo intercetta ciò che un semplice controllo di raggiungibilità non può.
value lt 90
Un servizio TCP che risponde con il banner sbagliato
Una porta che accetta connessioni non è lo stesso di avere il servizio giusto in ascolto su di essa, un processo bloccato, un proxy mal configurato, o un servizio declassato/sostituito possono comunque completare un handshake TCP. Leggere il testo di saluto che un servizio invia subito dopo la connessione (un banner SMTP, FTP o simile) intercetta ciò che un semplice controllo porta-aperta non può.
banner contains "220"
Confrontare con il controllo precedente
Una manciata di soggetti guarda indietro invece di guardare solo la risposta attuale: metti previous. davanti a un soggetto per leggere qual era all'ultimo controllo, oppure avvolgilo in delta(...) per ottenere la differenza tra allora e ora, o in delta2(...) per ottenere il cambiamento di quel cambiamento, utile per individuare un valore che sta accelerando invece di semplicemente derivare (un tempo di risposta che sale sempre più rapidamente a ogni controllo). previous.body.hash eq body.hash sopra è esattamente questo, "l'impronta del corpo corrisponde a quella dell'ultima volta." delta(body.size, h) legge il cambiamento come un tasso all'ora invece che come una differenza grezza, per valori che ti aspetti crescano costantemente invece di saltare.
La prima volta che una regola come questa gira non ha nulla con cui confrontare, quindi viene saltata invece di fallire: il controllo viene segnato come "in fase di riscaldamento," non rotto, e aggiungere la regola non solleva alcun falso allarme. Il riscaldamento si applica solo quando la lettura attuale è valida e manca solo il riferimento. Se la lettura attuale stessa fallisce (per esempio, il corpo non è JSON valido questa volta), la regola fallisce esattamente come farebbe la sua versione semplice, senza previous.. Una regola simile ha anche bisogno che il valore cambi tra un controllo e l'altro, il che la rende priva di senso su un metodo di controllo che non fa mai avanzare lo stato, una richiesta HEAD per esempio.
Confrontare con il controllo precedente richiede un piano di livello superiore; senza di esso, quei soggetti appaiono disattivati nell'editor con una spiegazione.
Limiti, e cosa manca deliberatamente
Quante regole puoi aggiungere dipende dal tuo piano, mostrato come un contatore in tempo reale accanto a "Add rule." Il motore applica anche un tetto assoluto su ogni controllo indipendentemente dal piano, una protezione contro l'abuso più che un limite all'uso ordinario: un controllo con un numero di regole anche solo vicino a quel tetto sarebbe già insolitamente grande.
Non c'è modo di scrivere JavaScript personalizzato per una regola, e non ci sarà mai. Ogni regola è costruita da un vocabolario fisso e nominato di soggetti e predicati invece che da una sandbox di scripting aperta, il che mantiene una regola leggibile a colpo d'occhio e sicura da eseguire su ogni agente di monitoraggio nel mondo.
Non ogni regola funziona ovunque nel momento in cui viene scritta: alcune condizioni più recenti richiedono una versione recente dell'agente di monitoraggio che esegue il tuo controllo, quindi una nuova capacità impiega del tempo a raggiungere ogni controllo del tuo account man mano che gli agenti si aggiornano in background. Le regole costruite sul nucleo stabile del linguaggio non ne sono influenzate.
Una manciata di voci in questa referenza non è ancora pienamente live, e ciascuna è etichettata nella sua tabella sopra:
- Riservato (dichiarato, non ancora popolato da alcun agente):
ttfb,httpVersion,cert.subject. - Candidato (già in fase di distribuzione, non ancora su ogni agente):
conn.ip.familyeconn.failedIpssui controlli HTTP, Port e Ping,value.typesui controlli SNMP,banner.hashebanner.sizesui controlli Port,sentCountsui controlli Ping, e iltimeproprio del controllo Counter. - Non ancora disponibile:
steps, riservato per un futuro tipo di controllo multi-step. - Richiede un piano con asserzioni con stato: l'intera famiglia di wrapper
previous/delta/delta2, su ogni tipo di controllo.
Tutto il resto in questa referenza è live oggi su ogni piano che ha la modalità assert.
Dove funziona oggi la modalità assert
L'interruttore di Response Validation per la modalità assert compare sui monitor HTTP (sito web) e API, che condividono lo stesso editor di regole e la stessa sintassi. Lo stesso linguaggio e lo stesso motore di valutazione già girano sotto i controlli Database, Counter, Port, Ping e SNMP a livello di protocollo: il registro sopra serve tutti e sei i tipi di controllo, e una regola salvata per uno si legge allo stesso modo se la modalità raggiunge l'editor di un altro tipo più avanti.
SNMP mostra l'anteprima più chiara: il suo editor ha già un pannello Regole di asserzione che nomina value e value.type, etichettato "Coming soon", senza ancora un elenco di regole funzionante dietro. I controlli Database, Counter e Ping non mostrano affatto un pannello della modalità assert, anche se i loro soggetti sono ugualmente live nel motore sottostante.
Configurare un controllo reale
Se stai convalidando un'API REST invece di una semplice pagina web, parti da convalida della risposta API, che copre insieme l'uptime, il tempo di risposta e il corpo della tua API. Per una pagina o un sito che deve restare raggiungibile e rispondere correttamente da ovunque si trovino i tuoi utenti, il monitoraggio globale dell'uptime da oltre 300 ubicazioni è il quadro più ampio in cui si inserisce la modalità assert. Per impostare le regole tramite codice invece che tramite il pannello, la API v2 propria di HostTracker crea e aggiorna le regole di assert di un monitor allo stesso modo dell'editor. Per la regola sulla scadenza del certificato sopra e tutto il resto su TLS, il monitoraggio di dominio e certificato TLS copre il tipo di controllo su cui vivono cert.days.left e gli altri soggetti TLS. Per osservare una regola valutata contro un URL reale proprio ora, senza account, usa lo strumento gratuito di controllo HTTP. Per i codici di stato con cui il soggetto status confronta, inizia con 200 OK, e le guide al monitoraggio coprono la configurazione di ogni tipo di controllo su cui gira questo linguaggio.
Domande frequenti
Cosa succede alle mie vecchie impostazioni di codice di stato e parola chiave se attivo la modalità assert?
Vengono sostituite dall'elenco di regole mentre la modalità è attiva. Disattivarla di nuovo prima di salvare ripristina i campi classici esattamente come erano: nulla viene eliminato, le due modalità semplicemente non possono essere entrambe attive.
Posso combinare più condizioni in un unico monitor?
Sì: ogni regola nell'elenco deve passare. Non c'è ancora un "OR" tra regole separate, quindi per accettare uno tra diversi valori usa un'unica regola con in [...] o containsAny [...].
La modalità assert mi permetterà mai di scrivere un mio script?
No. Ogni regola è composta dall'insieme fisso di soggetti e predicati del linguaggio. Non c'è JavaScript personalizzato, di proposito.
Cosa succede la prima volta che aggiungo una regola che confronta con il controllo precedente?
Non ha ancora nulla con cui confrontare, quindi viene segnata come in fase di riscaldamento e saltata invece che fallita. Aggiungere una regola "questo è cambiato" non solleva mai da sola un falso allarme.
Mi serve un piano specifico per usare la modalità assert?
La modalità stessa e le regole quotidiane (stato, corpo, intestazioni, timing, redirect) sono ampiamente disponibili; quante regole puoi aggiungere in una volta dipende dal tuo piano ed è mostrato in tempo reale nell'editor. Le regole che confrontano con un controllo precedente (previous, delta, delta2) richiedono un piano di livello superiore e appaiono disattivate con una spiegazione.
La modalità assert funziona sui monitor API allo stesso modo dei monitor sito web?
Sì. I monitor HTTP e API condividono lo stesso editor di regole, gli stessi soggetti e predicati, e una regola scritta per uno si legge in modo identico sull'altro.
Cosa fa esattamente where(...), e quando mi serve?
Filtra una collezione fino agli elementi che corrispondono a una condizione prima che tu legga un campo del risultato. Usalo quando una semplice proiezione come requests.status non è abbastanza specifica e hai bisogno di un particolare salto, link o elemento invece dell'intera collezione (vedi la sezione sopra).
Posso scrivere oggi una regola contro una query di database, un valore SNMP, un banner di porta o un risultato ping?
Il linguaggio e il motore di valutazione li supportano tutti, e le tabelle dei soggetti sopra coprono ciascuno di essi. L'editor delle regole no: solo i monitor HTTP e API mostrano oggi l'interruttore Response Validation. SNMP mostra un'anteprima "Coming soon" dei suoi due soggetti, e Database, Counter e Ping non mostrano affatto un pannello della modalità assert.
Perché alcuni soggetti in questa referenza dicono "riservato" o "candidato" invece di essere semplicemente elencati normalmente?
"Riservato" significa che il campo è dichiarato nel registro ma nessun agente lo popola ancora; "candidato" significa che è in fase di distribuzione agli agenti ma non li ha ancora raggiunti tutti. Entrambi sono segnalati ovunque compaiano in questa referenza e nell'elenco riassuntivo nella sezione Limiti sopra.