#!/usr/bin/perl
# -*- cperl -*-
#
# Plugin to monitor memcache statistics
#
# This module has 3 seperate graph datasets:
# rates
# bytes
# counters
#
# For each of them, symlink the memcached_ script to memcached_FOO where foo is
# the datset name.
#
# Parameters supported:
#
#  config
#  autoconf
#
# Configurable variables
#
# host  Host of the memcache daemon
# port  Port of the memcache daemon
#
# Author: Robin H. Johnson <robbat2@gentoo.org>
# Slightly based on the original version by Joshua Thijssen
# <jthijssen@noxlogic.nl>
#
# Included in trunk for 1.4 by Nicolai Langfeldt.  Set family to contrib
# and disabled autoconf due to lack of "suggest".
#
# Magic markers:
#%# family=contrib
#%# capabilities=noautoconf

use strict;
my $ret = undef;
if (! eval "require Cache::Memcached;") {
$ret = "Cache::Memcached not found";
}
my $HOST = exists $ENV{'host'} ? $ENV{'host'} : "127.0.0.1";
my $PORT = exists $ENV{'port'} ? $ENV{'port'} : 11211;
if ( exists $ARGV[0] and $ARGV[0] eq "autoconf" ) {
if ($ret) {
  print "no ($ret)\n";
  exit 1;
}
# Todo: we can always connect to a memcache server without any errors so I cannot really
# find a way to detect the presence of a memcache instance. Maybe a forced write/read/delete
# but there should be a better way somewhere...
print "yes\n";
exit 0;
}

if($ret) {
print "no ($ret)\n";
exit 1;
}

# We do everything by this array
my %all_vars = (
              rates => {
                        master => {
                                   graph_title => 'Memcached - Commands',
                                   graph_args => '--base 1000',
                                   graph_vlabel => '/${graph_period}',
                                   graph_category => 'memcache',
                        },
                        memcache_cache_hits => {
                                               label => 'Cache hits',
                                               type => 'DERIVE',
                                               min => '0',
                                               max => '5000',
                                               draw => 'LINE2',
                                               info => 'Number of cache hits',
                                               stat_group => 'misc',
                                               stat_name => 'get_hits'
                        },
                        memcache_cache_misses  => {
                                  label => 'Cache misses',
                                  type => 'DERIVE',
                                  min => '0',
                                  max => '5000',
                                  draw => 'LINE2',
                                  info => 'Number of cache misses',
                                  stat_group => 'misc',
                                  stat_name => 'get_misses'
                        },
                        memcache_cmd_get => {
                                  label => 'GET requests',
                                  type => 'DERIVE',
                                  min => '0',
                                  max => '5000',
                                  draw => 'LINE2',
                                  info => 'Number of GET commands seen',
                                  stat_group => 'misc',
                                  stat_name => 'cmd_get'
                        },
                        memcache_cmd_set => {
                                  label => 'SET requests',
                                  type => 'DERIVE',
                                  min => '0',
                                  max => '5000',
                                  draw => 'LINE2',
                                  info => 'Number of SET commands seen',
                                  stat_group => 'misc',
                                  stat_name => 'cmd_set'
                        },
                        memcache_total_items => {
                                  label => 'New items*5',
                                  type => 'DERIVE',
                                  min => '0',
                                  max => '5000',
                                  draw => 'LINE2',
                                  info => 'New items*5',
                                  cdef => 'memcache_total_items,5,*',
                                  stat_group => 'misc',
                                  stat_name => 'total_items'
                        },
                        memcache_total_connections => {
                                  label => 'New connections*100',
                                  type => 'DERIVE',
                                  min => '0',
                                  max => '5000',
                                  cdef => 'memcache_total_connections,100,*',
                                  draw => 'LINE2',
                                  info => 'New connections*100',
                                  stat_group => 'misc',
                                  stat_name => 'total_connections'
                        },
                },
                bytes => {
                        master => {
                                graph_title => 'Memcached - Network traffic',
                                graph_args => '--base 1000',
                                graph_vlabel => 'bytes in(-)/out(+) per ${graph_period}',
                                graph_category => 'memcache',
                        },
                        memcache_bytes_read => {
                                label => 'Bytes read',
                                type => 'COUNTER',
                                draw => 'LINE2',
                                max => '1000000',
                                info => 'Bytes read from network',
                                graph => 'no',
                                stat_group => 'misc',
                                stat_name => 'bytes_read'
                        },
                        memcache_bytes_written => {
                                label => 'Bytes written',
                                negative => 'memcache_bytes_read',
                                type => 'COUNTER',
                                max => '1000000',
                                draw => 'LINE2',
                                info => 'Bytes written to network',
                                stat_group => 'misc',
                                stat_name => 'bytes_written'
                        },
                },
                counters => {
                        master => {
                                graph_title => 'Memcached - Current values',
                                graph_args => '--base 1000',
                                #graph_args => '--base 1000 --loga',
                                graph_vlabel => 'Totals',
                                graph_category => 'memcache',
                                graph_scale => 'no',
                        },
                        memcache_curr_items => {
                                label => 'Current items',
                                type => 'GAUGE',
                                min => '0',
                                draw => 'LINE2',
                                info => 'Number of items in cache',
                                stat_group => 'misc',
                                stat_name => 'curr_items'
                        },
                        memcache_curr_connections => {
                                label => 'Current connections*100',
                                type => 'GAUGE',
                                min => '0',
                                draw => 'LINE2',
                                cdef => 'memcache_curr_connections,100,*',
                                info => 'Number of connections*100',
                                stat_group => 'misc',
                                stat_name => 'curr_connections'
                        },
                        memcache_bytes_allocated => {
                                label => 'Bytes allocated (KiB)',
                                type => 'GAUGE',
                                min => '0',
                                draw => 'LINE2',
                                cdef => 'memcache_bytes_allocated,1024,/',
                                info => 'Bytes allocated (KiB)',
                                stat_group => 'misc',
                                stat_name => 'bytes'
                        },
                }
      );

$0 =~ /memcached_(.+)*$/;
my $func = $1;
exit 2 unless defined $func;
my %vars = %{$all_vars{$func}};

#          STAT rusage_user 3941.052868
#          STAT rusage_system 18436.366246
#          STAT connection_structures 1112
#          STAT bytes 382985002
#          STAT limit_maxbytes 536870912

if ( exists $ARGV[0] and $ARGV[0] eq "config" ) {
        my %v = %{$vars{'master'}};
        foreach my $k ( keys %v ) {
                print "$k ".$v{$k}."\n"
        }
        print 'graph_order ';
        foreach my $k ( sort(keys %vars) ) {
                if($k eq 'master') { next; }
                print $k." ";
        }
        print "\n";
        foreach my $k ( sort(keys %vars) ) {
                if($k eq 'master') { next; }
                my %v = %{$vars{$k}};
                foreach my $k2 (keys %v) {
                        if($k2 eq 'stat_group' or $k2 eq 'stat_name') { next; }
                        print "$k.$k2 ".$v{"$k2"}."\n";
                }
        }
        exit 0;
}
my $mc = new Cache::Memcached { 'servers' => [ "$HOST:$PORT" ] };
my $stats = $mc->stats ('misc');

foreach my $k ( sort(keys %vars) ) {
        if($k eq 'master') { next; }
        my %v = %{$vars{$k}};
        if($v{type} eq 'COMPUTE') { next; }
        my $sg = $v{stat_group};
        my $sn = $v{stat_name};
        my $value = $stats->{hosts}->{"$HOST:$PORT"}->{$sg}->{$sn};
        defined($value) or $value = 'U';
        print "$k.value ".$value."\n";
}
