The full switch: Monitors and Disks read only the sensor API; /api/metrics retired
- stock Monitors modules fed by one sensor stream, the catalog and one batch of histories (GET /api/sensors/history?ids=…), through sampleAdapter.ts - the stream closes while the page is hidden and refills its curves on return - Disks tab live rates from the stream - new sensors: hamlab.sample_interval, ups.last_event - stream: asking for about the sampling rate means every sample - NUT runtime rounded at the source Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
f01175ceca
commit
4ddf10be51
+16
-17
@@ -110,12 +110,11 @@ func New(cfg *config.Config, sessions *auth.Sessions, mgr *term.Manager, col *me
|
||||
m.HandleFunc("PATCH /api/terminals/{id}", s.auth(s.renameTerminal))
|
||||
m.HandleFunc("DELETE /api/terminals/{id}", s.auth(s.deleteTerminal))
|
||||
m.HandleFunc("GET /api/terminals/{id}/attach", s.auth(s.attach))
|
||||
m.HandleFunc("GET /api/metrics", s.auth(s.metricsLatest))
|
||||
m.HandleFunc("GET /api/metrics/history", s.auth(s.metricsHistory))
|
||||
m.HandleFunc("GET /api/sensors", s.sensorAuth(s.sensorCatalog))
|
||||
m.HandleFunc("GET /api/sensors/query", s.sensorAuth(s.sensorQuery))
|
||||
m.HandleFunc("POST /api/sensors/query", s.sensorAuth(s.sensorQuery))
|
||||
m.HandleFunc("GET /api/sensors/stream", s.sensorAuth(s.sensorStream))
|
||||
m.HandleFunc("GET /api/sensors/history", s.sensorAuth(s.sensorHistories))
|
||||
m.HandleFunc("GET /api/sensors/prometheus", s.sensorAuth(s.sensorProm))
|
||||
m.HandleFunc("GET /metrics", s.sensorAuth(s.sensorProm))
|
||||
m.HandleFunc("GET /api/sensors/{id}", s.sensorAuth(s.sensorOne))
|
||||
@@ -652,21 +651,6 @@ func (s *Server) me(w http.ResponseWriter, _ *http.Request) {
|
||||
})
|
||||
}
|
||||
|
||||
// ---- metrics (Dashboard) ----
|
||||
|
||||
func (s *Server) metricsLatest(w http.ResponseWriter, _ *http.Request) {
|
||||
smp, ok := s.metrics.Latest()
|
||||
if !ok {
|
||||
jsonErr(w, 503, "no sample yet")
|
||||
return
|
||||
}
|
||||
jsonOK(w, 200, smp)
|
||||
}
|
||||
|
||||
func (s *Server) metricsHistory(w http.ResponseWriter, _ *http.Request) {
|
||||
jsonOK(w, 200, s.metrics.History())
|
||||
}
|
||||
|
||||
// ---- sensors: the standard read interface (SENSORS.md) ----
|
||||
|
||||
// sensorCatalog lists every sensor with its current value; ?ids= narrows it with
|
||||
@@ -713,6 +697,16 @@ func (s *Server) sensorHistory(w http.ResponseWriter, r *http.Request) {
|
||||
jsonOK(w, 200, h)
|
||||
}
|
||||
|
||||
// sensorHistories is many histories in one request: ?ids= takes IDs and globs.
|
||||
func (s *Server) sensorHistories(w http.ResponseWriter, r *http.Request) {
|
||||
match, err := sensors.Matcher(r.URL.Query().Get("ids"))
|
||||
if err != nil {
|
||||
jsonErr(w, 400, err.Error())
|
||||
return
|
||||
}
|
||||
jsonOK(w, 200, map[string]any{"series": s.sensors.Histories(match)})
|
||||
}
|
||||
|
||||
// sensorProm is every numeric sensor in the Prometheus text format.
|
||||
func (s *Server) sensorProm(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain; version=0.0.4; charset=utf-8")
|
||||
@@ -770,6 +764,11 @@ func (s *Server) sensorStream(w http.ResponseWriter, r *http.Request) {
|
||||
if ms, err := strconv.Atoi(r.URL.Query().Get("every")); err == nil && ms > 0 {
|
||||
every = time.Duration(ms) * time.Millisecond
|
||||
}
|
||||
// Asking for roughly the sampling rate means "every sample": don't let timer jitter
|
||||
// drop alternate ticks.
|
||||
if iv := s.metrics.Interval(); every <= iv+iv/2 {
|
||||
every = 0
|
||||
}
|
||||
h := w.Header()
|
||||
h.Set("Content-Type", "text/event-stream")
|
||||
h.Set("Cache-Control", "no-store")
|
||||
|
||||
Reference in New Issue
Block a user