fix: probe Prometheus /metrics at server root, not under /v1 (v2.03.10)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c3cf123afe
commit
c292ff2242
@ -9,6 +9,13 @@ The version is defined in [`blitztext/__init__.py`](blitztext/__init__.py).
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [2.03.10] - 2026-06-09
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- **Server RAM probe.** Prometheus `/metrics` is almost always at the server
|
||||||
|
root (`http://host:port/metrics`), not under `/v1`. Now tries the root URL
|
||||||
|
first before falling back to the API base path.
|
||||||
|
|
||||||
## [2.03.09] - 2026-06-09
|
## [2.03.09] - 2026-06-09
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@ -6,4 +6,4 @@ counterpart to the macOS Blitztext menu bar app: it runs natively on the host
|
|||||||
(not in a container) so it can type into any application via xdotool.
|
(not in a container) so it can type into any application via xdotool.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = "2.03.09"
|
__version__ = "2.03.10"
|
||||||
|
|||||||
@ -154,34 +154,45 @@ def probe_server_ram_mb(base_url: str, timeout: float = 3.0) -> float | None:
|
|||||||
Returns RSS in MB if the server exposes Prometheus metrics with either
|
Returns RSS in MB if the server exposes Prometheus metrics with either
|
||||||
``process_resident_memory_bytes`` (standard Python/Go exporter) or
|
``process_resident_memory_bytes`` (standard Python/Go exporter) or
|
||||||
``container_memory_rss`` (cAdvisor). Returns None if not available.
|
``container_memory_rss`` (cAdvisor). Returns None if not available.
|
||||||
|
|
||||||
|
Tries the server root first (http://host:port/metrics) then the api base
|
||||||
|
path (http://host:port/v1/metrics), because Prometheus endpoints are almost
|
||||||
|
always mounted at root even when the API lives under /v1.
|
||||||
"""
|
"""
|
||||||
if not base_url:
|
if not base_url:
|
||||||
return None
|
return None
|
||||||
base = _api_base(base_url)
|
p = urlparse(base_url.rstrip("/"))
|
||||||
try:
|
root = f"{p.scheme}://{p.netloc}"
|
||||||
req = urllib.request.Request(base + "/metrics")
|
candidates = [root + "/metrics"]
|
||||||
with urllib.request.urlopen(req, timeout=timeout) as resp:
|
api_base_metrics = _api_base(base_url) + "/metrics"
|
||||||
text = resp.read().decode("utf-8", "replace")
|
if api_base_metrics != candidates[0]:
|
||||||
except Exception:
|
candidates.append(api_base_metrics)
|
||||||
|
|
||||||
|
def _parse(text: str) -> float | None:
|
||||||
|
for line in text.splitlines():
|
||||||
|
line = line.strip()
|
||||||
|
if line.startswith("#"):
|
||||||
|
continue
|
||||||
|
for metric in ("process_resident_memory_bytes", "container_memory_rss"):
|
||||||
|
if line.startswith(metric):
|
||||||
|
parts = line.split()
|
||||||
|
if len(parts) >= 2:
|
||||||
|
try:
|
||||||
|
return float(parts[-1]) / (1024 * 1024) # bytes → MB
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Parse Prometheus text format — we only need two specific metric names.
|
for url in candidates:
|
||||||
# Lines look like: process_resident_memory_bytes 1.23456e+08
|
try:
|
||||||
best: float | None = None
|
req = urllib.request.Request(url)
|
||||||
for line in text.splitlines():
|
with urllib.request.urlopen(req, timeout=timeout) as resp:
|
||||||
line = line.strip()
|
result = _parse(resp.read().decode("utf-8", "replace"))
|
||||||
if line.startswith("#"):
|
if result is not None:
|
||||||
|
return result
|
||||||
|
except Exception:
|
||||||
continue
|
continue
|
||||||
for metric in ("process_resident_memory_bytes", "container_memory_rss"):
|
return None
|
||||||
if line.startswith(metric):
|
|
||||||
parts = line.split()
|
|
||||||
if len(parts) >= 2:
|
|
||||||
try:
|
|
||||||
best = float(parts[-1]) / (1024 * 1024) # bytes → MB
|
|
||||||
return best
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
return best
|
|
||||||
|
|
||||||
|
|
||||||
def detect_remote_device(base_url: str, timeout: float = 3.0) -> str:
|
def detect_remote_device(base_url: str, timeout: float = 3.0) -> str:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user