POST one SQL statement to Better Stack ClickHouse, return JSONEachRow rows.
(token: str, sql: str)
| 36 | |
| 37 | |
| 38 | def _query(token: str, sql: str) -> list[dict]: |
| 39 | """POST one SQL statement to Better Stack ClickHouse, return JSONEachRow rows.""" |
| 40 | body = sql.encode("utf-8") |
| 41 | req = urllib.request.Request(BS_URL, data=body, method="POST") |
| 42 | req.add_header("Content-Type", "text/plain") |
| 43 | req.add_header( |
| 44 | "Authorization", "Basic " + base64.b64encode(token.encode()).decode() |
| 45 | ) |
| 46 | try: |
| 47 | with urllib.request.urlopen(req, timeout=120) as resp: |
| 48 | raw = resp.read().decode("utf-8", errors="replace") |
| 49 | except urllib.error.HTTPError as e: |
| 50 | detail = e.read().decode("utf-8", errors="replace")[:500] |
| 51 | raise SystemExit( |
| 52 | f"Better Stack query failed: HTTP {e.code}\nSQL: {sql[:200]}...\n{detail}" |
| 53 | ) from e |
| 54 | rows: list[dict] = [] |
| 55 | for line in raw.splitlines(): |
| 56 | line = line.strip() |
| 57 | if not line: |
| 58 | continue |
| 59 | try: |
| 60 | rows.append(json.loads(line)) |
| 61 | except ValueError: |
| 62 | log.warning("non-JSON row dropped: %s", line[:200]) |
| 63 | return rows |
| 64 | |
| 65 | |
| 66 | # --- SQL fragments ---------------------------------------------------------- |