Projet

Général

Profil

Révision 384d482f

ID384d482fe2f5ce5479f1ff6430bf206e5ec20210
Parent 91cffec4
Enfant 09b88141

Ajouté par Rowan Wookey il y a environ 5 ans

Added mulitgraph redis plugin

This is a replacement for the redis_ plugin

Changes in the replacement:

  • Supports multiple redis instances
  • Supports AWS elasticache and other environments where the CONFIG
    command is disabled
  • Uses multigraph to separate graphs by instance

Voir les différences:

plugins/redis/redis
1
#!/usr/bin/perl -w
2

  
3
=head CONFIGURATION
4

  
5
    Based on Redis module code v0.08 2009/from http://svn.rot13.org/index.cgi/Redis
6

  
7
    Installation process:
8

  
9
    1. Download the plugin to your plugins directory (e.g. /usr/share/munin/plugins)
10
    2. Symlink it to your configuration directory (e.g. ln -s /usr/share/munin/plugins/redis /etc/munin/plugins/redis)
11
    3. Edit plugin-conf.d/munin-node with the options to connect to your redis instances (see below for an example)
12
    4. Restart munin-node service
13

  
14
    Example config
15
    [redis]
16
    env.host1 127.0.0.1
17
    env.port1 6379
18
    env.password1 password
19
    env.title_prefix1 redis-1
20
    env.host2 /run/redis.sock
21
    env.title_prefix2 redis-2
22

  
23
    Each host should be specified with at least a host or unixsocket variable suffixed with
24
    a number, the first being 1, the second being 2 etc. They must be in sequence.
25
    Other options are:
26
    * port - the redis port to connect to
27
    * password - the password to use with the AUTH command
28
    * title_prefix - a prefix to put before the title of the graph, this is strongly recommended for multiple instances
29

  
30
    Graphs:
31
    This generates multigraphs for:
32
    * Connected clients
33
    * Key Hit vs Miss ratio
34
    * Keys per second, hits/misses/expirations/evictions
35
    * Replication backlog
36
    * Replication lag
37
    * Request per second
38
    * Total number of keys and keys with expires
39
    * Used memory
40

  
41
=head COPYRIGHT
42

  
43
    Copyright (C) 2020 Rowan Wookey <https://www.rwky.net/>
44
    Copyright (C) 2009 Gleb Voronich <http://stanly.net.ua/>
45

  
46
=head LICENSE
47

  
48
    This program is free software; you can redistribute it and/or
49
    modify it under the terms of the GNU General Public License
50
    as published by the Free Software Foundation; version 2 dated June,
51
    1991.
52

  
53
    This program is distributed in the hope that it will be useful,
54
    but WITHOUT ANY WARRANTY; without even the implied warranty of
55
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
56
    GNU General Public License for more details.
57

  
58
    You should have received a copy of the GNU General Public License
59
    along with this program; if not, write to the Free Software
60
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
61

  
62
=head MAGIC MARKERS
63

  
64
    #%# family=auto
65
    #%# capabilities=autoconf
66

  
67
=cut
68

  
69
use strict;
70
use IO::Socket::INET;
71
use IO::Socket::UNIX;
72

  
73
my %INSTANCES;
74
my $HOST;
75
my $PORT;
76
my $PASSWORD;
77

  
78
for (my $i = 1; $ENV{"host$i"}; $i++)
79
{
80
    $HOST = exists $ENV{"host$i"} ? $ENV{"host$i"} : "127.0.0.1";
81
    $PORT = exists $ENV{"port$i"} ? $ENV{"port$i"} : 6379;
82
    $PASSWORD = exists $ENV{"password$i"} ? $ENV{"password$i"} : undef;
83
    my $TITLE_PREFIX = exists $ENV{"title_prefix$i"} ? $ENV{"title_prefix$i"} . ": " : "";
84
    my $SOCK = &get_conn();
85
    $INSTANCES{"instance$i"} = {
86
        HOST => $HOST,
87
        PORT => $PORT,
88
        PASSWORD => $PASSWORD,
89
        TITLE_PREFIX => $TITLE_PREFIX,
90
        SOCK => $SOCK
91
    };
92
}
93

  
94

  
95
my $config = ( defined $ARGV[0] and $ARGV[0] eq "config" );
96
my $autoconf = ( defined $ARGV[0] and $ARGV[0] eq "autoconf" );
97
if ( $autoconf ) {
98
    my $err = '';
99
    for my $INSTANCE (keys %INSTANCES) {
100
        if (! defined( $INSTANCES{$INSTANCE}{'SOCK'} ) ) {
101
            $err .= "no (unable to connect to ".$INSTANCES{$INSTANCE}{'HOST'}."\[:". $INSTANCES{$INSTANCE}{'PORT'}."\])\n";
102
        }
103
    }
104
    if ($err) {
105
        print $err;
106
    } else {
107
        print 'yes';
108
    }
109
    exit 0;
110
}
111

  
112
my $total = 0;
113

  
114
my $multi_graph_output = "multigraph redis\n";
115
my $instance_graph_output = '';
116

  
117
my $connected_clients = 0;
118
my $keyspace_hits = 0;
119
my $keyspace_misses = 0;
120
my $expired_keys = 0;
121
my $evicted_keys = 0;
122
my $total_commands_processed = 0;
123
my $total_connections_received = 0;
124
my $repl_backlog_size = 0;
125
my $used_memory = 0;
126
my $used_memory_rss = 0;
127
my $used_memory_peak = 0;
128
my $total_keys = 0;
129
my $total_expires = 0;
130
foreach my $INSTANCE (keys %INSTANCES) {
131

  
132
    my $sock = $INSTANCES{$INSTANCE}{'SOCK'};
133
    my $TITLE_PREFIX = $INSTANCES{$INSTANCE}{'TITLE_PREFIX'};
134
    my $hash = get_info($sock);
135

  
136
    my $dbs;
137
    foreach my $key (keys %{$hash}) {
138
        if ( $key =~ /^db\d+$/ && $hash->{$key} =~ /keys=(\d+),expires=(\d+)/ ) {
139
            $total_keys += $1;
140
            $total_expires += $2;
141
            $dbs->{$key} = [ $1, $2 ];
142
        }
143
    }
144

  
145
    if ( $config ) {
146
        my $ret = get_config("maxclients", $sock);
147
        # if the CONFIG command is disabled we don't show the max clients
148
        my $maxclients = defined $ret ? $ret->{"maxclients"} : 0;
149
        $instance_graph_output .=  "multigraph redis_connected_clients.$INSTANCE\n";
150
        $instance_graph_output .=  "graph_title ${TITLE_PREFIX}Connected clients\n";
151
        $instance_graph_output .=  "graph_vlabel Connected clients\n";
152
        $instance_graph_output .=  "graph_category db\n";
153
        $instance_graph_output .=  "graph_args -l 0\n";
154
        if ($maxclients) {
155
            $instance_graph_output .=  "connected_clients.line $maxclients:ff0000:Limit\n";
156
        }
157
        $instance_graph_output .=  "connected_clients.label connected clients\n";
158
        $instance_graph_output .=  "multigraph keys_per_sec.$INSTANCE\n";
159
        $instance_graph_output .=  "graph_title ${TITLE_PREFIX}Keys Per Second\n";
160
        $instance_graph_output .=  "graph_vlabel per \${graph_period}\n";
161
        $instance_graph_output .=  "graph_category db\n";
162
        $instance_graph_output .=  "graph_args -l 0\n";
163
        $instance_graph_output .=  "hits.label hits\n";
164
        $instance_graph_output .=  "hits.type COUNTER\n";
165
        $instance_graph_output .=  "misses.label misses\n";
166
        $instance_graph_output .=  "misses.type COUNTER\n";
167
        $instance_graph_output .=  "expired.label expirations\n";
168
        $instance_graph_output .=  "expired.type COUNTER\n";
169
        $instance_graph_output .=  "evicted_keys.label evictions\n";
170
        $instance_graph_output .=  "evicted_keys.type COUNTER\n";
171
        $instance_graph_output .=  "multigraph redis_key_ratio.$INSTANCE\n";
172
        $instance_graph_output .=  "graph_title ${TITLE_PREFIX}Key Hit vs Miss Ratio\n";
173
        $instance_graph_output .=  "graph_vlabel per \${graph_period}\n";
174
        $instance_graph_output .=  "graph_category db\n";
175
        $instance_graph_output .=  "graph_args -u 100 -l 0 -r --base 1000\n";
176
        $instance_graph_output .=  "hitratio.label hit ratio\n";
177
        $instance_graph_output .=  "hitratio.type GAUGE\n";
178
        $instance_graph_output .=  "hitratio.draw AREA\n";
179
        $instance_graph_output .=  "missratio.label miss ratio\n";
180
        $instance_graph_output .=  "missratio.type GAUGE\n";
181
        $instance_graph_output .=  "missratio.draw STACK\n";
182
        $instance_graph_output .=  "multigraph redis_per_sec.$INSTANCE\n";
183
        $instance_graph_output .=  "graph_title ${TITLE_PREFIX}Requests Per second\n";
184
        $instance_graph_output .=  "graph_vlabel per \${graph_period}\n";
185
        $instance_graph_output .=  "graph_category db\n";
186
        $instance_graph_output .=  "graph_args -l 0\n";
187
        $instance_graph_output .=  "requests.label requests\n";
188
        $instance_graph_output .=  "requests.type COUNTER\n";
189
        $instance_graph_output .=  "connections.label connections\n";
190
        $instance_graph_output .=  "connections.type COUNTER\n";
191
        $instance_graph_output .=  "multigraph redis_repl_backlog_size.$INSTANCE\n";
192
        $instance_graph_output .=  "graph_title ${TITLE_PREFIX}replication backlog\n";
193
        $instance_graph_output .=  "graph_vlabel replication backlog\n";
194
        $instance_graph_output .=  "graph_category db\n";
195
        $instance_graph_output .=  "graph_args -l 0\n";
196
        $instance_graph_output .=  "repl_backlog_size.label bytes behind master\n";
197
        $instance_graph_output .=  "multigraph redis_repl_lag.$INSTANCE\n";
198
        $instance_graph_output .=  "graph_title ${TITLE_PREFIX}replication lag\n";
199
        $instance_graph_output .=  "graph_vlabel replication lag\n";
200
        $instance_graph_output .=  "graph_category db\n";
201
        $instance_graph_output .=  "graph_args -l 0\n";
202
        $instance_graph_output .=  "repl_backlog_size.label amount behind master\n";
203
        # if the CONFIG command is disabled we don't show maxmemory
204
        $ret = get_config("maxmemory", $sock);
205
        my $maxmemory = defined $ret ? $ret->{"maxmemory"} : 0;
206
        $instance_graph_output .=  "multigraph redis_used_memory.$INSTANCE\n";
207
        $instance_graph_output .=  "graph_title ${TITLE_PREFIX}Used memory\n";
208
        $instance_graph_output .=  "graph_vlabel Used memory\n";
209
        $instance_graph_output .=  "graph_category db\n";
210
        $instance_graph_output .=  "graph_args -l 0 --base 1024\n";
211
        if ($maxmemory) {
212
            $instance_graph_output .=  "used_memory.line $maxmemory:ff0000:Limit\n";
213
        }
214
        $instance_graph_output .=  "used_memory.label used memory\n";
215
        $instance_graph_output .=  "used_memory_peak.label used memory in peak\n";
216
        $instance_graph_output .=  "used_memory_rss.label Resident set size memory usage\n";
217
        $instance_graph_output .=  "multigraph redis_used_keys.$INSTANCE\n";
218
        $instance_graph_output .=  "graph_title ${TITLE_PREFIX}Used keys\n";
219
        $instance_graph_output .=  "graph_vlabel Used keys\n";
220
        $instance_graph_output .=  "graph_category db\n";
221
        $instance_graph_output .=  "graph_args -l 0\n";
222

  
223
        foreach my $db (keys %{$dbs}) {
224
            $instance_graph_output .= sprintf "%s_keys.label %s keys\n", $db, $db;
225
            $instance_graph_output .= sprintf "%s_expires.label %s expires\n", $db, $db;
226
        }
227

  
228
        next;
229
    }
230

  
231
    $instance_graph_output .=  "multigraph redis_connected_clients.$INSTANCE\n";
232
    $instance_graph_output .=  "connected_clients.value " . $hash->{'connected_clients'} . "\n";
233
    $connected_clients += $hash->{'connected_clients'}; 
234
    $instance_graph_output .=  "multigraph keys_per_sec.$INSTANCE\n";
235
    $instance_graph_output .=  "hits.value " . $hash->{'keyspace_hits'} . "\n";
236
    $keyspace_hits += $hash->{'keyspace_hits'};
237
    $instance_graph_output .=  "misses.value " . $hash->{'keyspace_misses'} . "\n";
238
    $keyspace_misses += $hash->{'keyspace_misses'};
239
    $instance_graph_output .=  "expired.value " . $hash->{'expired_keys'} . "\n";
240
    $expired_keys += $hash->{'expired_keys'};
241
    $instance_graph_output .=  "evicted_keys.value " . $hash->{'evicted_keys'} . "\n";
242
    $evicted_keys += $hash->{'evicted_keys'};
243
    $instance_graph_output .=  "multigraph redis_key_ratio.$INSTANCE\n";
244
    my $total = $hash->{'keyspace_hits'} + $hash->{'keyspace_misses'};
245
    my $hitratio = 0;
246
    my $missratio = 0;
247
    if ($total > 0) {
248
        $hitratio = $hash->{'keyspace_hits'} / $total * 100;
249
        $missratio = $hash->{'keyspace_misses'} / $total * 100;
250
    }
251
    $instance_graph_output .= sprintf("hitratio.value %.2f\n", $hitratio);
252
    $instance_graph_output .= sprintf("missratio.value %.2f\n", $missratio);
253
    $instance_graph_output .=  "multigraph redis_per_sec.$INSTANCE\n";
254
    $instance_graph_output .=  "requests.value ". $hash->{'total_commands_processed'} ."\n";
255
    $total_commands_processed += $hash->{'total_commands_processed'};
256
    $instance_graph_output .=  "connections.value ". $hash->{'total_connections_received'} ."\n";
257
    $total_connections_received += $hash->{'total_connections_received'};
258
    $instance_graph_output .=  "multigraph redis_repl_backlog_size.$INSTANCE\n";
259
    $instance_graph_output .=  "repl_backlog_size.value " . $hash->{'repl_backlog_size'} . "\n";
260
    $repl_backlog_size += $hash->{'repl_backlog_size'};
261

  
262
    $instance_graph_output .=  "multigraph redis_repl_lag.$INSTANCE\n";
263
    if (exists $hash->{slave0} && $hash->{slave0} =~ /lag=(\d+)/) { 
264
        $repl_backlog_size += $1;
265
        $instance_graph_output .=  "repl_backlog_size.value " . $1 . "\n";
266
    } else {
267
        $instance_graph_output .=  "repl_backlog_size.value 0\n";
268
    }
269

  
270

  
271
    $instance_graph_output .=  "multigraph redis_used_memory.$INSTANCE\n";
272
    $instance_graph_output .=  "used_memory.value ". $hash->{'used_memory'}  ."\n";
273

  
274
    $used_memory += $hash->{'used_memory'};
275
    $instance_graph_output .=  "used_memory_rss.value ". $hash->{'used_memory_rss'}  ."\n";
276
    $used_memory_rss += $hash->{'used_memory_rss'};
277
    $instance_graph_output .=  "used_memory_peak.value ". $hash->{'used_memory_peak'}  ."\n";
278
    $used_memory_peak += $hash->{'used_memory_peak'};
279

  
280
    $instance_graph_output .=  "multigraph redis_used_keys.$INSTANCE\n";
281
    foreach my $db (keys %{$dbs}) {
282
        $instance_graph_output .= sprintf "%s_keys.value %d\n", $db, $dbs->{$db}[0];
283
        $instance_graph_output .= sprintf "%s_expires.value %d\n", $db, $dbs->{$db}[1];
284
    }
285
    close ($sock);
286
}
287

  
288
# multigraph output
289
if ($config) {
290
    $multi_graph_output .=  "multigraph redis_connected_clients\n";
291
    $multi_graph_output .=  "graph_title Connected clients\n";
292
    $multi_graph_output .=  "graph_vlabel Connected clients\n";
293
    $multi_graph_output .=  "graph_category db\n";
294
    $multi_graph_output .=  "graph_args -l 0\n";
295
    $multi_graph_output .=  "connected_clients.label connected clients\n";
296
    $multi_graph_output .=  "multigraph keys_per_sec\n";
297
    $multi_graph_output .=  "graph_title Keys Per Second\n";
298
    $multi_graph_output .=  "graph_vlabel per \${graph_period}\n";
299
    $multi_graph_output .=  "graph_category db\n";
300
    $multi_graph_output .=  "graph_args -l 0\n";
301
    $multi_graph_output .=  "hits.label hits\n";
302
    $multi_graph_output .=  "hits.type COUNTER\n";
303
    $multi_graph_output .=  "misses.label misses\n";
304
    $multi_graph_output .=  "misses.type COUNTER\n";
305
    $multi_graph_output .=  "expired.label expirations\n";
306
    $multi_graph_output .=  "expired.type COUNTER\n";
307
    $multi_graph_output .=  "evicted_keys.label evictions\n";
308
    $multi_graph_output .=  "evicted_keys.type COUNTER\n";
309
    $multi_graph_output .=  "multigraph redis_key_ratio\n";
310
    $multi_graph_output .=  "graph_title Key Hit vs Miss Ratio\n";
311
    $multi_graph_output .=  "graph_vlabel per \${graph_period}\n";
312
    $multi_graph_output .=  "graph_category db\n";
313
    $multi_graph_output .=  "graph_args -u 100 -l 0 -r --base 1000\n";
314
    $multi_graph_output .=  "hitratio.label hit ratio\n";
315
    $multi_graph_output .=  "hitratio.type GAUGE\n";
316
    $multi_graph_output .=  "hitratio.draw AREA\n";
317
    $multi_graph_output .=  "missratio.label miss ratio\n";
318
    $multi_graph_output .=  "missratio.type GAUGE\n";
319
    $multi_graph_output .=  "missratio.draw STACK\n";
320
    $multi_graph_output .=  "multigraph redis_per_sec\n";
321
    $multi_graph_output .=  "graph_title Requests Per second\n";
322
    $multi_graph_output .=  "graph_vlabel per \${graph_period}\n";
323
    $multi_graph_output .=  "graph_category db\n";
324
    $multi_graph_output .=  "graph_args -l 0\n";
325
    $multi_graph_output .=  "requests.label requests\n";
326
    $multi_graph_output .=  "requests.type COUNTER\n";
327
    $multi_graph_output .=  "connections.label connections\n";
328
    $multi_graph_output .=  "connections.type COUNTER\n";
329
    $multi_graph_output .=  "multigraph redis_repl_backlog_size\n";
330
    $multi_graph_output .=  "graph_title replication backlog\n";
331
    $multi_graph_output .=  "graph_vlabel replication backlog\n";
332
    $multi_graph_output .=  "graph_category db\n";
333
    $multi_graph_output .=  "graph_args -l 0\n";
334
    $multi_graph_output .=  "repl_backlog_size.label bytes behind master\n";
335
    $multi_graph_output .=  "multigraph redis_repl_lag\n";
336
    $multi_graph_output .=  "graph_title replication lag\n";
337
    $multi_graph_output .=  "graph_vlabel replication lag\n";
338
    $multi_graph_output .=  "graph_category db\n";
339
    $multi_graph_output .=  "graph_args -l 0\n";
340
    $multi_graph_output .=  "repl_backlog_size.label amount behind master\n";
341
    $multi_graph_output .=  "multigraph redis_used_memory\n";
342
    $multi_graph_output .=  "graph_title Used memory\n";
343
    $multi_graph_output .=  "graph_vlabel Used memory\n";
344
    $multi_graph_output .=  "graph_category db\n";
345
    $multi_graph_output .=  "graph_args -l 0 --base 1024\n";
346
    $multi_graph_output .=  "used_memory.label used memory\n";
347
    $multi_graph_output .=  "used_memory_peak.label used memory in peak\n";
348
    $multi_graph_output .=  "used_memory_rss.label Resident set size memory usage\n";
349
    $multi_graph_output .=  "multigraph redis_used_keys\n";
350
    $multi_graph_output .=  "graph_title Used keys\n";
351
    $multi_graph_output .=  "graph_vlabel Used keys\n";
352
    $multi_graph_output .=  "graph_category db\n";
353
    $multi_graph_output .=  "graph_args -l 0\n";
354
    $multi_graph_output .=  "total_keys.label Total keys\n";
355
    $multi_graph_output .=  "total_expires.label Total expires\n";
356
} else {
357

  
358
    $multi_graph_output .=  "multigraph redis_connected_clients\n";
359
    $multi_graph_output .=  "connected_clients.value " . $connected_clients . "\n";
360
    $multi_graph_output .=  "multigraph keys_per_sec\n";
361
    $multi_graph_output .=  "hits.value " . $keyspace_hits . "\n";
362
    $multi_graph_output .=  "misses.value " . $keyspace_misses . "\n";
363
    $multi_graph_output .=  "expired.value " . $expired_keys . "\n";
364
    $multi_graph_output .=  "evicted_keys.value " . $evicted_keys . "\n";
365
    $multi_graph_output .=  "multigraph redis_key_ratio\n";
366
    my $total = $keyspace_hits + $keyspace_misses;
367
    my $hitratio = 0;
368
    my $missratio = 0;
369
    if ($total > 0) {
370
        $hitratio = $keyspace_hits / $total * 100;
371
        $missratio = $keyspace_misses / $total * 100;
372
    }
373
    $multi_graph_output .= sprintf("hitratio.value %.2f\n", $hitratio);
374
    $multi_graph_output .= sprintf("missratio.value %.2f\n", $missratio);
375
    $multi_graph_output .=  "multigraph redis_per_sec\n";
376
    $multi_graph_output .=  "requests.value ". $total_commands_processed ."\n";
377
    $multi_graph_output .=  "connections.value ". $total_connections_received ."\n";
378
    $multi_graph_output .=  "multigraph redis_repl_backlog_size\n";
379
    $multi_graph_output .=  "repl_backlog_size.value " . $repl_backlog_size . "\n";
380

  
381
    $multi_graph_output .=  "multigraph redis_repl_lag\n";
382
    $multi_graph_output .=  "repl_backlog_size.value " . $repl_backlog_size  . "\n";
383

  
384

  
385
    $multi_graph_output .=  "multigraph redis_used_memory\n";
386
    $multi_graph_output .=  "used_memory.value ". $used_memory  ."\n";
387

  
388
    $multi_graph_output .=  "used_memory_rss.value ". $used_memory_rss  ."\n";
389
    $multi_graph_output .=  "used_memory_peak.value ". $used_memory_peak  ."\n";
390

  
391
    $multi_graph_output .=  "multigraph redis_used_keys\n";
392
    $multi_graph_output .=  "total_keys.value $total_keys\n";
393
    $multi_graph_output .=  "total_expires.value $total_expires\n";
394

  
395
}
396
print $multi_graph_output;
397
print $instance_graph_output;
398

  
399
sub get_conn {
400

  
401
    my $sock;
402

  
403
    if(-S $HOST ){
404

  
405
        $sock = IO::Socket::UNIX->new(
406
            Type => SOCK_STREAM(),
407
            Peer => $HOST,
408
        );
409
    }else{
410

  
411
        $sock = IO::Socket::INET->new(
412
            PeerAddr => $HOST,
413
            PeerPort => $PORT,
414
            Timeout => 10,
415
            Proto => 'tcp'
416
        );
417
    }
418

  
419
	if (! defined($sock)) {
420
         die "can't read socket: $!";
421
	}
422

  
423
    if ( defined( $PASSWORD )  ) {
424
        print $sock "AUTH ", $PASSWORD, "\r\n";
425
        my $result = <$sock> || die "can't read socket: $!";
426
    }
427

  
428
    return $sock;
429
}
430

  
431
sub get_info{
432
    my $sock = $_[0];
433
    print $sock "INFO\r\n";
434
    my $result = <$sock> || die "can't read socket: $!";
435

  
436
    my $rep;
437
    # +2 characters for \r\n at end of the data block
438
    read($sock, $rep, substr($result,1)+2) || die "can't read from socket: $!";
439

  
440
    my $hash;
441
    foreach (split(/\r\n/, substr($rep, 0, -2))) {
442
        my ($key,$val) = split(/:/, $_, 2);
443
        if (defined($key)) {
444
            $hash->{$key} = $val;
445
        }
446
    }
447
    return $hash;
448
}
449

  
450
# This subroutine returns configuration matched to supplied as object
451
sub get_config{
452
    my $sock = $_[1];
453
    print $sock "*3\r\n\$6\r\nCONFIG\r\n\$3\r\nGET\r\n\$".length($_[0])."\r\n".$_[0]."\r\n";
454
    # Response will look like like
455
    # *2\r\n$9\r\nmaxmemory\r\n$10\r\n3221225472\r\n
456

  
457
    my $type = <$sock> || die "can't read socket: $!";
458
    my $conf;
459
    if( substr($type,0,1) ne "*" ) {
460
        return $conf;
461
    }
462

  
463
    my $count=substr($type,1);
464

  
465
    my ( $namesize, $name, $valuesize, $value );
466
    while ( $count > 1 ){
467
        $count=$count-2;
468

  
469
        $namesize=<$sock>;
470
        read($sock, $name, substr($namesize,1)+2) || die "can't read from socket: $!";
471

  
472
        $valuesize=<$sock>;
473
        read($sock, $value, substr($valuesize,1)+2) || die "can't read from socket: $!";
474

  
475
        $conf->{substr($name, 0, -2)}=substr($value, 0, -2);
476
    }
477

  
478
    return $conf;
479
}
480

  
481
# vim: ft=perl ai ts=4 sw=4 et:
plugins/redis/redis_
1
#!/usr/bin/perl -w
2

  
3
#
4
## Copyright (C) 2009 Gleb Voronich <http://stanly.net.ua/>
5
##
6
## This program is free software; you can redistribute it and/or
7
## modify it under the terms of the GNU General Public License
8
## as published by the Free Software Foundation; version 2 dated June,
9
## 1991.
10
##
11
## This program is distributed in the hope that it will be useful,
12
## but WITHOUT ANY WARRANTY; without even the implied warranty of
13
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
## GNU General Public License for more details.
15
##
16
## You should have received a copy of the GNU General Public License
17
## along with this program; if not, write to the Free Software
18
## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19
##
20
##
21
## $Log$
22
##
23
## Based on Redis module code v0.08 2009/from http://svn.rot13.org/index.cgi/Redis
24
##
25
## Installation process:
26
##
27
## 1. Download the plugin to your plugins directory (e.g. /usr/share/munin/plugins)
28
## 2. Create 3 symlinks at the directory that us used by munin for plugins detection (e.g. /etc/munin/plugins): redis_connected_clients, redis_per_sec and and redis_used_memory
29
## 3. Edit plugin-conf.d/munin-node if it is needed (env.host and  env.port variables are accepted; set env.password for password protected Redis server)
30
## 4. Restart munin-node service
31
##
32
## Magic Markers
33
#%# family=auto
34
#%# capabilities=autoconf suggest
35

  
36
use strict;
37
use IO::Socket::INET;
38
use IO::Socket::UNIX;
39
use Switch;
40

  
41
my $HOST = exists $ENV{'host'} ? $ENV{'host'} : "127.0.0.1";
42
my $UNIX_SOCKET = exists $ENV{'unixsocket'} ? $ENV{'unixsocket'} : ''; # path to Redis Unix sock file
43
my $PORT = exists $ENV{'port'} ? $ENV{'port'} : 6379;
44
my $PASSWORD = exists $ENV{'password'} ? $ENV{'password'} : undef;
45
my $TITLE_PREFIX = exists $ENV{'title_prefix'} ? $ENV{'title_prefix'} . ": " : "";
46

  
47
my $sock = &get_conn();
48
my $config = ( defined $ARGV[0] and $ARGV[0] eq "config" );
49
my $autoconf = ( defined $ARGV[0] and $ARGV[0] eq "autoconf" );
50
if ( $autoconf ) {
51
    if ( defined( $sock ) ) {
52
        print "yes\n";
53
        exit 0;
54
    } else {
55
        print "no (unable to connect to $HOST\[:$PORT\])\n";
56
        exit 0;
57
    }
58
}
59
my $suggest = ( defined $ARGV[0] and $ARGV[0] eq "suggest" );
60
if ( $suggest ) {
61
    if ( defined( $sock ) ) {
62
        my @plugins = ('connected_clients', 'key_ratio', 'keys_per_sec', 'per_sec', 'repl_backlog_size', 'repl_lag', 'used_keys', 'used_memory');
63
        foreach my $plugin (@plugins) {
64
            print "$plugin\n";
65
        }
66
        exit 0;
67
    } else {
68
        print "no (unable to connect to $HOST\[:$PORT\])\n";
69
        exit 0;
70
    }
71
}
72

  
73
my $hash=&get_info();
74

  
75
$0 =~ s/(.+)redis_//g;
76

  
77
switch ($0) {
78
    case "connected_clients" {
79
        if ( $config ) {
80
            my $maxclients= get_config("maxclients")->{"maxclients"};
81
            print "graph_title ${TITLE_PREFIX}Connected clients\n";
82
            print "graph_vlabel Connected clients\n";
83
            print "graph_category search\n";
84
            print "graph_args -l 0\n";
85
            print "connected_clients.line $maxclients:ff0000:Limit\n";
86
            print "connected_clients.label connected clients\n";
87
            exit 0;
88
        }
89

  
90
        print "connected_clients.value " . $hash->{'connected_clients'} . "\n";
91
    }
92

  
93

  
94
    case "keys_per_sec" {
95
        if ( $config ) {
96
            print "graph_title ${TITLE_PREFIX}Keys Per Second\n";
97
            print "graph_vlabel per \${graph_period}\n";
98
            print "graph_category search\n";
99
            print "graph_args -l 0\n";
100
            print "hits.label hits\n";
101
            print "hits.type COUNTER\n";
102
            print "misses.label misses\n";
103
            print "misses.type COUNTER\n";
104
            print "expired.label expirations\n";
105
            print "expired.type COUNTER\n";
106
            print "evictions.label evictions\n";
107
            print "evictions.type COUNTER\n";
108
            exit 0;
109
        }
110

  
111
        print "hits.value " . $hash->{'keyspace_hits'} . "\n";
112
        print "misses.value " . $hash->{'keyspace_misses'} . "\n";
113
        print "expired.value " . $hash->{'expired_keys'} . "\n";
114
        print "evictions.value " . $hash->{'evicted_keys'} . "\n";
115
    }
116

  
117
    case "key_ratio" {
118
        if ( $config ) {
119
            print "graph_title ${TITLE_PREFIX}Key Hit vs Miss Ratio\n";
120
            print "graph_vlabel per \${graph_period}\n";
121
            print "graph_category search\n";
122
            print "graph_args -u 100 -l 0 -r --base 1000\n";
123
            print "hitratio.label hit ratio\n";
124
            print "hitratio.type GAUGE\n";
125
            print "hitratio.draw AREA\n";
126
            print "missratio.label miss ratio\n";
127
            print "missratio.type GAUGE\n";
128
            print "missratio.draw STACK\n";
129
            exit 0;
130
        }
131

  
132
        my $total = $hash->{'keyspace_hits'} + $hash->{'keyspace_misses'};
133
        my $hitratio = 0;
134
        my $missratio = 0;
135
        if ($total > 0) {
136
            $hitratio = $hash->{'keyspace_hits'} / $total * 100;
137
            $missratio = $hash->{'keyspace_misses'} / $total * 100;
138
        }
139
        printf("hitratio.value %.2f\n", $hitratio);
140
        printf("missratio.value %.2f\n", $missratio);
141
    }
142

  
143

  
144
    case "per_sec" {
145
        if ( $config ) {
146
            print "graph_title ${TITLE_PREFIX}Requests Per second\n";
147
            print "graph_vlabel per \${graph_period}\n";
148
            print "graph_category search\n";
149
            print "graph_args -l 0\n";
150
            print "requests.label requests\n";
151
            print "requests.type COUNTER\n";
152
            print "connections.label connections\n";
153
            print "connections.type COUNTER\n";
154
            exit 0;
155
        }
156

  
157
        print "requests.value ". $hash->{'total_commands_processed'} ."\n";
158
        print "connections.value ". $hash->{'total_connections_received'} ."\n";
159
    }
160

  
161
    case "repl_backlog_size" {
162
        if ( $config ) {
163
            print "graph_title ${TITLE_PREFIX}replication backlog\n";
164
            print "graph_vlabel replication backlog\n";
165
            print "graph_category search\n";
166
            print "graph_args -l 0\n";
167
            print "repl_backlog_size.label bytes behind master\n";
168
            exit 0;
169
        }
170

  
171
        print "repl_backlog_size.value " . $hash->{'repl_backlog_size'} . "\n";
172
    }
173

  
174
    case "repl_lag" {
175
        if ( $config ) {
176
            print "graph_title ${TITLE_PREFIX}replication lag\n";
177
            print "graph_vlabel replication lag\n";
178
            print "graph_category search\n";
179
            print "graph_args -l 0\n";
180
            print "repl_backlog_size.label amount behind master\n";
181
            exit 0;
182
        }
183
        
184
        if ($hash->{slave0} =~ /lag=(\d+)/) { 
185
            print "repl_backlog_size.value " . $1 . "\n";
186
        }
187
    }
188

  
189

  
190
    case "used_memory" {
191
        if ( $config ) {
192
            my $maxmemory = get_config("maxmemory")->{"maxmemory"};
193
            print "graph_title ${TITLE_PREFIX}Used memory\n";
194
            print "graph_vlabel Used memory\n";
195
            print "graph_category search\n";
196
            print "graph_args -l 0 --base 1024\n";
197
            print "used_memory.line $maxmemory:ff0000:Limit\n";
198
            print "used_memory.label used memory\n";
199
            print "used_memory_peak.label used memory in peak\n";
200
            print "used_memory_rss.label Resident set size memory usage\n";
201
            exit 0;
202
        }
203

  
204
        print "used_memory.value ". $hash->{'used_memory'}  ."\n";
205
        print "used_memory_rss.value ". $hash->{'used_memory_rss'}  ."\n";
206
        print "used_memory_peak.value ". $hash->{'used_memory_peak'}  ."\n";
207
    }
208

  
209
    case "used_keys" {
210
        my $dbs;
211
        foreach my $key (keys %{$hash}) {
212
            if ( $key =~ /^db\d+$/ && $hash->{$key} =~ /keys=(\d+),expires=(\d+)/ ) {
213
                $dbs->{$key} = [ $1, $2 ];
214
            }
215
        }
216

  
217
        if ( $config ) {
218
            print "graph_title ${TITLE_PREFIX}Used keys\n";
219
            print "graph_vlabel Used keys\n";
220
            print "graph_category search\n";
221
            print "graph_args -l 0\n";
222

  
223
            foreach my $db (keys %{$dbs}) {
224
                printf "%s_keys.label %s keys\n", $db, $db;
225
                printf "%s_expires.label %s expires\n", $db, $db;
226
            }
227

  
228
            exit 0;
229
        }
230

  
231
        foreach my $db (keys %{$dbs}) {
232
            printf "%s_keys.value %d\n", $db, $dbs->{$db}[0];
233
            printf "%s_expires.value %d\n", $db, $dbs->{$db}[1];
234
        }
235
    }
236
}
237

  
238
close ($sock);
239

  
240
sub get_conn {
241

  
242
    my $sock;
243

  
244
    if( $UNIX_SOCKET && -S $UNIX_SOCKET ){
245

  
246
	$sock = IO::Socket::UNIX->new(
247
		Type => SOCK_STREAM(),
248
		Peer => $UNIX_SOCKET,
249
	);
250

  
251
    }else{
252

  
253
	$sock = IO::Socket::INET->new(
254
		PeerAddr => $HOST,
255
		PeerPort => $PORT,
256
		Timeout => 10,
257
		Proto => 'tcp'
258
	);
259
    }
260

  
261
    if ( defined( $PASSWORD )  ) {
262
        print $sock "AUTH ", $PASSWORD, "\r\n";
263
        my $result = <$sock> || die "can't read socket: $!";
264
    }
265
    return $sock;
266
}
267

  
268
sub get_info{
269
    print $sock "INFO\r\n";
270
    my $result = <$sock> || die "can't read socket: $!";
271

  
272
    my $rep;
273
    # +2 characters for \r\n at end of the data block
274
    read($sock, $rep, substr($result,1)+2) || die "can't read from socket: $!";
275

  
276
    my $hash;
277
    foreach (split(/\r\n/, substr($rep, 0, -2))) {
278
        my ($key,$val) = split(/:/, $_, 2);
279
        if (defined($key)) {
280
            $hash->{$key} = $val;
281
        }
282
    }
283
    return $hash;
284
}
285

  
286
# This subroutine returns configuration matched to supplied as object
287
sub get_config{
288

  
289
    print $sock "*3\r\n\$6\r\nCONFIG\r\n\$3\r\nGET\r\n\$".length($_[0])."\r\n".$_[0]."\r\n";
290
    # Response will look like like
291
    # *2\r\n$9\r\nmaxmemory\r\n$10\r\n3221225472\r\n
292

  
293
    my $type = <$sock> || die "can't read socket: $!";
294

  
295
    my $conf;
296
    if( substr($type,0,1) ne "*" ) {
297
        return $conf;
298
    }
299

  
300
    my $count=substr($type,1);
301

  
302
    my ( $namesize, $name, $valuesize, $value );
303
    while ( $count > 1 ){
304
        $count=$count-2;
305

  
306
        $namesize=<$sock>;
307
        read($sock, $name, substr($namesize,1)+2) || die "can't read from socket: $!";
308

  
309
        $valuesize=<$sock>;
310
        read($sock, $value, substr($valuesize,1)+2) || die "can't read from socket: $!";
311

  
312
        $conf->{substr($name, 0, -2)}=substr($value, 0, -2);
313
    }
314

  
315
    return $conf;
316
}
317

  
318
# vim: ft=perl ai ts=4 sw=4 et:

Formats disponibles : Unified diff