mirror of
https://github.com/XuehaiPan/nvitop.git
synced 2026-05-21 06:45:24 -06:00
fix(examples/monitor-web): emit strict JSON by mapping NaN/Inf to null
`json.dumps` defaults to `allow_nan=True` and emits bare `NaN`/`Infinity` tokens, which the browser's `JSON.parse` rejects with ``Unexpected token 'N'``. The collector writes `math.nan` for any metric key that was sampled previously but is missing from the current snapshot, so the dashboard hit this on its first poll. Add a small `_finite()` walker that maps non-finite floats to `None` (serialized as JSON `null`) before encoding, and switch the dumper to `allow_nan=False` so any future leak fails loudly. The dashboard JS already treats non-finite values as `'—'` via `Number.isFinite()`, so `null` flows through to the same fallback with no client-side change.
This commit is contained in:
parent
7b53aafdd4
commit
5c66a9ae28
1 changed files with 21 additions and 1 deletions
|
|
@ -27,6 +27,7 @@ from __future__ import annotations
|
|||
import argparse
|
||||
import http.server
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
import re
|
||||
import ssl
|
||||
|
|
@ -257,7 +258,10 @@ class MonitorRequestHandler(http.server.BaseHTTPRequestHandler):
|
|||
self._send_json(payload)
|
||||
|
||||
def _send_json(self, payload: object) -> None:
|
||||
body = json.dumps(payload, default=float).encode('utf-8')
|
||||
# `allow_nan=False` makes strict JSON; ``_finite()`` first maps
|
||||
# `math.nan`/`math.inf` (which the collector emits for missing samples)
|
||||
# to `None` so the browser's `JSON.parse` accepts the body.
|
||||
body = json.dumps(_finite(payload), allow_nan=False, default=float).encode('utf-8')
|
||||
self.send_response(200)
|
||||
self.send_header('Content-Type', 'application/json; charset=utf-8')
|
||||
self.send_header('Cache-Control', 'no-store')
|
||||
|
|
@ -274,6 +278,22 @@ class MonitorRequestHandler(http.server.BaseHTTPRequestHandler):
|
|||
self.wfile.write(body)
|
||||
|
||||
|
||||
def _finite(value: Any) -> Any:
|
||||
"""Replace `nan`/`+inf`/`-inf` with :data:`None` so the result is strict JSON.
|
||||
|
||||
The collector writes :data:`math.nan` for any metric key that was sampled previously but is
|
||||
missing from the current snapshot (see :class:`nvitop.ResourceMetricCollector`), and strict
|
||||
JSON has no representation for ``NaN`` or ``Infinity``.
|
||||
"""
|
||||
if isinstance(value, float):
|
||||
return value if math.isfinite(value) else None
|
||||
if isinstance(value, dict):
|
||||
return {k: _finite(v) for k, v in value.items()}
|
||||
if isinstance(value, (list, tuple)):
|
||||
return [_finite(v) for v in value]
|
||||
return value
|
||||
|
||||
|
||||
def _maybe_positive_int(text: str | None) -> int | None:
|
||||
if text is None:
|
||||
return None
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue