]> git.openstreetmap.org Git - chef.git/blobdiff - cookbooks/munin/files/default/plugins/memcached_multi_
Add munin plugin to monitor rrdcached
[chef.git] / cookbooks / munin / files / default / plugins / memcached_multi_
index a2028995b42914da4c082bf03b742b4d2ac78274..12027269b2e01e67883d13fec088ae4a5f7fe4f8 100755 (executable)
@@ -1,46 +1,71 @@
 #!/usr/bin/perl
 #
-=head1 NAME
 
-Memcached - A Plugin to monitor Memcached Servers (Multigraph)
+=head1 MEMCACHED MULTI
 
-=head1 MUNIN CONFIGURATION
+Memcached Multi - A Plugin to monitor Memcached Servers (Multigraph)
 
-[memcached_*]
- env.host 127.0.0.1     *default*
- env.port 11211         *default*
- env.timescale 3        *default*
+ The common difference between this memcached Munin plugin and others that exists, is that
+ others don't expose slab information from memcached, so you can better tune your memcached
+ interaction / stability / etc. With this plugin we leverage multigraph capabilities in
+ Munin to "hide" the slab information underneath of their parent graphs.
 
-=head2 MUNIN ENVIRONMENT CONFIGURATION EXPLANATION
+=head1 MUNIN NODE CONFIGURATION
 
- host = host we are going to monitor
+The following configuration information can be overridden by placing environment definitions
+ like shown here, in a file located in /etc/munin/plugin-conf.d
+
+[memcached_multi_*]
+ env.host 127.0.0.1                             *default*
+ env.port 11211                                 *default*
+ env.timescale 3                                *default*
+ env.cmds get set delete incr decr touch        *default*
+ env.leitime -1                                 *default*
+
+=head2 MUNIN NODE ENVIRONMENT CONFIGURATION EXPLANATION
+
+ host = host we are going to monitor, this can be used to specify a unix socket.
  port = port we are connecting to, in order to gather stats
  timescale = what time frame do we want to format our graphs too
+ cmds = cmd types to display on cmd graph, remove cmds you don't want displayed from list.
+ leitime = setting this to 1 will re-enable slab eviction time graphs, see note below.
 
-=head1 NODE CONFIGURATION
+=head2 BASIC TROUBLESHOOTING
 
 Please make sure you can telnet to your memcache servers and issue the
  following commands: stats, stats settings, stats items and stats slabs.
 
+=head2 PLUGIN INFORMATION
+
 Available Graphs contained in this Plugin
 
 bytes => This graphs the current network traffic in and out
 
-commands => I<MULTIGRAPH> This graphs the current commands being issued to the memcache machine. B<Multigraph breaks this down to per slab.>
+commands => I<MULTIGRAPH> This graphs the current commands being issued to the memcache machine.
+                                B<Multigraph breaks this down to per slab.>
 
-conns => This graphs the current, max connections as well as avg conns per sec avg conns per sec is derived from total_conns / uptime.
+conns => This graphs the current, max connections as well as avg conns per sec avg conns per sec
+            and is derived from total_conns / uptime.
 
-evictions => I<MULTIGRAPH> This graphs the current evictions on the node. B<Multigraph breaks this down to per slab.>
+evictions => I<MULTIGRAPH> This graphs the current evictions on the node.
+                                B<Multigraph breaks this down to per slab.>
 
-items => I<MULTIGRAPH> This graphs the current items and total items in the memcached node. B<Multigraph breaks this down to per slab.>
+items => I<MULTIGRAPH> This graphs the current items and total items in the memcached node.
+                                B<Multigraph breaks this down to per slab.>
 
-memory => I<MULTIGRAPH> This graphs the current and max memory allocation B<Multigraph breaks this down to per slab.>
+memory => I<MULTIGRAPH> This graphs the current and max memory allocation.
+                                B<Multigraph breaks this down to per slab.>
 
-The following example holds true for all graphing options in this plugin.
- Example: ln -s /usr/share/munin/plugins/memcached_multi_ /etc/munin/plugins/memcached_multi_bytes
+unfetched => I<MULTIGRAPH> This graphs the number of items that were never touched by a
+                get/incr/append/etc before being evicted or expiring from the cache.
+                                B<Multigraph breaks this down to per slab.>
 
 =head1 ADDITIONAL INFORMATION
 
+B<NOTE:> The slab plugin for LEI has been disabled since I believe the counters to be inaccurate,
+    or perhaps not being updated as often I thought they would be. They can be re-enabled by
+    setting an environment variable, see munin configuration section at the top.
+
 You will find that some of the graphs have LEI on them. This was done in order to save room
 on space for text and stands for B<Last Evicted Item>.
 
@@ -52,13 +77,11 @@ The B<Timescale> variable formats certain graphs based on the following guidelin
 
 =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
 
@@ -66,703 +89,1543 @@ GPLv2
 
 =head1 MAGIC MARKERS
 
-    #%# family=auto
-    #%# capabilities=autoconf suggest
+#%# family=auto
+#%# capabilities=autoconf suggest
 
 =cut
 
 use strict;
+use warnings;
 use IO::Socket;
 use Munin::Plugin;
+use File::Basename;
+
+if ( basename($0) !~ /(?:([^\/]+)_)?memcached_multi_/ ) {
+    print
+"This script needs to be named (prefix_)?memcached_multi_ to run properly.\n";
+    exit 1;
+}
 
+# tell munin about our multigraph capabilities
 need_multigraph();
 
+=head1 Variable Declarations
+
+    This section of code is to declare the variables used throughout the plugin
+    Some of them are imported as environment variables from munin plugin conf.d
+    file, others are hashes used for storing information that comes from the
+    stats commands issued to memcached.
+
+=cut
+
+# lets import environment variables for the plugin or use the default
 my $host = $ENV{host} || "127.0.0.1";
 my $port = $ENV{port} || 11211;
+my $connection;
+
+# This gives us the ability to control the timescale our graphs are displaying.
+# The default it set to divide by hours, if you want to get seconds set it to 1.
+# Options: 1 = seconds, 2 = minutes, 3 = hours, 4 = days
+my $timescale = $ENV{timescale} || 3;
+
+# This gives us the ability to turn the Last Evicted Item time slab graph on.
+# It was removed because I believe the counter / response to be broken but
+# perhaps this was useful to someone.
+my $leitime = $ENV{leitime} || -1;
+
+# This gives us the ability to specify which commands we want to display on the
+# command graph. Allowing finer control since some environments don't leverage
+# every command possible in memcached.
+# Options: get set delete incr decr cas touch flush
+my $commands = $ENV{cmds} || "get set delete incr decr touch";
 
-my %stats;
 # This hash contains the information contained in two memcache commands
 # stats and stats settings.
+my %stats;
 
-my %items;
 # This gives us eviction rates and other hit stats per slab
 # We track this so we can see if something was evicted earlier than necessary
+my %items;
 
-my %chnks;
 # This gives us the memory size and usage per slab
-# We track this so we can see what slab is being used the most and has no free chunks 
+# We track this so we can see what slab is being used the most and has no free chunks
 # so we can re-tune memcached to allocate more pages for the specified chunk size
+my %chnks;
 
-my $timescale = $ENV{timescale} || 3;
-# This gives us the ability to control the timescale our graphs are displaying.
-# The default it set to divide by hours, if you want to get seconds set it to 1.
-# Options: 1 = seconds, 2 = minutes, 3 = hours, 4 = days
+# Variable for setting up a quick access map for plugin configurations / version adherence
+my $globalmap;
+
+=head2 Graph Declarations
+
+    This block of code builds up all of the graph info for all root / subgraphs.
+
+    %graphs: is a container for all of the graph definition information. In here is where you'll
+             find the configuration information for munin's graphing procedure.
+    Format:
+
+    $graph{graph_name} => {
+        config => {
+            You'll find the main graph config stored here
+            { key => value },
+            { ... },
+        },
+        datasrc => [
+            Name: name given to data value
+            Attr: Attribute and value, attribute must be valid plugin argument
+            { name => 'Name', info => 'info about graph', ... },
+            { ... },
+        ],
+    }
+
+=cut
 
-# So I was trying to figure out how to build this up, and looking at some good examples
-# I decided to use the format, or for the most part, the format from the mysql_ munin plugin
-# for Innodb by Kjell-Magne Ãierud, it just spoke ease of flexibility especially with multigraphs
-# thanks btw ;)
-#
-# %graphs   is a container for all of the graph definition information. In here is where you'll
-#           find the configuration information for munin's graphing procedure.
-#   Format:
-#
-#   $graph{graph_name} => {
-#       config => {
-#           # You'll find keys and values stored here for graph manipulation
-#       },
-#       datasrc => [
-#           # Name: name given to data value
-#           # Attr: Attribute for given value
-#           { name => 'Name', (Attr) },
-#           { ... },
-#       ],
-#   }
 my %graphs;
 
+# main graph for memcached item count
 $graphs{items} = {
     config => {
-        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',
+        args     => '--base 1000 --lower-limit 0',
+        vlabel   => 'Items in Memcached',
+        category => 'memcached global items',
+        title    => 'Items',
+        info     => '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'
+        },
     ],
 };
 
+# main graph for memcached memory usage
 $graphs{memory} = {
     config => {
-        args => '--base 1024 --lower-limit 0',
-        vlabel => 'Bytes Used',
-        category => 'memcached',
-        title => 'Memory Usage',
-        info => 'This graph shows the memory consumption of memcached',
+        args     => '--base 1024 --lower-limit 0',
+        vlabel   => 'Bytes Used',
+        category => 'memcached global memory',
+        title    => 'Memory Usage',
+        info     => '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'
+        },
     ],
 };
 
+# main graph for memcached network usage
 $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',
-        order => 'bytes_read bytes_written',
+        info     => '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'
+        },
     ],
 };
 
+# graph for memcached connections
 $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',
-        order => 'max_conns curr_conns avg_conns',
+        title    => 'Connections',
+        info     => 'Number of connections being handled by memcached',
+        order    => 'max_conns curr_conns avg_conns',
     },
     datasrc => [
         { name => 'curr_conns', label => 'Current Connections', min => '0' },
-        { name => 'max_conns', label => 'Max Connections', min => '0' },
-        { name => 'avg_conns' , label => 'Avg Connections', min => '0' },
+        { name => 'max_conns',  label => 'Max Connections',     min => '0' },
+        { name => 'avg_conns',  label => 'Avg Connections',     min => '0' },
     ],
 };
 
+# main graph for memcached commands issued
 $graphs{commands} = {
     config => {
-        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',
+        args     => '--base 1000 --lower-limit 0',
+        vlabel   => 'Commands per ${graph_period}',
+        category => 'memcached global commands',
+        title    => 'Commands',
+        info     => '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 => 'delete_hits', type => 'DERIVE', label => 'Delete Hits', info => 'Number of delete requests that resulted in a deletion of a key', min => '0' },
-        { name => 'delete_misses', type => 'DERIVE', label => 'Delete Misses', info => 'Number of delete requests for missing key', min => '0' },
-        { name => 'incr_hits', type => 'DERIVE', label => 'Increment Hits', info => 'Number of successful increment requests', min => '0' },
-        { name => 'incr_misses', type => 'DERIVE', label => 'Increment Misses', info => 'Number of unsuccessful increment requests', min => '0' },
-        { name => 'decr_hits', type => 'DERIVE', label => 'Decrement Hits', info => 'Number of successful decrement requests', min => '0' },
-        { name => 'decr_misses', type => 'DERIVE', label => 'Decrement Misses', info => 'Number of unsuccessful decrement requests', 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  => 'cmd_flush',
+            type  => 'DERIVE',
+            label => 'Flushes',
+            info  => 'Cumulative number of flush reqs',
+            min   => '0'
+        },
+        {
+            name  => 'cmd_touch',
+            type  => 'DERIVE',
+            label => 'Touches',
+            info  => 'Cumulative number of touch 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  => 'delete_hits',
+            type  => 'DERIVE',
+            label => 'Delete Hits',
+            info =>
+              'Number of delete requests that resulted in a deletion of a key',
+            min => '0'
+        },
+        {
+            name  => 'delete_misses',
+            type  => 'DERIVE',
+            label => 'Delete Misses',
+            info  => 'Number of delete requests for missing key',
+            min   => '0'
+        },
+        {
+            name  => 'incr_hits',
+            type  => 'DERIVE',
+            label => 'Increment Hits',
+            info  => 'Number of successful increment requests',
+            min   => '0'
+        },
+        {
+            name  => 'incr_misses',
+            type  => 'DERIVE',
+            label => 'Increment Misses',
+            info  => 'Number of unsuccessful increment requests',
+            min   => '0'
+        },
+        {
+            name  => 'decr_hits',
+            type  => 'DERIVE',
+            label => 'Decrement Hits',
+            info  => 'Number of successful decrement requests',
+            min   => '0'
+        },
+        {
+            name  => 'decr_misses',
+            type  => 'DERIVE',
+            label => 'Decrement Misses',
+            info  => 'Number of unsuccessful decrement requests',
+            min   => '0'
+        },
+        {
+            name  => 'cas_misses',
+            type  => 'DERIVE',
+            label => 'CAS Misses',
+            info  => 'Number of Compare and Swap requests against missing keys',
+            min   => '0'
+        },
+        {
+            name  => 'cas_hits',
+            type  => 'DERIVE',
+            label => 'CAS Hits',
+            info  => 'Number of successful Compare and Swap requests',
+            min   => '0'
+        },
+        {
+            name  => 'cas_badval',
+            type  => 'DERIVE',
+            label => 'CAS Badval',
+            info  => 'Number of unsuccessful Compare and Swap requests',
+            min   => '0'
+        },
+        {
+            name  => 'touch_hits',
+            type  => 'DERIVE',
+            label => 'Touch Hits',
+            info  => 'Number of successfully touched keys',
+            min   => '0'
+        },
+        {
+            name  => 'touch_misses',
+            type  => 'DERIVE',
+            label => 'Touch Misses',
+            info  => 'Number of unsuccessful touch keys',
+            min   => '0'
+        },
     ],
 };
 
+# main graph for memcached eviction rates
 $graphs{evictions} = {
     config => {
-        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',
+        args     => '--base 1000 --lower-limit 0',
+        vlabel   => 'Evictions per ${graph_period}',
+        category => 'memcached global evictions',
+        title    => 'Evictions',
+        info     => 'Number of evictions per second',
     },
     datasrc => [
-        { name => 'evictions', label => 'Evictions', info => 'Cumulative Evictions Across All Slabs', type => 'DERIVE', min => '0' },
-        { name => 'evicted_nonzero', label => 'Evictions prior to Expire', info => 'Cumulative Evictions forced to expire prior to expiration', type => 'DERIVE', min => '0' },
-        { name => 'reclaimed', label => 'Reclaimed Items', info => 'Cumulative Reclaimed Item Entries Across All Slabs', type => 'DERIVE', min => '0' },
+        {
+            name  => 'evictions',
+            type  => 'DERIVE',
+            label => 'Evictions',
+            info  => 'Cumulative Evictions Across All Slabs',
+            min   => '0'
+        },
+        {
+            name  => 'evicted_nonzero',
+            type  => 'DERIVE',
+            label => 'Evictions prior to Expire',
+            info => 'Cumulative Evictions forced to expire prior to expiration',
+            min  => '0'
+        },
+        {
+            name  => 'reclaimed',
+            type  => 'DERIVE',
+            label => 'Reclaimed Items',
+            info  => 'Cumulative Reclaimed Item Entries Across All Slabs',
+            min   => '0'
+        },
     ],
 };
 
+# main graph for memcached eviction rates
+$graphs{unfetched} = {
+    config => {
+        args     => '--base 1000 --lower-limit 0',
+        vlabel   => 'Unfetched Items per ${graph_period}',
+        category => 'memcached global unfetched',
+        title    => 'Unfetched Items',
+        info =>
+'Number of items that were never touched get/incr/append/etc before X occured',
+    },
+    datasrc => [
+        {
+            name  => 'expired_unfetched',
+            type  => 'DERIVE',
+            label => 'Expired Unfetched',
+            min   => '0',
+            info =>
+'Number of items that expired and never had get/incr/append/etc performed'
+        },
+        {
+            name  => 'evicted_unfetched',
+            type  => 'DERIVE',
+            label => 'Evictioned Unfetched',
+            min   => '0',
+            info =>
+'Number of items that evicted and never had get/incr/append/etc performed'
+        },
+    ],
+};
+
+# subgraph for breaking memory info down by slab ( subgraph of memory )
 $graphs{slabchnks} = {
     config => {
-        args => '--base 1000 --lower-limit 0',
-        vlabel => 'Available Chunks for this Slab',
-        category => 'memcached',
-        title => 'Chunk Usage for Slab: ',
+        args     => '--base 1000 --lower-limit 0',
+        vlabel   => 'Available Chunks for this Slab',
+        category => 'memcached slab chunk usage',
+        title    => 'Chunk Usage for Slab: ',
         info => 'This graph shows you the chunk usage for this memory slab.',
     },
     datasrc => [
-        { name => 'total_chunks', label => 'Total Chunks Available', min => '0' },
+        {
+            name  => 'total_chunks',
+            label => 'Total Chunks Available',
+            min   => '0'
+        },
         { name => 'used_chunks', label => 'Total Chunks in Use', min => '0' },
-        { name => 'free_chunks', label => 'Total Chunks Not in Use (Free)', min => '0' },
+        {
+            name  => 'free_chunks',
+            label => 'Total Chunks Not in Use (Free)',
+            min   => '0'
+        },
     ],
 };
 
+# subgraph for breaking commands down by slab ( subgraph of commands )
 $graphs{slabhits} = {
     config => {
-        args => '--base 1000 --lower-limit 0',
-        vlabel => 'Hits per Slab per ${graph_period}',
-        category => 'memcached',
-        title => 'Hits for Slab: ',
-        info => 'This graph shows you the successful hit rate for this memory slab.',
+        args     => '--base 1000 --lower-limit 0',
+        vlabel   => 'Hits per Slab per ${graph_period}',
+        category => 'memcached slab commands',
+        title    => 'Hits for Slab: ',
+        info =>
+          'This graph shows you the successful hit rate for this memory slab.',
     },
     datasrc => [
-        { name => 'get_hits', label => 'Get Requests', type => 'DERIVE', min => '0' },
-        { name => 'cmd_set', label => 'Set Requests', type => 'DERIVE', min => '0' },
-        { name => 'delete_hits', label => 'Delete Requests', type => 'DERIVE', min => '0' },
-        { name => 'incr_hits', label => 'Increment Requests', type => 'DERIVE', min => '0' },
-        { name => 'decr_hits', label => 'Decrement Requests', type => 'DERIVE', min => '0' },
+        {
+            name  => 'get_hits',
+            label => 'Get Requests',
+            type  => 'DERIVE',
+            min   => '0'
+        },
+        {
+            name  => 'cmd_set',
+            label => 'Set Requests',
+            type  => 'DERIVE',
+            min   => '0'
+        },
+        {
+            name  => 'delete_hits',
+            label => 'Delete Requests',
+            type  => 'DERIVE',
+            min   => '0'
+        },
+        {
+            name  => 'incr_hits',
+            label => 'Increment Requests',
+            type  => 'DERIVE',
+            min   => '0'
+        },
+        {
+            name  => 'decr_hits',
+            label => 'Decrement Requests',
+            type  => 'DERIVE',
+            min   => '0'
+        },
+        {
+            name  => 'cas_hits',
+            label => 'Sucessful CAS Requests',
+            type  => 'DERIVE',
+            min   => '0'
+        },
+        {
+            name  => 'cas_badval',
+            label => 'UnSucessful CAS Requests',
+            type  => 'DERIVE',
+            min   => '0'
+        },
+        {
+            name  => 'touch_hits',
+            label => 'Touch Requests',
+            type  => 'DERIVE',
+            min   => '0'
+        },
     ],
 };
 
+# subgraph for breaking evictions down by slab ( subgraph of evictions )
 $graphs{slabevics} = {
     config => {
-        args => '--base 1000 --lower-limit 0',
-        vlabel => 'Evictions per Slab per ${graph_period}',
-        category => 'memcached',
-        title => 'Evictions for Slab: ',
+        args     => '--base 1000 --lower-limit 0',
+        vlabel   => 'Evictions per Slab per ${graph_period}',
+        category => 'memcached slab evictions',
+        title    => 'Evictions for Slab: ',
         info => 'This graph shows you the eviction rate for this memory slab.',
     },
     datasrc => [
-        { name => 'evicted', label => 'Total Evictions', type => 'DERIVE', min => '0' },
-        { name => 'evicted_nonzero', label => 'Evictions from LRU Prior to Expire', type => 'DERIVE', min => '0' },
-        { name => 'reclaimed', label => 'Reclaimed Expired Items', info => 'This is number of times items were stored in expired entry memory space', type => 'DERIVE', min => '0' },
+        {
+            name  => 'evicted',
+            label => 'Total Evictions',
+            type  => 'DERIVE',
+            min   => '0',
+            info  => 'Items evicted from memory slab'
+        },
+        {
+            name  => 'evicted_nonzero',
+            type  => 'DERIVE',
+            label => 'Evictions from LRU Prior to Expire',
+            info  => 'Items evicted from memory slab before ttl expiration',
+            min   => '0'
+        },
+        {
+            name  => 'reclaimed',
+            type  => 'DERIVE',
+            label => 'Reclaimed Expired Items',
+            info =>
+              'Number of times an item was stored in expired memory slab space',
+            min => '0'
+        },
     ],
 };
 
+# subgraph for showing the time between an item was last evicted and requested ( subgraph of evictions )
 $graphs{slabevictime} = {
     config => {
-        args => '--base 1000 --lower-limit 0',
-        vlabel => ' since Request for LEI',
-        category => 'memcached',
-        title => 'Eviction Request Time for Slab: ',
-        info => 'This graph shows you the time since we requested the last evicted item',
+        args     => '--base 1000 --lower-limit 0',
+        vlabel   => ' since Request for LEI',
+        category => 'memcached slab eviction time',
+        title    => 'Eviction Request Time for Slab: ',
+        info =>
+'This graph shows you the time since we requested the last evicted item',
     },
     datasrc => [
-        { name => 'evicted_time', label => 'Eviction Time (LEI)', info => 'Time Since Request for Last Evicted Item', min => '0' },
+        {
+            name  => 'evicted_time',
+            label => 'Eviction Time (LEI)',
+            info  => 'Time Since Request for Last Evicted Item',
+            min   => '0'
+        },
     ],
 };
 
+# subgraph for breaking items down by slab ( subgraph of items )
 $graphs{slabitems} = {
     config => {
-        args => '--base 1000 --lower-limit 0',
-        vlabel => 'Items per Slab',
-        category => 'memcached',
-        title => 'Items in Slab: ',
-        info => 'This graph shows you the number of items and reclaimed items per slab.',
+        args     => '--base 1000 --lower-limit 0',
+        vlabel   => 'Items per Slab',
+        category => 'memcached slab item count',
+        title    => 'Items in Slab: ',
+        info =>
+'This graph shows you the number of items and reclaimed items per slab.',
     },
     datasrc => [
-        { name => 'number', label => 'Items', info => 'This is the amount of items stored in this slab', min => '0' },
+        {
+            name  => 'number',
+            label => 'Items',
+            draw  => 'AREA',
+            info  => 'This is the amount of items stored in this slab',
+            min   => '0'
+        },
     ],
 };
 
+# subgraph for showing the age of the eldest item stored in a slab ( subgraph of items )
 $graphs{slabitemtime} = {
     config => {
-        args => '--base 1000 --lower-limit 0',
-        vlabel => ' since item was stored',
-        category => 'memcached',
-        title => 'Age of Eldest Item in Slab: ',
+        args     => '--base 1000 --lower-limit 0',
+        vlabel   => ' since item was stored',
+        category => 'memcached slab item age',
+        title    => 'Age of Eldest Item in Slab: ',
         info => 'This graph shows you the time of the eldest item in this slab',
     },
+    datasrc =>
+      [ { name => 'age', label => 'Eldest Item\'s Age', min => '0' }, ],
+};
+
+# main graph for memcached eviction rates
+$graphs{slabunfetched} = {
+    config => {
+        args     => '--base 1000 --lower-limit 0',
+        vlabel   => 'Unfetched Items per ${graph_period}',
+        category => 'memcached slab unfetched',
+        title    => 'Unfetched Items in Slab: ',
+        info =>
+'Number of items that were never touched get/incr/append/etc before X occured',
+    },
     datasrc => [
-        { name => 'age', label => 'Eldest Item\'s Age', min => '0' },
+        {
+            name  => 'expired_unfetched',
+            type  => 'DERIVE',
+            label => 'Expired Unfetched',
+            min   => '0',
+            info =>
+'Number of items that expired and never had get/incr/append/etc performed'
+        },
+        {
+            name  => 'evicted_unfetched',
+            type  => 'DERIVE',
+            label => 'Evictioned Unfetched',
+            min   => '0',
+            info =>
+'Number of items that evicted and never had get/incr/append/etc performed'
+        },
     ],
 };
 
-##
-#### Config Check ####
-##
+=head1 Munin Checks
+
+    These checks look for config / autoconf / suggest params
 
-if (defined $ARGV[0] && $ARGV[0] eq 'config') {
+=head2 Config Check
 
-    $0 =~ /memcached_multi_(.+)*/;
-    my $plugin = $1;
+    This block of code looks at the argument that is possibly supplied,
+    should it be config, it then checks to make sure the plugin 
+    specified exists, assuming it does, it will run the do_config 
+    subroutine for the plugin specified, otherwise it dies complaining
+    about an unknown plugin.
 
-    die 'Unknown Plugin Specified: ' . ($plugin ? $plugin : '') unless $graphs{$plugin};
+=cut
+
+if ( defined $ARGV[0] && $ARGV[0] eq 'config' ) {
+
+# Lets get our plugin from the symlink being called up, we'll also verify its a valid
+# plugin that we have graph information for
+    $0 =~ /(?:([^\/]+)_)?memcached_multi_(.+)$/;
+    my $prefix = $1 ? $1 : '';
+    my $plugin = $2;
+    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
+# subgraphs which use slab information for title / info per slab
     fetch_stats();
+    $globalmap = buildglobalmap();
 
     # Now lets go ahead and print out our config.
-       do_config($plugin);
-       exit 0;
+    do_config( $prefix, $plugin );
+    exit 0;
 }
 
-##
-#### Autoconf Check ####
-##
+=head2 Autoconf Check
 
-if (defined $ARGV[0] && $ARGV[0] eq 'autoconf') {
+    This block of code looks at the argument that is possibly supplied,
+    should it be autoconf, we will attempt to connect to the memcached
+    service specified on the host:port, upon successful connection it
+    prints yes, otherwise it prints no.
+
+=cut
 
-    my $s = IO::Socket::INET->new(
-        Proto    => "tcp",
-        PeerAddr => $host,
-        PeerPort => $port,
-    );
+if ( defined $ARGV[0] && $ARGV[0] eq 'autoconf' ) {
 
-    if (defined($s)) {
+    # Lets attempt to connect to memcached
+    my $s = get_conn();
+
+    # Lets verify 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 ####
-##
+=head2 Suggest Check
+
+    This block of code looks at the argument that is possibly supplied,
+    should it be suggest, we are going to print the possible plugins
+    which can be specified. Note we only specify the root graphs for the
+    multigraphs, since the rest of the subgraphs will appear "behind" the
+    root graphs. It also attempts to connect to the memcached service to
+    verify it is infact running.
+
+=cut
 
-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) ) {
+        fetch_stats();
+        my @rootplugins =
+          ( 'bytes', 'conns', 'commands', 'evictions', 'items', 'memory' );
+        if ( $stats{version} !~ /^1\.4\.[0-7]$/ ) {
+            push( @rootplugins, 'unfetched' );
+        }
         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;
     }
 }
 
-##
-#### Well We aren't running (auto)config/suggest so lets print some stats ####
-##
+=head1 Output Subroutines
 
-fetch_output();
+    Output Subroutine calls to output data values
 
-##
-#### Subroutines for printing info gathered from memcached ####
-##
+=head2 fetch_output
 
-##
-#### This subroutine performs the bulk processing for printing statistics.
-##
+    This subroutine is the main call for printing data for the plugin.
+    No parameters are taken as this is the default call if no arguments
+    are supplied from the command line.
 
-sub fetch_output {
+=cut
 
-    $0 =~ /memcached_multi_(.+)*/;
-    my $plugin = $1;
+# Well, no arguments were supplied that we know about, so lets print some data
+$0 =~ /(?:([^\/]+)_)?memcached_multi_(.+)$/;
+my $prefix = $1 ? $1 : '';
+my $plugin = $2;
+die 'Unknown Plugin Specified: ' . ( $plugin ? $plugin : '' )
+  unless $graphs{$plugin};
+fetch_stats();
+$globalmap = buildglobalmap();
+fetch_output( $prefix, $plugin );
 
-    die 'Unknown Plugin Specified: ' . ($plugin ? $plugin : '') unless $graphs{$plugin};
+sub fetch_output {
+    my ( $prefix, $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.
     my @subgraphs;
-    if ($plugin eq 'memory') {
+    if ( $plugin eq 'memory' ) {
         @subgraphs = ('slabchnks');
-        foreach my $slabid(sort{$a <=> $b} keys %chnks) {
-            print_submulti_output($slabid,$plugin,@subgraphs);
+        foreach my $slabid ( sort { $a <=> $b } keys %chnks ) {
+            print_submulti_output( $prefix, $slabid, $plugin, @subgraphs );
         }
-        print_rootmulti_output($plugin);
-    } elsif ($plugin eq 'commands') {
+        print_subrootmulti_output( $prefix, $plugin );
+        print_rootmulti_output( $prefix, $plugin );
+    }
+    elsif ( $plugin eq 'commands' ) {
         @subgraphs = ('slabhits');
-        foreach my $slabid(sort{$a <=> $b} keys %chnks) {
-            print_submulti_output($slabid,$plugin,@subgraphs);
-        }
-        print_rootmulti_output($plugin);
-    } elsif ($plugin eq 'evictions') {
-        @subgraphs = ('slabevics','slabevictime');
-        foreach my $slabid (sort{$a <=> $b} keys %items) {
-            print_submulti_output($slabid,$plugin,@subgraphs);
-        }
-        print_rootmulti_output($plugin);
-    } elsif ($plugin eq 'items') {
-        @subgraphs = ('slabitems','slabitemtime');
-        foreach my $slabid (sort{$a <=> $b} keys %items) {
-            print_submulti_output($slabid,$plugin,@subgraphs);
-        }
-        print_rootmulti_output($plugin);
-    } else {
+        foreach my $slabid ( sort { $a <=> $b } keys %chnks ) {
+            print_submulti_output( $prefix, $slabid, $plugin, @subgraphs );
+        }
+        print_subrootmulti_output( $prefix, $plugin );
+        print_rootmulti_output( $prefix, $plugin );
+    }
+    elsif ( $plugin eq 'evictions' ) {
+        @subgraphs = ('slabevics');
+        if ( $leitime == 1 ) { push( @subgraphs, 'slabevictime' ); }
+        foreach my $slabid ( sort { $a <=> $b } keys %items ) {
+            print_submulti_output( $prefix, $slabid, $plugin, @subgraphs );
+        }
+        print_subrootmulti_output( $prefix, $plugin );
+        print_rootmulti_output( $prefix, $plugin );
+    }
+    elsif ( $plugin eq 'items' ) {
+        @subgraphs = ( 'slabitems', 'slabitemtime' );
+        foreach my $slabid ( sort { $a <=> $b } keys %items ) {
+            print_submulti_output( $prefix, $slabid, $plugin, @subgraphs );
+        }
+        print_subrootmulti_output( $prefix, $plugin );
+        print_rootmulti_output( $prefix, $plugin );
+    }
+    elsif ( $plugin eq 'unfetched' ) {
+        @subgraphs = ('slabunfetched');
+        foreach my $slabid ( sort { $a <=> $b } keys %items ) {
+            print_submulti_output( $prefix, $slabid, $plugin, @subgraphs );
+        }
+        print_subrootmulti_output( $prefix, $plugin );
+        print_rootmulti_output( $prefix, $plugin );
+    }
+    else {
         print_root_output($plugin);
     }
 
     return;
 }
 
-##
-#### This subroutine is for the root non-multigraph graphs which render on the main node page ####
-##
+=head2 print_root_output
+
+    This subroutine prints out the return values for our non-multigraph root graphs.
+    It takes one parameter $plugin and returns when completed.
+
+        $plugin;    graph we are calling up to print data values for 
+
+    Example: print_root_output($plugin);
+
+=cut
 
 sub print_root_output {
-    my ($plugin) = (@_);
 
+    # Lets get our plugin, set our graph reference and print out info for Munin
+    my ($plugin) = (@_);
     my $graph = $graphs{$plugin};
 
-    print "graph memcached_$plugin\n";
-
-    if ($plugin ne 'conns') {
-        foreach my $dsrc (@{$graph->{datasrc}}) {
+    # The conns plugin has some specific needs, looking for plugin type
+    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 'max_conns') {
+            while ( my ( $key, $value ) = each(%datasrc) ) {
+                if ( $value eq 'max_conns' ) {
                     $output = $stats{maxconns};
-                } elsif ($value eq 'curr_conns') {
+                }
+                elsif ( $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";
             }
         }
     }
-
     return;
 }
 
-##
-#### This subroutine is for the root multigraph graphs which render on the main node page ####
-##
+=head2 print_rootmulti_output
+
+    This subroutine prints out the return values for our multigraph root graphs.
+    It takes one parameter $plugin and returns when completed.
+
+        $plugin;    root graph we are calling up to print data values for
+
+    Example: print_rootmulti_output($plugin);
+
+=cut
 
 sub print_rootmulti_output {
-    my ($plugin) = (@_);
 
+    # Lets get our plugin, set our graph reference and print out info for Munin
+    my ( $prefix, $plugin ) = (@_);
     my $graph = $graphs{$plugin};
+    if ($prefix) {
+        print "multigraph $prefix\_memcached_multi_$plugin\n";
+    }
+    else {
+        print "multigraph memcached_multi_$plugin\n";
+    }
 
-    print "multigraph memcached_$plugin\n";
-    
-    foreach my $dsrc (@{$graph->{datasrc}}) {
-        my $output = 0;
+    # Lets print our data values with their appropriate name
+    foreach my $dsrc ( @{ $graph->{datasrc} } ) {
+        my $output  = 0;
         my %datasrc = %$dsrc;
-        while ( my ($key, $value) = each(%datasrc)) {
-            next if ($key ne 'name');
-            if (($plugin eq 'evictions') && ($value eq 'evicted_nonzero')) {
-                foreach my $slabid (sort{$a <=> $b} keys %items) {
+        while ( my ( $key, $value ) = each(%datasrc) ) {
+            next if ( $key ne 'name' );
+            next
+              if ( ( $plugin eq 'evictions' )
+                && ( !exists( $globalmap->{globalevics}->{ $dsrc->{name} } ) )
+              );
+            next
+              if ( ( $plugin eq 'commands' )
+                && ( !exists( $globalmap->{globalcmds}->{ $dsrc->{name} } ) ) );
+            if ( ( $plugin eq 'evictions' ) && ( $value eq 'evicted_nonzero' ) )
+            {
+                foreach my $slabid ( sort { $a <=> $b } keys %items ) {
                     $output += $items{$slabid}->{evicted_nonzero};
                 }
-            } else {
+            }
+            else {
                 $output = $stats{$value};
             }
             print "$dsrc->{name}.value $output\n";
         }
     }
+    return;
+}
+
+=head2 print_subrootmulti_output
+
+    This subroutine prints out the return values for our multigraph root graphs, only this set of
+    data will display on the subpage made by the multigraph capabilities of munin and the plugin.
+    It takes one parameter $plugin and returns when completed.
+
+        $plugin;    root graph we are calling up to print data values for
+
+    Example: print_rootmulti_output($plugin);
+
+=cut
+
+sub print_subrootmulti_output {
+
+    # Lets get our plugin, set our graph reference and print out info for Munin
+    my ( $prefix, $plugin ) = (@_);
+    my $graph = $graphs{$plugin};
+    if ($prefix) {
+        if ( $plugin eq 'evictions' ) {
+            print "multigraph $prefix\_memcached_multi_$plugin.global$plugin\n";
+        }
+        else {
+            print "multigraph $prefix\_memcached_multi_$plugin.$plugin\n";
+        }
+    }
+    else {
+        if ( $plugin eq 'evictions' ) {
+            print "multigraph memcached_multi_$plugin.global$plugin\n";
+        }
+        else {
+            print "multigraph memcached_multi_$plugin.$plugin\n";
+        }
+    }
 
+    # Lets print our data values with their appropriate name
+    foreach my $dsrc ( @{ $graph->{datasrc} } ) {
+        my $output  = 0;
+        my %datasrc = %$dsrc;
+        while ( my ( $key, $value ) = each(%datasrc) ) {
+            next if ( $key ne 'name' );
+            next
+              if ( ( $plugin eq 'evictions' )
+                && ( !exists( $globalmap->{globalevics}->{ $dsrc->{name} } ) )
+              );
+            next
+              if ( ( $plugin eq 'commands' )
+                && ( !exists( $globalmap->{globalcmds}->{ $dsrc->{name} } ) ) );
+            if ( ( $plugin eq 'evictions' ) && ( $value eq 'evicted_nonzero' ) )
+            {
+                foreach my $slabid ( sort { $a <=> $b } keys %items ) {
+                    $output += $items{$slabid}->{evicted_nonzero};
+                }
+            }
+            else {
+                $output = $stats{$value};
+            }
+            print "$dsrc->{name}.value $output\n";
+        }
+    }
     return;
 }
 
-##
-#### This subroutine is for the sub multigraph graphs created via the multigraph plugin ####
-##
+=head2 print_submulti_output
+
+    This subroutine prints out the return values for our multigraph subgraphs. It takes
+    three parameters $slabid, $plugin, @subgraphs and then rReturns when completed.
+
+        $slabid;    slab id that we will use to grab info from and print out
+        $plugin;    root graph being called, used for multigraph output and slab id
+        @subgraphs; graphs we are actually trying to print data values for
+
+    Example: print_submulti_output($slabid,$plugin,@subgraphs);
+
+=cut
 
 sub print_submulti_output {
-    my ($slabid,$plugin,@subgraphs) = (@_);
+
+    # Lets get our slabid, plugin, and subgraphs
+    my ( $prefix, $slabid, $plugin, @subgraphs ) = (@_);
     my $currslab = undef;
 
+    # Time to loop over our subgraphs array
     foreach my $sgraph (@subgraphs) {
 
+ # Lets set our graph reference for quick calling, and print some info for munin
         my $graph = $graphs{$sgraph};
+        if ($prefix) {
+            print
+              "multigraph $prefix\_memcached_multi_$plugin.$sgraph\_$slabid\n";
+        }
+        else {
+            print "multigraph memcached_multi_$plugin.$sgraph\_$slabid\n";
+        }
 
-        print "multigraph memcached_$plugin.$sgraph\_$slabid\n";
-
-        if ($plugin eq 'evictions') {
+        # Lets figure out what slab info we are trying to call up
+        if (   ( $plugin eq 'evictions' )
+            || ( $plugin eq 'items' )
+            || ( $plugin eq 'unfetched' ) )
+        {
             $currslab = $items{$slabid};
-        } elsif ($plugin eq 'memory') {
-            $currslab = $chnks{$slabid};
-        } elsif ($plugin eq 'commands') {
+        }
+        elsif ( ( $plugin eq 'memory' ) || ( $plugin eq 'commands' ) ) {
             $currslab = $chnks{$slabid};
-        } elsif ($plugin eq 'items') {
-            $currslab = $items{$slabid};
-        } else {
+        }
+        else {
             return;
         }
 
-        foreach my $dsrc (@{$graph->{datasrc}}) {
+        # Lets print our data values with their appropriate name
+        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' );
+                next
+                  if ( ( $sgraph eq 'slabevics' )
+                    && ( !exists( $globalmap->{slabevics}->{ $dsrc->{name} } ) )
+                  );
+                next
+                  if ( ( $plugin eq 'commands' )
+                    && ( !exists( $globalmap->{slabcmds}->{ $dsrc->{name} } ) )
+                  );
                 my $output = $currslab->{$value};
-                if (($sgraph eq 'slabevictime') || ($sgraph eq 'slabitemtime')) {
-                    $output = time_scale('data',$output); ;
+                if (   ( $sgraph eq 'slabevictime' )
+                    || ( $sgraph eq 'slabitemtime' ) )
+                {
+                    $output = time_scale( 'data', $output );
                 }
                 print "$dsrc->{name}.value $output\n";
             }
         }
     }
-
     return;
 }
 
-##
-#### Subroutines for printing out config information for graphs ####
-##
+=head1 Config Subroutines
+
+    These subroutines handle the config portion of munin calls.
+
+=head2 do_config
+
+    This is the main call issued assuming we call up config and plugin specified exists
+    The subroutine takes one parameter $plugin, and returns when completed.
 
-##
-#### This subroutine does the bulk printing the config info per graph ####
-##
+        $plugin; root graph being called
+
+    Example: do_config($prefix, $plugin);
+
+=cut
 
 sub do_config {
-    my ($plugin) = (@_);
+    my ( $prefix, $plugin ) = (@_);
     my @subgraphs;
-    if ($plugin eq 'memory') {
+    if ( $plugin eq 'memory' ) {
         @subgraphs = ('slabchnks');
-        foreach my $slabid (sort{$a <=> $b} keys %chnks) {
-            print_submulti_config($slabid,$plugin,@subgraphs);
+        foreach my $slabid ( sort { $a <=> $b } keys %chnks ) {
+            print_submulti_config( $prefix, $slabid, $plugin, @subgraphs );
         }
-        print_rootmulti_config($plugin);
-    } elsif ($plugin eq 'commands') {
+        print_subrootmulti_config( $prefix, $plugin );
+        print_rootmulti_config( $prefix, $plugin );
+    }
+    elsif ( $plugin eq 'commands' ) {
         @subgraphs = ('slabhits');
-        foreach my $slabid (sort{$a <=> $b} keys %chnks) {
-            print_submulti_config($slabid,$plugin,@subgraphs);
+        foreach my $slabid ( sort { $a <=> $b } keys %chnks ) {
+            print_submulti_config( $prefix, $slabid, $plugin, @subgraphs );
         }
-        print_rootmulti_config($plugin);
-    } elsif ($plugin eq 'evictions') {
-        @subgraphs = ('slabevics','slabevictime');
-        foreach my $slabid (sort{$a <=> $b}  keys %items) {
-            print_submulti_config($slabid,$plugin,@subgraphs);
+        print_subrootmulti_config( $prefix, $plugin );
+        print_rootmulti_config( $prefix, $plugin );
+    }
+    elsif ( $plugin eq 'evictions' ) {
+        @subgraphs = ('slabevics');
+        if ( $leitime == 1 ) { push( @subgraphs, 'slabevictime' ); }
+        foreach my $slabid ( sort { $a <=> $b } keys %items ) {
+            print_submulti_config( $prefix, $slabid, $plugin, @subgraphs );
+        }
+        print_subrootmulti_config( $prefix, $plugin );
+        print_rootmulti_config( $prefix, $plugin );
+    }
+    elsif ( $plugin eq 'items' ) {
+        @subgraphs = ( 'slabitems', 'slabitemtime' );
+        foreach my $slabid ( sort { $a <=> $b } keys %items ) {
+            print_submulti_config( $prefix, $slabid, $plugin, @subgraphs );
         }
-        print_rootmulti_config($plugin);
-    } elsif ($plugin eq 'items') {
-        @subgraphs = ('slabitems','slabitemtime');
-        foreach my $slabid (sort{$a <=> $b} keys %items) {
-            print_submulti_config($slabid,$plugin,@subgraphs);
+        print_subrootmulti_config( $prefix, $plugin );
+        print_rootmulti_config( $prefix, $plugin );
+    }
+    elsif ( $plugin eq 'unfetched' ) {
+        @subgraphs = ('slabunfetched');
+        foreach my $slabid ( sort { $a <=> $b } keys %items ) {
+            print_submulti_config( $prefix, $slabid, $plugin, @subgraphs );
         }
-        print_rootmulti_config($plugin);
-    } else {
-        print_root_config($plugin);
+        print_subrootmulti_config( $prefix, $plugin );
+        print_rootmulti_config( $prefix, $plugin );
+    }
+    else {
+        print_root_config( $prefix, $plugin );
     }
 
     return;
 }
 
-##
-#### This subroutine is for the config info for sub multigraph graphs created via the multigraph plugin ####
-##
+=head2 print_root_config
 
-sub print_submulti_config {
-    my ($slabid,$plugin,@subgraphs) = (@_);
-    my ($slabitems,$slabchnks) = undef;
+    This subroutine prints out the config information for all of the non-multigraph root graphs.
+    It takes one parameter, $plugin, returns when completed.
 
-    foreach my $sgraph (@subgraphs) {
+        $prefix;    possible prefix used to allow multiple plugins per machine
+        $plugin;    root graph used for multigraph call
 
-        my $graph = $graphs{$sgraph};
+    Example:  print_root_config($prefix,$plugin);
 
-        my %graphconf = %{$graph->{config}};
-        
-        print "multigraph memcached_$plugin.$sgraph\_$slabid\n";
+=cut
 
-        while ( my ($key, $value) = each(%graphconf)) {
-               if ($key eq 'title') {
-                   print "graph_$key $value" . "$slabid" . " ($chnks{$slabid}->{chunk_size} Bytes)\n";
-               } elsif (($key eq 'vlabel') && (($sgraph eq 'slabevictime') || ($sgraph eq 'slabitemtime'))) {
-                $value = time_scale('config',$value);
-                print "graph_$key $value\n";
-            } else {
-                print "graph_$key $value\n";
-               }
-        }
+sub print_root_config {
 
-        foreach my $dsrc (@{$graph->{datasrc}}) {
-            my %datasrc = %$dsrc;
-            while ( my ($key, $value) = each(%datasrc)) {
-                next if ($key eq 'name');
-                print "$dsrc->{name}.$key $value\n";
+    # Lets get our plugin, set our graph reference and our graph config info
+    my ( $prefix, $plugin ) = (@_);
+    my $graph     = $graphs{$plugin};
+    my %graphconf = %{ $graph->{config} };
+
+  # Lets tell munin about the graph we are referencing and print the main config
+    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";
+        }
     }
 
+    # Lets tell munin about our data values and how to treat them
+    foreach my $dsrc ( @{ $graph->{datasrc} } ) {
+        my %datasrc = %$dsrc;
+        while ( my ( $key, $value ) = each(%datasrc) ) {
+            next if ( $key eq 'name' );
+            print "$dsrc->{name}.$key $value\n";
+        }
+    }
     return;
 }
 
-##
-#### This subroutine is for the config info for root multigraph graphs which render on the main node page ####
-##
+=head2 print_rootmulti_config
 
-sub print_rootmulti_config {
-    my ($plugin) = (@_);
+    This subroutine prints out the config information for all of the multigraph root graphs.
+    It takes one parameter, $plugin, returns when completed.
 
-    die 'Unknown Plugin Specified: ' . ($plugin ? $plugin : '') unless $graphs{$plugin};
+        $prefix;    possible prefix used to allow multiple plugins per machine
+        $plugin;    root graph used for multigraph call
 
-    my $graph = $graphs{$plugin};
+    Example:  print_rootmulti_config($prefix,$plugin);
 
-    my %graphconf = %{$graph->{config}};
+=cut
 
-    print "multigraph memcached_$plugin\n";
+sub print_rootmulti_config {
+
+    # Lets get out plugin, set our graph reference and our graph config info
+    my ( $prefix, $plugin ) = (@_);
+    my $graph     = $graphs{$plugin};
+    my %graphconf = %{ $graph->{config} };
 
-    while ( my ($key, $value) = each(%graphconf)) {
-        print "graph_$key $value\n";
+  # Lets tell munin about the graph we are referencing and print the main config
+    if ($prefix) {
+        print "multigraph $prefix\_memcached_multi_$plugin\n";
+    }
+    else {
+        print "multigraph memcached_multi_$plugin\n";
+    }
+    while ( my ( $key, $value ) = each(%graphconf) ) {
+        if ( $key eq 'category' ) {
+            print "graph_$key memcached\n";
+        }
+        elsif ( $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}}) {
+    # Lets tell munin about our data values and how to treat them
+    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' );
+            next
+              if ( ( $plugin eq 'evictions' )
+                && ( !exists( $globalmap->{globalevics}->{ $dsrc->{name} } ) )
+              );
+            next
+              if ( ( $plugin eq 'commands' )
+                && ( !exists( $globalmap->{globalcmds}->{ $dsrc->{name} } ) ) );
             print "$dsrc->{name}.$key $value\n";
         }
     }
-
     return;
 }
 
-##
-#### This subroutine is for the config info for non multigraph graphs which render on the main node page ####
-##
+=head2 print_subrootmulti_config
 
-sub print_root_config {
-    my ($plugin) = (@_);
+    This subroutine prints out the config information for all of the multigraph root graph, only this
+    graph of the data will display on the subpage made by the multigraph capabilities of munin and
+    the plugin. It takes one parameter, $plugin, returns when completed.
 
-    die 'Unknown Plugin Specified: ' . ($plugin ? $plugin : '') unless $graphs{$plugin};
+        $prefix;    possible prefix used to allow multiple plugins per machine
+        $plugin;    root graph used for multigraph call
 
-    my $graph = $graphs{$plugin};
+    Example:  print_rootmulti_config($prefix,$plugin);
+
+=cut
 
-    my %graphconf = %{$graph->{config}};
+sub print_subrootmulti_config {
 
-    print "graph memcached_$plugin\n";
+    # Lets get out plugin, set our graph reference and our graph config info
+    my ( $prefix, $plugin ) = (@_);
+    my $graph     = $graphs{$plugin};
+    my %graphconf = %{ $graph->{config} };
+    if ($prefix) {
+        if ( $plugin eq 'evictions' ) {
+            print "multigraph $prefix\_memcached_multi_$plugin.global$plugin\n";
+        }
+        else {
+            print "multigraph $prefix\_memcached_multi_$plugin.$plugin\n";
+        }
+    }
+    else {
+        if ( $plugin eq 'evictions' ) {
+            print "multigraph memcached_multi_$plugin.global$plugin\n";
+        }
+        else {
+            print "multigraph memcached_multi_$plugin.$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}}) {
+    # Lets tell munin about our data values and how to treat them
+    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' );
+            next
+              if ( ( $plugin eq 'evictions' )
+                && ( !exists( $globalmap->{globalevics}->{ $dsrc->{name} } ) )
+              );
+            next
+              if ( ( $plugin eq 'commands' )
+                && ( !exists( $globalmap->{globalcmds}->{ $dsrc->{name} } ) ) );
             print "$dsrc->{name}.$key $value\n";
         }
     }
+    return;
+}
+
+=head2 print_submulti_config
+
+    This subroutine prints out the config information for all of the multigraph subgraphs.
+    It takes three parameters, $slabid, $plugin and @subgraphs, returns when completed.
+
+        $prefix;    possible prefix used to allow multiple plugins per machine
+        $slabid;    slab id that we will use to grab info from and print out
+        $plugin;    root graph being called, used for multigraph output and slab id
+        @subgraphs; graphs we are actually trying to print data values for
+
+    Example:  print_submulti_config($prefix,$slabid,$plugin,@subgraphs);
+
+=cut
+
+sub print_submulti_config {
+
+    # Lets get our slabid, plugin, and subgraphs
+    my ( $prefix, $slabid, $plugin, @subgraphs ) = (@_);
+    my ( $slabitems, $slabchnks ) = undef;
+
+    # Time to loop over our subgraphs array
+    foreach my $sgraph (@subgraphs) {
 
+        # Lets set our graph reference, and main graph config for easy handling
+        my $graph     = $graphs{$sgraph};
+        my %graphconf = %{ $graph->{config} };
+
+# Lets tell munin which graph we are graphing, and what our main graph config info is
+        if ($prefix) {
+            print
+              "multigraph $prefix\_memcached_multi_$plugin.$sgraph\_$slabid\n";
+        }
+        else {
+            print "multigraph memcached_multi_$plugin.$sgraph\_$slabid\n";
+        }
+        while ( my ( $key, $value ) = each(%graphconf) ) {
+            if ( $key eq 'title' ) {
+                if ($prefix) {
+                    print "graph_$key "
+                      . ucfirst($prefix)
+                      . " $value"
+                      . "$slabid"
+                      . " ($chnks{$slabid}->{chunk_size} Bytes)\n";
+                }
+                else {
+                    print "graph_$key $value"
+                      . "$slabid"
+                      . " ($chnks{$slabid}->{chunk_size} Bytes)\n";
+                }
+            }
+            elsif (
+                ( $key eq 'vlabel' )
+                && (   ( $sgraph eq 'slabevictime' )
+                    || ( $sgraph eq 'slabitemtime' ) )
+              )
+            {
+                $value = time_scale( 'config', $value );
+                print "graph_$key $value\n";
+            }
+            else {
+                print "graph_$key $value\n";
+            }
+        }
+
+        # Lets tell munin about our data values and how to treat them
+        foreach my $dsrc ( @{ $graph->{datasrc} } ) {
+            my %datasrc = %$dsrc;
+            while ( my ( $key, $value ) = each(%datasrc) ) {
+                next if ( $key eq 'name' );
+                next
+                  if ( ( $sgraph eq 'slabevics' )
+                    && ( !exists( $globalmap->{slabevics}->{ $dsrc->{name} } ) )
+                  );
+                next
+                  if ( ( $plugin eq 'commands' )
+                    && ( !exists( $globalmap->{slabcmds}->{ $dsrc->{name} } ) )
+                  );
+                print "$dsrc->{name}.$key $value\n";
+            }
+        }
+    }
     return;
 }
 
-##
-#### This subroutine actually performs the data fetch for us ####
-#### These commands do not lock up Memcache at all ####
-##
+=head1 Misc Subroutines
+
+    These subroutines are misc ones, and are referenced inside of the code. They
+    should never be called up by Munin.
+
+=head2 get_conn
+
+    This subroutine returns a socket connection
+
+=cut
+
+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;
+}
+
+=head2 fetch_stats
+
+    This subroutine fetches the information from memcached and stores it into our
+    hashes for later referencing throughout the graph. Returns when completed
+
+=cut
 
 sub fetch_stats {
-    my $s = IO::Socket::INET->new(
-        Proto    => "tcp",
-        PeerAddr => $host,
-        PeerPort => $port,
-    );
 
-    die "Error: Unable to Connect to $host\[:$port\]\n" unless $s;
+    # Lets try and connect to memcached
+    my $s = get_conn();
 
-    print $s "stats\r\n";
+    # Die if we can't establish a connection to memcached
+    die "Error: Unable to Connect to $connection\n" unless $s;
 
-    while (my $line = <$s>) {
-        if ($line =~ /STAT\s(.+?)\s(\d+)/) {
-            my ($skey,$svalue) = ($1,$2);
+    # Lets print the stats command and store the info from the output
+    print $s "stats\r\n";
+    while ( my $line = <$s> ) {
+        if ( $line =~ /STAT\s(.+?)\s((\w|\d|\S)+)/ ) {
+            my ( $skey, $svalue ) = ( $1, $2 );
             $stats{$skey} = $svalue;
         }
         last if $line =~ /^END/;
     }
 
+    # Lets print the stats settings command and store the info from the output
     print $s "stats settings\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((\w|\d|\S)+)/ ) {
+            my ( $skey, $svalue ) = ( $1, $2 );
+            if ( $skey eq 'evictions' ) {
+                $skey = 'evictions_active';
+            }
             $stats{$skey} = $svalue;
         }
         last if $line =~ /^END/;
     }
 
+    # Lets print the stats slabs command and store the info from the output
     print $s "stats slabs\r\n";
-
-    while (my $line = <$s>) {
-        if ($line =~ /STAT\s(\d+):(.+)\s(\d+)/) {
-            my ($slabid,$slabkey,$slabvalue) = ($1,$2,$3);
+    while ( my $line = <$s> ) {
+        if ( $line =~ /STAT\s(\d+):(.+)\s(\d+)/ ) {
+            my ( $slabid, $slabkey, $slabvalue ) = ( $1, $2, $3 );
             $chnks{$slabid}->{$slabkey} = $slabvalue;
         }
         last if $line =~ /^END/;
     }
 
+    # Lets print the stats items command and store the info from the output
     print $s "stats items\r\n";
-
-    while (my $line = <$s>) {
-        if ($line =~ /STAT\sitems:(\d+):(.+?)\s(\d+)/) {
-            my ($itemid,$itemkey,$itemvalue) = ($1,$2,$3);
+    while ( my $line = <$s> ) {
+        if ( $line =~ /STAT\sitems:(\d+):(.+?)\s(\d+)/ ) {
+            my ( $itemid, $itemkey, $itemvalue ) = ( $1, $2, $3 );
             $items{$itemid}->{$itemkey} = $itemvalue;
         }
         last if $line =~ /^END/;
     }
 }
 
-##
-#### This subroutine is to help manage the time_scale settings for the graph
-##
+=head2 time_scale
+
+    This subroutine is here for me to adjust the timescale of the time graphs
+    for last evicted item and age of eldest item in cache.
+
+        Please note, after long usage I have noticed these counters may not
+        be accurate, I believe the developers are aware and have submitted
+        a patch upstream.
+
+=cut
 
 sub time_scale {
-    my ($configopt,$origvalue) = (@_);
+
+    # Lets get our config option and value to adjust
+    my ( $configopt, $origvalue ) = (@_);
     my $value;
 
-    if ($configopt eq 'config') {
-        if ($timescale == 1) {
+    # If config is defined, it returns the config info for time scale
+    # If data is defined, it returns the original value after its been adjusted
+    if ( $configopt eq 'config' ) {
+        if ( $timescale == 1 ) {
             $value = "Seconds" . $origvalue;
-        } elsif ($timescale == 2) {
+        }
+        elsif ( $timescale == 2 ) {
             $value = "Minutes" . $origvalue;
-        } elsif (($timescale == 3) || ($timescale > 4) || (!defined($timescale))) {
+        }
+        elsif (( $timescale == 3 )
+            || ( $timescale > 4 )
+            || ( !defined($timescale) ) )
+        {
             $value = "Hours" . $origvalue;
-        } elsif ($timescale == 4) {
+        }
+        elsif ( $timescale == 4 ) {
             $value = "Days" . $origvalue;
         }
-    } elsif ($configopt eq 'data') {
-        if ($timescale == 1) {
-            $value = sprintf("%02.2f", $origvalue / 1);
-        } elsif ($timescale == 2) {
-            $value = sprintf("%02.2f", $origvalue / 60);
-        } elsif (($timescale == 3) || ($timescale > 4) || (!defined($timescale))) {
-            $value = sprintf("%02.2f", $origvalue / 3600);
-        } elsif ($timescale == 4) {
-            $value = sprintf("%02.2f", $origvalue / 86400);
-        }
-    } else {
+    }
+    elsif ( $configopt eq 'data' ) {
+        if ( $timescale == 1 ) {
+            $value = sprintf( "%02.2f", $origvalue / 1 );
+        }
+        elsif ( $timescale == 2 ) {
+            $value = sprintf( "%02.2f", $origvalue / 60 );
+        }
+        elsif (( $timescale == 3 )
+            || ( $timescale > 4 )
+            || ( !defined($timescale) ) )
+        {
+            $value = sprintf( "%02.2f", $origvalue / 3600 );
+        }
+        elsif ( $timescale == 4 ) {
+            $value = sprintf( "%02.2f", $origvalue / 86400 );
+        }
+    }
+    else {
         die "Unknown time_scale option given: either [config/data]\n";
     }
     return $value;
 }
+
+=head2 buildglobalmap
+
+    This subroutine looks at the specified commands inputted, and generates
+    a hashref containing two arrays, one for global command keys and one for
+    slab command keys.
+
+=cut
+
+sub buildglobalmap {
+    my $results;
+    my @cmds = split( ' ', $commands );
+    foreach my $cmd (@cmds) {
+        if ( $cmd eq "get" ) {
+            $results->{globalcmds}->{cmd_get}    = 1;
+            $results->{globalcmds}->{get_hits}   = 1;
+            $results->{globalcmds}->{get_misses} = 1;
+            $results->{slabcmds}->{get_hits}     = 1;
+        }
+        elsif ( $cmd eq "set" ) {
+            $results->{globalcmds}->{cmd_set} = 1;
+            $results->{slabcmds}->{cmd_set}   = 1;
+        }
+        elsif ( $cmd eq "delete" ) {
+            $results->{globalcmds}->{delete_hits}   = 1;
+            $results->{globalcmds}->{delete_misses} = 1;
+            $results->{slabcmds}->{delete_hits}     = 1;
+        }
+        elsif ( $cmd eq "incr" ) {
+            $results->{globalcmds}->{incr_hits}   = 1;
+            $results->{globalcmds}->{incr_misses} = 1;
+            $results->{slabcmds}->{incr_hits}     = 1;
+        }
+        elsif ( $cmd eq "decr" ) {
+            $results->{globalcmds}->{decr_hits}   = 1;
+            $results->{globalcmds}->{decr_misses} = 1;
+            $results->{slabcmds}->{decr_hits}     = 1;
+        }
+        elsif ( $cmd eq "cas" ) {
+            $results->{globalcmds}->{cas_hits}   = 1;
+            $results->{globalcmds}->{cas_misses} = 1;
+            $results->{globalcmds}->{cas_badval} = 1;
+            $results->{slabcmds}->{cas_hits}     = 1;
+            $results->{slabcmds}->{cas_badval}   = 1;
+        }
+        elsif ( $cmd eq "touch" ) {
+            if ( $stats{version} !~ /^1\.4\.[0-7]$/ ) {
+                $results->{globalcmds}->{cmd_touch}    = 1;
+                $results->{globalcmds}->{touch_hits}   = 1;
+                $results->{globalcmds}->{touch_misses} = 1;
+                $results->{slabcmds}->{touch_hits}     = 1;
+            }
+        }
+        elsif ( $cmd eq "flush" ) {
+            if ( $stats{version} !~ /^1\.4\.[0-7]$/ ) {
+                $results->{globalcmds}->{cmd_flush} = 1;
+            }
+        }
+        else {
+
+            # Do absolutely nothing...
+        }
+    }
+    $results->{globalevics}->{evictions}       = 1;
+    $results->{globalevics}->{evicted_nonzero} = 1;
+    $results->{slabevics}->{evicted}           = 1;
+    $results->{slabevics}->{evicted_nonzero}   = 1;
+    if ( $stats{version} !~ /^1\.4\.[0-2]$/ ) {
+        $results->{globalevics}->{reclaimed} = 1;
+        $results->{slabevics}->{reclaimed}   = 1;
+    }
+    return $results;
+}