const R = require('ramda')
, S = require('sanctuary')
const R = require('ramda')
, S = require('sanctuary')
log :: a -> a
Uses R.tap
to print to console
const log = R.tap(x => console.log('log: ', x))
printLens :: Lens s a -> String
Prints lensPath
/lensProp
lenses
const printLens = lens => JSON.stringify(R.set(lens, true, {}))
toInt :: String -> Int
const toInt = R.curryN(1, parseInt)
mLenses :: String -> Object -> [Lens s a]
Takes a metric type and the metrics, and returns lenses to all the keys in that metric
const mLenses = R.curry((type, metrics) => S.pipe([R.prop(type), R.keys, R.map(R.pipe(R.pair(type), R.lensPath))], metrics))
_initStats :: Object -> [Lens s a] -> Object -> Object
const _initStats = R.curry((object, mLenses, stats) =>
R.reduce((stats, mLens) =>
R.when(R.pipe(R.view(mLens), R.isNil), R.set(mLens, object))(stats), stats, mLenses))
:: [Lens s a] -> Object -> Object
const initStats = _initStats({ x: [], y: [] })
, initTimers = _initStats({ hour: [], x: [], y: [], error_y: { array: [], arrayminus: [] } })
:: Lens s a => Lens s a
const x = lens => R.compose(lens, R.lensProp('x'))
, y = lens => R.compose(lens, R.lensProp('y'))
, hour = lens => R.compose(lens, R.lensProp('hour'))
, store = lens => R.compose(lens, R.lensProp('store'))
, aplus = lens => R.compose(lens, R.lensPath(['error_y', 'array']))
, aminus = lens => R.compose(lens, R.lensPath(['error_y', 'arrayminus']))
setX :: Int -> Object -> [Lens s a] -> Object
const setX = R.curry((timestamp, mLenses, stats) =>
R.reduce((stats, mLens) =>
R.over(x(mLens), R.append(timestamp), stats), stats, mLenses))
setY :: String -> Object -> [Lens s a] -> Object
const setY = R.curry((metrics, mLenses, stats) =>
R.reduce((stats, mLens) => {
return S.pipe([R.view(store(mLens)), R.isNil, R.not], metrics) ?
R.over(y(mLens), R.concat(R.__, S.pipe([R.keys, R.map(toInt)], R.view(store(mLens), metrics))), stats) :
R.over(y(mLens), R.append(R.view(mLens, metrics)), stats)
}, stats, mLenses))
setXY :: Object -> Int -> Object
const setXY = R.curry((timestamp, metrics, stats) => {
const lenses = R.flatten(['counters', 'counter_rates', 'gauges'].map(type => mLenses(type, metrics)))
return S.pipe([initStats(lenses), setX(timestamp, lenses), setY(metrics, lenses)], stats)
})
setSets :: String -> Object -> Object -> Object
const setSets = R.curry((timestamp, metrics, stats) => {
const lenses = mLenses('sets', metrics)
return R.reduce((stats, mLens) => {
const setCount = R.keys(R.view(store(mLens), metrics)).length
return S.pipe([ R.over(x(mLens), R.concat(R.__, R.repeat(timestamp, setCount)))
, R.over(y(mLens), R.concat(R.__, S.pipe([R.keys, R.map(toInt)], R.view(store(mLens), metrics))))
], stats)
}, initStats(lenses, stats), lenses)
})
setTimersHour :: [Lenses s a] -> String -> Object -> Object -> Object
const setTimersHour = R.curry((mLenses, timestamp, metrics, stats) =>
R.reduce((stats, mLens) => {
const timerHour = R.view(hour(mLens), stats)
, lastY = R.compose(hour(mLens), R.lensIndex(timerHour.length - 1), R.lensProp('y'))
if (R.not(R.isEmpty(timerHour)) && timestamp - R.last(timerHour).x < 60 * 1000)
return R.over(lastY, R.concat(R.view(mLens, metrics)), stats)
else
return R.over(hour(mLens), R.append({
x: timestamp,
y: R.view(mLens, metrics),
name: new Date(timestamp).toLocaleString(),
type: 'box',
boxmean: true
}), stats)
}, stats, mLenses))
setTimersXY :: [Lenses s a] -> String -> Object -> Object -> Object
const setTimersXY = R.curry((mLenses, timestamp, metrics, stats) =>
R.reduce((stats, mLens) => {
const mean = Math.round(R.mean(R.view(mLens, metrics)))
, plus = R.reduce(R.max, 0, R.view(mLens, metrics)) - mean
, minus = mean - R.reduce(R.min, Infinity, R.view(mLens, metrics))
return S.pipe([ R.over(x(mLens), R.append(timestamp))
, R.over(y(mLens), R.append(mean))
, R.over(aplus(mLens), R.append(plus))
, R.over(aminus(mLens), R.append(minus))], stats)
}, stats, mLenses))
setTimers :: Object -> Object -> Object -> Object
const setTimers = R.curry((timestamp, metrics, stats) => {
const lenses = mLenses('timers', metrics)
return S.pipe([ initTimers(lenses)
, setTimersHour(lenses, timestamp, metrics)
, setTimersXY(lenses, timestamp, metrics)
], stats)
})
setStats :: Object -> Object -> Object -> Object
const setStats = R.curry((timestamp, metrics, stats) =>
S.pipe([ setXY(timestamp, metrics)
, setSets(timestamp, metrics)
, setTimers(timestamp, metrics) ], stats))
testNs :: String -> String -> Boolean
const testNs = R.curry((namespace, string) => R.test(new RegExp(`^${namespace.replace(/\./g, '\\.')}`), string))
pickNs :: String -> Object -> Object
const pickNs = R.curry((namespace, stats) =>
R.ifElse(R.isArrayLike,
R.filter(testNs(namespace)),
R.pickBy(R.flip(testNs(namespace))))(stats))
filterStats :: String -> String -> Object -> Object
const filterStats = R.curry((namespace, metric, stats) => {
if (metric === 'all')
return R.map(pickNs(namespace), stats)
else
return pickNs(namespace, stats[metric])
})
module.exports = {
setTimersHour: setTimersHour,
setTimersXY: setTimersXY,
initTimers: initTimers,
initStats: initStats,
setTimers: setTimers,
setStats: setStats,
setSets: setSets,
setXY: setXY,
setX: setX,
setY: setY,
mLenses: mLenses,
filterStats: filterStats,
pickNs: pickNs,
testNs: testNs,
printLens: printLens,
toInt: toInt,
log: log
}