6 Memcached Multi - A Plugin to monitor Memcached Servers (Multigraph)
8 The common difference between this memcached Munin plugin and others that exists, is that
9 others don't expose slab information from memcached, so you can better tune your memcached
10 interaction / stability / etc. With this plugin we leverage multigraph capabilities in
11 Munin to "hide" the slab information underneath of their parent graphs.
13 =head1 MUNIN NODE CONFIGURATION
15 The following configuration information can be overridden by placing environment definitions
16 like shown here, in a file located in /etc/munin/plugin-conf.d
19 env.host 127.0.0.1 *default*
20 env.port 11211 *default*
21 env.timescale 3 *default*
22 env.cmds get set delete incr decr touch *default*
23 env.leitime -1 *default*
25 =head2 MUNIN NODE ENVIRONMENT CONFIGURATION EXPLANATION
27 host = host we are going to monitor, this can be used to specify a unix socket.
28 port = port we are connecting to, in order to gather stats
29 timescale = what time frame do we want to format our graphs too
30 cmds = cmd types to display on cmd graph, remove cmds you don't want displayed from list.
31 leitime = setting this to 1 will re-enable slab eviction time graphs, see note below.
33 =head2 BASIC TROUBLESHOOTING
35 Please make sure you can telnet to your memcache servers and issue the
36 following commands: stats, stats settings, stats items and stats slabs.
38 =head2 PLUGIN INFORMATION
40 Available Graphs contained in this Plugin
42 bytes => This graphs the current network traffic in and out
44 commands => I<MULTIGRAPH> This graphs the current commands being issued to the memcache machine.
45 B<Multigraph breaks this down to per slab.>
47 conns => This graphs the current, max connections as well as avg conns per sec avg conns per sec
48 and is derived from total_conns / uptime.
50 evictions => I<MULTIGRAPH> This graphs the current evictions on the node.
51 B<Multigraph breaks this down to per slab.>
53 items => I<MULTIGRAPH> This graphs the current items and total items in the memcached node.
54 B<Multigraph breaks this down to per slab.>
56 memory => I<MULTIGRAPH> This graphs the current and max memory allocation.
57 B<Multigraph breaks this down to per slab.>
59 unfetched => I<MULTIGRAPH> This graphs the number of items that were never touched by a
60 get/incr/append/etc before being evicted or expiring from the cache.
61 B<Multigraph breaks this down to per slab.>
63 =head1 ADDITIONAL INFORMATION
65 B<NOTE:> The slab plugin for LEI has been disabled since I believe the counters to be inaccurate,
66 or perhaps not being updated as often I thought they would be. They can be re-enabled by
67 setting an environment variable, see munin configuration section at the top.
69 You will find that some of the graphs have LEI on them. This was done in order to save room
70 on space for text and stands for B<Last Evicted Item>.
72 The B<Timescale> variable formats certain graphs based on the following guidelines.
75 3 => Hours B<*Default*>
78 =head1 ACKNOWLEDGEMENTS
80 Thanks to dormando for putting up with me ;)
84 Matt West < https://github.com/mhwest13/Memcached-Munin-Plugin >
93 #%# capabilities=autoconf suggest
103 if ( basename($0) !~ /(?:([^\/]+)_)?memcached_multi_/ ) {
105 "This script needs to be named (prefix_)?memcached_multi_ to run properly.\n";
109 # tell munin about our multigraph capabilities
112 =head1 Variable Declarations
114 This section of code is to declare the variables used throughout the plugin
115 Some of them are imported as environment variables from munin plugin conf.d
116 file, others are hashes used for storing information that comes from the
117 stats commands issued to memcached.
121 # lets import environment variables for the plugin or use the default
122 my $host = $ENV{host} || "127.0.0.1";
123 my $port = $ENV{port} || 11211;
126 # This gives us the ability to control the timescale our graphs are displaying.
127 # The default it set to divide by hours, if you want to get seconds set it to 1.
128 # Options: 1 = seconds, 2 = minutes, 3 = hours, 4 = days
129 my $timescale = $ENV{timescale} || 3;
131 # This gives us the ability to turn the Last Evicted Item time slab graph on.
132 # It was removed because I believe the counter / response to be broken but
133 # perhaps this was useful to someone.
134 my $leitime = $ENV{leitime} || -1;
136 # This gives us the ability to specify which commands we want to display on the
137 # command graph. Allowing finer control since some environments don't leverage
138 # every command possible in memcached.
139 # Options: get set delete incr decr cas touch flush
140 my $commands = $ENV{cmds} || "get set delete incr decr touch";
142 # This hash contains the information contained in two memcache commands
143 # stats and stats settings.
146 # This gives us eviction rates and other hit stats per slab
147 # We track this so we can see if something was evicted earlier than necessary
150 # This gives us the memory size and usage per slab
151 # We track this so we can see what slab is being used the most and has no free chunks
152 # so we can re-tune memcached to allocate more pages for the specified chunk size
155 # Variable for setting up a quick access map for plugin configurations / version adherence
158 =head2 Graph Declarations
160 This block of code builds up all of the graph info for all root / subgraphs.
162 %graphs: is a container for all of the graph definition information. In here is where you'll
163 find the configuration information for munin's graphing procedure.
166 $graph{graph_name} => {
168 You'll find the main graph config stored here
173 Name: name given to data value
174 Attr: Attribute and value, attribute must be valid plugin argument
175 { name => 'Name', info => 'info about graph', ... },
184 # main graph for memcached item count
187 args => '--base 1000 --lower-limit 0',
188 vlabel => 'Items in Memcached',
189 category => 'memcached global items',
191 info => 'Number of items in use by memcached',
194 { name => 'curr_items', label => 'Current Items', min => '0' },
196 name => 'total_items',
197 label => 'New Items',
204 # main graph for memcached memory usage
207 args => '--base 1024 --lower-limit 0',
208 vlabel => 'Bytes Used',
209 category => 'memcached global memory',
210 title => 'Memory Usage',
211 info => 'Memory consumption of memcached',
215 name => 'limit_maxbytes',
217 label => 'Maximum Bytes Allocated',
223 label => 'Current Bytes Used',
229 # main graph for memcached network usage
232 args => '--base 1000',
233 vlabel => 'bits in (-) / out (+)',
234 title => 'Network Traffic',
235 category => 'memcached',
236 info => 'Network traffic in (-) / out (+) of the machine',
237 order => 'bytes_read bytes_written',
241 name => 'bytes_read',
243 label => 'Network Traffic coming in (-)',
245 cdef => 'bytes_read,8,*',
249 name => 'bytes_written',
251 label => 'Traffic in (-) / out (+)',
252 negative => 'bytes_read',
253 cdef => 'bytes_written,8,*',
259 # graph for memcached connections
262 args => '--base 1000 --lower-limit 0',
263 vlabel => 'Connections per ${graph_period}',
264 category => 'memcached',
265 title => 'Connections',
266 info => 'Number of connections being handled by memcached',
267 order => 'max_conns curr_conns avg_conns',
270 { name => 'curr_conns', label => 'Current Connections', min => '0' },
271 { name => 'max_conns', label => 'Max Connections', min => '0' },
272 { name => 'avg_conns', label => 'Avg Connections', min => '0' },
276 # main graph for memcached commands issued
277 $graphs{commands} = {
279 args => '--base 1000 --lower-limit 0',
280 vlabel => 'Commands per ${graph_period}',
281 category => 'memcached global commands',
283 info => 'Number of commands being handled by memcached',
290 info => 'Cumulative number of retrieval reqs',
297 info => 'Cumulative number of storage reqs',
304 info => 'Cumulative number of flush reqs',
311 info => 'Cumulative number of touch reqs',
318 info => 'Number of keys that were requested and found',
322 name => 'get_misses',
324 label => 'Get Misses',
325 info => 'Number of keys there were requested and not found',
329 name => 'delete_hits',
331 label => 'Delete Hits',
333 'Number of delete requests that resulted in a deletion of a key',
337 name => 'delete_misses',
339 label => 'Delete Misses',
340 info => 'Number of delete requests for missing key',
346 label => 'Increment Hits',
347 info => 'Number of successful increment requests',
351 name => 'incr_misses',
353 label => 'Increment Misses',
354 info => 'Number of unsuccessful increment requests',
360 label => 'Decrement Hits',
361 info => 'Number of successful decrement requests',
365 name => 'decr_misses',
367 label => 'Decrement Misses',
368 info => 'Number of unsuccessful decrement requests',
372 name => 'cas_misses',
374 label => 'CAS Misses',
375 info => 'Number of Compare and Swap requests against missing keys',
382 info => 'Number of successful Compare and Swap requests',
386 name => 'cas_badval',
388 label => 'CAS Badval',
389 info => 'Number of unsuccessful Compare and Swap requests',
393 name => 'touch_hits',
395 label => 'Touch Hits',
396 info => 'Number of successfully touched keys',
400 name => 'touch_misses',
402 label => 'Touch Misses',
403 info => 'Number of unsuccessful touch keys',
409 # main graph for memcached eviction rates
410 $graphs{evictions} = {
412 args => '--base 1000 --lower-limit 0',
413 vlabel => 'Evictions per ${graph_period}',
414 category => 'memcached global evictions',
415 title => 'Evictions',
416 info => 'Number of evictions per second',
422 label => 'Evictions',
423 info => 'Cumulative Evictions Across All Slabs',
427 name => 'evicted_nonzero',
429 label => 'Evictions prior to Expire',
430 info => 'Cumulative Evictions forced to expire prior to expiration',
436 label => 'Reclaimed Items',
437 info => 'Cumulative Reclaimed Item Entries Across All Slabs',
443 # main graph for memcached eviction rates
444 $graphs{unfetched} = {
446 args => '--base 1000 --lower-limit 0',
447 vlabel => 'Unfetched Items per ${graph_period}',
448 category => 'memcached global unfetched',
449 title => 'Unfetched Items',
451 'Number of items that were never touched get/incr/append/etc before X occured',
455 name => 'expired_unfetched',
457 label => 'Expired Unfetched',
460 'Number of items that expired and never had get/incr/append/etc performed'
463 name => 'evicted_unfetched',
465 label => 'Evictioned Unfetched',
468 'Number of items that evicted and never had get/incr/append/etc performed'
473 # subgraph for breaking memory info down by slab ( subgraph of memory )
474 $graphs{slabchnks} = {
476 args => '--base 1000 --lower-limit 0',
477 vlabel => 'Available Chunks for this Slab',
478 category => 'memcached slab chunk usage',
479 title => 'Chunk Usage for Slab: ',
480 info => 'This graph shows you the chunk usage for this memory slab.',
484 name => 'total_chunks',
485 label => 'Total Chunks Available',
488 { name => 'used_chunks', label => 'Total Chunks in Use', min => '0' },
490 name => 'free_chunks',
491 label => 'Total Chunks Not in Use (Free)',
497 # subgraph for breaking commands down by slab ( subgraph of commands )
498 $graphs{slabhits} = {
500 args => '--base 1000 --lower-limit 0',
501 vlabel => 'Hits per Slab per ${graph_period}',
502 category => 'memcached slab commands',
503 title => 'Hits for Slab: ',
505 'This graph shows you the successful hit rate for this memory slab.',
510 label => 'Get Requests',
516 label => 'Set Requests',
521 name => 'delete_hits',
522 label => 'Delete Requests',
528 label => 'Increment Requests',
534 label => 'Decrement Requests',
540 label => 'Sucessful CAS Requests',
545 name => 'cas_badval',
546 label => 'UnSucessful CAS Requests',
551 name => 'touch_hits',
552 label => 'Touch Requests',
559 # subgraph for breaking evictions down by slab ( subgraph of evictions )
560 $graphs{slabevics} = {
562 args => '--base 1000 --lower-limit 0',
563 vlabel => 'Evictions per Slab per ${graph_period}',
564 category => 'memcached slab evictions',
565 title => 'Evictions for Slab: ',
566 info => 'This graph shows you the eviction rate for this memory slab.',
571 label => 'Total Evictions',
574 info => 'Items evicted from memory slab'
577 name => 'evicted_nonzero',
579 label => 'Evictions from LRU Prior to Expire',
580 info => 'Items evicted from memory slab before ttl expiration',
586 label => 'Reclaimed Expired Items',
588 'Number of times an item was stored in expired memory slab space',
594 # subgraph for showing the time between an item was last evicted and requested ( subgraph of evictions )
595 $graphs{slabevictime} = {
597 args => '--base 1000 --lower-limit 0',
598 vlabel => ' since Request for LEI',
599 category => 'memcached slab eviction time',
600 title => 'Eviction Request Time for Slab: ',
602 'This graph shows you the time since we requested the last evicted item',
606 name => 'evicted_time',
607 label => 'Eviction Time (LEI)',
608 info => 'Time Since Request for Last Evicted Item',
614 # subgraph for breaking items down by slab ( subgraph of items )
615 $graphs{slabitems} = {
617 args => '--base 1000 --lower-limit 0',
618 vlabel => 'Items per Slab',
619 category => 'memcached slab item count',
620 title => 'Items in Slab: ',
622 'This graph shows you the number of items and reclaimed items per slab.',
629 info => 'This is the amount of items stored in this slab',
635 # subgraph for showing the age of the eldest item stored in a slab ( subgraph of items )
636 $graphs{slabitemtime} = {
638 args => '--base 1000 --lower-limit 0',
639 vlabel => ' since item was stored',
640 category => 'memcached slab item age',
641 title => 'Age of Eldest Item in Slab: ',
642 info => 'This graph shows you the time of the eldest item in this slab',
645 [ { name => 'age', label => 'Eldest Item\'s Age', min => '0' }, ],
648 # main graph for memcached eviction rates
649 $graphs{slabunfetched} = {
651 args => '--base 1000 --lower-limit 0',
652 vlabel => 'Unfetched Items per ${graph_period}',
653 category => 'memcached slab unfetched',
654 title => 'Unfetched Items in Slab: ',
656 'Number of items that were never touched get/incr/append/etc before X occured',
660 name => 'expired_unfetched',
662 label => 'Expired Unfetched',
665 'Number of items that expired and never had get/incr/append/etc performed'
668 name => 'evicted_unfetched',
670 label => 'Evictioned Unfetched',
673 'Number of items that evicted and never had get/incr/append/etc performed'
680 These checks look for config / autoconf / suggest params
684 This block of code looks at the argument that is possibly supplied,
685 should it be config, it then checks to make sure the plugin
686 specified exists, assuming it does, it will run the do_config
687 subroutine for the plugin specified, otherwise it dies complaining
688 about an unknown plugin.
692 if ( defined $ARGV[0] && $ARGV[0] eq 'config' ) {
694 # Lets get our plugin from the symlink being called up, we'll also verify its a valid
695 # plugin that we have graph information for
696 $0 =~ /(?:([^\/]+)_)?memcached_multi_(.+)$/;
697 my $prefix = $1 ? $1 : '';
699 die 'Unknown Plugin Specified: ' . ( $plugin ? $plugin : '' )
700 unless $graphs{$plugin};
702 # We need to fetch the stats before we do any config, cause its needed for multigraph
703 # subgraphs which use slab information for title / info per slab
705 $globalmap = buildglobalmap();
707 # Now lets go ahead and print out our config.
708 do_config( $prefix, $plugin );
712 =head2 Autoconf Check
714 This block of code looks at the argument that is possibly supplied,
715 should it be autoconf, we will attempt to connect to the memcached
716 service specified on the host:port, upon successful connection it
717 prints yes, otherwise it prints no.
721 if ( defined $ARGV[0] && $ARGV[0] eq 'autoconf' ) {
723 # Lets attempt to connect to memcached
726 # Lets verify that we did connect to memcached
732 print "no (unable to connect to $connection)\n";
739 This block of code looks at the argument that is possibly supplied,
740 should it be suggest, we are going to print the possible plugins
741 which can be specified. Note we only specify the root graphs for the
742 multigraphs, since the rest of the subgraphs will appear "behind" the
743 root graphs. It also attempts to connect to the memcached service to
744 verify it is infact running.
748 if ( defined $ARGV[0] && $ARGV[0] eq 'suggest' ) {
750 # Lets attempt to connect to memcached
753 # Lets check that we did connect to memcached
757 ( 'bytes', 'conns', 'commands', 'evictions', 'items', 'memory' );
758 if ( $stats{version} !~ /^1\.4\.[0-7]$/ ) {
759 push( @rootplugins, 'unfetched' );
761 foreach my $plugin (@rootplugins) {
767 print "no (unable to connect to $connection)\n";
772 =head1 Output Subroutines
774 Output Subroutine calls to output data values
778 This subroutine is the main call for printing data for the plugin.
779 No parameters are taken as this is the default call if no arguments
780 are supplied from the command line.
784 # Well, no arguments were supplied that we know about, so lets print some data
785 $0 =~ /(?:([^\/]+)_)?memcached_multi_(.+)$/;
786 my $prefix = $1 ? $1 : '';
788 die 'Unknown Plugin Specified: ' . ( $plugin ? $plugin : '' )
789 unless $graphs{$plugin};
791 $globalmap = buildglobalmap();
792 fetch_output( $prefix, $plugin );
795 my ( $prefix, $plugin ) = (@_);
797 # Now lets go ahead and print out our output.
799 if ( $plugin eq 'memory' ) {
800 @subgraphs = ('slabchnks');
801 foreach my $slabid ( sort { $a <=> $b } keys %chnks ) {
802 print_submulti_output( $prefix, $slabid, $plugin, @subgraphs );
804 print_subrootmulti_output( $prefix, $plugin );
805 print_rootmulti_output( $prefix, $plugin );
807 elsif ( $plugin eq 'commands' ) {
808 @subgraphs = ('slabhits');
809 foreach my $slabid ( sort { $a <=> $b } keys %chnks ) {
810 print_submulti_output( $prefix, $slabid, $plugin, @subgraphs );
812 print_subrootmulti_output( $prefix, $plugin );
813 print_rootmulti_output( $prefix, $plugin );
815 elsif ( $plugin eq 'evictions' ) {
816 @subgraphs = ('slabevics');
817 if ( $leitime == 1 ) { push( @subgraphs, 'slabevictime' ); }
818 foreach my $slabid ( sort { $a <=> $b } keys %items ) {
819 print_submulti_output( $prefix, $slabid, $plugin, @subgraphs );
821 print_subrootmulti_output( $prefix, $plugin );
822 print_rootmulti_output( $prefix, $plugin );
824 elsif ( $plugin eq 'items' ) {
825 @subgraphs = ( 'slabitems', 'slabitemtime' );
826 foreach my $slabid ( sort { $a <=> $b } keys %items ) {
827 print_submulti_output( $prefix, $slabid, $plugin, @subgraphs );
829 print_subrootmulti_output( $prefix, $plugin );
830 print_rootmulti_output( $prefix, $plugin );
832 elsif ( $plugin eq 'unfetched' ) {
833 @subgraphs = ('slabunfetched');
834 foreach my $slabid ( sort { $a <=> $b } keys %items ) {
835 print_submulti_output( $prefix, $slabid, $plugin, @subgraphs );
837 print_subrootmulti_output( $prefix, $plugin );
838 print_rootmulti_output( $prefix, $plugin );
841 print_root_output($plugin);
847 =head2 print_root_output
849 This subroutine prints out the return values for our non-multigraph root graphs.
850 It takes one parameter $plugin and returns when completed.
852 $plugin; graph we are calling up to print data values for
854 Example: print_root_output($plugin);
858 sub print_root_output {
860 # Lets get our plugin, set our graph reference and print out info for Munin
862 my $graph = $graphs{$plugin};
864 # The conns plugin has some specific needs, looking for plugin type
865 if ( $plugin ne 'conns' ) {
866 foreach my $dsrc ( @{ $graph->{datasrc} } ) {
867 my %datasrc = %$dsrc;
868 while ( my ( $key, $value ) = each(%datasrc) ) {
869 next if ( $key ne 'name' );
870 my $output = $stats{$value};
871 print "$dsrc->{name}.value $output\n";
877 foreach my $dsrc ( @{ $graph->{datasrc} } ) {
878 my %datasrc = %$dsrc;
879 while ( my ( $key, $value ) = each(%datasrc) ) {
880 if ( $value eq 'max_conns' ) {
881 $output = $stats{maxconns};
883 elsif ( $value eq 'curr_conns' ) {
884 $output = $stats{curr_connections};
886 elsif ( $value eq 'avg_conns' ) {
887 $output = sprintf( "%02d",
888 $stats{total_connections} / $stats{uptime} );
893 print "$dsrc->{name}.value $output\n";
900 =head2 print_rootmulti_output
902 This subroutine prints out the return values for our multigraph root graphs.
903 It takes one parameter $plugin and returns when completed.
905 $plugin; root graph we are calling up to print data values for
907 Example: print_rootmulti_output($plugin);
911 sub print_rootmulti_output {
913 # Lets get our plugin, set our graph reference and print out info for Munin
914 my ( $prefix, $plugin ) = (@_);
915 my $graph = $graphs{$plugin};
917 print "multigraph $prefix\_memcached_multi_$plugin\n";
920 print "multigraph memcached_multi_$plugin\n";
923 # Lets print our data values with their appropriate name
924 foreach my $dsrc ( @{ $graph->{datasrc} } ) {
926 my %datasrc = %$dsrc;
927 while ( my ( $key, $value ) = each(%datasrc) ) {
928 next if ( $key ne 'name' );
930 if ( ( $plugin eq 'evictions' )
931 && ( !exists( $globalmap->{globalevics}->{ $dsrc->{name} } ) )
934 if ( ( $plugin eq 'commands' )
935 && ( !exists( $globalmap->{globalcmds}->{ $dsrc->{name} } ) ) );
936 if ( ( $plugin eq 'evictions' ) && ( $value eq 'evicted_nonzero' ) )
938 foreach my $slabid ( sort { $a <=> $b } keys %items ) {
939 $output += $items{$slabid}->{evicted_nonzero};
943 $output = $stats{$value};
945 print "$dsrc->{name}.value $output\n";
951 =head2 print_subrootmulti_output
953 This subroutine prints out the return values for our multigraph root graphs, only this set of
954 data will display on the subpage made by the multigraph capabilities of munin and the plugin.
955 It takes one parameter $plugin and returns when completed.
957 $plugin; root graph we are calling up to print data values for
959 Example: print_rootmulti_output($plugin);
963 sub print_subrootmulti_output {
965 # Lets get our plugin, set our graph reference and print out info for Munin
966 my ( $prefix, $plugin ) = (@_);
967 my $graph = $graphs{$plugin};
969 if ( $plugin eq 'evictions' ) {
970 print "multigraph $prefix\_memcached_multi_$plugin.global$plugin\n";
973 print "multigraph $prefix\_memcached_multi_$plugin.$plugin\n";
977 if ( $plugin eq 'evictions' ) {
978 print "multigraph memcached_multi_$plugin.global$plugin\n";
981 print "multigraph memcached_multi_$plugin.$plugin\n";
985 # Lets print our data values with their appropriate name
986 foreach my $dsrc ( @{ $graph->{datasrc} } ) {
988 my %datasrc = %$dsrc;
989 while ( my ( $key, $value ) = each(%datasrc) ) {
990 next if ( $key ne 'name' );
992 if ( ( $plugin eq 'evictions' )
993 && ( !exists( $globalmap->{globalevics}->{ $dsrc->{name} } ) )
996 if ( ( $plugin eq 'commands' )
997 && ( !exists( $globalmap->{globalcmds}->{ $dsrc->{name} } ) ) );
998 if ( ( $plugin eq 'evictions' ) && ( $value eq 'evicted_nonzero' ) )
1000 foreach my $slabid ( sort { $a <=> $b } keys %items ) {
1001 $output += $items{$slabid}->{evicted_nonzero};
1005 $output = $stats{$value};
1007 print "$dsrc->{name}.value $output\n";
1013 =head2 print_submulti_output
1015 This subroutine prints out the return values for our multigraph subgraphs. It takes
1016 three parameters $slabid, $plugin, @subgraphs and then rReturns when completed.
1018 $slabid; slab id that we will use to grab info from and print out
1019 $plugin; root graph being called, used for multigraph output and slab id
1020 @subgraphs; graphs we are actually trying to print data values for
1022 Example: print_submulti_output($slabid,$plugin,@subgraphs);
1026 sub print_submulti_output {
1028 # Lets get our slabid, plugin, and subgraphs
1029 my ( $prefix, $slabid, $plugin, @subgraphs ) = (@_);
1030 my $currslab = undef;
1032 # Time to loop over our subgraphs array
1033 foreach my $sgraph (@subgraphs) {
1035 # Lets set our graph reference for quick calling, and print some info for munin
1036 my $graph = $graphs{$sgraph};
1039 "multigraph $prefix\_memcached_multi_$plugin.$sgraph\_$slabid\n";
1042 print "multigraph memcached_multi_$plugin.$sgraph\_$slabid\n";
1045 # Lets figure out what slab info we are trying to call up
1046 if ( ( $plugin eq 'evictions' )
1047 || ( $plugin eq 'items' )
1048 || ( $plugin eq 'unfetched' ) )
1050 $currslab = $items{$slabid};
1052 elsif ( ( $plugin eq 'memory' ) || ( $plugin eq 'commands' ) ) {
1053 $currslab = $chnks{$slabid};
1059 # Lets print our data values with their appropriate name
1060 foreach my $dsrc ( @{ $graph->{datasrc} } ) {
1061 my %datasrc = %$dsrc;
1062 while ( my ( $key, $value ) = each(%datasrc) ) {
1063 next if ( $key ne 'name' );
1065 if ( ( $sgraph eq 'slabevics' )
1066 && ( !exists( $globalmap->{slabevics}->{ $dsrc->{name} } ) )
1069 if ( ( $plugin eq 'commands' )
1070 && ( !exists( $globalmap->{slabcmds}->{ $dsrc->{name} } ) )
1072 my $output = $currslab->{$value};
1073 if ( ( $sgraph eq 'slabevictime' )
1074 || ( $sgraph eq 'slabitemtime' ) )
1076 $output = time_scale( 'data', $output );
1078 print "$dsrc->{name}.value $output\n";
1085 =head1 Config Subroutines
1087 These subroutines handle the config portion of munin calls.
1091 This is the main call issued assuming we call up config and plugin specified exists
1092 The subroutine takes one parameter $plugin, and returns when completed.
1094 $plugin; root graph being called
1096 Example: do_config($prefix, $plugin);
1101 my ( $prefix, $plugin ) = (@_);
1103 if ( $plugin eq 'memory' ) {
1104 @subgraphs = ('slabchnks');
1105 foreach my $slabid ( sort { $a <=> $b } keys %chnks ) {
1106 print_submulti_config( $prefix, $slabid, $plugin, @subgraphs );
1108 print_subrootmulti_config( $prefix, $plugin );
1109 print_rootmulti_config( $prefix, $plugin );
1111 elsif ( $plugin eq 'commands' ) {
1112 @subgraphs = ('slabhits');
1113 foreach my $slabid ( sort { $a <=> $b } keys %chnks ) {
1114 print_submulti_config( $prefix, $slabid, $plugin, @subgraphs );
1116 print_subrootmulti_config( $prefix, $plugin );
1117 print_rootmulti_config( $prefix, $plugin );
1119 elsif ( $plugin eq 'evictions' ) {
1120 @subgraphs = ('slabevics');
1121 if ( $leitime == 1 ) { push( @subgraphs, 'slabevictime' ); }
1122 foreach my $slabid ( sort { $a <=> $b } keys %items ) {
1123 print_submulti_config( $prefix, $slabid, $plugin, @subgraphs );
1125 print_subrootmulti_config( $prefix, $plugin );
1126 print_rootmulti_config( $prefix, $plugin );
1128 elsif ( $plugin eq 'items' ) {
1129 @subgraphs = ( 'slabitems', 'slabitemtime' );
1130 foreach my $slabid ( sort { $a <=> $b } keys %items ) {
1131 print_submulti_config( $prefix, $slabid, $plugin, @subgraphs );
1133 print_subrootmulti_config( $prefix, $plugin );
1134 print_rootmulti_config( $prefix, $plugin );
1136 elsif ( $plugin eq 'unfetched' ) {
1137 @subgraphs = ('slabunfetched');
1138 foreach my $slabid ( sort { $a <=> $b } keys %items ) {
1139 print_submulti_config( $prefix, $slabid, $plugin, @subgraphs );
1141 print_subrootmulti_config( $prefix, $plugin );
1142 print_rootmulti_config( $prefix, $plugin );
1145 print_root_config( $prefix, $plugin );
1151 =head2 print_root_config
1153 This subroutine prints out the config information for all of the non-multigraph root graphs.
1154 It takes one parameter, $plugin, returns when completed.
1156 $prefix; possible prefix used to allow multiple plugins per machine
1157 $plugin; root graph used for multigraph call
1159 Example: print_root_config($prefix,$plugin);
1163 sub print_root_config {
1165 # Lets get our plugin, set our graph reference and our graph config info
1166 my ( $prefix, $plugin ) = (@_);
1167 my $graph = $graphs{$plugin};
1168 my %graphconf = %{ $graph->{config} };
1170 # Lets tell munin about the graph we are referencing and print the main config
1171 while ( my ( $key, $value ) = each(%graphconf) ) {
1172 if ( $key eq 'title' ) {
1174 print "graph_$key " . ucfirst($prefix) . " $value\n";
1177 print "graph_$key $value\n";
1181 print "graph_$key $value\n";
1185 # Lets tell munin about our data values and how to treat them
1186 foreach my $dsrc ( @{ $graph->{datasrc} } ) {
1187 my %datasrc = %$dsrc;
1188 while ( my ( $key, $value ) = each(%datasrc) ) {
1189 next if ( $key eq 'name' );
1190 print "$dsrc->{name}.$key $value\n";
1196 =head2 print_rootmulti_config
1198 This subroutine prints out the config information for all of the multigraph root graphs.
1199 It takes one parameter, $plugin, returns when completed.
1201 $prefix; possible prefix used to allow multiple plugins per machine
1202 $plugin; root graph used for multigraph call
1204 Example: print_rootmulti_config($prefix,$plugin);
1208 sub print_rootmulti_config {
1210 # Lets get out plugin, set our graph reference and our graph config info
1211 my ( $prefix, $plugin ) = (@_);
1212 my $graph = $graphs{$plugin};
1213 my %graphconf = %{ $graph->{config} };
1215 # Lets tell munin about the graph we are referencing and print the main config
1217 print "multigraph $prefix\_memcached_multi_$plugin\n";
1220 print "multigraph memcached_multi_$plugin\n";
1222 while ( my ( $key, $value ) = each(%graphconf) ) {
1223 if ( $key eq 'category' ) {
1224 print "graph_$key memcached\n";
1226 elsif ( $key eq 'title' ) {
1228 print "graph_$key " . ucfirst($prefix) . " $value\n";
1231 print "graph_$key $value\n";
1235 print "graph_$key $value\n";
1239 # Lets tell munin about our data values and how to treat them
1240 foreach my $dsrc ( @{ $graph->{datasrc} } ) {
1241 my %datasrc = %$dsrc;
1242 while ( my ( $key, $value ) = each(%datasrc) ) {
1243 next if ( $key eq 'name' );
1245 if ( ( $plugin eq 'evictions' )
1246 && ( !exists( $globalmap->{globalevics}->{ $dsrc->{name} } ) )
1249 if ( ( $plugin eq 'commands' )
1250 && ( !exists( $globalmap->{globalcmds}->{ $dsrc->{name} } ) ) );
1251 print "$dsrc->{name}.$key $value\n";
1257 =head2 print_subrootmulti_config
1259 This subroutine prints out the config information for all of the multigraph root graph, only this
1260 graph of the data will display on the subpage made by the multigraph capabilities of munin and
1261 the plugin. It takes one parameter, $plugin, returns when completed.
1263 $prefix; possible prefix used to allow multiple plugins per machine
1264 $plugin; root graph used for multigraph call
1266 Example: print_rootmulti_config($prefix,$plugin);
1270 sub print_subrootmulti_config {
1272 # Lets get out plugin, set our graph reference and our graph config info
1273 my ( $prefix, $plugin ) = (@_);
1274 my $graph = $graphs{$plugin};
1275 my %graphconf = %{ $graph->{config} };
1277 if ( $plugin eq 'evictions' ) {
1278 print "multigraph $prefix\_memcached_multi_$plugin.global$plugin\n";
1281 print "multigraph $prefix\_memcached_multi_$plugin.$plugin\n";
1285 if ( $plugin eq 'evictions' ) {
1286 print "multigraph memcached_multi_$plugin.global$plugin\n";
1289 print "multigraph memcached_multi_$plugin.$plugin\n";
1293 while ( my ( $key, $value ) = each(%graphconf) ) {
1294 if ( $key eq 'title' ) {
1296 print "graph_$key " . ucfirst($prefix) . " $value\n";
1299 print "graph_$key $value\n";
1303 print "graph_$key $value\n";
1307 # Lets tell munin about our data values and how to treat them
1308 foreach my $dsrc ( @{ $graph->{datasrc} } ) {
1309 my %datasrc = %$dsrc;
1310 while ( my ( $key, $value ) = each(%datasrc) ) {
1311 next if ( $key eq 'name' );
1313 if ( ( $plugin eq 'evictions' )
1314 && ( !exists( $globalmap->{globalevics}->{ $dsrc->{name} } ) )
1317 if ( ( $plugin eq 'commands' )
1318 && ( !exists( $globalmap->{globalcmds}->{ $dsrc->{name} } ) ) );
1319 print "$dsrc->{name}.$key $value\n";
1325 =head2 print_submulti_config
1327 This subroutine prints out the config information for all of the multigraph subgraphs.
1328 It takes three parameters, $slabid, $plugin and @subgraphs, returns when completed.
1330 $prefix; possible prefix used to allow multiple plugins per machine
1331 $slabid; slab id that we will use to grab info from and print out
1332 $plugin; root graph being called, used for multigraph output and slab id
1333 @subgraphs; graphs we are actually trying to print data values for
1335 Example: print_submulti_config($prefix,$slabid,$plugin,@subgraphs);
1339 sub print_submulti_config {
1341 # Lets get our slabid, plugin, and subgraphs
1342 my ( $prefix, $slabid, $plugin, @subgraphs ) = (@_);
1343 my ( $slabitems, $slabchnks ) = undef;
1345 # Time to loop over our subgraphs array
1346 foreach my $sgraph (@subgraphs) {
1348 # Lets set our graph reference, and main graph config for easy handling
1349 my $graph = $graphs{$sgraph};
1350 my %graphconf = %{ $graph->{config} };
1352 # Lets tell munin which graph we are graphing, and what our main graph config info is
1355 "multigraph $prefix\_memcached_multi_$plugin.$sgraph\_$slabid\n";
1358 print "multigraph memcached_multi_$plugin.$sgraph\_$slabid\n";
1360 while ( my ( $key, $value ) = each(%graphconf) ) {
1361 if ( $key eq 'title' ) {
1367 . " ($chnks{$slabid}->{chunk_size} Bytes)\n";
1370 print "graph_$key $value"
1372 . " ($chnks{$slabid}->{chunk_size} Bytes)\n";
1376 ( $key eq 'vlabel' )
1377 && ( ( $sgraph eq 'slabevictime' )
1378 || ( $sgraph eq 'slabitemtime' ) )
1381 $value = time_scale( 'config', $value );
1382 print "graph_$key $value\n";
1385 print "graph_$key $value\n";
1389 # Lets tell munin about our data values and how to treat them
1390 foreach my $dsrc ( @{ $graph->{datasrc} } ) {
1391 my %datasrc = %$dsrc;
1392 while ( my ( $key, $value ) = each(%datasrc) ) {
1393 next if ( $key eq 'name' );
1395 if ( ( $sgraph eq 'slabevics' )
1396 && ( !exists( $globalmap->{slabevics}->{ $dsrc->{name} } ) )
1399 if ( ( $plugin eq 'commands' )
1400 && ( !exists( $globalmap->{slabcmds}->{ $dsrc->{name} } ) )
1402 print "$dsrc->{name}.$key $value\n";
1409 =head1 Misc Subroutines
1411 These subroutines are misc ones, and are referenced inside of the code. They
1412 should never be called up by Munin.
1416 This subroutine returns a socket connection
1423 # check if we want to use sockets instead of tcp
1424 my ($sock) = ( $host =~ /unix:\/\/(.+)*$/ );
1427 $connection = "unix:\/\/$sock";
1428 $s = IO::Socket::UNIX->new( Peer => $sock );
1431 $connection = "$host:$port";
1432 $s = IO::Socket::INET->new(
1444 This subroutine fetches the information from memcached and stores it into our
1445 hashes for later referencing throughout the graph. Returns when completed
1451 # Lets try and connect to memcached
1454 # Die if we can't establish a connection to memcached
1455 die "Error: Unable to Connect to $connection\n" unless $s;
1457 # Lets print the stats command and store the info from the output
1458 print $s "stats\r\n";
1459 while ( my $line = <$s> ) {
1460 if ( $line =~ /STAT\s(.+?)\s((\w|\d|\S)+)/ ) {
1461 my ( $skey, $svalue ) = ( $1, $2 );
1462 $stats{$skey} = $svalue;
1464 last if $line =~ /^END/;
1467 # Lets print the stats settings command and store the info from the output
1468 print $s "stats settings\r\n";
1469 while ( my $line = <$s> ) {
1470 if ( $line =~ /STAT\s(.+?)\s((\w|\d|\S)+)/ ) {
1471 my ( $skey, $svalue ) = ( $1, $2 );
1472 if ( $skey eq 'evictions' ) {
1473 $skey = 'evictions_active';
1475 $stats{$skey} = $svalue;
1477 last if $line =~ /^END/;
1480 # Lets print the stats slabs command and store the info from the output
1481 print $s "stats slabs\r\n";
1482 while ( my $line = <$s> ) {
1483 if ( $line =~ /STAT\s(\d+):(.+)\s(\d+)/ ) {
1484 my ( $slabid, $slabkey, $slabvalue ) = ( $1, $2, $3 );
1485 $chnks{$slabid}->{$slabkey} = $slabvalue;
1487 last if $line =~ /^END/;
1490 # Lets print the stats items command and store the info from the output
1491 print $s "stats items\r\n";
1492 while ( my $line = <$s> ) {
1493 if ( $line =~ /STAT\sitems:(\d+):(.+?)\s(\d+)/ ) {
1494 my ( $itemid, $itemkey, $itemvalue ) = ( $1, $2, $3 );
1495 $items{$itemid}->{$itemkey} = $itemvalue;
1497 last if $line =~ /^END/;
1503 This subroutine is here for me to adjust the timescale of the time graphs
1504 for last evicted item and age of eldest item in cache.
1506 Please note, after long usage I have noticed these counters may not
1507 be accurate, I believe the developers are aware and have submitted
1514 # Lets get our config option and value to adjust
1515 my ( $configopt, $origvalue ) = (@_);
1518 # If config is defined, it returns the config info for time scale
1519 # If data is defined, it returns the original value after its been adjusted
1520 if ( $configopt eq 'config' ) {
1521 if ( $timescale == 1 ) {
1522 $value = "Seconds" . $origvalue;
1524 elsif ( $timescale == 2 ) {
1525 $value = "Minutes" . $origvalue;
1527 elsif (( $timescale == 3 )
1528 || ( $timescale > 4 )
1529 || ( !defined($timescale) ) )
1531 $value = "Hours" . $origvalue;
1533 elsif ( $timescale == 4 ) {
1534 $value = "Days" . $origvalue;
1537 elsif ( $configopt eq 'data' ) {
1538 if ( $timescale == 1 ) {
1539 $value = sprintf( "%02.2f", $origvalue / 1 );
1541 elsif ( $timescale == 2 ) {
1542 $value = sprintf( "%02.2f", $origvalue / 60 );
1544 elsif (( $timescale == 3 )
1545 || ( $timescale > 4 )
1546 || ( !defined($timescale) ) )
1548 $value = sprintf( "%02.2f", $origvalue / 3600 );
1550 elsif ( $timescale == 4 ) {
1551 $value = sprintf( "%02.2f", $origvalue / 86400 );
1555 die "Unknown time_scale option given: either [config/data]\n";
1560 =head2 buildglobalmap
1562 This subroutine looks at the specified commands inputted, and generates
1563 a hashref containing two arrays, one for global command keys and one for
1568 sub buildglobalmap {
1570 my @cmds = split( ' ', $commands );
1571 foreach my $cmd (@cmds) {
1572 if ( $cmd eq "get" ) {
1573 $results->{globalcmds}->{cmd_get} = 1;
1574 $results->{globalcmds}->{get_hits} = 1;
1575 $results->{globalcmds}->{get_misses} = 1;
1576 $results->{slabcmds}->{get_hits} = 1;
1578 elsif ( $cmd eq "set" ) {
1579 $results->{globalcmds}->{cmd_set} = 1;
1580 $results->{slabcmds}->{cmd_set} = 1;
1582 elsif ( $cmd eq "delete" ) {
1583 $results->{globalcmds}->{delete_hits} = 1;
1584 $results->{globalcmds}->{delete_misses} = 1;
1585 $results->{slabcmds}->{delete_hits} = 1;
1587 elsif ( $cmd eq "incr" ) {
1588 $results->{globalcmds}->{incr_hits} = 1;
1589 $results->{globalcmds}->{incr_misses} = 1;
1590 $results->{slabcmds}->{incr_hits} = 1;
1592 elsif ( $cmd eq "decr" ) {
1593 $results->{globalcmds}->{decr_hits} = 1;
1594 $results->{globalcmds}->{decr_misses} = 1;
1595 $results->{slabcmds}->{decr_hits} = 1;
1597 elsif ( $cmd eq "cas" ) {
1598 $results->{globalcmds}->{cas_hits} = 1;
1599 $results->{globalcmds}->{cas_misses} = 1;
1600 $results->{globalcmds}->{cas_badval} = 1;
1601 $results->{slabcmds}->{cas_hits} = 1;
1602 $results->{slabcmds}->{cas_badval} = 1;
1604 elsif ( $cmd eq "touch" ) {
1605 if ( $stats{version} !~ /^1\.4\.[0-7]$/ ) {
1606 $results->{globalcmds}->{cmd_touch} = 1;
1607 $results->{globalcmds}->{touch_hits} = 1;
1608 $results->{globalcmds}->{touch_misses} = 1;
1609 $results->{slabcmds}->{touch_hits} = 1;
1612 elsif ( $cmd eq "flush" ) {
1613 if ( $stats{version} !~ /^1\.4\.[0-7]$/ ) {
1614 $results->{globalcmds}->{cmd_flush} = 1;
1619 # Do absolutely nothing...
1622 $results->{globalevics}->{evictions} = 1;
1623 $results->{globalevics}->{evicted_nonzero} = 1;
1624 $results->{slabevics}->{evicted} = 1;
1625 $results->{slabevics}->{evicted_nonzero} = 1;
1626 if ( $stats{version} !~ /^1\.4\.[0-2]$/ ) {
1627 $results->{globalevics}->{reclaimed} = 1;
1628 $results->{slabevics}->{reclaimed} = 1;