Files
laermsensor-stack/sensorapi/databases/victoria.js
admin 23fe7d2ed2 VictoriaMetrics als zusätzliche Datenbank-Option für Messwerte ergänzt (STORE/DBASE=victoria)
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>
2026-08-20 21:31:06 +02:00

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
}