Skip to content

Instantly share code, notes, and snippets.

@rickosborne
Last active December 18, 2022 23:24
Show Gist options
  • Save rickosborne/509acbff60e3949fae80acd9a33ec597 to your computer and use it in GitHub Desktop.
Save rickosborne/509acbff60e3949fae80acd9a33ec597 to your computer and use it in GitHub Desktop.
Apache2 status to CloudWatch metrics shovel/export script
/*
-----------------------------------------------------------
The world's simplest Apache2-to-CloudWatch metrics shovel,
by Rick Osborne (rickosborne.org, github:rickosborne)
LICENSE: CC BY-NC-SA 4.0
Creative Commons Attribution-NonCommercial-ShareAlike 4.0
https://creativecommons.org/licenses/by-nc-sa/4.0/
Basically:
1. Enable mod_status:
$ a2enmod status
It will likely tell you it's already enabled.
2. If you don't already have one, add a localhost vhost:
/etc/apache2/sites-available/localhost.conf
<VirtualHost localhost:80>
ServerName localhost:80
KeepAlive Off
LogLevel warn
CustomLog "/var/log/apache2/localhost/nossl.log" "combined"
ErrorLog "/var/log/apache2/localhost/nossl-err.log"
<Location "/server-status">
SetHandler server-status
Require host localhost
</Location>
</VirtualHost>
3. Make sure that site works:
$ a2ensite localhost
4. Make sure that status page is available:
$ curl -v 'http://localhost/server-status?auto'
5. Add this script somewhere, such as:
/opt/cloudwatch/a2cw.js
Make sure you change the `aws` and `host` variables
if your system is weird.
6. Figure out where your node is installed:
$ which node
7. Run the script manually once just to be sure it's okay:
$ node /opt/cloudwatch/a2cw.js
You should see a bunch of aws commands logged.
8. Copy and run one of those commands to make sure your
awscli setup is correct. If you don't have awscli:
$ apt install awscli
Or yum or whatever.
9. If awscli tells you to configure the region or credentials,
do so now. Re-rerun one of the logged commands to test.
10. Add a crontab entry for 1-minute intervals:
$ crontab -e
And then a line like:
* * * * * /usr/bin/node /opt/cloudwatch/a2cw.js
11. Give it a few minutes and you should see the metrics
in CloudWatch.
12. Optionally, add more entries to the `units` map below.
-----------------------------------------------------------
*/
const child = require("child_process");
const http = require("http");
const aws = child.execSync("which aws", {encoding: "utf-8"}).trim();
const host = child.execSync("hostname", {encoding: "utf-8"}).trim();
const units = {
"ServerUptimeSeconds": "Seconds",
"Load1": "Count",
"Load5": "Count",
"Load15": "Count",
"TotalAccesses": "Count",
"TotalkBytes": "Kilobytes",
"ReqPerSec": "Count/Second",
"BytesPerSec": "Bytes/Second",
"BytesPerReq": "Bytes",
"BusyWorkers": "Count",
"IdleWorkers": "Count",
"ConnsTotal": "Count",
"CacheUsage": "Percent",
};
http.get({
host: "localhost",
protocol: "http:",
path: "/server-status?auto",
method: "GET",
timeout: 30,
agent: false,
}, (res) => {
if (res.statusCode < 200 || res.statusCode >= 300) {
console.error("Bad status code: " + res.statusCode);
process.exit(0);
}
res.on("error", (e) => {
console.error(e);
process.exit(0);
});
let data = '';
res.on("data", (chunk) => {
data += chunk;
});
res.on("end", () => {
const lines = data.split("\n");
for (const line of lines) {
const match = line.match(/^([^:]+):\s+(\d+(\.\d+)?)%?$/);
if (match) {
const key = (match[1] || '').replace(/\s+/g, "");
const value = parseFloat(match[2]);
const unit = units[key];
if (unit != null) {
const command = `${aws} cloudwatch put-metric-data --metric-name 'httpd-${key}' --unit '${unit}' --value ${value} --dimensions 'host=${host}' --namespace 'HTTP:Apache'`;
console.log(command);
child.execSync(command);
}
}
}
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment