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