cloki
Version:
LogQL API with Clickhouse Backend
109 lines (98 loc) • 3.1 kB
JavaScript
const logger = require('./logger')
/* Function Helpers */
/* Label Parser */
const labelParser = function (labels) {
// Label Parser
const rx = /\"?\b(\w+)\"?(!?=~?)("[^"\n]*?")/g
let matches
const output = []
matches = rx.exec(labels)
while (matches) {
if (matches.length > 3) output.push([matches[1], matches[2], matches[3].replace(/['"]+/g, '')])
matches = rx.exec(labels)
}
let regex = false
try {
regex = /\}\s*(.*)/g.exec(labels)[1] || false
} catch (e) {
}
return { labels: output, regex: regex }
}
/* Fingerprinting */
const shortHash = require('short-hash')
let xxh = null
require('xxhash-wasm')().then((res) => {
xxh = res
logger.info('xxh ready')
}, (err) => {
logger.error(err)
process.exit(1)
})
const fingerPrint = function (text, hex, alg) {
alg = alg || process.env.HASH || 'short-hash'
switch (alg) {
case 'xxhash64':
if (!xxh) {
throw new Error('Hasher is not ready')
}
if (hex) return xxh.h64(text).toString()
else return BigInt('0x' + xxh.h64(text))
}
if (hex) return shortHash(text)
else return parseInt(shortHash(text), 16)
}
const toJSON = require('jsonic')
const parseOrDefault = (str, def) => {
try {
return str ? parseFloat(str) : def
} catch (e) {
return def
}
}
const parseMs = (time, def) => {
try {
return time ? Math.floor(parseInt(time) / 1000000) : def
} catch (e) {
return def
}
}
/**
*
* @param time {string | BigInt}
* @return {BigInt | undefined}
*/
const parseStringifiedNanosOrRFC3339 = (time) => {
if (typeof time === 'bigint') {
return time
}
const iMatch = time.match(/^[0-9]+$/)
if (iMatch) {
// It is nanos
return BigInt(time)
}
const dMatch = time.match(/(?<y>[0-9]{4})-(?<m>[0-1][0-9])-(?<d>[0-3][0-9])T(?<h>[0-2][0-9]):(?<i>[0-6][0-9]):(?<s>[0-6][0-9])(?<ns>\.[0-9]+)?(?<offs>Z|(\+|-)(?<oh>[0-2][0-9]):(?<oi>[0-6][0-9]))/)
if (dMatch) {
const g = dMatch.groups
let iTime = Date.UTC(g.y, parseInt(g.m) - 1, g.d, g.h, g.i, g.s)
if (g.offs !== 'Z') {
iTime += (g.offs[0] === '+' ? 1 : -1) * (parseInt(g.oh) * 3600 * 1000 + parseInt(g.oi) * 60 * 1000)
}
const ns = g.ns ? BigInt((g.ns + '000000000').substr(1, 9)) : BigInt(0)
return BigInt(iTime) * BigInt(1e6) + ns
}
}
let _samplesReadTableName = () => 'samples_read'
let _checkVersion = () => false
module.exports.DATABASE_NAME = () => process.env.CLICKHOUSE_DB || 'cloki'
module.exports.fingerPrint = fingerPrint
module.exports.labelParser = labelParser
module.exports.toJSON = toJSON
module.exports.parseMs = parseMs
module.exports.parseOrDefault = parseOrDefault
module.exports.onSamplesReadTableName = (fn) => { _samplesReadTableName = fn }
module.exports.onCheckVersion = (fn) => { _checkVersion = fn }
module.exports.samplesReadTableName = (from) => _samplesReadTableName(from)
module.exports.checkVersion = (ver, from) => _checkVersion(ver, from)
module.exports.schemaVer = 'v3'
module.exports.samplesTableName = 'samples_v3'
module.exports.parseStringifiedNanosOrRFC3339 = parseStringifiedNanosOrRFC3339