]> git.openstreetmap.org Git - chef.git/blobdiff - cookbooks/munin/files/default/plugins/memcached_multi_
Add a bunch more cookbooks
[chef.git] / cookbooks / munin / files / default / plugins / memcached_multi_
diff --git a/cookbooks/munin/files/default/plugins/memcached_multi_ b/cookbooks/munin/files/default/plugins/memcached_multi_
new file mode 100755 (executable)
index 0000000..a202899
--- /dev/null
@@ -0,0 +1,768 @@
+#!/usr/bin/perl
+#
+=head1 NAME
+
+Memcached - A Plugin to monitor Memcached Servers (Multigraph)
+
+=head1 MUNIN CONFIGURATION
+
+[memcached_*]
+ env.host 127.0.0.1     *default*
+ env.port 11211         *default*
+ env.timescale 3        *default*
+
+=head2 MUNIN ENVIRONMENT CONFIGURATION EXPLANATION
+
+ host = host we are going to monitor
+ port = port we are connecting to, in order to gather stats
+ timescale = what time frame do we want to format our graphs too
+
+=head1 NODE CONFIGURATION
+
+Please make sure you can telnet to your memcache servers and issue the
+ following commands: stats, stats settings, stats items and stats slabs.
+
+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.>
+
+conns => This graphs the current, max connections as well as avg conns per sec avg conns per sec 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.>
+
+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.>
+
+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
+
+=head1 ADDITIONAL INFORMATION
+
+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>.
+
+The B<Timescale> variable formats certain graphs based on the following guidelines.
+ 1 => Seconds
+ 2 => Minutes
+ 3 => Hours  B<*Default*>
+ 4 => Days
+
+=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 ;)
+
+=head1 AUTHOR
+
+Matt West < https://code.google.com/p/memcached-munin-plugin/ >
+
+=head1 LICENSE
+
+GPLv2
+
+=head1 MAGIC MARKERS
+
+    #%# family=auto
+    #%# capabilities=autoconf suggest
+
+=cut
+
+use strict;
+use IO::Socket;
+use Munin::Plugin;
+
+need_multigraph();
+
+my $host = $ENV{host} || "127.0.0.1";
+my $port = $ENV{port} || 11211;
+
+my %stats;
+# This hash contains the information contained in two memcache commands
+# stats and stats settings.
+
+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 %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 
+# so we can re-tune memcached to allocate more pages for the specified chunk size
+
+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
+
+# 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;
+
+$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',
+    },
+    datasrc => [
+        { name => 'curr_items', label => 'Current Items', min => '0' },
+        { name => 'total_items', label => 'New Items', min => '0', type => 'DERIVE' },
+    ],
+};
+
+$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',
+    },
+    datasrc => [
+        { 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',
+        category => 'memcached',
+        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' },
+    ],
+};
+
+$graphs{conns} = {
+    config => {
+        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',
+    },
+    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' },
+    ],
+};
+
+$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',
+    },
+    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' },
+    ],
+};
+
+$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',
+    },
+    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' },
+    ],
+};
+
+$graphs{slabchnks} = {
+    config => {
+        args => '--base 1000 --lower-limit 0',
+        vlabel => 'Available Chunks for this Slab',
+        category => 'memcached',
+        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 => 'used_chunks', label => 'Total Chunks in Use', min => '0' },
+        { name => 'free_chunks', label => 'Total Chunks Not in Use (Free)', min => '0' },
+    ],
+};
+
+$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.',
+    },
+    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' },
+    ],
+};
+
+$graphs{slabevics} = {
+    config => {
+        args => '--base 1000 --lower-limit 0',
+        vlabel => 'Evictions per Slab per ${graph_period}',
+        category => 'memcached',
+        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' },
+    ],
+};
+
+$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',
+    },
+    datasrc => [
+        { name => 'evicted_time', label => 'Eviction Time (LEI)', info => 'Time Since Request for Last Evicted Item', min => '0' },
+    ],
+};
+
+$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.',
+    },
+    datasrc => [
+        { name => 'number', label => 'Items', info => 'This is the amount of items stored in this slab', min => '0' },
+    ],
+};
+
+$graphs{slabitemtime} = {
+    config => {
+        args => '--base 1000 --lower-limit 0',
+        vlabel => ' since item was stored',
+        category => 'memcached',
+        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' },
+    ],
+};
+
+##
+#### Config Check ####
+##
+
+if (defined $ARGV[0] && $ARGV[0] eq 'config') {
+
+    $0 =~ /memcached_multi_(.+)*/;
+    my $plugin = $1;
+
+    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
+    fetch_stats();
+
+    # Now lets go ahead and print out our config.
+       do_config($plugin);
+       exit 0;
+}
+
+##
+#### Autoconf Check ####
+##
+
+if (defined $ARGV[0] && $ARGV[0] eq 'autoconf') {
+
+    my $s = IO::Socket::INET->new(
+        Proto    => "tcp",
+        PeerAddr => $host,
+        PeerPort => $port,
+    );
+
+    if (defined($s)) {
+        print "yes\n";
+        exit 0;
+    } else {
+        print "no (unable to connect to $host\[:$port\])\n";
+        exit 0;
+    }
+}
+
+##
+#### Suggest Check ####
+##
+
+if (defined $ARGV[0] && $ARGV[0] eq 'suggest') {
+
+    my $s = IO::Socket::INET->new(
+        Proto    => "tcp",
+        PeerAddr => $host,
+        PeerPort => $port,
+    );
+
+    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";
+        exit 0;
+    }
+}
+
+##
+#### Well We aren't running (auto)config/suggest so lets print some stats ####
+##
+
+fetch_output();
+
+##
+#### Subroutines for printing info gathered from memcached ####
+##
+
+##
+#### This subroutine performs the bulk processing for printing statistics.
+##
+
+sub fetch_output {
+
+    $0 =~ /memcached_multi_(.+)*/;
+    my $plugin = $1;
+
+    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.
+    my @subgraphs;
+    if ($plugin eq 'memory') {
+        @subgraphs = ('slabchnks');
+        foreach my $slabid(sort{$a <=> $b} keys %chnks) {
+            print_submulti_output($slabid,$plugin,@subgraphs);
+        }
+        print_rootmulti_output($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 {
+        print_root_output($plugin);
+    }
+
+    return;
+}
+
+##
+#### This subroutine is for the root non-multigraph graphs which render on the main node page ####
+##
+
+sub print_root_output {
+    my ($plugin) = (@_);
+
+    my $graph = $graphs{$plugin};
+
+    print "graph memcached_$plugin\n";
+
+    if ($plugin ne 'conns') {
+        foreach my $dsrc (@{$graph->{datasrc}}) {
+            my %datasrc = %$dsrc;
+            while ( my ($key, $value) = each(%datasrc)) {
+                next if ($key ne 'name');
+                my $output = $stats{$value};
+                print "$dsrc->{name}.value $output\n";
+            }
+        }
+    } else {
+        my $output;
+        foreach my $dsrc (@{$graph->{datasrc}}) {
+            my %datasrc = %$dsrc;
+            while ( my ($key, $value) = each(%datasrc)) {
+                if ($value eq 'max_conns') {
+                    $output = $stats{maxconns};
+                } elsif ($value eq 'curr_conns') {
+                    $output = $stats{curr_connections};
+                } 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 ####
+##
+
+sub print_rootmulti_output {
+    my ($plugin) = (@_);
+
+    my $graph = $graphs{$plugin};
+
+    print "multigraph memcached_$plugin\n";
+    
+    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) {
+                    $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 ####
+##
+
+sub print_submulti_output {
+    my ($slabid,$plugin,@subgraphs) = (@_);
+    my $currslab = undef;
+
+    foreach my $sgraph (@subgraphs) {
+
+        my $graph = $graphs{$sgraph};
+
+        print "multigraph memcached_$plugin.$sgraph\_$slabid\n";
+
+        if ($plugin eq 'evictions') {
+            $currslab = $items{$slabid};
+        } elsif ($plugin eq 'memory') {
+            $currslab = $chnks{$slabid};
+        } elsif ($plugin eq 'commands') {
+            $currslab = $chnks{$slabid};
+        } elsif ($plugin eq 'items') {
+            $currslab = $items{$slabid};
+        } else {
+            return;
+        }
+
+        foreach my $dsrc (@{$graph->{datasrc}}) {
+            my %datasrc = %$dsrc;
+            while ( my ($key, $value) = each(%datasrc)) {
+                next if ($key ne 'name');
+                my $output = $currslab->{$value};
+                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 ####
+##
+
+##
+#### This subroutine does the bulk printing the config info per graph ####
+##
+
+sub do_config {
+    my ($plugin) = (@_);
+    my @subgraphs;
+    if ($plugin eq 'memory') {
+        @subgraphs = ('slabchnks');
+        foreach my $slabid (sort{$a <=> $b} keys %chnks) {
+            print_submulti_config($slabid,$plugin,@subgraphs);
+        }
+        print_rootmulti_config($plugin);
+    } elsif ($plugin eq 'commands') {
+        @subgraphs = ('slabhits');
+        foreach my $slabid (sort{$a <=> $b} keys %chnks) {
+            print_submulti_config($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_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_rootmulti_config($plugin);
+    } else {
+        print_root_config($plugin);
+    }
+
+    return;
+}
+
+##
+#### This subroutine is for the config info for sub multigraph graphs created via the multigraph plugin ####
+##
+
+sub print_submulti_config {
+    my ($slabid,$plugin,@subgraphs) = (@_);
+    my ($slabitems,$slabchnks) = undef;
+
+    foreach my $sgraph (@subgraphs) {
+
+        my $graph = $graphs{$sgraph};
+
+        my %graphconf = %{$graph->{config}};
+        
+        print "multigraph memcached_$plugin.$sgraph\_$slabid\n";
+
+        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";
+               }
+        }
+
+        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 ####
+##
+
+sub print_rootmulti_config {
+    my ($plugin) = (@_);
+
+    die 'Unknown Plugin Specified: ' . ($plugin ? $plugin : '') unless $graphs{$plugin};
+
+    my $graph = $graphs{$plugin};
+
+    my %graphconf = %{$graph->{config}};
+
+    print "multigraph memcached_$plugin\n";
+
+    while ( my ($key, $value) = each(%graphconf)) {
+        print "graph_$key $value\n";
+    }
+
+    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 non multigraph graphs which render on the main node page ####
+##
+
+sub print_root_config {
+    my ($plugin) = (@_);
+
+    die 'Unknown Plugin Specified: ' . ($plugin ? $plugin : '') unless $graphs{$plugin};
+
+    my $graph = $graphs{$plugin};
+
+    my %graphconf = %{$graph->{config}};
+
+    print "graph memcached_$plugin\n";
+
+    while ( my ($key, $value) = each(%graphconf)) {
+        print "graph_$key $value\n";
+    }
+
+    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 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,
+    );
+
+    die "Error: Unable to Connect to $host\[:$port\]\n" unless $s;
+
+    print $s "stats\r\n";
+
+    while (my $line = <$s>) {
+        if ($line =~ /STAT\s(.+?)\s(\d+)/) {
+            my ($skey,$svalue) = ($1,$2);
+            $stats{$skey} = $svalue;
+        }
+        last if $line =~ /^END/;
+    }
+
+    print $s "stats settings\r\n";
+
+    while (my $line = <$s>) {
+        if ($line =~ /STAT\s(.+?)\s(\d+)/) {
+            my ($skey,$svalue) = ($1,$2);
+            $stats{$skey} = $svalue;
+        }
+        last if $line =~ /^END/;
+    }
+
+    print $s "stats slabs\r\n";
+
+    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/;
+    }
+
+    print $s "stats items\r\n";
+
+    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
+##
+
+sub time_scale {
+    my ($configopt,$origvalue) = (@_);
+    my $value;
+
+    if ($configopt eq 'config') {
+        if ($timescale == 1) {
+            $value = "Seconds" . $origvalue;
+        } elsif ($timescale == 2) {
+            $value = "Minutes" . $origvalue;
+        } elsif (($timescale == 3) || ($timescale > 4) || (!defined($timescale))) {
+            $value = "Hours" . $origvalue;
+        } 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 {
+        die "Unknown time_scale option given: either [config/data]\n";
+    }
+    return $value;
+}