#!/usr/bin/perl
#
-=head1 NAME
+
+=head1 MEMCACHED
Memcached - A Plugin to monitor Memcached Servers
items => This graphs the current items and total items in the memcached node.
-memory => This graphs the current and max memory allocation.
+memory => This graphs the current and max memory allocation.
The following example holds true for all graphing options in this plugin.
Example: ln -s /usr/share/munin/plugins/memcached_ /etc/munin/plugins/memcached_bytes
=head1 ACKNOWLEDGEMENTS
-The core of this plugin is based on the mysql_ plugin maintained by Kjell-Magne Ãierud
-
-Thanks to dormando as well for putting up with me ;)
+Thanks to dormando for putting up with me ;)
=head1 AUTHOR
-Matt West < https://code.google.com/p/memcached-munin-plugin/ >
+Matt West < https://github.com/mhwest13/Memcached-Munin-Plugin >
=head1 LICENSE
=head1 MAGIC MARKERS
- #%# family=manual
- #%# capabilities=autoconf suggest
+#%# family=auto
+#%# capabilities=autoconf suggest
=cut
my $host = $ENV{host} || "127.0.0.1";
my $port = $ENV{port} || 11211;
+my $connection;
my %stats;
+
# This hash contains the information contained in two memcache commands
# stats and stats settings.
$graphs{items} = {
config => {
- args => '--base 1000 --lower-limit 0',
- vlabel => 'Items in Memcached',
+ args => '--base 1000 --lower-limit 0',
+ vlabel => 'Items in Memcached',
category => 'memcached',
- title => 'Items',
- info => 'This graph shows the number of items in use by memcached',
+ title => 'Items',
+ info => 'This graph shows the number of items in use by memcached',
},
datasrc => [
{ name => 'curr_items', label => 'Current Items', min => '0' },
- { name => 'total_items', label => 'New Items', min => '0', type => 'DERIVE' },
+ {
+ name => 'total_items',
+ label => 'New Items',
+ min => '0',
+ type => 'DERIVE'
+ },
],
};
$graphs{memory} = {
config => {
- args => '--base 1024 --lower-limit 0',
- vlabel => 'Bytes Used',
+ args => '--base 1024 --lower-limit 0',
+ vlabel => 'Bytes Used',
category => 'memcached',
- title => 'Memory Usage',
- info => 'This graph shows the memory consumption of memcached',
+ title => 'Memory Usage',
+ info => 'This graph shows the memory consumption of memcached',
},
datasrc => [
- { name => 'limit_maxbytes', draw => 'AREA', label => 'Maximum Bytes Allocated', min => '0' },
- { name => 'bytes', draw => 'AREA', label => 'Current Bytes Used', min => '0' },
+ {
+ name => 'limit_maxbytes',
+ draw => 'AREA',
+ label => 'Maximum Bytes Allocated',
+ min => '0'
+ },
+ {
+ name => 'bytes',
+ draw => 'AREA',
+ label => 'Current Bytes Used',
+ min => '0'
+ },
],
};
$graphs{bytes} = {
config => {
- args => '--base 1000',
- vlabel => 'bits in (-) / out (+)',
- title => 'Network Traffic',
+ args => '--base 1000',
+ vlabel => 'bits in (-) / out (+)',
+ title => 'Network Traffic',
category => 'memcached',
- info => 'This graph shows the network traffic in (-) / out (+) of the machine',
+ info =>
+'This graph shows the network traffic in (-) / out (+) of the machine',
order => 'bytes_read bytes_written',
},
datasrc => [
- { name => 'bytes_read', type => 'DERIVE', label => 'Network Traffic coming in (-)', graph => 'no', cdef => 'bytes_read,8,*', min => '0' },
- { name => 'bytes_written', type => 'DERIVE', label => 'Traffic in (-) / out (+)', negative => 'bytes_read', cdef => 'bytes_written,8,*', min => '0' },
+ {
+ name => 'bytes_read',
+ type => 'DERIVE',
+ label => 'Network Traffic coming in (-)',
+ graph => 'no',
+ cdef => 'bytes_read,8,*',
+ min => '0'
+ },
+ {
+ name => 'bytes_written',
+ type => 'DERIVE',
+ label => 'Traffic in (-) / out (+)',
+ negative => 'bytes_read',
+ cdef => 'bytes_written,8,*',
+ min => '0'
+ },
],
};
$graphs{conns} = {
config => {
- args => '--base 1000 --lower-limit 0',
- vlabel => 'Connections per ${graph_period}',
+ args => '--base 1000 --lower-limit 0',
+ vlabel => 'Connections per ${graph_period}',
category => 'memcached',
- title => 'Connections',
- info => 'This graph shows the number of connections being handled by memcached',
+ title => 'Connections',
+ info =>
+'This graph shows the number of connections being handled by memcached',
order => 'curr_conns avg_conns',
},
datasrc => [
{ name => 'curr_conns', label => 'Current Connections', min => '0' },
- { name => 'avg_conns' , label => 'Avg Connections', min => '0' },
+ { name => 'avg_conns', label => 'Avg Connections', min => '0' },
],
};
$graphs{commands} = {
config => {
- args => '--base 1000 --lower-limit 0',
- vlabel => 'Commands per ${graph_period}',
+ args => '--base 1000 --lower-limit 0',
+ vlabel => 'Commands per ${graph_period}',
category => 'memcached',
- title => 'Commands',
- info => 'This graph shows the number of commands being handled by memcached',
+ title => 'Commands',
+ info =>
+ 'This graph shows the number of commands being handled by memcached',
},
datasrc => [
- { name => 'cmd_get', type => 'DERIVE', label => 'Gets', info => 'Cumulative number of retrieval reqs', min => '0' },
- { name => 'cmd_set', type => 'DERIVE', label => 'Sets', info => 'Cumulative number of storage reqs', min => '0' },
- { name => 'get_hits', type => 'DERIVE', label => 'Get Hits', info => 'Number of keys that were requested and found', min => '0' },
- { name => 'get_misses', type => 'DERIVE', label => 'Get Misses', info => 'Number of keys there were requested and not found', min => '0' },
+ {
+ name => 'cmd_get',
+ type => 'DERIVE',
+ label => 'Gets',
+ info => 'Cumulative number of retrieval reqs',
+ min => '0'
+ },
+ {
+ name => 'cmd_set',
+ type => 'DERIVE',
+ label => 'Sets',
+ info => 'Cumulative number of storage reqs',
+ min => '0'
+ },
+ {
+ name => 'get_hits',
+ type => 'DERIVE',
+ label => 'Get Hits',
+ info => 'Number of keys that were requested and found',
+ min => '0'
+ },
+ {
+ name => 'get_misses',
+ type => 'DERIVE',
+ label => 'Get Misses',
+ info => 'Number of keys there were requested and not found',
+ min => '0'
+ },
],
};
$graphs{evictions} = {
config => {
- args => '--base 1000 --lower-limit 0',
- vlabel => 'Evictions per ${graph_period}',
+ args => '--base 1000 --lower-limit 0',
+ vlabel => 'Evictions per ${graph_period}',
category => 'memcached',
- title => 'Evictions',
- info => 'This graph shows the number of evictions per second',
+ title => 'Evictions',
+ info => 'This graph shows the number of evictions per second',
},
datasrc => [
- { name => 'evictions', label => 'Evictions', info => 'Cumulative Evictions Across All Slabs', type => 'DERIVE', min => '0' },
+ {
+ name => 'evictions',
+ label => 'Evictions',
+ info => 'Cumulative Evictions Across All Slabs',
+ type => 'DERIVE',
+ min => '0'
+ },
],
};
#### Config Check ####
##
-if (defined $ARGV[0] && $ARGV[0] eq 'config') {
+if ( defined $ARGV[0] && $ARGV[0] eq 'config' ) {
- $0 =~ /memcached_(.+)*/;
- my $plugin = $1;
+ $0 =~ /(?:([^\/]+)_)?memcached_(.+)$/;
+ my $prefix = $1 ? $1 : '';
+ my $plugin = $2;
- die 'Unknown Plugin Specified: ' . ($plugin ? $plugin : '') unless $graphs{$plugin};
+ die 'Unknown Plugin Specified: ' . ( $plugin ? $plugin : '' )
+ unless $graphs{$plugin};
- # We need to fetch the stats before we do any config, cause its needed for multigraph
+# We need to fetch the stats before we do any config, cause its needed for multigraph
fetch_stats();
# Now lets go ahead and print out our config.
- do_config($plugin);
- exit 0;
+ do_config( $prefix, $plugin );
+ exit 0;
}
##
#### Autoconf Check ####
##
-if (defined $ARGV[0] && $ARGV[0] eq 'autoconf') {
+if ( defined $ARGV[0] && $ARGV[0] eq 'autoconf' ) {
- my $s = IO::Socket::INET->new(
- Proto => "tcp",
- PeerAddr => $host,
- PeerPort => $port,
- );
+ # Lets attempt to connect to memcached
+ my $s = get_conn();
- if (defined($s)) {
+ # Lets check that we did connect to memcached
+ if ( defined($s) ) {
print "yes\n";
exit 0;
- } else {
- print "no (unable to connect to $host\[:$port\])\n";
+ }
+ else {
+ print "no (unable to connect to $connection)\n";
exit 0;
}
}
#### Suggest Check ####
##
-if (defined $ARGV[0] && $ARGV[0] eq 'suggest') {
+if ( defined $ARGV[0] && $ARGV[0] eq 'suggest' ) {
- my $s = IO::Socket::INET->new(
- Proto => "tcp",
- PeerAddr => $host,
- PeerPort => $port,
- );
+ # Lets attempt to connect to memcached
+ my $s = get_conn();
- if (defined($s)) {
- my @rootplugins = ('bytes','conns','commands','evictions','items','memory');
+ # Lets check that we did connect to memcached
+ if ( defined($s) ) {
+ my @rootplugins =
+ ( 'bytes', 'conns', 'commands', 'evictions', 'items', 'memory' );
foreach my $plugin (@rootplugins) {
print "$plugin\n";
}
exit 0;
- } else {
- print "no (unable to connect to $host\[:$port\])\n";
+ }
+ else {
+ print "no (unable to connect to $connection)\n";
exit 0;
}
}
sub fetch_output {
- $0 =~ /memcached_(.+)*/;
- my $plugin = $1;
+ $0 =~ /(?:([^\/]+)_)?memcached_(.+)$/;
+ my $prefix = $1 ? $1 : '';
+ my $plugin = $2;
- die 'Unknown Plugin Specified: ' . ($plugin ? $plugin : '') unless $graphs{$plugin};
+ die 'Unknown Plugin Specified: ' . ( $plugin ? $plugin : '' )
+ unless $graphs{$plugin};
# Well we need to actually fetch the stats before we do anything to them.
fetch_stats();
-
+
# Now lets go ahead and print out our output.
print_root_output($plugin);
#print "graph memcached_$plugin\n";
- if ($plugin ne 'conns') {
- foreach my $dsrc (@{$graph->{datasrc}}) {
+ if ( $plugin ne 'conns' ) {
+ foreach my $dsrc ( @{ $graph->{datasrc} } ) {
my %datasrc = %$dsrc;
- while ( my ($key, $value) = each(%datasrc)) {
- next if ($key ne 'name');
+ while ( my ( $key, $value ) = each(%datasrc) ) {
+ next if ( $key ne 'name' );
my $output = $stats{$value};
print "$dsrc->{name}.value $output\n";
}
}
- } else {
+ }
+ else {
my $output;
- foreach my $dsrc (@{$graph->{datasrc}}) {
+ foreach my $dsrc ( @{ $graph->{datasrc} } ) {
my %datasrc = %$dsrc;
- while ( my ($key, $value) = each(%datasrc)) {
- if ($value eq 'curr_conns') {
+ while ( my ( $key, $value ) = each(%datasrc) ) {
+ if ( $value eq 'curr_conns' ) {
$output = $stats{curr_connections};
- } elsif ($value eq 'avg_conns') {
- $output = sprintf("%02d", $stats{total_connections} / $stats{uptime});
- } else {
+ }
+ elsif ( $value eq 'avg_conns' ) {
+ $output = sprintf( "%02d",
+ $stats{total_connections} / $stats{uptime} );
+ }
+ else {
next;
}
print "$dsrc->{name}.value $output\n";
##
sub do_config {
- my ($plugin) = (@_);
- print_root_config($plugin);
+ my ( $prefix, $plugin ) = (@_);
+ print_root_config( $prefix, $plugin );
return;
}
##
sub print_root_config {
- my ($plugin) = (@_);
+ my ( $prefix, $plugin ) = (@_);
- die 'Unknown Plugin Specified: ' . ($plugin ? $plugin : '') unless $graphs{$plugin};
+ die 'Unknown Plugin Specified: ' . ( $plugin ? $plugin : '' )
+ unless $graphs{$plugin};
my $graph = $graphs{$plugin};
- my %graphconf = %{$graph->{config}};
+ my %graphconf = %{ $graph->{config} };
#print "graph memcached_$plugin\n";
- while ( my ($key, $value) = each(%graphconf)) {
- print "graph_$key $value\n";
+ while ( my ( $key, $value ) = each(%graphconf) ) {
+ if ( $key eq 'title' ) {
+ if ($prefix) {
+ print "graph_$key " . ucfirst($prefix) . " $value\n";
+ }
+ else {
+ print "graph_$key $value\n";
+ }
+ }
+ else {
+ print "graph_$key $value\n";
+ }
}
- foreach my $dsrc (@{$graph->{datasrc}}) {
+ foreach my $dsrc ( @{ $graph->{datasrc} } ) {
my %datasrc = %$dsrc;
- while ( my ($key, $value) = each(%datasrc)) {
- next if ($key eq 'name');
+ while ( my ( $key, $value ) = each(%datasrc) ) {
+ next if ( $key eq 'name' );
print "$dsrc->{name}.$key $value\n";
}
}
return;
}
+##
+#### This subroutine returns a socket connection ####
+##
+
+sub get_conn {
+ my $s = undef;
+
+ # check if we want to use sockets instead of tcp
+ my ($sock) = ( $host =~ /unix:\/\/(.+)$/ );
+
+ if ($sock) {
+ $connection = "unix:\/\/$sock";
+ $s = IO::Socket::UNIX->new( Peer => $sock );
+ }
+ else {
+ $connection = "$host:$port";
+ $s = IO::Socket::INET->new(
+ Proto => "tcp",
+ PeerAddr => $host,
+ PeerPort => $port,
+ Timeout => 10,
+ );
+ }
+
+ return $s;
+}
+
##
#### This subroutine actually performs the data fetch for us ####
#### These commands do not lock up Memcache at all ####
##
sub fetch_stats {
- my $s = IO::Socket::INET->new(
- Proto => "tcp",
- PeerAddr => $host,
- PeerPort => $port,
- );
+ my $s = get_conn();
- die "Error: Unable to Connect to $host\[:$port\]\n" unless $s;
+ die "Error: Unable to Connect to $connection\n" unless $s;
print $s "stats\r\n";
- while (my $line = <$s>) {
- if ($line =~ /STAT\s(.+?)\s(\d+)/) {
- my ($skey,$svalue) = ($1,$2);
+ while ( my $line = <$s> ) {
+ if ( $line =~ /STAT\s(.+?)\s(\d+)/ ) {
+ my ( $skey, $svalue ) = ( $1, $2 );
$stats{$skey} = $svalue;
}
last if $line =~ /^END/;