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/redis/ssh/

persistence

The last snapshot of a Redis server, its age, the changes not saved and the state of its append-only file, by SSH and redis-cli INFO.

  • services
  • redis
  • valkey
  • persistence
  • rdb
  • aof
  • redis-cli
  • ssh

by banshee1 installation1 version

v1Latest

Published on October 27, 2026. First version.

Keen 1.0.0 · 74 lines
// The persistence of a Redis server, by SSH and redis-cli INFO on its server: whether its last snapshot (RDB)
// was saved, how old the last one saved is, the changes not saved yet, and the state of its append-only file
// (AOF). The password, when Redis asks for one, stays on the server.
need('protocol:ssh');
$port = variable('redis:port', 'integer', array(
    'label'   => 'Port',
    'help'    => 'The port Redis listens on, on the server itself.',
    'default' => 6379,
));
$password_file = variable('redis:password-file', 'text', array(
    'label'    => 'Password file',
    'help'     => 'The path, on the server, of a file the SSH account reads and that holds the Redis password alone, for instance /home/monitoring/.redis-password. Empty: no password.',
    'required' => false,
));

output('rdb', 'text', array('label' => 'Last snapshot'));
output('rdb-age', 'number', array('label' => 'Age of the last snapshot saved', 'unit' => 'h'));
output('changes', 'number', array('label' => 'Changes not saved'));
output('aof', 'text', array('label' => 'Append-only file'));

watch.expect('rdb-failed', 'Snapshot failed', 'rdb', array('critical' => array('ok')));
watch.expect('aof-failed', 'Append-only file failing', 'aof', array('critical' => array('ok', 'off')));
watch.above('rdb-old', 'Snapshot too old', 'rdb-age', array('warning' => 24, 'enabled' => false));
watch.above('changes', 'Many changes not saved', 'changes', array('enabled' => false));

// INFO through redis-cli, to the Redis of the server on its port: one line "field:value" per figure. A
// password goes from its file into REDISCLI_AUTH, which redis-cli reads, by the shell of the server: it is
// never written on a command line, and never leaves the server. LC_ALL=C keeps the messages in English.
function redis_info($port, $password_file) {
    $command = 'LC_ALL=C redis-cli -p ' . $port;
    if ($password_file != '') {
        if (list.count(text.match($password_file, '^/[A-Za-z0-9_./-]+$')) == 0) {
            fail('misconfigured', 'The password file must be an absolute path of letters, digits and . _ / -');
        }
        $command = 'REDISCLI_AUTH="$(cat \'' . $password_file . '\')" ' . $command;
    }
    $read = ssh.run($command . ' INFO');
    $said = $read['output'] . $read['errors'];
    if (!text.contains($read['output'], 'redis_version:')) {
        if (text.contains($said, 'Could not connect') || text.contains($said, 'Connection refused')) {
            fail('critical', 'Redis is not running', $said);
        }
        if (list.count(text.match($said, 'NOAUTH|WRONGPASS|NOPERM|invalid password')) > 0) {
            fail('misconfigured', 'Redis refuses the account', $said);
        }
        fail('misconfigured', 'redis-cli did not answer INFO', $said);
    }
    $info = array();
    foreach (text.lines($read['output']) as $line) {
        $m = text.match($line, '^([a-z0-9_]+):(.*)$');
        if (list.count($m) > 0) {
            $info[$m[1]] = $m[2];
        }
    }
    return $info;
}

$info = redis_info($port, $password_file);

// rdb_last_save_time is the time of the last snapshot saved, in seconds since 1970, or the start of Redis
// when none was saved since; rdb_last_bgsave_status is ok or err.
value('rdb', $info['rdb_last_bgsave_status']);
value('rdb-age', number.round((time.now() - $info['rdb_last_save_time']) / 3600, 1));
value('changes', $info['rdb_changes_since_last_save']);

// The append-only file: off when it is not enabled, err when its last write or its last rewrite failed.
$aof = 'off';
if ($info['aof_enabled'] == 1) {
    $aof = 'ok';
    if ($info['aof_last_write_status'] != 'ok' || $info['aof_last_bgrewrite_status'] != 'ok') {
        $aof = 'err';
    }
}
value('aof', $aof);