Projet

Général

Profil

Paste
Télécharger au format
Statistiques
| Branche: | Révision:

root / plugins / memcached / memcached_multi_ @ a8f7b903

Historique | Voir | Annoter | Télécharger (31,3 ko)

1
#!/usr/bin/perl
2
#
3
=head1 MEMCACHED
4

    
5
Memcached - A Plugin to monitor Memcached Servers (Multigraph)
6

    
7
=head1 MUNIN CONFIGURATION
8

    
9
[memcached_*]
10
 env.host 127.0.0.1     *default*
11
 env.port 11211         *default*
12
 env.timescale 3        *default*
13

    
14
=head2 MUNIN ENVIRONMENT CONFIGURATION EXPLANATION
15

    
16
 host = host we are going to monitor
17
 port = port we are connecting to, in order to gather stats
18
 timescale = what time frame do we want to format our graphs too
19

    
20
=head1 NODE CONFIGURATION
21

    
22
Please make sure you can telnet to your memcache servers and issue the
23
 following commands: stats, stats settings, stats items and stats slabs.
24

    
25
Available Graphs contained in this Plugin
26

    
27
bytes => This graphs the current network traffic in and out
28

    
29
commands => I<MULTIGRAPH> This graphs the current commands being issued to the memcache machine. B<Multigraph breaks this down to per slab.>
30

    
31
conns => This graphs the current, max connections as well as avg conns per sec avg conns per sec is derived from total_conns / uptime.
32

    
33
evictions => I<MULTIGRAPH> This graphs the current evictions on the node. B<Multigraph breaks this down to per slab.>
34

    
35
items => I<MULTIGRAPH> This graphs the current items and total items in the memcached node. B<Multigraph breaks this down to per slab.>
36

    
37
memory => I<MULTIGRAPH> This graphs the current and max memory allocation B<Multigraph breaks this down to per slab.>
38

    
39
=head1 ADDITIONAL INFORMATION
40

    
41
You will find that some of the graphs have LEI on them. This was done in order to save room
42
on space for text and stands for B<Last Evicted Item>.
43

    
44
The B<Timescale> variable formats certain graphs based on the following guidelines.
45
 1 => Seconds
46
 2 => Minutes
47
 3 => Hours  B<*Default*>
48
 4 => Days
49

    
50
=head1 ACKNOWLEDGEMENTS
51

    
52
Thanks to dormando for putting up with me ;)
53

    
54
=head1 AUTHOR
55

    
56
Matt West < https://github.com/mhwest13/Memcached-Munin-Plugin >
57

    
58
=head1 LICENSE
59

    
60
GPLv2
61

    
62
=head1 MAGIC MARKERS
63

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

    
67
=cut
68

    
69
use strict;
70
use warnings;
71
use IO::Socket;
72
use Munin::Plugin;
73
use File::Basename;
74

    
75
if (basename($0) !~ /^memcached_multi_/) {
76
    print "This script needs to be named memcached_multi_ and have symlinks which start the same.\n";
77
    exit 1;
78
}
79

    
80
# tell munin about our multigraph capabilities
81
need_multigraph();
82

    
83
=head1 Variable Declarations
84

    
85
    This section of code is to declare the variables used throughout the plugin
86
    Some of them are imported as environment variables from munin plugin conf.d
87
    file, others are hashes used for storing information that comes from the
88
    stats commands issued to memcached.
89

    
90
=cut
91

    
92
# lets import environment variables for the plugin or use the default
93
my $host = $ENV{host} || "127.0.0.1";
94
my $port = $ENV{port} || 11211;
95

    
96
# This gives us the ability to control the timescale our graphs are displaying.
97
# The default it set to divide by hours, if you want to get seconds set it to 1.
98
# Options: 1 = seconds, 2 = minutes, 3 = hours, 4 = days
99
my $timescale = $ENV{timescale} || 3;
100

    
101
# This hash contains the information contained in two memcache commands
102
# stats and stats settings.
103
my %stats;
104

    
105
# This gives us eviction rates and other hit stats per slab
106
# We track this so we can see if something was evicted earlier than necessary
107
my %items;
108

    
109
# This gives us the memory size and usage per slab
110
# We track this so we can see what slab is being used the most and has no free chunks 
111
# so we can re-tune memcached to allocate more pages for the specified chunk size
112
my %chnks;
113

    
114
=head2 Graph Declarations
115

    
116
    This block of code builds up all of the graph info for all root / sub graphs.
117

    
118
    %graphs: is a container for all of the graph definition information. In here is where you'll
119
             find the configuration information for munin's graphing procedure.
120
    Format:
121

    
122
    $graph{graph_name} => {
123
        config => {
124
            You'll find the main graph config stored here
125
            { key => value },
126
            { ... },
127
        },
128
        datasrc => [
129
            Name: name given to data value
130
            Attr: Attribute and value, attribute must be valid plugin argument
131
            { name => 'Name', info => 'info about graph', ... },
132
            { ... },
133
        ],
134
    }
135

    
136
=cut
137

    
138
my %graphs;
139

    
140
# main graph for memcached item count
141
$graphs{items} = {
142
    config => {
143
        args => '--base 1000 --lower-limit 0',
144
        vlabel => 'Items in Memcached',
145
        category => 'memcached',
146
        title => 'Items',
147
        info => 'This graph shows the number of items in use by memcached',
148
    },
149
    datasrc => [
150
        { name => 'curr_items', label => 'Current Items', min => '0' },
151
        { name => 'total_items', label => 'New Items', min => '0', type => 'DERIVE' },
152
    ],
153
};
154
# main graph for memcached memory usage
155
$graphs{memory} = {
156
    config => {
157
        args => '--base 1024 --lower-limit 0',
158
        vlabel => 'Bytes Used',
159
        category => 'memcached',
160
        title => 'Memory Usage',
161
        info => 'This graph shows the memory consumption of memcached',
162
    },
163
    datasrc => [
164
        { name => 'limit_maxbytes', draw => 'AREA', label => 'Maximum Bytes Allocated', min => '0' },
165
        { name => 'bytes', draw => 'AREA', label => 'Current Bytes Used', min => '0' },
166
    ],
167
};
168
# main graph for memcached network usage
169
$graphs{bytes} = {
170
    config => {
171
        args => '--base 1000',
172
        vlabel => 'bits in (-) / out (+)',
173
        title => 'Network Traffic',
174
        category => 'memcached',
175
        info => 'This graph shows the network traffic in (-) / out (+) of the machine',
176
        order => 'bytes_read bytes_written',
177
    },
178
    datasrc => [
179
        { name => 'bytes_read', type => 'DERIVE', label => 'Network Traffic coming in (-)', graph => 'no', cdef => 'bytes_read,8,*', min => '0' },
180
        { name => 'bytes_written', type => 'DERIVE', label => 'Traffic in (-) / out (+)', negative => 'bytes_read', cdef => 'bytes_written,8,*', min => '0' },
181
    ],
182
};
183
# graph for memcached connections
184
$graphs{conns} = {
185
    config => {
186
        args => '--base 1000 --lower-limit 0',
187
        vlabel => 'Connections per ${graph_period}',
188
        category => 'memcached',
189
        title => 'Connections',
190
        info => 'This graph shows the number of connections being handled by memcached',
191
        order => 'max_conns curr_conns avg_conns',
192
    },
193
    datasrc => [
194
        { name => 'curr_conns', label => 'Current Connections', min => '0' },
195
        { name => 'max_conns', label => 'Max Connections', min => '0' },
196
        { name => 'avg_conns' , label => 'Avg Connections', min => '0' },
197
    ],
198
};
199
# main graph for memcached commands issued
200
$graphs{commands} = {
201
    config => {
202
        args => '--base 1000 --lower-limit 0',
203
        vlabel => 'Commands per ${graph_period}',
204
        category => 'memcached',
205
        title => 'Commands',
206
        info => 'This graph shows the number of commands being handled by memcached',
207
    },
208
    datasrc => [
209
        { name => 'cmd_get', type => 'DERIVE', label => 'Gets', info => 'Cumulative number of retrieval reqs', min => '0' },
210
        { name => 'cmd_set', type => 'DERIVE', label => 'Sets', info => 'Cumulative number of storage reqs', min => '0' },
211
        { name => 'get_hits', type => 'DERIVE', label => 'Get Hits', info => 'Number of keys that were requested and found', min => '0' },
212
        { name => 'get_misses', type => 'DERIVE', label => 'Get Misses', info => 'Number of keys there were requested and not found', min => '0' },
213
        { name => 'delete_hits', type => 'DERIVE', label => 'Delete Hits', info => 'Number of delete requests that resulted in a deletion of a key', min => '0' },
214
        { name => 'delete_misses', type => 'DERIVE', label => 'Delete Misses', info => 'Number of delete requests for missing key', min => '0' },
215
        { name => 'incr_hits', type => 'DERIVE', label => 'Increment Hits', info => 'Number of successful increment requests', min => '0' },
216
        { name => 'incr_misses', type => 'DERIVE', label => 'Increment Misses', info => 'Number of unsuccessful increment requests', min => '0' },
217
        { name => 'decr_hits', type => 'DERIVE', label => 'Decrement Hits', info => 'Number of successful decrement requests', min => '0' },
218
        { name => 'decr_misses', type => 'DERIVE', label => 'Decrement Misses', info => 'Number of unsuccessful decrement requests', min => '0' },
219
    ],
220
};
221
# main graph for memcached eviction rates
222
$graphs{evictions} = {
223
    config => {
224
        args => '--base 1000 --lower-limit 0',
225
        vlabel => 'Evictions per ${graph_period}',
226
        category => 'memcached',
227
        title => 'Evictions',
228
        info => 'This graph shows the number of evictions per second',
229
    },
230
    datasrc => [
231
        { name => 'evictions', label => 'Evictions', info => 'Cumulative Evictions Across All Slabs', type => 'DERIVE', min => '0' },
232
        { name => 'evicted_nonzero', label => 'Evictions prior to Expire', info => 'Cumulative Evictions forced to expire prior to expiration', type => 'DERIVE', min => '0' },
233
        { name => 'reclaimed', label => 'Reclaimed Items', info => 'Cumulative Reclaimed Item Entries Across All Slabs', type => 'DERIVE', min => '0' },
234
    ],
235
};
236
# sub graph for breaking memory info down by slab ( sub graph of memory )
237
$graphs{slabchnks} = {
238
    config => {
239
        args => '--base 1000 --lower-limit 0',
240
        vlabel => 'Available Chunks for this Slab',
241
        category => 'memcached',
242
        title => 'Chunk Usage for Slab: ',
243
        info => 'This graph shows you the chunk usage for this memory slab.',
244
    },
245
    datasrc => [
246
        { name => 'total_chunks', label => 'Total Chunks Available', min => '0' },
247
        { name => 'used_chunks', label => 'Total Chunks in Use', min => '0' },
248
        { name => 'free_chunks', label => 'Total Chunks Not in Use (Free)', min => '0' },
249
    ],
250
};
251
# sub graph for breaking commands down by slab ( sub graph of commands )
252
$graphs{slabhits} = {
253
    config => {
254
        args => '--base 1000 --lower-limit 0',
255
        vlabel => 'Hits per Slab per ${graph_period}',
256
        category => 'memcached',
257
        title => 'Hits for Slab: ',
258
        info => 'This graph shows you the successful hit rate for this memory slab.',
259
    },
260
    datasrc => [
261
        { name => 'get_hits', label => 'Get Requests', type => 'DERIVE', min => '0' },
262
        { name => 'cmd_set', label => 'Set Requests', type => 'DERIVE', min => '0' },
263
        { name => 'delete_hits', label => 'Delete Requests', type => 'DERIVE', min => '0' },
264
        { name => 'incr_hits', label => 'Increment Requests', type => 'DERIVE', min => '0' },
265
        { name => 'decr_hits', label => 'Decrement Requests', type => 'DERIVE', min => '0' },
266
    ],
267
};
268
# sub graph for breaking evictions down by slab ( sub graph of evictions )
269
$graphs{slabevics} = {
270
    config => {
271
        args => '--base 1000 --lower-limit 0',
272
        vlabel => 'Evictions per Slab per ${graph_period}',
273
        category => 'memcached',
274
        title => 'Evictions for Slab: ',
275
        info => 'This graph shows you the eviction rate for this memory slab.',
276
    },
277
    datasrc => [
278
        { name => 'evicted', label => 'Total Evictions', type => 'DERIVE', min => '0' },
279
        { name => 'evicted_nonzero', label => 'Evictions from LRU Prior to Expire', type => 'DERIVE', min => '0' },
280
        { name => 'reclaimed', label => 'Reclaimed Expired Items', info => 'This is number of times items were stored in expired entry memory space', type => 'DERIVE', min => '0' },
281
    ],
282
};
283
# sub graph for showing the time between an item was last evicted and requested ( sub graph of evictions )
284
$graphs{slabevictime} = {
285
    config => {
286
        args => '--base 1000 --lower-limit 0',
287
        vlabel => ' since Request for LEI',
288
        category => 'memcached',
289
        title => 'Eviction Request Time for Slab: ',
290
        info => 'This graph shows you the time since we requested the last evicted item',
291
    },
292
    datasrc => [
293
        { name => 'evicted_time', label => 'Eviction Time (LEI)', info => 'Time Since Request for Last Evicted Item', min => '0' },
294
    ],
295
};
296
# sub graph for breaking items down by slab ( sub graph of items )
297
$graphs{slabitems} = {
298
    config => {
299
        args => '--base 1000 --lower-limit 0',
300
        vlabel => 'Items per Slab',
301
        category => 'memcached',
302
        title => 'Items in Slab: ',
303
        info => 'This graph shows you the number of items and reclaimed items per slab.',
304
    },
305
    datasrc => [
306
        { name => 'number', label => 'Items', info => 'This is the amount of items stored in this slab', min => '0' },
307
    ],
308
};
309
# sub graph for showing the age of the eldest item stored in a slab ( sub graph of items )
310
$graphs{slabitemtime} = {
311
    config => {
312
        args => '--base 1000 --lower-limit 0',
313
        vlabel => ' since item was stored',
314
        category => 'memcached',
315
        title => 'Age of Eldest Item in Slab: ',
316
        info => 'This graph shows you the time of the eldest item in this slab',
317
    },
318
    datasrc => [
319
        { name => 'age', label => 'Eldest Item\'s Age', min => '0' },
320
    ],
321
};
322

    
323
=head1 Munin Checks
324

    
325
    These checks look for config / autoconf / suggest params
326

    
327
=head2 Config Check
328

    
329
    This block of code looks at the argument that is possibly supplied,
330
    should it be config, it then checks to make sure the plugin 
331
    specified exists, assuming it does, it will run the do_config 
332
    subroutine for the plugin specified, otherwise it dies complaining
333
    about an unknown plugin.
334

    
335
=cut
336

    
337
if (defined $ARGV[0] && $ARGV[0] eq 'config') {
338
    # Lets get our plugin from the symlink being called up, we'll also verify its a valid
339
    # plugin that we have graph information for
340
    $0 =~ /memcached_multi_(.+)*/;
341
    my $plugin = $1;
342
    die 'Unknown Plugin Specified: ' . ($plugin ? $plugin : '') unless $graphs{$plugin};
343
    # We need to fetch the stats before we do any config, cause its needed for multigraph
344
    # subgraphs which use slab information for title / info per slab
345
    fetch_stats();
346
    # Now lets go ahead and print out our config.
347
	do_config($plugin);
348
	exit 0;
349
}
350

    
351
=head2 Autoconf Check
352

    
353
    This block of code looks at the argument that is possibly supplied,
354
    should it be autoconf, we will attempt to connect to the memcached
355
    service specified on the host:port, upon successful connection it
356
    prints yes, otherwise it prints no.
357

    
358
=cut
359

    
360
if (defined $ARGV[0] && $ARGV[0] eq 'autoconf') {
361
    # Lets attempt to connect to memcached
362
    my $s = get_conn();
363
    # Lets verify that we did connect to memcached
364
    if (defined($s)) {
365
        print "yes\n";
366
        exit 0;
367
    } else {
368
        print "no (unable to connect to $host\[:$port\])\n";
369
        exit 0;
370
    }
371
}
372

    
373
=head2 Suggest Check
374

    
375
    This block of code looks at the argument that is possibly supplied,
376
    should it be suggest, we are going to print the possible plugins
377
    which can be specified. Note we only specify the root graphs for the
378
    multigraphs, since the rest of the subgraphs will appear "behind" the
379
    root graphs. It also attempts to connect to the memcached service to
380
    verify it is infact running.
381

    
382
=cut
383

    
384
if (defined $ARGV[0] && $ARGV[0] eq 'suggest') {
385
    # Lets attempt to connect to memcached
386
    my $s = get_conn();
387
    # Lets check that we did connect to memcached
388
    if (defined($s)) {
389
        my @rootplugins = ('bytes','conns','commands','evictions','items','memory');
390
        foreach my $plugin (@rootplugins) {
391
            print "$plugin\n";
392
        }
393
        exit 0;
394
    } else {
395
        print "no (unable to connect to $host\[:$port\])\n";
396
        exit 0;
397
    }
398
}
399

    
400
=head1 Output Subroutines
401

    
402
    Output Subroutine calls to output data values
403

    
404
=head2 fetch_output
405

    
406
    This subroutine is the main call for printing data for the plugin.
407
    No parameters are taken as this is the default call if no arguments
408
    are supplied from the command line.
409

    
410
=cut
411

    
412
# Well, no arguments were supplied that we know about, so lets print some data
413
fetch_output();
414

    
415
sub fetch_output {
416
    # Lets get our plugin from the symlink being called up, we'll also verify its a valid
417
    # plugin that we have graph information for
418
    $0 =~ /memcached_multi_(.+)*/;
419
    my $plugin = $1;
420
    die 'Unknown Plugin Specified: ' . ($plugin ? $plugin : '') unless $graphs{$plugin};
421
    # Well we need to actually fetch the stats before we do anything to them.
422
    fetch_stats();
423
    # Now lets go ahead and print out our output.
424
    my @subgraphs;
425
    if ($plugin eq 'memory') {
426
        @subgraphs = ('slabchnks');
427
        foreach my $slabid(sort{$a <=> $b} keys %chnks) {
428
            print_submulti_output($slabid,$plugin,@subgraphs);
429
        }
430
        print_rootmulti_output($plugin);
431
    } elsif ($plugin eq 'commands') {
432
        @subgraphs = ('slabhits');
433
        foreach my $slabid(sort{$a <=> $b} keys %chnks) {
434
            print_submulti_output($slabid,$plugin,@subgraphs);
435
        }
436
        print_rootmulti_output($plugin);
437
    } elsif ($plugin eq 'evictions') {
438
        @subgraphs = ('slabevics','slabevictime');
439
        foreach my $slabid (sort{$a <=> $b} keys %items) {
440
            print_submulti_output($slabid,$plugin,@subgraphs);
441
        }
442
        print_rootmulti_output($plugin);
443
    } elsif ($plugin eq 'items') {
444
        @subgraphs = ('slabitems','slabitemtime');
445
        foreach my $slabid (sort{$a <=> $b} keys %items) {
446
            print_submulti_output($slabid,$plugin,@subgraphs);
447
        }
448
        print_rootmulti_output($plugin);
449
    } else {
450
        print_root_output($plugin);
451
    }
452

    
453
    return;
454
}
455

    
456
=head2 print_root_output
457

    
458
    This block of code prints out the return values for our root graphs. It takes
459
    one parameter $plugin. Returns when completed, this is the non multigraph
460
    output subroutine.
461

    
462
        $plugin;    graph we are calling up to print data values for 
463

    
464
    Example: print_root_output($plugin);
465

    
466
=cut
467

    
468
sub print_root_output {
469
    # Lets get our plugin, set our graph reference and print out info for Munin
470
    my ($plugin) = (@_);
471
    my $graph = $graphs{$plugin};
472
    print "graph memcached_$plugin\n";
473
    # The conns plugin has some specific needs, looking for plugin type
474
    if ($plugin ne 'conns') {
475
        foreach my $dsrc (@{$graph->{datasrc}}) {
476
            my %datasrc = %$dsrc;
477
            while ( my ($key, $value) = each(%datasrc)) {
478
                next if ($key ne 'name');
479
                my $output = $stats{$value};
480
                print "$dsrc->{name}.value $output\n";
481
            }
482
        }
483
    } else {
484
        my $output;
485
        foreach my $dsrc (@{$graph->{datasrc}}) {
486
            my %datasrc = %$dsrc;
487
            while ( my ($key, $value) = each(%datasrc)) {
488
                if ($value eq 'max_conns') {
489
                    $output = $stats{maxconns};
490
                } elsif ($value eq 'curr_conns') {
491
                    $output = $stats{curr_connections};
492
                } elsif ($value eq 'avg_conns') {
493
                    $output = sprintf("%02d", $stats{total_connections} / $stats{uptime});
494
                } else {
495
                    next;
496
                }
497
                print "$dsrc->{name}.value $output\n";
498
            }
499
        }
500
    }
501
    return;
502
}
503

    
504
=head2 print_rootmulti_output
505

    
506
    This block of code prints out the return values for our root graphs. It takes
507
    one parameter $plugin. Returns when completed, this is the multigraph
508
    output subroutine
509

    
510
        $plugin;    main(root) graph we are calling up to print data values for
511

    
512
    Example: print_rootmulti_output($plugin);
513

    
514
=cut
515

    
516
sub print_rootmulti_output {
517
    # Lets get our plugin, set our graph reference and print out info for Munin
518
    my ($plugin) = (@_);
519
    my $graph = $graphs{$plugin};
520
    print "multigraph memcached_$plugin\n";
521
    # Lets print our data values with their appropriate name
522
    foreach my $dsrc (@{$graph->{datasrc}}) {
523
        my $output = 0;
524
        my %datasrc = %$dsrc;
525
        while ( my ($key, $value) = each(%datasrc)) {
526
            next if ($key ne 'name');
527
            next if (($plugin eq 'evictions') && ($value eq 'reclaimed') && ($stats{version} =~ /1\.4\.[0-2]/));
528
            if (($plugin eq 'evictions') && ($value eq 'evicted_nonzero')) {
529
                foreach my $slabid (sort{$a <=> $b} keys %items) {
530
                    $output += $items{$slabid}->{evicted_nonzero};
531
                }
532
            } else {
533
                $output = $stats{$value};
534
            }
535
            print "$dsrc->{name}.value $output\n";
536
        }
537
    }
538
    return;
539
}
540

    
541
=head2 print_submulti_output
542

    
543
    This block of code prints out the return values for our root graphs. It takes
544
    three parameters $slabid, $plugin and @subgraphs. Returns when completed, this
545
    is the multigraph output subroutine for our subgraphs
546

    
547
        $slabid;    slab id that we will use to grab info from and print out
548
        $plugin;    main(root) being called, used for multigraph output and slab id
549
        @subgraphs; graphs we are actually trying to print data values for
550

    
551
    Example: print_submulti_output($slabid,$plugin,@subgraphs);
552

    
553
=cut
554

    
555
sub print_submulti_output {
556
    # Lets get our slabid, plugin, and subgraphs
557
    my ($slabid,$plugin,@subgraphs) = (@_);
558
    my $currslab = undef;
559
    # Time to loop over our subgraphs array
560
    foreach my $sgraph (@subgraphs) {
561
        # Lets set our graph reference for quick calling, and print some info for munin
562
        my $graph = $graphs{$sgraph};
563
        print "multigraph memcached_$plugin.$sgraph\_$slabid\n";
564
        # Lets figure out what slab info we are trying to call up
565
        if ($plugin eq 'evictions') {
566
            $currslab = $items{$slabid};
567
        } elsif ($plugin eq 'memory') {
568
            $currslab = $chnks{$slabid};
569
        } elsif ($plugin eq 'commands') {
570
            $currslab = $chnks{$slabid};
571
        } elsif ($plugin eq 'items') {
572
            $currslab = $items{$slabid};
573
        } else {
574
            return;
575
        }
576
        # Lets print our data values with their appropriate name
577
        foreach my $dsrc (@{$graph->{datasrc}}) {
578
            my %datasrc = %$dsrc;
579
            while ( my ($key, $value) = each(%datasrc)) {
580
                next if ($key ne 'name');
581
                next if (($sgraph eq 'slabevics') && ($value eq 'reclaimed') && ($stats{version} =~ /1\.4\.[0-2]/));
582
                my $output = $currslab->{$value};
583
                if (($sgraph eq 'slabevictime') || ($sgraph eq 'slabitemtime')) {
584
                    $output = time_scale('data',$output); ;
585
                }
586
                print "$dsrc->{name}.value $output\n";
587
            }
588
        }
589
    }
590
    return;
591
}
592

    
593
=head1 Config Subroutines
594

    
595
    These subroutines handle the config portion of munin calls.
596

    
597
=head2 do_config
598

    
599
    This is the main call issued assuming we call up config and plugin specified exists
600
    The subroutine takes one parameter $plugin, and returns when completed.
601

    
602
        $plugin; main(root) graph being called
603

    
604
    Example: do_config($plugin);
605

    
606
=cut
607

    
608
sub do_config {
609
    my ($plugin) = (@_);
610
    my @subgraphs;
611
    if ($plugin eq 'memory') {
612
        @subgraphs = ('slabchnks');
613
        foreach my $slabid (sort{$a <=> $b} keys %chnks) {
614
            print_submulti_config($slabid,$plugin,@subgraphs);
615
        }
616
        print_rootmulti_config($plugin);
617
    } elsif ($plugin eq 'commands') {
618
        @subgraphs = ('slabhits');
619
        foreach my $slabid (sort{$a <=> $b} keys %chnks) {
620
            print_submulti_config($slabid,$plugin,@subgraphs);
621
        }
622
        print_rootmulti_config($plugin);
623
    } elsif ($plugin eq 'evictions') {
624
        @subgraphs = ('slabevics','slabevictime');
625
        foreach my $slabid (sort{$a <=> $b}  keys %items) {
626
            print_submulti_config($slabid,$plugin,@subgraphs);
627
        }
628
        print_rootmulti_config($plugin);
629
    } elsif ($plugin eq 'items') {
630
        @subgraphs = ('slabitems','slabitemtime');
631
        foreach my $slabid (sort{$a <=> $b} keys %items) {
632
            print_submulti_config($slabid,$plugin,@subgraphs);
633
        }
634
        print_rootmulti_config($plugin);
635
    } else {
636
        print_root_config($plugin);
637
    }
638

    
639
    return;
640
}
641

    
642
=head2 get_conn
643

    
644
    This subroutine returns a socket connection
645

    
646
=cut
647

    
648
sub get_conn {
649
    my $s = undef;
650

    
651
    # check if we want to use sockets instead of tcp
652
    my ($sock) = ($host =~ /unix:\/\/(.+)*$/);
653

    
654
    if ($sock) {
655
       $s = IO::Socket::UNIX->new(
656
            Peer     => $sock
657
      );
658
    } else {
659
       $s = IO::Socket::INET->new(
660
            Proto    => "tcp",
661
            PeerAddr => $host,
662
            PeerPort => $port,
663
            Timeout  => 10,
664
       );
665
    }
666

    
667
    return $s;
668
}
669

    
670
=head2 print_submulti_config
671

    
672
    This subroutine prints out the config information for all of the subgraphs.
673
    It takes three parameters, $slabid, $plugin and @subgraphs, returns when
674
    completed, this is the mutligraph config output for our subgraphs
675

    
676
        $slabid;    slab id that we will use to grab info from and print out
677
        $plugin;    main(root) being called, used for multigraph output and slab id
678
        @subgraphs; graphs we are actually trying to print data values for
679

    
680
    Example:  print_submulti_config($slabid,$plugin,@subgraphs);
681

    
682
=cut
683

    
684
sub print_submulti_config {
685
    # Lets get our slabid, plugin, and subgraphs
686
    my ($slabid,$plugin,@subgraphs) = (@_);
687
    my ($slabitems,$slabchnks) = undef;
688
    # Time to loop over our subgraphs array
689
    foreach my $sgraph (@subgraphs) {
690
        # Lets set our graph reference, and main graph config for easy handling
691
        my $graph = $graphs{$sgraph};
692
        my %graphconf = %{$graph->{config}};
693
        # Lets tell munin which graph we are graphing, and what our main graph config info is 
694
        print "multigraph memcached_$plugin.$sgraph\_$slabid\n";
695
        while ( my ($key, $value) = each(%graphconf)) {
696
	        if ($key eq 'title') {
697
	            print "graph_$key $value" . "$slabid" . " ($chnks{$slabid}->{chunk_size} Bytes)\n";
698
	        } elsif (($key eq 'vlabel') && (($sgraph eq 'slabevictime') || ($sgraph eq 'slabitemtime'))) {
699
                $value = time_scale('config',$value);
700
                print "graph_$key $value\n";
701
            } else {
702
                print "graph_$key $value\n";
703
	        }
704
        }
705
        # Lets tell munin about our data values and how to treat them
706
        foreach my $dsrc (@{$graph->{datasrc}}) {
707
            my %datasrc = %$dsrc;
708
            while ( my ($key, $value) = each(%datasrc)) {
709
                next if ($key eq 'name');
710
                print "$dsrc->{name}.$key $value\n";
711
            }
712
        }
713
    }
714

    
715
    return;
716
}
717

    
718
=head2 print_rootmulti_config
719

    
720
    This subroutine prints out the config information for all of the main(root) graphs.
721
    It takes one parameter, $plugin, returns when completed.
722

    
723
        $plugin;    main(root) graph used for multigraph call
724

    
725
    Example:  print_rootmulti_config($plugin);
726

    
727
=cut
728

    
729
sub print_rootmulti_config {
730
    # Lets get out plugin, set our graph reference and our graph config info
731
    my ($plugin) = (@_);
732
    my $graph = $graphs{$plugin};
733
    my %graphconf = %{$graph->{config}};
734
    # Lets tell munin about the graph we are referencing and print the main config
735
    print "multigraph memcached_$plugin\n";
736
    while ( my ($key, $value) = each(%graphconf)) {
737
        print "graph_$key $value\n";
738
    }
739
    # Lets tell munin about our data values and how to treat them
740
    foreach my $dsrc (@{$graph->{datasrc}}) {
741
        my %datasrc = %$dsrc;
742
        while ( my ($key, $value) = each(%datasrc)) {
743
            next if ($key eq 'name');
744
            print "$dsrc->{name}.$key $value\n";
745
        }
746
    }
747
    return;
748
}
749

    
750
=head2 print_root_config
751

    
752
    This subroutine prints out the config information for all of the main(root) graphs.
753
    It takes one parameter, $plugin, returns when completed.
754

    
755
        $plugin;    main(root) graph used for multigraph call
756

    
757
    Example:  print_root_config($plugin);
758

    
759
=cut
760

    
761
sub print_root_config {
762
    # Lets get our plugin, set our graph reference and our graph config info
763
    my ($plugin) = (@_);
764
    my $graph = $graphs{$plugin};
765
    my %graphconf = %{$graph->{config}};
766
    # Lets tell munin about the graph we are referencing and print the main config
767
    print "graph memcached_$plugin\n";
768
    while ( my ($key, $value) = each(%graphconf)) {
769
        print "graph_$key $value\n";
770
    }
771
    # Lets tell munin about our data values and how to treat them
772
    foreach my $dsrc (@{$graph->{datasrc}}) {
773
        my %datasrc = %$dsrc;
774
        while ( my ($key, $value) = each(%datasrc)) {
775
            next if ($key eq 'name');
776
            print "$dsrc->{name}.$key $value\n";
777
        }
778
    }
779
    return;
780
}
781

    
782
=head1 Misc Subroutines
783

    
784
    These subroutines are misc ones, and are referenced inside of the code. They
785
    should never be called up by Munin.
786

    
787
=head2 fetch_stats
788

    
789
    This subroutine fetches the information from memcached and stores it into our
790
    hashes for later referencing throughout the graph. Returns when completed
791

    
792
=cut
793

    
794
sub fetch_stats {
795
    # Lets try and connect to memcached
796
    my $s = get_conn();
797
    # Die if we can't establish a connection to memcached
798
    die "Error: Unable to Connect to $host\[:$port\]\n" unless $s;
799
    # Lets print the stats command and store the info from the output
800
    print $s "stats\r\n";
801
    while (my $line = <$s>) {
802
        if ($line =~ /STAT\s(.+?)\s(.*)/) {
803
            my ($skey,$svalue) = ($1,$2);
804
            $stats{$skey} = $svalue;
805
        }
806
        last if $line =~ /^END/;
807
    }
808
    # Lets print the stats settings command and store the info from the output
809
    print $s "stats settings\r\n";
810
    while (my $line = <$s>) {
811
        if ($line =~ /STAT\s(.+?)\s(.*)/) {
812
            my ($skey,$svalue) = ($1,$2);
813
            if ($skey eq 'evictions') {
814
                $skey = 'evictions_active';
815
            }
816
            $stats{$skey} = $svalue;
817
        }
818
        last if $line =~ /^END/;
819
    }
820
    # Lets print the stats slabs command and store the info from the output
821
    print $s "stats slabs\r\n";
822
    while (my $line = <$s>) {
823
        if ($line =~ /STAT\s(\d+):(.+)\s(\d+)/) {
824
            my ($slabid,$slabkey,$slabvalue) = ($1,$2,$3);
825
            $chnks{$slabid}->{$slabkey} = $slabvalue;
826
        }
827
        last if $line =~ /^END/;
828
    }
829
    # Lets print the stats items command and store the info from the output
830
    print $s "stats items\r\n";
831
    while (my $line = <$s>) {
832
        if ($line =~ /STAT\sitems:(\d+):(.+?)\s(\d+)/) {
833
            my ($itemid,$itemkey,$itemvalue) = ($1,$2,$3);
834
            $items{$itemid}->{$itemkey} = $itemvalue;
835
        }
836
        last if $line =~ /^END/;
837
    }
838
}
839

    
840
=head2 time_scale
841

    
842
    This subroutine is here for me to adjust the timescale of the time graphs
843
    for last evicted item and age of eldest item in cache.
844

    
845
        Please note, after long usage I have noticed these counters may not
846
        be accurate, I believe the developers are aware and have submitted
847
        a patch upstream.
848

    
849
=cut
850

    
851
sub time_scale {
852
    # Lets get our config option and value to adjust
853
    my ($configopt,$origvalue) = (@_);
854
    my $value;
855
    # If config is defined, it returns the config info for time scale
856
    # If data is defined, it returns the original value after its been adjusted
857
    if ($configopt eq 'config') {
858
        if ($timescale == 1) {
859
            $value = "Seconds" . $origvalue;
860
        } elsif ($timescale == 2) {
861
            $value = "Minutes" . $origvalue;
862
        } elsif (($timescale == 3) || ($timescale > 4) || (!defined($timescale))) {
863
            $value = "Hours" . $origvalue;
864
        } elsif ($timescale == 4) {
865
            $value = "Days" . $origvalue;
866
        }
867
    } elsif ($configopt eq 'data') {
868
        if ($timescale == 1) {
869
            $value = sprintf("%02.2f", $origvalue / 1);
870
        } elsif ($timescale == 2) {
871
            $value = sprintf("%02.2f", $origvalue / 60);
872
        } elsif (($timescale == 3) || ($timescale > 4) || (!defined($timescale))) {
873
            $value = sprintf("%02.2f", $origvalue / 3600);
874
        } elsif ($timescale == 4) {
875
            $value = sprintf("%02.2f", $origvalue / 86400);
876
        }
877
    } else {
878
        die "Unknown time_scale option given: either [config/data]\n";
879
    }
880
    return $value;
881
}