Uptime checks
Uptime checks for a status page: whether a host's port is open and how fast, a URL's status and response time, many at once.
Version 1.0.0 · 3 functions · 1 crate
Functions
What use uptime_check.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use uptime_tcp, uptime_http from uptime_check (Quillo 0.6).
uptime_tcp(host: str, port: int, timeout_ms: int) → anyCan a TCP connection be opened to host:port within timeout_ms (50 to 60,000)? { up, ms, address, error }, ms the time to connect (or to fail).
uptime_http(url: str, timeout_ms: int) → anyMakes a GET to url (redirects followed, up to 5) and times it: { up, status, ms, error }. up is true for a 2xx or 3xx status; a 4xx or 5xx is down with its status, and a timeout or refused connection is down with status 0.
uptime_check_all(targets: list, timeout_ms: int) → listor an errorChecks many targets at once, each on its own thread: URLs (https://...) with uptime_http, host:port with uptime_tcp. Gives one result per target, in the order given, each with its target. At most 100 targets.
Get it
$ quillo install uptime_check # uptime_check.qwer into this folder$ quillo install uptime_check --example # and its example, uptime_check.qweOr with curl:
$ curl -O https://quillolang.org/plugins/files/uptime_check.qwer$ curl -O https://quillolang.org/plugins/files/uptime_check.qweThen, in your program, all of it or only what you call:
use uptime_check.qweruse uptime_tcp, uptime_http from uptime_check // Quillo 0.6: only theseIt uses this crate, which cargo fetches the first time the plugin is built:
ureq = "2"Example
// A status page: this server's own health route, its port, and a port nothing listens on.//// quillo run uptime_check.qwe then open http://localhost:8080/statususe "uptime_check.qwer"route GET /health = { ok: true }route GET /broken = respond(503, "down for maintenance")route GET /status { let me = request.headers.host // this server, e.g. localhost:8080 let port = int(split(me, ":")[1] ?? "80") let checks = uptime_check_all([`http://${me}/health`, `http://${me}/broken`, `127.0.0.1:${port}`, "127.0.0.1:9"], 2000)? { all_up: all(checks, (c) => c.up), checks: checks | map((c) => { target: replace(c.target, me, "self"), up: c.up, status: c.status ?? null, fast: c.ms < 1000 }), }}route GET /ping ? { host: str = "127.0.0.1", port: int = 9 } = uptime_tcp(host, port, 1000)$ quillo run uptime_check.qwe$ curl 'localhost:8080/status'$ curl 'localhost:8080/ping?port=9'Source
//! Uptime checks for a status page or a monitor: is a host's port open and how fast it answers, and a URL's status code and response time, many checked at once.//! version: 1.0.0//!//! [dependencies]//! ureq = "2"use serde_json::{json, Value};use std::net::{TcpStream, ToSocketAddrs};use std::time::{Duration, Instant};fn ms(t: Instant) -> f64 { (t.elapsed().as_secs_f64() * 10_000.0).round() / 10.0}fn timeout(ms: i64) -> Duration { Duration::from_millis(ms.clamp(50, 60_000) as u64)}/// Can a TCP connection be opened to `host`:`port` within `timeout_ms` (50 to 60,000)? `{ up, ms, address, error }`, `ms` the time to connect (or to fail).pub fn uptime_tcp(host: &str, port: i64, timeout_ms: i64) -> Value { let t = Instant::now(); if !(1..=65535).contains(&port) { return json!({ "up": false, "ms": 0.0, "address": null, "error": format!("{} is not a port", port) }); } let addrs: Vec<_> = match (host, port as u16).to_socket_addrs() { Ok(a) => a.collect(), Err(e) => return json!({ "up": false, "ms": ms(t), "address": null, "error": format!("cannot resolve {}: {}", host, e) }), }; let mut last = String::from("no address"); for a in &addrs { match TcpStream::connect_timeout(a, timeout(timeout_ms)) { Ok(_) => return json!({ "up": true, "ms": ms(t), "address": a.to_string(), "error": null }), Err(e) => last = e.to_string(), } } json!({ "up": false, "ms": ms(t), "address": addrs.first().map(|a| a.to_string()), "error": last })}/// Makes a GET to `url` (redirects followed, up to 5) and times it: `{ up, status, ms, error }`. `up` is true for a 2xx or 3xx status;/// a 4xx or 5xx is down with its status, and a timeout or refused connection is down with status 0.pub fn uptime_http(url: &str, timeout_ms: i64) -> Value { let t = Instant::now(); let agent = ureq::AgentBuilder::new().timeout(timeout(timeout_ms)).user_agent("quillo-uptime/1.0").build(); match agent.get(url).call() { Ok(r) => json!({ "up": r.status() < 400, "status": r.status(), "ms": ms(t), "error": null }), Err(ureq::Error::Status(code, _)) => json!({ "up": false, "status": code, "ms": ms(t), "error": format!("status {}", code) }), Err(e) => json!({ "up": false, "status": 0, "ms": ms(t), "error": e.to_string() }), }}/// Checks many targets at once, each on its own thread: URLs (`https://...`) with `uptime_http`, `host:port` with `uptime_tcp`./// Gives one result per target, in the order given, each with its `target`. At most 100 targets.pub fn uptime_check_all(targets: Vec<String>, timeout_ms: i64) -> Result<Vec<Value>, String> { if targets.len() > 100 { return Err("at most 100 targets at once".into()); } let handles: Vec<_> = targets .into_iter() .map(|target| { std::thread::spawn(move || { let mut r = if target.contains("://") { uptime_http(&target, timeout_ms) } else { match target.rsplit_once(':').and_then(|(h, p)| p.parse::<i64>().ok().map(|p| (h.trim_matches(|c| c == '[' || c == ']').to_string(), p))) { Some((h, p)) => uptime_tcp(&h, p, timeout_ms), None => json!({ "up": false, "ms": 0.0, "error": "a target is a URL or host:port" }), } }; r["target"] = json!(target); r }) }) .collect(); Ok(handles.into_iter().map(|h| h.join().unwrap_or_else(|_| json!({ "up": false, "error": "the check failed" }))).collect())}Related
system_info.qwer · 1.0.0The machine a program runs on: CPU usage per core measured between readings, memory and swap with cgroup limits, disks with free space and the one holding a path, network totals and rates, load per core, uptime, processes sorted and searched, and a health check that turns limits into warnings.3 views · 12 downloadsHTTP Archive files har.qwer · 1.0.0HAR files from a browser's network panel read: pages with their load times, each request flat with timings and sizes (-1 given as null, SSL not counted twice), the slowest and largest requests, totals by host and type. Secrets masked from headers, cookies, query strings, form and JSON bodies before the file goes on a ticket, with a list of what was found and never its value.3 views · 6 downloadsLog parser log_parse.qwer · 1.0.0Log lines into rows: nginx and Apache access logs, syslog, logfmt and JSON lines, the format found by itself, with counts by any field.7 views · 7 downloadsPrometheus metrics prometheus.qwer · 1.0.0Counters, gauges and histograms with labels kept in memory, and the /metrics text Prometheus and Grafana scrape.8 views · 8 downloadsSource maps source_maps.qwer · 1.0.0Minified JavaScript stack traces mapped back to the original files, lines, columns and function names with their source maps, and the code around each place.7 views · 8 downloadsIPP printing ipp.qwer · 1.0.0IPP, the protocol behind AirPrint and CUPS: requests built for a printer's attributes, print jobs with copies, duplex, paper and colour, its jobs and cancelling them, sent over ipp:// or ipps://, and answers read into a summary of the printer.6 views · 7 downloadsThread 0 posts
On Uptime checks: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.