From 541bdace4b9cc330da3308f88bdcf886d049e282 Mon Sep 17 00:00:00 2001 From: Adam Janis Date: Thu, 12 Nov 2020 18:57:42 +0100 Subject: [PATCH] chore(perf): save only failed days to KV storage --- config.yaml | 56 +++------------------------- pages/index.js | 12 ++++-- src/components/monitorHistogram.js | 18 ++++----- src/components/monitorStatusLabel.js | 6 ++- src/functions/cronTrigger.js | 39 +++++++++++-------- src/functions/helpers.js | 46 ++++++++++++++++++----- 6 files changed, 88 insertions(+), 89 deletions(-) diff --git a/config.yaml b/config.yaml index bdf621e..4e97ff7 100644 --- a/config.yaml +++ b/config.yaml @@ -1,6 +1,7 @@ settings: title: "Status Page" - logo: logo-192x192.png + url: "https://status-page.eidam.dev" # for Slack messages + logo: logo-192x192.png # image in ./public/ folder daysInHistogram: 90 allmonitorsOperational: "All Systems Operational" @@ -8,7 +9,9 @@ settings: monitorLabelOperational: "Operational" monitorLabelNotOperational: "Not great not terrible" monitorLabelNoData: "No data" - + dayInHistogramNoData: "No data" + dayInHistogramOperational: "All good" + dayInHistogramNotOperational: "Some checks failed" monitors: - id: kiwi-com-homepage @@ -71,13 +74,6 @@ monitors: method: GET expectStatus: 403 - - id: google-com-2 - name: Google.com - description: Google homepage - url: 'https://www.google.com' - method: GET - expectStatus: 200 - - id: cf-workers-status-page-2 name: This Workers Status Page project made public description: /shrug @@ -114,13 +110,6 @@ monitors: method: GET expectStatus: 403 - - id: google-com-22 - name: Google.com - description: Google homepage - url: 'https://www.google.com' - method: GET - expectStatus: 200 - - id: cf-workers-status-page-22 name: This Workers Status Page project made public description: /shrug @@ -146,7 +135,7 @@ monitors: name: Hello World url: 'http://cnn.cn/' method: GET - expectStatus: 200 + expectStatus: 201 - id: eidam-dev-333 @@ -156,13 +145,6 @@ monitors: method: GET expectStatus: 403 - - id: google-com-333 - name: Google.com - description: Google homepage - url: 'https://www.google.com' - method: GET - expectStatus: 200 - - id: cf-workers-status-page-333 name: This Workers Status Page project made public description: /shrug @@ -206,13 +188,6 @@ monitors: method: GET expectStatus: 403 - - id: 25-google-com - name: Bing.com - description: Bing homepage - url: 'https://www.google.com' - method: GET - expectStatus: 200 - - id: 25-cf-workers-status-page name: This Workers Status Page project made public description: /shrug @@ -251,12 +226,6 @@ monitors: method: GET expectStatus: 403 - - id: 25-google-com-2 - name: Google.com - description: Google homepage - url: 'https://www.google.com' - method: GET - expectStatus: 200 - id: 25-cf-workers-status-page-2 name: This Workers Status Page project made public @@ -294,13 +263,6 @@ monitors: method: GET expectStatus: 403 - - id: 25-google-com-22 - name: Google.com - description: Google homepage - url: 'https://www.google.com' - method: GET - expectStatus: 200 - - id: 25-cf-workers-status-page-22 name: This Workers Status Page project made public description: /shrug @@ -336,12 +298,6 @@ monitors: method: GET expectStatus: 403 - - id: 25-google-com-333 - name: Google.com - description: Google homepage - url: 'https://www.google.com' - method: GET - expectStatus: 200 - id: 25-cf-workers-status-page-333 name: This Workers Status Page project made public diff --git a/pages/index.js b/pages/index.js index 4022899..7fe237e 100644 --- a/pages/index.js +++ b/pages/index.js @@ -24,6 +24,8 @@ export async function getEdgeProps() { if (x.metadata.operational === false) monitorsOperational = false }) + console.log(JSON.stringify(kvMonitorsMap)) + // transform KV list to array of failed days const kvMonitorsFailedDaysArray = kvMonitorsFailedDays.map(x => { return x.name @@ -79,9 +81,13 @@ export default function Index({ ? config.settings.allmonitorsOperational : config.settings.notAllmonitorsOperational} -
- checked {Math.round((Date.now() - kvLastUpdate) / 1000)} sec ago -
+ {typeof window !== 'undefined' ? ( +
+ checked {Math.round((Date.now() - kvLastUpdate) / 1000)} sec ago +
+ ) : ( + '' + )} {config.monitors.map((monitor, key) => { diff --git a/src/components/monitorHistogram.js b/src/components/monitorHistogram.js index d676fa8..7a0cd78 100644 --- a/src/components/monitorHistogram.js +++ b/src/components/monitorHistogram.js @@ -15,22 +15,22 @@ export default function MonitorHistogram({ key={`${monitor.id}-histogram`} className="horizontal flex histogram" > - {Array.from(Array(config.settings.daysInHistogram + 1).keys()).map(key => { + {Array.from(Array(config.settings.daysInHistogram).keys()).map(key => { date.setDate(date.getDate() + 1) - const dayInHistory = date.toISOString().split('T')[0] - const dayInHistoryKey = 'h_' + monitor.id + '_' + dayInHistory + const dayInHistogram = date.toISOString().split('T')[0] + const dayInHistogramKey = 'h_' + monitor.id + '_' + dayInHistogram let bg = '' - let dayInHistoryStatus = 'No data' + let dayInHistogramLabel = config.settings.dayInHistogramNoData // filter all dates before first check, check the rest - if (kvMonitor && kvMonitor.firstCheck <= dayInHistory) { - if (!kvMonitorsFailedDaysArray.includes(dayInHistoryKey)) { + if (kvMonitor && kvMonitor.firstCheck <= dayInHistogram) { + if (!kvMonitorsFailedDaysArray.includes(dayInHistogramKey)) { bg = 'green' - dayInHistoryStatus = 'No outage recorded' + dayInHistogramLabel = config.settings.dayInHistogramOperational } else { bg = 'orange' - dayInHistoryStatus = 'Some outages' + dayInHistogramLabel = config.settings.dayInHistogramNotOperational } } @@ -38,7 +38,7 @@ export default function MonitorHistogram({
) diff --git a/src/components/monitorStatusLabel.js b/src/components/monitorStatusLabel.js index 19b4957..6a976eb 100644 --- a/src/components/monitorStatusLabel.js +++ b/src/components/monitorStatusLabel.js @@ -1,3 +1,5 @@ +import config from '../../config.yaml' + export default function MonitorStatusLabel({ kvMonitorsMap, monitor }) { let labelColor = 'grey' let labelText = 'No data' @@ -5,10 +7,10 @@ export default function MonitorStatusLabel({ kvMonitorsMap, monitor }) { if (typeof kvMonitorsMap[monitor.id] !== 'undefined') { if (kvMonitorsMap[monitor.id].operational) { labelColor = 'green' - labelText = 'Operational' + labelText = config.settings.monitorLabelOperational } else { labelColor = 'orange' - labelText = 'Not great not terrible' + labelText = config.settings.monitorLabelNotOperational } } diff --git a/src/functions/cronTrigger.js b/src/functions/cronTrigger.js index c4307fa..43351f4 100644 --- a/src/functions/cronTrigger.js +++ b/src/functions/cronTrigger.js @@ -1,6 +1,12 @@ import config from '../../config.yaml' -import { setKV, getKVWithMetadata, gcMonitors, getKV } from './helpers' +import { + setKV, + getKVWithMetadata, + gcMonitors, + getKV, + notifySlack, +} from './helpers' function getDate() { return new Date().toISOString().split('T')[0] @@ -14,7 +20,7 @@ export async function processCronTrigger(event) { method: monitor.method || 'GET', redirect: monitor.followRedirect ? 'follow' : 'manual', headers: { - 'User-Agent': 'cf-worker-status-page', + 'User-Agent': config.settings.user_agent || 'cf-worker-status-page', }, } @@ -28,29 +34,32 @@ export async function processCronTrigger(event) { firstCheck: kvState.metadata ? kvState.metadata.firstCheck : getDate(), } - // Write current status if status changed or for first time + // write current status if status changed or for first time if ( !kvState.metadata || kvState.metadata.operational !== newMetadata.operational ) { console.log('Saving changed state..') - await setKV('s_' + monitor.id, null, newMetadata) - - if (typeof SECRET_SLACK_WEBHOOK !== 'undefined') { + // first try to notify Slack in case fetch() or other limit is reached + if (typeof SECRET_SLACK_WEBHOOK_URL !== 'undefined') { await notifySlack(monitor, newMetadata) } - if (!newMetadata.operational) { - // try to get failed daily status first as KV read is cheaper than write - const kvFailedDayStatusKey = 'h_' + monitor.id + '_' + getDate() - const kvFailedDayStatus = await getKV(kvFailedDayStatusKey) + await setKV('s_' + monitor.id, null, newMetadata) + } - // write if not found - if (!kvFailedDayStatus) { - console.log('Saving new failed daily status..') - await setKV(kvFailedDayStatusKey, null) - } + // write daily status if monitor is not operational + if (!newMetadata.operational) { + // try to get failed daily status first as KV read is cheaper than write + const kvFailedDayStatusKey = 'h_' + monitor.id + '_' + getDate() + console.log(kvFailedDayStatusKey) + const kvFailedDayStatus = await getKV(kvFailedDayStatusKey) + + // write if not found + if (!kvFailedDayStatus) { + console.log('Saving new failed daily status..') + await setKV(kvFailedDayStatusKey, null) } } diff --git a/src/functions/helpers.js b/src/functions/helpers.js index fff99d3..fd95312 100644 --- a/src/functions/helpers.js +++ b/src/functions/helpers.js @@ -1,3 +1,5 @@ +import config from '../../config.yaml' + export async function getMonitors() { const monitors = await listKV('s_') return monitors.keys @@ -73,18 +75,42 @@ export async function gcMonitors(config) { }) } -async function notifySlack(monitor, metadata) { - const blocks = [ - { - type: 'section', - text: { - type: 'mrkdwn', - text: `Some monitor is now in :this: status`, +export async function notifySlack(monitor, newMetadata) { + const payload = { + attachments: [ + { + color: newMetadata.operational ? '#36a64f' : '#f2c744', + blocks: [ + { + type: 'section', + text: { + type: 'mrkdwn', + text: `Monitor *${monitor.name}* changed status to *${ + newMetadata.operational + ? config.settings.monitorLabelOperational + : config.settings.monitorLabelNotOperational + }*`, + }, + }, + { + type: 'context', + elements: [ + { + type: 'mrkdwn', + text: `${ + newMetadata.operational ? ':white_check_mark:' : ':x:' + } \`${monitor.method} ${monitor.url}\` - :eyes: <${ + config.settings.url + }|Status Page>`, + }, + ], + }, + ], }, - }, - ] + ], + } return fetch(SECRET_SLACK_WEBHOOK_URL, { - body: JSON.stringify({ blocks }), + body: JSON.stringify(payload), method: 'POST', headers: { 'Content-Type': 'application/json' }, })