]> git.openstreetmap.org Git - chef.git/blob - cookbooks/munin/files/default/plugins/memcached_
Add munin plugin to monitor rrdcached
[chef.git] / cookbooks / munin / files / default / plugins / memcached_
1 #!/usr/bin/perl
2 #
3
4 =head1 MEMCACHED
5
6 Memcached - A Plugin to monitor Memcached Servers
7
8 =head1 MUNIN CONFIGURATION
9
10 [memcached_*]
11  env.host 127.0.0.1     *default*
12  env.port 11211         *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
19 =head1 NODE CONFIGURATION
20
21 Please make sure you can telnet to your memcache servers and issue the
22  following commands: stats
23
24 Available Graphs contained in this Plugin
25
26 bytes => This graphs the current network traffic in and out
27
28 commands => This graphs the current commands being issued to the memcache machine.
29
30 conns => This graphs the current, max connections as well as avg conns per sec avg conns per sec is derived from total_conns / uptime.
31
32 evictions => This graphs the current evictions on the node.
33
34 items => This graphs the current items and total items in the memcached node.
35
36 memory => This graphs the current and max memory allocation.
37
38 The following example holds true for all graphing options in this plugin.
39  Example: ln -s /usr/share/munin/plugins/memcached_ /etc/munin/plugins/memcached_bytes
40
41 =head1 ACKNOWLEDGEMENTS
42
43 Thanks to dormando for putting up with me ;)
44
45 =head1 AUTHOR
46
47 Matt West < https://github.com/mhwest13/Memcached-Munin-Plugin >
48
49 =head1 LICENSE
50
51 GPLv2
52
53 =head1 MAGIC MARKERS
54
55 #%# family=auto
56 #%# capabilities=autoconf suggest
57
58 =cut
59
60 use strict;
61 use IO::Socket;
62
63 my $host = $ENV{host} || "127.0.0.1";
64 my $port = $ENV{port} || 11211;
65 my $connection;
66
67 my %stats;
68
69 # This hash contains the information contained in two memcache commands
70 # stats and stats settings.
71
72 # So I was trying to figure out how to build this up, and looking at some good examples
73 # I decided to use the format, or for the most part, the format from the mysql_ munin plugin
74 # for Innodb by Kjell-Magne Ãierud, it just spoke ease of flexibility especially with multigraphs
75 # thanks btw ;)
76 #
77 # %graphs   is a container for all of the graph definition information. In here is where you'll
78 #           find the configuration information for munin's graphing procedure.
79 #   Format:
80 #
81 #   $graph{graph_name} => {
82 #       config => {
83 #           # You'll find keys and values stored here for graph manipulation
84 #       },
85 #       datasrc => [
86 #           # Name: name given to data value
87 #           # Attr: Attribute for given value
88 #           { name => 'Name', (Attr) },
89 #           { ... },
90 #       ],
91 #   }
92 my %graphs;
93
94 $graphs{items} = {
95     config => {
96         args     => '--base 1000 --lower-limit 0',
97         vlabel   => 'Items in Memcached',
98         category => 'memcached',
99         title    => 'Items',
100         info     => 'This graph shows the number of items in use by memcached',
101     },
102     datasrc => [
103         { name => 'curr_items', label => 'Current Items', min => '0' },
104         {
105             name  => 'total_items',
106             label => 'New Items',
107             min   => '0',
108             type  => 'DERIVE'
109         },
110     ],
111 };
112
113 $graphs{memory} = {
114     config => {
115         args     => '--base 1024 --lower-limit 0',
116         vlabel   => 'Bytes Used',
117         category => 'memcached',
118         title    => 'Memory Usage',
119         info     => 'This graph shows the memory consumption of memcached',
120     },
121     datasrc => [
122         {
123             name  => 'limit_maxbytes',
124             draw  => 'AREA',
125             label => 'Maximum Bytes Allocated',
126             min   => '0'
127         },
128         {
129             name  => 'bytes',
130             draw  => 'AREA',
131             label => 'Current Bytes Used',
132             min   => '0'
133         },
134     ],
135 };
136
137 $graphs{bytes} = {
138     config => {
139         args     => '--base 1000',
140         vlabel   => 'bits in (-) / out (+)',
141         title    => 'Network Traffic',
142         category => 'memcached',
143         info =>
144 'This graph shows the network traffic in (-) / out (+) of the machine',
145         order => 'bytes_read bytes_written',
146     },
147     datasrc => [
148         {
149             name  => 'bytes_read',
150             type  => 'DERIVE',
151             label => 'Network Traffic coming in (-)',
152             graph => 'no',
153             cdef  => 'bytes_read,8,*',
154             min   => '0'
155         },
156         {
157             name     => 'bytes_written',
158             type     => 'DERIVE',
159             label    => 'Traffic in (-) / out (+)',
160             negative => 'bytes_read',
161             cdef     => 'bytes_written,8,*',
162             min      => '0'
163         },
164     ],
165 };
166
167 $graphs{conns} = {
168     config => {
169         args     => '--base 1000 --lower-limit 0',
170         vlabel   => 'Connections per ${graph_period}',
171         category => 'memcached',
172         title    => 'Connections',
173         info =>
174 'This graph shows the number of connections being handled by memcached',
175         order => 'curr_conns avg_conns',
176     },
177     datasrc => [
178         { name => 'curr_conns', label => 'Current Connections', min => '0' },
179         { name => 'avg_conns',  label => 'Avg Connections',     min => '0' },
180     ],
181 };
182
183 $graphs{commands} = {
184     config => {
185         args     => '--base 1000 --lower-limit 0',
186         vlabel   => 'Commands per ${graph_period}',
187         category => 'memcached',
188         title    => 'Commands',
189         info =>
190           'This graph shows the number of commands being handled by memcached',
191     },
192     datasrc => [
193         {
194             name  => 'cmd_get',
195             type  => 'DERIVE',
196             label => 'Gets',
197             info  => 'Cumulative number of retrieval reqs',
198             min   => '0'
199         },
200         {
201             name  => 'cmd_set',
202             type  => 'DERIVE',
203             label => 'Sets',
204             info  => 'Cumulative number of storage reqs',
205             min   => '0'
206         },
207         {
208             name  => 'get_hits',
209             type  => 'DERIVE',
210             label => 'Get Hits',
211             info  => 'Number of keys that were requested and found',
212             min   => '0'
213         },
214         {
215             name  => 'get_misses',
216             type  => 'DERIVE',
217             label => 'Get Misses',
218             info  => 'Number of keys there were requested and not found',
219             min   => '0'
220         },
221     ],
222 };
223
224 $graphs{evictions} = {
225     config => {
226         args     => '--base 1000 --lower-limit 0',
227         vlabel   => 'Evictions per ${graph_period}',
228         category => 'memcached',
229         title    => 'Evictions',
230         info     => 'This graph shows the number of evictions per second',
231     },
232     datasrc => [
233         {
234             name  => 'evictions',
235             label => 'Evictions',
236             info  => 'Cumulative Evictions Across All Slabs',
237             type  => 'DERIVE',
238             min   => '0'
239         },
240     ],
241 };
242
243 ##
244 #### Config Check ####
245 ##
246
247 if ( defined $ARGV[0] && $ARGV[0] eq 'config' ) {
248
249     $0 =~ /(?:([^\/]+)_)?memcached_(.+)$/;
250     my $prefix = $1 ? $1 : '';
251     my $plugin = $2;
252
253     die 'Unknown Plugin Specified: ' . ( $plugin ? $plugin : '' )
254       unless $graphs{$plugin};
255
256 # We need to fetch the stats before we do any config, cause its needed for multigraph
257     fetch_stats();
258
259     # Now lets go ahead and print out our config.
260     do_config( $prefix, $plugin );
261     exit 0;
262 }
263
264 ##
265 #### Autoconf Check ####
266 ##
267
268 if ( defined $ARGV[0] && $ARGV[0] eq 'autoconf' ) {
269
270     # Lets attempt to connect to memcached
271     my $s = get_conn();
272
273     # Lets check that we did connect to memcached
274     if ( defined($s) ) {
275         print "yes\n";
276         exit 0;
277     }
278     else {
279         print "no (unable to connect to $connection)\n";
280         exit 0;
281     }
282 }
283
284 ##
285 #### Suggest Check ####
286 ##
287
288 if ( defined $ARGV[0] && $ARGV[0] eq 'suggest' ) {
289
290     # Lets attempt to connect to memcached
291     my $s = get_conn();
292
293     # Lets check that we did connect to memcached
294     if ( defined($s) ) {
295         my @rootplugins =
296           ( 'bytes', 'conns', 'commands', 'evictions', 'items', 'memory' );
297         foreach my $plugin (@rootplugins) {
298             print "$plugin\n";
299         }
300         exit 0;
301     }
302     else {
303         print "no (unable to connect to $connection)\n";
304         exit 0;
305     }
306 }
307
308 ##
309 #### Well We aren't running (auto)config/suggest so lets print some stats ####
310 ##
311
312 fetch_output();
313
314 ##
315 #### Subroutines for printing info gathered from memcached ####
316 ##
317
318 ##
319 #### This subroutine performs the bulk processing for printing statistics.
320 ##
321
322 sub fetch_output {
323
324     $0 =~ /(?:([^\/]+)_)?memcached_(.+)$/;
325     my $prefix = $1 ? $1 : '';
326     my $plugin = $2;
327
328     die 'Unknown Plugin Specified: ' . ( $plugin ? $plugin : '' )
329       unless $graphs{$plugin};
330
331     # Well we need to actually fetch the stats before we do anything to them.
332     fetch_stats();
333
334     # Now lets go ahead and print out our output.
335     print_root_output($plugin);
336
337     return;
338 }
339
340 ##
341 #### This subroutine is for the root non-multigraph graphs which render on the main node page ####
342 ##
343
344 sub print_root_output {
345     my ($plugin) = (@_);
346
347     my $graph = $graphs{$plugin};
348
349     #print "graph memcached_$plugin\n";
350
351     if ( $plugin ne 'conns' ) {
352         foreach my $dsrc ( @{ $graph->{datasrc} } ) {
353             my %datasrc = %$dsrc;
354             while ( my ( $key, $value ) = each(%datasrc) ) {
355                 next if ( $key ne 'name' );
356                 my $output = $stats{$value};
357                 print "$dsrc->{name}.value $output\n";
358             }
359         }
360     }
361     else {
362         my $output;
363         foreach my $dsrc ( @{ $graph->{datasrc} } ) {
364             my %datasrc = %$dsrc;
365             while ( my ( $key, $value ) = each(%datasrc) ) {
366                 if ( $value eq 'curr_conns' ) {
367                     $output = $stats{curr_connections};
368                 }
369                 elsif ( $value eq 'avg_conns' ) {
370                     $output = sprintf( "%02d",
371                         $stats{total_connections} / $stats{uptime} );
372                 }
373                 else {
374                     next;
375                 }
376                 print "$dsrc->{name}.value $output\n";
377             }
378         }
379     }
380
381     return;
382 }
383
384 ##
385 #### Subroutines for printing out config information for graphs ####
386 ##
387
388 ##
389 #### This subroutine does the bulk printing the config info per graph ####
390 ##
391
392 sub do_config {
393     my ( $prefix, $plugin ) = (@_);
394     print_root_config( $prefix, $plugin );
395
396     return;
397 }
398
399 ##
400 #### This subroutine is for the config info for non multigraph graphs which render on the main node page ####
401 ##
402
403 sub print_root_config {
404     my ( $prefix, $plugin ) = (@_);
405
406     die 'Unknown Plugin Specified: ' . ( $plugin ? $plugin : '' )
407       unless $graphs{$plugin};
408
409     my $graph = $graphs{$plugin};
410
411     my %graphconf = %{ $graph->{config} };
412
413     #print "graph memcached_$plugin\n";
414
415     while ( my ( $key, $value ) = each(%graphconf) ) {
416         if ( $key eq 'title' ) {
417             if ($prefix) {
418                 print "graph_$key " . ucfirst($prefix) . " $value\n";
419             }
420             else {
421                 print "graph_$key $value\n";
422             }
423         }
424         else {
425             print "graph_$key $value\n";
426         }
427     }
428
429     foreach my $dsrc ( @{ $graph->{datasrc} } ) {
430         my %datasrc = %$dsrc;
431         while ( my ( $key, $value ) = each(%datasrc) ) {
432             next if ( $key eq 'name' );
433             print "$dsrc->{name}.$key $value\n";
434         }
435     }
436
437     return;
438 }
439
440 ##
441 #### This subroutine returns a socket connection ####
442 ##
443
444 sub get_conn {
445     my $s = undef;
446
447     # check if we want to use sockets instead of tcp
448     my ($sock) = ( $host =~ /unix:\/\/(.+)$/ );
449
450     if ($sock) {
451         $connection = "unix:\/\/$sock";
452         $s = IO::Socket::UNIX->new( Peer => $sock );
453     }
454     else {
455         $connection = "$host:$port";
456         $s          = IO::Socket::INET->new(
457             Proto    => "tcp",
458             PeerAddr => $host,
459             PeerPort => $port,
460             Timeout  => 10,
461         );
462     }
463
464     return $s;
465 }
466
467 ##
468 #### This subroutine actually performs the data fetch for us ####
469 #### These commands do not lock up Memcache at all ####
470 ##
471
472 sub fetch_stats {
473     my $s = get_conn();
474
475     die "Error: Unable to Connect to $connection\n" unless $s;
476
477     print $s "stats\r\n";
478
479     while ( my $line = <$s> ) {
480         if ( $line =~ /STAT\s(.+?)\s(\d+)/ ) {
481             my ( $skey, $svalue ) = ( $1, $2 );
482             $stats{$skey} = $svalue;
483         }
484         last if $line =~ /^END/;
485     }
486 }