diff --git a/scripts/show-stats.js b/scripts/show-stats.js index 3766a01..b008480 100644 --- a/scripts/show-stats.js +++ b/scripts/show-stats.js @@ -1,65 +1,13 @@ -const redis = require('redis') const subDays = require('date-fns/sub_days') const prettyBytes = require('pretty-bytes') -const invariant = require('invariant') const table = require('text-table') +const { + sumKeys, + sumTopScores, + createDayKey +} = require('../server/StatsServer') -const RedisURL = process.env.REDIS_URL - -invariant( - RedisURL, - 'Missing the $REDIS_URL environment variable' -) - -const sumValues = (array) => - array.reduce((memo, n) => memo + (parseInt(n, 10) || 0), 0) - -const db = redis.createClient(RedisURL) - -const getKeyValues = (keys) => - new Promise((resolve, reject) => { - db.mget(keys, (error, values) => { - if (error) { - reject(error) - } else { - resolve(values) - } - }) - }) - -const sumKeys = (keys) => - getKeyValues(keys).then(sumValues) - -const createScoresMap = (array) => { - const map = {} - - for (let i = 0; i < array.length; i += 2) - map[array[i]] = parseInt(array[i + 1], 10) - - return map -} - -const getTopScores = (key, n = 10) => - new Promise((resolve, reject) => { - db.zrevrange(key, 0, n, 'withscores', (error, value) => { - if (error) { - reject(error) - } else { - resolve(createScoresMap(value)) - } - }) - }) - -const sumTopScores = (keys, n) => - Promise.all(keys.map(key => getTopScores(key, n))).then(values => { - return values.reduce((memo, map) => { - Object.keys(map).forEach(key => { - memo[key] = (memo[key] || 0) + map[key] - }) - - return memo - }, {}) - }) +const now = new Date const createRange = (start, end) => { const range = [] @@ -70,14 +18,6 @@ const createRange = (start, end) => { return range } -const createDayKey = (date) => - `${date.getUTCFullYear()}-${date.getUTCMonth()}-${date.getUTCDate()}` - -const createHourKey = (date) => - `${createDayKey(date)}-${date.getUTCHours()}` - -const now = new Date - const createPastDays = (n) => createRange(1, n + 1).map(days => subDays(now, days)).reverse() diff --git a/server/StatsServer.js b/server/StatsServer.js new file mode 100644 index 0000000..3b5ee02 --- /dev/null +++ b/server/StatsServer.js @@ -0,0 +1,78 @@ +const redis = require('redis') +const invariant = require('invariant') + +const RedisURL = process.env.REDIS_URL + +invariant( + RedisURL, + 'Missing the $REDIS_URL environment variable' +) + +const db = redis.createClient(RedisURL) + +const sumValues = (array) => + array.reduce((memo, n) => memo + (parseInt(n, 10) || 0), 0) + +const getKeyValues = (keys) => + new Promise((resolve, reject) => { + db.mget(keys, (error, values) => { + if (error) { + reject(error) + } else { + resolve(values) + } + }) + }) + +const sumKeys = (keys) => + getKeyValues(keys).then(sumValues) + +const createScoresMap = (array) => { + const map = {} + + for (let i = 0; i < array.length; i += 2) + map[array[i]] = parseInt(array[i + 1], 10) + + return map +} + +const getTopScores = (key, n = 10) => + new Promise((resolve, reject) => { + db.zrevrange(key, 0, n, 'withscores', (error, value) => { + if (error) { + reject(error) + } else { + resolve(createScoresMap(value)) + } + }) + }) + +const sumTopScores = (keys, n) => + Promise.all(keys.map(key => getTopScores(key, n))).then(values => { + return values.reduce((memo, map) => { + Object.keys(map).forEach(key => { + memo[key] = (memo[key] || 0) + map[key] + }) + + return memo + }, {}) + }) + +const createDayKey = (date) => + `${date.getUTCFullYear()}-${date.getUTCMonth()}-${date.getUTCDate()}` + +const createHourKey = (date) => + `${createDayKey(date)}-${date.getUTCHours()}` + +const createMinuteKey = (date) => + `${createDayKey(date)}-${date.getUTCMinutes()}` + +module.exports = { + getKeyValues, + sumKeys, + getTopScores, + sumTopScores, + createDayKey, + createHourKey, + createMinuteKey +} diff --git a/workers/ingest-stats.js b/workers/ingest-stats.js index 5a94210..988e368 100644 --- a/workers/ingest-stats.js +++ b/workers/ingest-stats.js @@ -1,6 +1,11 @@ require('isomorphic-fetch') -const invariant = require('invariant') const redis = require('redis') +const invariant = require('invariant') +const { + createDayKey, + createHourKey, + createMinuteKey +} = require('../server/StatsServer') const CloudflareEmail = process.env.CLOUDFLARE_EMAIL const CloudflareKey = process.env.CLOUDFLARE_KEY @@ -157,7 +162,7 @@ const processPerDayTimeseries = (ts) => 'ERROR: per-day timeseries must span exactly one day' ) - const dayKey = `${since.getUTCFullYear()}-${since.getUTCMonth()}-${since.getUTCDate()}` + const dayKey = createDayKey(since) // Q: How many requests do we serve per day? db.set(`stats-requests-${dayKey}`, ts.requests.all) @@ -223,7 +228,7 @@ const processPerHourTimeseries = (ts) => 'ERROR: per-hour timeseries must span exactly one hour' ) - const hourKey = `${since.getUTCFullYear()}-${since.getUTCMonth()}-${since.getUTCDate()}-${since.getUTCHours()}` + const hourKey = createHourKey(since) // Q: How many requests do we serve per hour? (expire after 7 days) db.setex(`stats-requests-${hourKey}`, (oneDaySeconds * 7), ts.requests.all) @@ -259,7 +264,7 @@ const processPerMinuteTimeseries = (ts) => 'ERROR: per-minute timeseries must span exactly one minute' ) - const minuteKey = `${since.getUTCFullYear()}-${since.getUTCMonth()}-${since.getUTCDate()}-${since.getUTCHours()}-${since.getUTCMinutes()}` + const minuteKey = createMinuteKey(since) // Q: How many requests do we serve per minute? (expire after 1 day) db.setex(`stats-requests-${minuteKey}`, oneDaySeconds, ts.requests.all)