Last active
April 4, 2020 20:20
-
-
Save renehamburger/14448d4a2b3c72aa66cdec0314da546e to your computer and use it in GitHub Desktop.
Send user_beancounters metrics to CloudRadar
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
// How to use: | |
// 1. Create a custom check on CloudRadar called 'beancounters', which should be updated every 5 minutes. | |
// 2. Insert the custom check token below. | |
// 3. Execute this script every 5 minutes with root privileges, | |
// e.g. by calling `sudo crontab -e` and adding `*/5 * * * * /usr/bin/node /<Path to script>/check-user-beancounters.js` | |
const axios = require('axios').default; | |
const { exec } = require('child_process'); | |
const { promisify } = require('util'); | |
// Unfortunately, CloudRadar only allows 12 values, so they need to be hand picked | |
const REPORTED_METRICS = ['numproc', 'numtcpsock', 'numothersock']; | |
const REPORTED_FIELDS = ['held', 'maxheld', 'failcnt']; | |
const WARNING_LEVEL = 0.9; | |
const url = 'https://hub.cloudradar.io/cct/'; | |
const options = { | |
headers: { | |
'X-CustomCheck-Token': '<Enter the custom check token here>' | |
} | |
}; | |
/** | |
* @param {string} cmd | |
* @return {Promise<string>} as | |
*/ | |
async function executeShellCommand(cmd) { | |
const results = await promisify(exec)(cmd); | |
if (results.stderr) { | |
throw results.stderr; | |
} | |
return results.stdout; | |
} | |
async function main() { | |
const textContent = await executeShellCommand('cat /proc/user_beancounters'); | |
const textContentWithoutUserId = textContent.replace(/\n *uid/, '\n').replace(/\n *\d+:/, '\n'); | |
const rows = textContentWithoutUserId.trim().split('\n'); | |
const header = rows[1].trim().split(/\s+/); | |
const metrics = rows.slice(2) | |
.map(row => { | |
const columns = row.trim().split(/\s+/); | |
return columns.map((column, index) => index ? parseFloat(column) : column); | |
}) | |
.filter(columns => columns[0] !== 'dummy'); | |
const failedMetrics = metrics.filter(metric => metric[5] !== 0); | |
const metricsAboveWarningLevel = metrics.filter(metric => metric[2] >= WARNING_LEVEL * metric[4]); | |
const payload = { | |
'beancounters.success': failedMetrics.length ? 0 : 1, | |
'beancounters.table': `${header}\n${metrics.join('\n')}` | |
}; | |
if (failedMetrics.length) { | |
const failedMetricsString = failedMetrics.map(metric => metric[0]).join(', '); | |
payload['beancounters.alert'] = `Failed metrics: ${failedMetricsString})}`; | |
} else if (metricsAboveWarningLevel.length) { | |
const warningString = metricsAboveWarningLevel.map(metric => `${metric[0]}: ${metric[2]} of ${metric[4]}`).join(', '); | |
payload['beancounters.warning'] = `Metrics closer to failure: ${warningString})}`; | |
} | |
metrics.forEach((columns) => { | |
const metricLabel = columns[0]; | |
columns.slice(1).forEach((value, index) => { | |
const columnLabel = header[index + 1]; | |
if (REPORTED_METRICS.includes(metricLabel) && REPORTED_FIELDS.includes(columnLabel)) { | |
payload[`beancounters.${metricLabel}.${columnLabel}`] = value; | |
} | |
}); | |
}); | |
await axios.post(url, payload, options); | |
} | |
main().catch((err) => { | |
if (err.response) { | |
console.error(`CloudRadar request failed: ${err.response.status} - ${err.response.statusText} - ${err.response.data.error}`); | |
} else { | |
console.error(err); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment