banshee is under active development: collectors will keep changing, and a version you publish will likely need adjustments. For stable use, wait for version 1.0.0.

Services

banshee/services-collection/services/apache/https/

server-status

The busy and idle workers, scoreboard use and requests per second of an Apache httpd server, from its server-status page.

  • services
  • apache
  • httpd
  • web
  • mod_status
  • server-status
  • http
  • https

by banshee1 installation1 version

v1Latest

Published on October 27, 2026. First version.

Keen 1.0.0 · 71 lines
// An Apache httpd server, by its mod_status page in its machine-readable form (?auto) over HTTP: the workers
// busy and idle, the share of the scoreboard busy, and the requests per second. The page answers lines
// "Key: value": "Total Accesses: 131", "BusyWorkers: 1", "IdleWorkers: 74", "Scoreboard: _W___....".
need('protocol:http');
$user = need('protocol:http:user', 'optional');
$password = need('protocol:http:password', 'optional');

$url = variable('apache:url', 'text', array(
    'label' => 'Status page address',
    'help'  => 'The address of the server-status page, http:// or https://, for instance https://www.example/server-status. The collector adds ?auto.',
));

output('busy', 'number', array('label' => 'Busy workers'));
output('idle', 'number', array('label' => 'Idle workers'));
output('busy-percent', 'number', array('label' => 'Scoreboard busy', 'unit' => '%'));
output('requests', 'number', array('label' => 'Requests', 'unit' => 'requests/s'));

watch.above('saturation', 'Workers saturated', 'busy-percent', array('warning' => 80, 'critical' => 95, 'for' => '3 runs'));
watch.below('no-idle', 'No idle worker', 'idle', array('warning' => 1, 'for' => '3 runs', 'enabled' => false));
watch.habit('requests-unusual', 'Unusual request rate', 'requests', array('enabled' => false));

// The machine-readable form of the page, unless the address already asks for it.
$address = $url;
if (!text.contains($url, '?')) {
    $address = $url . '?auto';
}

// A server that refuses the connection, or does not answer in time, is down: critical.
$answer = http.get($address, user=$user, password=$password, errors=$err);
if ($err['code'] == 'connection_refused' || $err['code'] == 'timeout') {
    fail('critical', 'Apache down', $err['text']);
}
if ($err['code'] != '') {
    fail('unreachable', 'Apache unreachable', $err['text']);
}
if ($answer['status'] == 401 || $answer['status'] == 403 || $answer['status'] == 404) {
    fail('misconfigured', 'Apache refuses the status page, code ' . $answer['status'],
        'See the server-status location and its Require line in the documentation.');
}
if ($answer['status'] != 200) {
    fail('unreachable', 'Apache answers the status page with code ' . $answer['status']);
}

$status = array();
foreach (text.lines($answer['body']) as $line) {
    $m = text.match($line, '^([A-Za-z ]+): *(.*)$');
    if (list.count($m) > 0) {
        $status[$m[1]] = $m[2];
    }
}
if (!list.has($status, 'BusyWorkers') || !list.has($status, 'IdleWorkers') || !list.has($status, 'Scoreboard')) {
    fail('misconfigured', 'The address does not serve an Apache server-status page', $address);
}
// Total Accesses is only counted with ExtendedStatus On, the default from Apache 2.3.6 on.
if (!list.has($status, 'Total Accesses')) {
    fail('misconfigured', 'The status page does not count the requests: set ExtendedStatus On');
}

// The requests per second, from the counter of this run and the previous one: none at the first run.
$requests = counter.rate('requests', $status['Total Accesses']);
if ($requests == '') {
    skip('First reading: the request rate comes at the next run');
}

// One character per worker slot the server may run: "_" waiting, "." an open slot with no worker, any other
// letter a worker busy (reading, writing, keepalive, closing...).
$slots = text.length($status['Scoreboard']);
value('busy', $status['BusyWorkers']);
value('idle', $status['IdleWorkers']);
value('busy-percent', number.round(100 * $status['BusyWorkers'] / $slots, 1));
value('requests', number.round($requests, 2));