const map = require('apr-map'); const forceArray = require('force-array'); const get = require('lodash.get'); const date = require('date.js'); const timestamp = require('internet-timestamp'); const got = require('got'); const url = require('url'); const qs = require('qs'); const transform = (res) => { return forceArray(res).reduce((sum, { data }) => { const result = !Array.isArray(data) ? data.result : data; return result.reduce((sum, inst) => { const metric = !inst.job ? inst.metric : inst; const { values = [], value = [] } = inst; const { instance, job, __name__ } = metric; const oldJob = get(sum, job, {}); const oldInstance = get(sum, `${job}.${instance}`, {}); const _value = values.length ? values : value return Object.assign(sum, { [job]: Object.assign(oldJob, { [instance]: Object.assign(oldInstance, { [__name__]: _value }) }) }) }, sum); }, {}); }; const range = module.exports.range = async ({ query = [], ago = '24h ago', step = '15s', host = 'localhost:9090' }) => { const end = timestamp(new Date()); const start = timestamp(date(ago)); const ranges = await map(forceArray(query), async (query) => { return await got(url.format({ protocol: 'http:', slashes: true, host: host, pathname: '/api/v1/query_range', query: { query, end, step, start } })) }); return transform( ranges.map((range) => JSON.parse(range.body)) ); }; const query = module.exports.query = async ({ host = 'localhost:9090', query = [] }) => { const res = await map(query, async (query) => { return await got(url.format({ protocol: 'http:', slashes: true, host: host, pathname: '/api/v1/query', query: { query: query } })) }); return transform( res.map((res) => JSON.parse(res.body)) ); }; const tree = module.exports.tree = async ({ host = 'localhost:9090', query = [] }) => { const res = await got(url.format({ protocol: 'http:', slashes: true, host: host, pathname: '/api/v1/series', search: qs.stringify({ match: query }, { arrayFormat: 'brackets' }) })); return transform(JSON.parse(res.body)); }; if (!module.parent) { process.on('unhandledRejection', (reason) => { throw reason }); const usage = () => { console.error(` Usage: node metrics.js --type={type} --query={metric} --step={step} --ago={ago} node scripts/prometheus.js --type=range --query=node_memory_heap_used_bytes --query=node_memory_heap_total_bytes `.trim()); return process.exit(1); } const argv = require('minimist')(process.argv.slice(2)); if (!argv.query || !argv.type) { return usage(); } const handlers = { tree, range, query }; if (!handlers[argv.type]) { return usage(); } const conf = { query: argv.query, ago: argv.ago, step: argv.step, host: argv.host }; handlers[argv.type](conf).then((res) => { console.log(JSON.stringify(res, null, 2)); }); }