#!/usr/bin/env perl =head1 NAME memcached_servers_ - Munin multigraph plugin to monitor multiple memcache servers =head1 CONFIGURATION You need to configure the to-be-used servers and the corresponding labels separated by spaace in your environment. Example: [memcached_servers_*] env.addresses cache1.server.com:11211 cache2.server.com:11211 env.labels master slave Please note that the number of labels and addresses must be equal. =head1 MULTIGRAPH With munin multigraph capabilities, you can generate different graphs. Available graphs include: =over =item bytes: memcached bytes usage =item hits: get and set hits =item items: number of stored items =item requests: number of requests =item traffic: traffic =back Link the plugin to get the desirec output, for example: memcached_multi_bytes =head1 DEPENDENCIES =over =item Cache::Memcached =back =head1 ACKNOWLEDGEMENTS This plugin is based on the available memcached plugins at L =head1 AUTHORS Jonas Kaufmann =cut use strict; use warnings; use Cache::Memcached; use File::Basename; #Configuration of used servers in environment my @addresses = split(/ /, $ENV{addresses}); my @labels = split(/ /, $ENV{labels}); if ($#addresses < 0 || $#labels < 0) { print "Error: you need to configure addresses and labels in your environment.\n"; exit 1; } if ($#addresses != $#labels) { print "Error: number of addresses and labels must be equal.\n"; exit 1; } # Configuration of modes for multigraph my @modes = qw(bytes hits items requests traffic); my $mode = substr(basename($0), length('memcached_servers_')); if (($mode eq '') || ! grep($_ eq $mode, @modes)) { $mode = $modes[0]; } # Output for munin config my $cmd = shift || ''; if ($cmd eq 'config') { # Labels and basic graph information if ($mode eq 'bytes') { print "graph_title Memcached bytes used\n"; print "graph_args --base 1024 -l 0\n"; print "graph_vlabel bytes\n"; print "graph_category memory\n"; print "graph_info This graph monitors the size of the memcached cache.\n"; } elsif ($mode eq 'hits') { print "graph_title Memcached cache hits and misses\n"; print "graph_args --base 1000 -l 0\n"; print "graph_vlabel requests\n"; print "graph_category memory\n"; print "graph_info This graph monitors the number of cache hits and misses.\n"; } elsif ($mode eq 'items') { print "graph_title Memcached cached items\n"; print "graph_args --base 1000 -l 0\n"; print "graph_vlabel items\n"; print "graph_category memory\n"; print "graph_info This graph monitors the number of items stored by the memcached server.\n"; } elsif ($mode eq 'requests') { print "graph_title Memcached requests\n"; print "graph_args --base 1000 -l 0\n"; print "graph_vlabel requests\n"; print "graph_category memory\n"; print "graph_info This graph monitors the number of get and set requests.\n"; } elsif ($mode eq 'traffic') { print "graph_title Memcached network traffic\n"; print "graph_args --base 1000 -l 0\n"; print "graph_vlabel bits per \${graph_period}\n"; print "graph_category memory\n"; print "graph_info This graph monitors the network traffic of the memcached server.\n"; } # Graph configuration for (my $i = 0; $i < @labels; $i++) { if ($mode eq 'bytes') { print "bytes_" . $labels[$i] . ".label bytes used (" . $labels[$i] . ")\n"; print "bytes_" . $labels[$i] . ".info Number of bytes currently used (" . $labels[$i] . ")\n"; print "bytes_" . $labels[$i] . ".min 0\n"; print "maxbytes_" . $labels[$i] . ".label maximum available (" . $labels[$i] . ")\n"; print "maxbytes_" . $labels[$i] . ".info The configured cache size (" . $labels[$i] . ")\n"; print "maxbytes_" . $labels[$i] . ".min 0\n"; } elsif ($mode eq 'hits') { print "hits_" . $labels[$i] . ".label hits (" . $labels[$i] . ")\n"; print "hits_" . $labels[$i] . ".info Number of cache hits (" . $labels[$i] . ")\n"; print "hits_" . $labels[$i] . ".min 0\n"; print "hits_" . $labels[$i] . ".type DERIVE\n"; print "misses_" . $labels[$i] . ".label misses (" . $labels[$i] . ")\n"; print "misses_" . $labels[$i] . ".info Number of cache misses (" . $labels[$i] . ")\n"; print "misses_" . $labels[$i] . ".min 0\n"; print "misses_" . $labels[$i] . ".type DERIVE\n"; } elsif ($mode eq 'items') { print "items_" . $labels[$i] . ".label items (" . $labels[$i] . ")\n"; print "items_" . $labels[$i] . ".info Number of cached items (" . $labels[$i] . ")\n"; print "items_" . $labels[$i] . ".min 0\n"; } elsif ($mode eq 'requests') { print "gets_" . $labels[$i] . ".label gets (" . $labels[$i] . ")\n"; print "gets_" . $labels[$i] . ".info Number of get requests (" . $labels[$i] . ")\n"; print "gets_" . $labels[$i] . ".min 0\n"; print "gets_" . $labels[$i] . ".type DERIVE\n"; print "sets_" . $labels[$i] . ".label sets (" . $labels[$i] . ")\n"; print "sets_" . $labels[$i] . ".info Number of set requests (" . $labels[$i] . ")\n"; print "sets_" . $labels[$i] . ".min 0\n"; print "sets_" . $labels[$i] . ".type DERIVE\n"; } elsif ($mode eq 'traffic') { print "up_" . $labels[$i] . ".label bits in (" . $labels[$i] . ")\n"; print "up_" . $labels[$i] . ".info Traffic received by memcached (" . $labels[$i] . ")\n"; print "up_" . $labels[$i] . ".min 0\n"; print "up_" . $labels[$i] . ".cdef up_" . $labels[$i] . ",8,*\n"; print "up_" . $labels[$i] . ".type COUNTER\n"; print "down_" . $labels[$i] . ".label bits out (" . $labels[$i] . ")\n"; print "down_" . $labels[$i] . ".info Traffic sent by memcached (" . $labels[$i] . ")\n"; print "down_" . $labels[$i] . ".min 0\n"; print "down_" . $labels[$i] . ".cdef down_" . $labels[$i] . ",8,*\n"; print "down_" . $labels[$i] . ".type COUNTER\n"; } } exit 0; } # Output for data queries for (my $i = 0; $i < @addresses; $i++) { my $memd = new Cache::Memcached { 'servers' => [$addresses[$i]] }; my $memstats = $memd->stats(['misc']); if ($mode eq 'bytes') { print "bytes_" . $labels[$i] . ".value " . $memstats->{hosts}->{$addresses[$i]}->{misc}->{bytes} . "\n"; print "maxbytes_" . $labels[$i] . ".value " . $memstats->{hosts}->{$addresses[$i]}->{misc}->{limit_maxbytes} . "\n"; } elsif ($mode eq 'hits') { print "hits_" . $labels[$i] . ".value " . $memstats->{hosts}->{$addresses[$i]}->{misc}->{get_hits} . "\n"; print "misses_" . $labels[$i] . ".value " . $memstats->{hosts}->{$addresses[$i]}->{misc}->{get_misses} . "\n"; } elsif ($mode eq 'items') { print "items_" . $labels[$i] . ".value " . $memstats->{hosts}->{$addresses[$i]}->{misc}->{curr_items} . "\n"; } elsif ($mode eq 'requests') { print "gets_" . $labels[$i] . ".value " . $memstats->{hosts}->{$addresses[$i]}->{misc}->{cmd_get} . "\n"; print "sets_" . $labels[$i] . ".value " . $memstats->{hosts}->{$addresses[$i]}->{misc}->{cmd_set} . "\n"; } elsif ($mode eq 'traffic') { print "up_" . $labels[$i] . ".value " . $memstats->{hosts}->{$addresses[$i]}->{misc}->{bytes_read} . "\n"; print "down_" . $labels[$i] . ".value " . $memstats->{hosts}->{$addresses[$i]}->{misc}->{bytes_written} . "\n"; } }