]> git.openstreetmap.org Git - chef.git/blob - cookbooks/munin/files/default/plugins/memcached_multi_
Fix more rubocop detected style issues
[chef.git] / cookbooks / munin / files / default / plugins / memcached_multi_
1 #!/usr/bin/perl
2 #
3 =head1 NAME
4
5 Memcached - A Plugin to monitor Memcached Servers (Multigraph)
6
7 =head1 MUNIN CONFIGURATION
8
9 [memcached_*]
10  env.host 127.0.0.1     *default*
11  env.port 11211         *default*
12  env.timescale 3        *default*
13
14 =head2 MUNIN ENVIRONMENT CONFIGURATION EXPLANATION
15
16  host = host we are going to monitor
17  port = port we are connecting to, in order to gather stats
18  timescale = what time frame do we want to format our graphs too
19
20 =head1 NODE CONFIGURATION
21
22 Please make sure you can telnet to your memcache servers and issue the
23  following commands: stats, stats settings, stats items and stats slabs.
24
25 Available Graphs contained in this Plugin
26
27 bytes => This graphs the current network traffic in and out
28
29 commands => I<MULTIGRAPH> This graphs the current commands being issued to the memcache machine. B<Multigraph breaks this down to per slab.>
30
31 conns => This graphs the current, max connections as well as avg conns per sec avg conns per sec is derived from total_conns / uptime.
32
33 evictions => I<MULTIGRAPH> This graphs the current evictions on the node. B<Multigraph breaks this down to per slab.>
34
35 items => I<MULTIGRAPH> This graphs the current items and total items in the memcached node. B<Multigraph breaks this down to per slab.>
36
37 memory => I<MULTIGRAPH> This graphs the current and max memory allocation B<Multigraph breaks this down to per slab.>
38
39 The following example holds true for all graphing options in this plugin.
40  Example: ln -s /usr/share/munin/plugins/memcached_multi_ /etc/munin/plugins/memcached_multi_bytes
41
42 =head1 ADDITIONAL INFORMATION
43
44 You will find that some of the graphs have LEI on them. This was done in order to save room
45 on space for text and stands for B<Last Evicted Item>.
46
47 The B<Timescale> variable formats certain graphs based on the following guidelines.
48  1 => Seconds
49  2 => Minutes
50  3 => Hours  B<*Default*>
51  4 => Days
52
53 =head1 ACKNOWLEDGEMENTS
54
55 The core of this plugin is based on the mysql_ plugin maintained by Kjell-Magne Ãierud
56
57 Thanks to dormando as well for putting up with me ;)
58
59 =head1 AUTHOR
60
61 Matt West < https://code.google.com/p/memcached-munin-plugin/ >
62
63 =head1 LICENSE
64
65 GPLv2
66
67 =head1 MAGIC MARKERS
68
69     #%# family=auto
70     #%# capabilities=autoconf suggest
71
72 =cut
73
74 use strict;
75 use IO::Socket;
76 use Munin::Plugin;
77
78 need_multigraph();
79
80 my $host = $ENV{host} || "127.0.0.1";
81 my $port = $ENV{port} || 11211;
82
83 my %stats;
84 # This hash contains the information contained in two memcache commands
85 # stats and stats settings.
86
87 my %items;
88 # This gives us eviction rates and other hit stats per slab
89 # We track this so we can see if something was evicted earlier than necessary
90
91 my %chnks;
92 # This gives us the memory size and usage per slab
93 # We track this so we can see what slab is being used the most and has no free chunks 
94 # so we can re-tune memcached to allocate more pages for the specified chunk size
95
96 my $timescale = $ENV{timescale} || 3;
97 # This gives us the ability to control the timescale our graphs are displaying.
98 # The default it set to divide by hours, if you want to get seconds set it to 1.
99 # Options: 1 = seconds, 2 = minutes, 3 = hours, 4 = days
100
101 # So I was trying to figure out how to build this up, and looking at some good examples
102 # I decided to use the format, or for the most part, the format from the mysql_ munin plugin
103 # for Innodb by Kjell-Magne Ãierud, it just spoke ease of flexibility especially with multigraphs
104 # thanks btw ;)
105 #
106 # %graphs   is a container for all of the graph definition information. In here is where you'll
107 #           find the configuration information for munin's graphing procedure.
108 #   Format:
109 #
110 #   $graph{graph_name} => {
111 #       config => {
112 #           # You'll find keys and values stored here for graph manipulation
113 #       },
114 #       datasrc => [
115 #           # Name: name given to data value
116 #           # Attr: Attribute for given value
117 #           { name => 'Name', (Attr) },
118 #           { ... },
119 #       ],
120 #   }
121 my %graphs;
122
123 $graphs{items} = {
124     config => {
125         args => '--base 1000 --lower-limit 0',
126         vlabel => 'Items in Memcached',
127         category => 'memcached',
128         title => 'Items',
129         info => 'This graph shows the number of items in use by memcached',
130     },
131     datasrc => [
132         { name => 'curr_items', label => 'Current Items', min => '0' },
133         { name => 'total_items', label => 'New Items', min => '0', type => 'DERIVE' },
134     ],
135 };
136
137 $graphs{memory} = {
138     config => {
139         args => '--base 1024 --lower-limit 0',
140         vlabel => 'Bytes Used',
141         category => 'memcached',
142         title => 'Memory Usage',
143         info => 'This graph shows the memory consumption of memcached',
144     },
145     datasrc => [
146         { name => 'limit_maxbytes', draw => 'AREA', label => 'Maximum Bytes Allocated', min => '0' },
147         { name => 'bytes', draw => 'AREA', label => 'Current Bytes Used', min => '0' },
148     ],
149 };
150
151 $graphs{bytes} = {
152     config => {
153         args => '--base 1000',
154         vlabel => 'bits in (-) / out (+)',
155         title => 'Network Traffic',
156         category => 'memcached',
157         info => 'This graph shows the network traffic in (-) / out (+) of the machine',
158         order => 'bytes_read bytes_written',
159     },
160     datasrc => [
161         { name => 'bytes_read', type => 'DERIVE', label => 'Network Traffic coming in (-)', graph => 'no', cdef => 'bytes_read,8,*', min => '0' },
162         { name => 'bytes_written', type => 'DERIVE', label => 'Traffic in (-) / out (+)', negative => 'bytes_read', cdef => 'bytes_written,8,*', min => '0' },
163     ],
164 };
165
166 $graphs{conns} = {
167     config => {
168         args => '--base 1000 --lower-limit 0',
169         vlabel => 'Connections per ${graph_period}',
170         category => 'memcached',
171         title => 'Connections',
172         info => 'This graph shows the number of connections being handled by memcached',
173         order => 'max_conns curr_conns avg_conns',
174     },
175     datasrc => [
176         { name => 'curr_conns', label => 'Current Connections', min => '0' },
177         { name => 'max_conns', label => 'Max Connections', min => '0' },
178         { name => 'avg_conns' , label => 'Avg Connections', min => '0' },
179     ],
180 };
181
182 $graphs{commands} = {
183     config => {
184         args => '--base 1000 --lower-limit 0',
185         vlabel => 'Commands per ${graph_period}',
186         category => 'memcached',
187         title => 'Commands',
188         info => 'This graph shows the number of commands being handled by memcached',
189     },
190     datasrc => [
191         { name => 'cmd_get', type => 'DERIVE', label => 'Gets', info => 'Cumulative number of retrieval reqs', min => '0' },
192         { name => 'cmd_set', type => 'DERIVE', label => 'Sets', info => 'Cumulative number of storage reqs', min => '0' },
193         { name => 'get_hits', type => 'DERIVE', label => 'Get Hits', info => 'Number of keys that were requested and found', min => '0' },
194         { name => 'get_misses', type => 'DERIVE', label => 'Get Misses', info => 'Number of keys there were requested and not found', min => '0' },
195         { name => 'delete_hits', type => 'DERIVE', label => 'Delete Hits', info => 'Number of delete requests that resulted in a deletion of a key', min => '0' },
196         { name => 'delete_misses', type => 'DERIVE', label => 'Delete Misses', info => 'Number of delete requests for missing key', min => '0' },
197         { name => 'incr_hits', type => 'DERIVE', label => 'Increment Hits', info => 'Number of successful increment requests', min => '0' },
198         { name => 'incr_misses', type => 'DERIVE', label => 'Increment Misses', info => 'Number of unsuccessful increment requests', min => '0' },
199         { name => 'decr_hits', type => 'DERIVE', label => 'Decrement Hits', info => 'Number of successful decrement requests', min => '0' },
200         { name => 'decr_misses', type => 'DERIVE', label => 'Decrement Misses', info => 'Number of unsuccessful decrement requests', min => '0' },
201     ],
202 };
203
204 $graphs{evictions} = {
205     config => {
206         args => '--base 1000 --lower-limit 0',
207         vlabel => 'Evictions per ${graph_period}',
208         category => 'memcached',
209         title => 'Evictions',
210         info => 'This graph shows the number of evictions per second',
211     },
212     datasrc => [
213         { name => 'evictions', label => 'Evictions', info => 'Cumulative Evictions Across All Slabs', type => 'DERIVE', min => '0' },
214         { name => 'evicted_nonzero', label => 'Evictions prior to Expire', info => 'Cumulative Evictions forced to expire prior to expiration', type => 'DERIVE', min => '0' },
215         { name => 'reclaimed', label => 'Reclaimed Items', info => 'Cumulative Reclaimed Item Entries Across All Slabs', type => 'DERIVE', min => '0' },
216     ],
217 };
218
219 $graphs{slabchnks} = {
220     config => {
221         args => '--base 1000 --lower-limit 0',
222         vlabel => 'Available Chunks for this Slab',
223         category => 'memcached',
224         title => 'Chunk Usage for Slab: ',
225         info => 'This graph shows you the chunk usage for this memory slab.',
226     },
227     datasrc => [
228         { name => 'total_chunks', label => 'Total Chunks Available', min => '0' },
229         { name => 'used_chunks', label => 'Total Chunks in Use', min => '0' },
230         { name => 'free_chunks', label => 'Total Chunks Not in Use (Free)', min => '0' },
231     ],
232 };
233
234 $graphs{slabhits} = {
235     config => {
236         args => '--base 1000 --lower-limit 0',
237         vlabel => 'Hits per Slab per ${graph_period}',
238         category => 'memcached',
239         title => 'Hits for Slab: ',
240         info => 'This graph shows you the successful hit rate for this memory slab.',
241     },
242     datasrc => [
243         { name => 'get_hits', label => 'Get Requests', type => 'DERIVE', min => '0' },
244         { name => 'cmd_set', label => 'Set Requests', type => 'DERIVE', min => '0' },
245         { name => 'delete_hits', label => 'Delete Requests', type => 'DERIVE', min => '0' },
246         { name => 'incr_hits', label => 'Increment Requests', type => 'DERIVE', min => '0' },
247         { name => 'decr_hits', label => 'Decrement Requests', type => 'DERIVE', min => '0' },
248     ],
249 };
250
251 $graphs{slabevics} = {
252     config => {
253         args => '--base 1000 --lower-limit 0',
254         vlabel => 'Evictions per Slab per ${graph_period}',
255         category => 'memcached',
256         title => 'Evictions for Slab: ',
257         info => 'This graph shows you the eviction rate for this memory slab.',
258     },
259     datasrc => [
260         { name => 'evicted', label => 'Total Evictions', type => 'DERIVE', min => '0' },
261         { name => 'evicted_nonzero', label => 'Evictions from LRU Prior to Expire', type => 'DERIVE', min => '0' },
262         { name => 'reclaimed', label => 'Reclaimed Expired Items', info => 'This is number of times items were stored in expired entry memory space', type => 'DERIVE', min => '0' },
263     ],
264 };
265
266 $graphs{slabevictime} = {
267     config => {
268         args => '--base 1000 --lower-limit 0',
269         vlabel => ' since Request for LEI',
270         category => 'memcached',
271         title => 'Eviction Request Time for Slab: ',
272         info => 'This graph shows you the time since we requested the last evicted item',
273     },
274     datasrc => [
275         { name => 'evicted_time', label => 'Eviction Time (LEI)', info => 'Time Since Request for Last Evicted Item', min => '0' },
276     ],
277 };
278
279 $graphs{slabitems} = {
280     config => {
281         args => '--base 1000 --lower-limit 0',
282         vlabel => 'Items per Slab',
283         category => 'memcached',
284         title => 'Items in Slab: ',
285         info => 'This graph shows you the number of items and reclaimed items per slab.',
286     },
287     datasrc => [
288         { name => 'number', label => 'Items', info => 'This is the amount of items stored in this slab', min => '0' },
289     ],
290 };
291
292 $graphs{slabitemtime} = {
293     config => {
294         args => '--base 1000 --lower-limit 0',
295         vlabel => ' since item was stored',
296         category => 'memcached',
297         title => 'Age of Eldest Item in Slab: ',
298         info => 'This graph shows you the time of the eldest item in this slab',
299     },
300     datasrc => [
301         { name => 'age', label => 'Eldest Item\'s Age', min => '0' },
302     ],
303 };
304
305 ##
306 #### Config Check ####
307 ##
308
309 if (defined $ARGV[0] && $ARGV[0] eq 'config') {
310
311     $0 =~ /memcached_multi_(.+)*/;
312     my $plugin = $1;
313
314     die 'Unknown Plugin Specified: ' . ($plugin ? $plugin : '') unless $graphs{$plugin};
315
316     # We need to fetch the stats before we do any config, cause its needed for multigraph
317     fetch_stats();
318
319     # Now lets go ahead and print out our config.
320         do_config($plugin);
321         exit 0;
322 }
323
324 ##
325 #### Autoconf Check ####
326 ##
327
328 if (defined $ARGV[0] && $ARGV[0] eq 'autoconf') {
329
330     my $s = IO::Socket::INET->new(
331         Proto    => "tcp",
332         PeerAddr => $host,
333         PeerPort => $port,
334     );
335
336     if (defined($s)) {
337         print "yes\n";
338         exit 0;
339     } else {
340         print "no (unable to connect to $host\[:$port\])\n";
341         exit 0;
342     }
343 }
344
345 ##
346 #### Suggest Check ####
347 ##
348
349 if (defined $ARGV[0] && $ARGV[0] eq 'suggest') {
350
351     my $s = IO::Socket::INET->new(
352         Proto    => "tcp",
353         PeerAddr => $host,
354         PeerPort => $port,
355     );
356
357     if (defined($s)) {
358         my @rootplugins = ('bytes','conns','commands','evictions','items','memory');
359         foreach my $plugin (@rootplugins) {
360             print "$plugin\n";
361         }
362         exit 0;
363     } else {
364         print "no (unable to connect to $host\[:$port\])\n";
365         exit 0;
366     }
367 }
368
369 ##
370 #### Well We aren't running (auto)config/suggest so lets print some stats ####
371 ##
372
373 fetch_output();
374
375 ##
376 #### Subroutines for printing info gathered from memcached ####
377 ##
378
379 ##
380 #### This subroutine performs the bulk processing for printing statistics.
381 ##
382
383 sub fetch_output {
384
385     $0 =~ /memcached_multi_(.+)*/;
386     my $plugin = $1;
387
388     die 'Unknown Plugin Specified: ' . ($plugin ? $plugin : '') unless $graphs{$plugin};
389
390     # Well we need to actually fetch the stats before we do anything to them.
391     fetch_stats();
392     
393     # Now lets go ahead and print out our output.
394     my @subgraphs;
395     if ($plugin eq 'memory') {
396         @subgraphs = ('slabchnks');
397         foreach my $slabid(sort{$a <=> $b} keys %chnks) {
398             print_submulti_output($slabid,$plugin,@subgraphs);
399         }
400         print_rootmulti_output($plugin);
401     } elsif ($plugin eq 'commands') {
402         @subgraphs = ('slabhits');
403         foreach my $slabid(sort{$a <=> $b} keys %chnks) {
404             print_submulti_output($slabid,$plugin,@subgraphs);
405         }
406         print_rootmulti_output($plugin);
407     } elsif ($plugin eq 'evictions') {
408         @subgraphs = ('slabevics','slabevictime');
409         foreach my $slabid (sort{$a <=> $b} keys %items) {
410             print_submulti_output($slabid,$plugin,@subgraphs);
411         }
412         print_rootmulti_output($plugin);
413     } elsif ($plugin eq 'items') {
414         @subgraphs = ('slabitems','slabitemtime');
415         foreach my $slabid (sort{$a <=> $b} keys %items) {
416             print_submulti_output($slabid,$plugin,@subgraphs);
417         }
418         print_rootmulti_output($plugin);
419     } else {
420         print_root_output($plugin);
421     }
422
423     return;
424 }
425
426 ##
427 #### This subroutine is for the root non-multigraph graphs which render on the main node page ####
428 ##
429
430 sub print_root_output {
431     my ($plugin) = (@_);
432
433     my $graph = $graphs{$plugin};
434
435     print "graph memcached_$plugin\n";
436
437     if ($plugin ne 'conns') {
438         foreach my $dsrc (@{$graph->{datasrc}}) {
439             my %datasrc = %$dsrc;
440             while ( my ($key, $value) = each(%datasrc)) {
441                 next if ($key ne 'name');
442                 my $output = $stats{$value};
443                 print "$dsrc->{name}.value $output\n";
444             }
445         }
446     } else {
447         my $output;
448         foreach my $dsrc (@{$graph->{datasrc}}) {
449             my %datasrc = %$dsrc;
450             while ( my ($key, $value) = each(%datasrc)) {
451                 if ($value eq 'max_conns') {
452                     $output = $stats{maxconns};
453                 } elsif ($value eq 'curr_conns') {
454                     $output = $stats{curr_connections};
455                 } elsif ($value eq 'avg_conns') {
456                     $output = sprintf("%02d", $stats{total_connections} / $stats{uptime});
457                 } else {
458                     next;
459                 }
460                 print "$dsrc->{name}.value $output\n";
461             }
462         }
463     }
464
465     return;
466 }
467
468 ##
469 #### This subroutine is for the root multigraph graphs which render on the main node page ####
470 ##
471
472 sub print_rootmulti_output {
473     my ($plugin) = (@_);
474
475     my $graph = $graphs{$plugin};
476
477     print "multigraph memcached_$plugin\n";
478     
479     foreach my $dsrc (@{$graph->{datasrc}}) {
480         my $output = 0;
481         my %datasrc = %$dsrc;
482         while ( my ($key, $value) = each(%datasrc)) {
483             next if ($key ne 'name');
484             if (($plugin eq 'evictions') && ($value eq 'evicted_nonzero')) {
485                 foreach my $slabid (sort{$a <=> $b} keys %items) {
486                     $output += $items{$slabid}->{evicted_nonzero};
487                 }
488             } else {
489                 $output = $stats{$value};
490             }
491             print "$dsrc->{name}.value $output\n";
492         }
493     }
494
495     return;
496 }
497
498 ##
499 #### This subroutine is for the sub multigraph graphs created via the multigraph plugin ####
500 ##
501
502 sub print_submulti_output {
503     my ($slabid,$plugin,@subgraphs) = (@_);
504     my $currslab = undef;
505
506     foreach my $sgraph (@subgraphs) {
507
508         my $graph = $graphs{$sgraph};
509
510         print "multigraph memcached_$plugin.$sgraph\_$slabid\n";
511
512         if ($plugin eq 'evictions') {
513             $currslab = $items{$slabid};
514         } elsif ($plugin eq 'memory') {
515             $currslab = $chnks{$slabid};
516         } elsif ($plugin eq 'commands') {
517             $currslab = $chnks{$slabid};
518         } elsif ($plugin eq 'items') {
519             $currslab = $items{$slabid};
520         } else {
521             return;
522         }
523
524         foreach my $dsrc (@{$graph->{datasrc}}) {
525             my %datasrc = %$dsrc;
526             while ( my ($key, $value) = each(%datasrc)) {
527                 next if ($key ne 'name');
528                 my $output = $currslab->{$value};
529                 if (($sgraph eq 'slabevictime') || ($sgraph eq 'slabitemtime')) {
530                     $output = time_scale('data',$output); ;
531                 }
532                 print "$dsrc->{name}.value $output\n";
533             }
534         }
535     }
536
537     return;
538 }
539
540 ##
541 #### Subroutines for printing out config information for graphs ####
542 ##
543
544 ##
545 #### This subroutine does the bulk printing the config info per graph ####
546 ##
547
548 sub do_config {
549     my ($plugin) = (@_);
550     my @subgraphs;
551     if ($plugin eq 'memory') {
552         @subgraphs = ('slabchnks');
553         foreach my $slabid (sort{$a <=> $b} keys %chnks) {
554             print_submulti_config($slabid,$plugin,@subgraphs);
555         }
556         print_rootmulti_config($plugin);
557     } elsif ($plugin eq 'commands') {
558         @subgraphs = ('slabhits');
559         foreach my $slabid (sort{$a <=> $b} keys %chnks) {
560             print_submulti_config($slabid,$plugin,@subgraphs);
561         }
562         print_rootmulti_config($plugin);
563     } elsif ($plugin eq 'evictions') {
564         @subgraphs = ('slabevics','slabevictime');
565         foreach my $slabid (sort{$a <=> $b}  keys %items) {
566             print_submulti_config($slabid,$plugin,@subgraphs);
567         }
568         print_rootmulti_config($plugin);
569     } elsif ($plugin eq 'items') {
570         @subgraphs = ('slabitems','slabitemtime');
571         foreach my $slabid (sort{$a <=> $b} keys %items) {
572             print_submulti_config($slabid,$plugin,@subgraphs);
573         }
574         print_rootmulti_config($plugin);
575     } else {
576         print_root_config($plugin);
577     }
578
579     return;
580 }
581
582 ##
583 #### This subroutine is for the config info for sub multigraph graphs created via the multigraph plugin ####
584 ##
585
586 sub print_submulti_config {
587     my ($slabid,$plugin,@subgraphs) = (@_);
588     my ($slabitems,$slabchnks) = undef;
589
590     foreach my $sgraph (@subgraphs) {
591
592         my $graph = $graphs{$sgraph};
593
594         my %graphconf = %{$graph->{config}};
595         
596         print "multigraph memcached_$plugin.$sgraph\_$slabid\n";
597
598         while ( my ($key, $value) = each(%graphconf)) {
599                 if ($key eq 'title') {
600                     print "graph_$key $value" . "$slabid" . " ($chnks{$slabid}->{chunk_size} Bytes)\n";
601                 } elsif (($key eq 'vlabel') && (($sgraph eq 'slabevictime') || ($sgraph eq 'slabitemtime'))) {
602                 $value = time_scale('config',$value);
603                 print "graph_$key $value\n";
604             } else {
605                 print "graph_$key $value\n";
606                 }
607         }
608
609         foreach my $dsrc (@{$graph->{datasrc}}) {
610             my %datasrc = %$dsrc;
611             while ( my ($key, $value) = each(%datasrc)) {
612                 next if ($key eq 'name');
613                 print "$dsrc->{name}.$key $value\n";
614             }
615         }
616     }
617
618     return;
619 }
620
621 ##
622 #### This subroutine is for the config info for root multigraph graphs which render on the main node page ####
623 ##
624
625 sub print_rootmulti_config {
626     my ($plugin) = (@_);
627
628     die 'Unknown Plugin Specified: ' . ($plugin ? $plugin : '') unless $graphs{$plugin};
629
630     my $graph = $graphs{$plugin};
631
632     my %graphconf = %{$graph->{config}};
633
634     print "multigraph memcached_$plugin\n";
635
636     while ( my ($key, $value) = each(%graphconf)) {
637         print "graph_$key $value\n";
638     }
639
640     foreach my $dsrc (@{$graph->{datasrc}}) {
641         my %datasrc = %$dsrc;
642         while ( my ($key, $value) = each(%datasrc)) {
643             next if ($key eq 'name');
644             print "$dsrc->{name}.$key $value\n";
645         }
646     }
647
648     return;
649 }
650
651 ##
652 #### This subroutine is for the config info for non multigraph graphs which render on the main node page ####
653 ##
654
655 sub print_root_config {
656     my ($plugin) = (@_);
657
658     die 'Unknown Plugin Specified: ' . ($plugin ? $plugin : '') unless $graphs{$plugin};
659
660     my $graph = $graphs{$plugin};
661
662     my %graphconf = %{$graph->{config}};
663
664     print "graph memcached_$plugin\n";
665
666     while ( my ($key, $value) = each(%graphconf)) {
667         print "graph_$key $value\n";
668     }
669
670     foreach my $dsrc (@{$graph->{datasrc}}) {
671         my %datasrc = %$dsrc;
672         while ( my ($key, $value) = each(%datasrc)) {
673             next if ($key eq 'name');
674             print "$dsrc->{name}.$key $value\n";
675         }
676     }
677
678     return;
679 }
680
681 ##
682 #### This subroutine actually performs the data fetch for us ####
683 #### These commands do not lock up Memcache at all ####
684 ##
685
686 sub fetch_stats {
687     my $s = IO::Socket::INET->new(
688         Proto    => "tcp",
689         PeerAddr => $host,
690         PeerPort => $port,
691     );
692
693     die "Error: Unable to Connect to $host\[:$port\]\n" unless $s;
694
695     print $s "stats\r\n";
696
697     while (my $line = <$s>) {
698         if ($line =~ /STAT\s(.+?)\s(\d+)/) {
699             my ($skey,$svalue) = ($1,$2);
700             $stats{$skey} = $svalue;
701         }
702         last if $line =~ /^END/;
703     }
704
705     print $s "stats settings\r\n";
706
707     while (my $line = <$s>) {
708         if ($line =~ /STAT\s(.+?)\s(\d+)/) {
709             my ($skey,$svalue) = ($1,$2);
710             $stats{$skey} = $svalue;
711         }
712         last if $line =~ /^END/;
713     }
714
715     print $s "stats slabs\r\n";
716
717     while (my $line = <$s>) {
718         if ($line =~ /STAT\s(\d+):(.+)\s(\d+)/) {
719             my ($slabid,$slabkey,$slabvalue) = ($1,$2,$3);
720             $chnks{$slabid}->{$slabkey} = $slabvalue;
721         }
722         last if $line =~ /^END/;
723     }
724
725     print $s "stats items\r\n";
726
727     while (my $line = <$s>) {
728         if ($line =~ /STAT\sitems:(\d+):(.+?)\s(\d+)/) {
729             my ($itemid,$itemkey,$itemvalue) = ($1,$2,$3);
730             $items{$itemid}->{$itemkey} = $itemvalue;
731         }
732         last if $line =~ /^END/;
733     }
734 }
735
736 ##
737 #### This subroutine is to help manage the time_scale settings for the graph
738 ##
739
740 sub time_scale {
741     my ($configopt,$origvalue) = (@_);
742     my $value;
743
744     if ($configopt eq 'config') {
745         if ($timescale == 1) {
746             $value = "Seconds" . $origvalue;
747         } elsif ($timescale == 2) {
748             $value = "Minutes" . $origvalue;
749         } elsif (($timescale == 3) || ($timescale > 4) || (!defined($timescale))) {
750             $value = "Hours" . $origvalue;
751         } elsif ($timescale == 4) {
752             $value = "Days" . $origvalue;
753         }
754     } elsif ($configopt eq 'data') {
755         if ($timescale == 1) {
756             $value = sprintf("%02.2f", $origvalue / 1);
757         } elsif ($timescale == 2) {
758             $value = sprintf("%02.2f", $origvalue / 60);
759         } elsif (($timescale == 3) || ($timescale > 4) || (!defined($timescale))) {
760             $value = sprintf("%02.2f", $origvalue / 3600);
761         } elsif ($timescale == 4) {
762             $value = sprintf("%02.2f", $origvalue / 86400);
763         }
764     } else {
765         die "Unknown time_scale option given: either [config/data]\n";
766     }
767     return $value;
768 }