23fe7d2ed2
Dritte, zu mongo/influx exklusive Auswahl für die laufenden Messwerte. Schreibpfad nutzt das bestehende Influx-Line-Protocol unverändert (common/victoria_post.js); Lesepfad (sensorapi/databases/victoria.js + victoria2json.js) holt Rohdaten per VictoriaMetrics' /api/v1/export und bucketet/aggregiert stundenweise clientseitig, nach Mongo-Konvention (Stunden-Start als Label, kein Zeit-Shift nötig wie bei Influx). Scope bewusst auf die schon heute per DBASE umschaltbaren Funktionen begrenzt (getActData/getNoiseAVGData) - getAvgData/getLongAvg/getGeigerData bleiben wie bisher. Docker-Compose um victoriametrics-Service ergänzt (Retention explizit auf 100y gesetzt, da VictoriaMetrics sonst nach 1 Monat Daten löscht). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
68 lines
2.6 KiB
JavaScript
68 lines
2.6 KiB
JavaScript
// Access to VictoriaMetrics via HTTP (Prometheus-compatible /api/v1/export,
|
|
// no Flux support - see common/victoria_post.js for the write side, which
|
|
// reuses the InfluxDB line-protocol format on VictoriaMetrics' /write endpoint).
|
|
|
|
import axios from 'axios'
|
|
import { logit, logerror } from '../utilities/logit.js'
|
|
import { returnOnError } from "../utilities/reporterror.js"
|
|
import { exportToRows, bucketNoiseAVG } from "../utilities/victoria2json.js"
|
|
|
|
let VICTORIAHOST = process.env.VICTORIAHOST || "localhost"
|
|
let VICTORIAPORT = process.env.VICTORIAPORT || 8428
|
|
|
|
const VICTORIAURL_EXPORT = `http://${VICTORIAHOST}:${VICTORIAPORT}/api/v1/export`
|
|
|
|
// opts.start/opts.stop arrive as Flux range() fragments ("start: <iso>" /
|
|
// "stop: <iso>") built by calcRange() in getsensorData.js - strip the Flux
|
|
// keyword the same way sensorapi/databases/mongo.js already does.
|
|
const isoStart = (opts) => opts.start.slice(7)
|
|
const isoStop = (opts) => opts.stop.slice(6)
|
|
|
|
const victoriaExport = async (matchSelector, start, end) => {
|
|
let erg = { values: '', err: null }
|
|
try {
|
|
let ret = await axios({
|
|
method: 'get',
|
|
url: VICTORIAURL_EXPORT,
|
|
params: { 'match[]': matchSelector, start, end },
|
|
timeout: 10000,
|
|
transformResponse: [(data) => data], // response body is ndjson, not a single JSON document - keep it raw
|
|
})
|
|
if (ret.status !== 200) {
|
|
return returnOnError(erg, 'RESPSTATUS', victoriaExport.name, ret.status)
|
|
}
|
|
erg.values = ret.data
|
|
} catch (e) {
|
|
return returnOnError(erg, e, victoriaExport.name)
|
|
}
|
|
return erg
|
|
}
|
|
|
|
export const fetchActData = async (opts) => {
|
|
let ret = { err: null, values: [] }
|
|
const match = `{__name__=~"noise_(LAeq|LA_min|LA_max|E10tel_eq)", sid="${opts.sensorid}"}`
|
|
let { values, err } = await victoriaExport(match, isoStart(opts), isoStop(opts))
|
|
if (err) {
|
|
return returnOnError(ret, err, fetchActData.name)
|
|
}
|
|
ret.values = exportToRows(values, opts.sort)
|
|
if (ret.values.length === 0) {
|
|
return returnOnError(ret, 'NODATA', fetchActData.name)
|
|
}
|
|
return ret
|
|
}
|
|
|
|
export const fetchNoiseAVGData = async (opts) => {
|
|
let ret = { err: null, values: [] }
|
|
const match = `{__name__=~"noise_(E10tel_eq|LA_max)", sid="${opts.sensorid}"}`
|
|
let { values, err } = await victoriaExport(match, isoStart(opts), isoStop(opts))
|
|
if (err) {
|
|
return returnOnError(ret, err, fetchNoiseAVGData.name)
|
|
}
|
|
ret.values = bucketNoiseAVG(values, opts.peak, opts.long)
|
|
if (ret.values.length === 0) {
|
|
return returnOnError(ret, 'NODATA', fetchNoiseAVGData.name)
|
|
}
|
|
return ret
|
|
}
|