Projet

Général

Profil

Révision 91fbc09d

ID91fbc09da0c0d0d4464cd2ca5efe02bd6ced6e4c
Parent a342708d
Enfant 299e9c16

Ajouté par ?var Arnfj?r? il y a presque 14 ans

Initial version

Voir les différences:

plugins/other/multipng_async
1
#!/usr/bin/env perl
2
package Munin::Plugin::Multiping::Async;
3
use 5.10.0;
4
use MooseX::POE;
5
use MooseX::POE::SweetArgs qw(event);
6
use POE::Quickie;
7
use Munin::Plugin;
8
use Storable;
9
use Digest;
10

  
11
=head1 NAME
12

  
13
multiping_async - Like the multiping plugin but runs asynchronously
14

  
15
=head1 SYNOPSIS
16

  
17
    munin-run multiping_async
18

  
19
=head1 CONFIGURATION
20

  
21
The following environment variables are used:
22

  
23
    host     - Whitespace-seperated list of hosts to ping
24
    times    - How many times to ping the hosts, 3 by default
25
    timeout  - The ping timeout (ping -W), 1 by default
26
    title    - The graph_title to use for the munin RRD graph
27
    category - What category the graph should be in, network by default
28

  
29
Configuration example, ping all the Linode clusters:
30

  
31
    # An optional custom category
32
    [multiping_async_*]
33
    env.category ping
34

  
35
    [multiping_async_linode]
36
    # From http://www.linode.com/speedtest/
37
    env.title Ping times to all the Linode clusters
38
    env.host  london1.linode.com newark1.linode.com atlanta1.linode.com dallas1.linode.com fremont1.linode.com
39

  
40
=head1 DESCRIPTION
41

  
42
Like the L<munin
43
multiping|http://munin-monitoring.org/browser/people/janl/src/node/node.d/multiping>
44
plugin except that it runs L<ping(1)> asynchronously with POE, and you
45
can add/remove hosts later on without screwing up your RRD files
46
(multiping reports statistics based on the order of hosts in
47
C<hosts=>).
48

  
49
This plugin used to use L<POE::Component::Client::Ping> but I switched
50
away from it due to having odd timing issues with it, and it had to
51
run as root.
52

  
53
This plugin requires the L<MooseX::POE> and L<POE::Quickie> modules
54
from CPAN.
55

  
56
=head1 AUTHOR
57

  
58
E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avar@cpan.org>
59

  
60
=head1 LICENSE
61

  
62
This program is in the public domain.
63

  
64
=head1 MAGIC MARKERS
65

  
66
 #%# family=manual
67

  
68
=cut
69

  
70
has graph_title => (
71
    isa => 'Str',
72
    is  => 'ro',
73
    default => $ENV{title} // 'Ping times',
74
    documentation => 'The munin graph_title',
75
);
76

  
77
has hosts => (
78
    isa        => 'ArrayRef',
79
    is         => 'ro',
80
    auto_deref => 1,
81
    default    => sub {
82
        my $host = $ENV{host} // '';
83
        return [ split /\s+/, $host ]
84
    },
85
    documentation => "Hosts we're going to ping",
86
);
87

  
88
has times => (
89
    isa           => 'Int',
90
    is            => 'ro',
91
    default       => $ENV{times} // 3,
92
    documentation => "How many times we ping each host (ping -c)",
93
);
94

  
95
has timeout => (
96
    isa           => 'Int',
97
    is            => 'ro',
98
    default       => $ENV{timeout} // 1,
99
    documentation => "How long until ping timeouts (ping -W)",
100
);
101

  
102
has category => (
103
    isa           => 'Str',
104
    is            => 'ro',
105
    default       => $ENV{category} // 'network',
106
    documentation => "What munin category we should appear in",
107
);
108

  
109
has should_config => (
110
    isa => 'Bool',
111
    is => 'ro',
112
    default => sub { defined $ARGV[0] and $ARGV[0] eq "config" },
113
    documentation => 'Spew out config section?',
114
);
115

  
116
has response => (
117
    isa        => 'HashRef',
118
    is         => 'ro',
119
    auto_deref => 0,
120
    default    => sub { +{} },
121
    documentation => 'To store ping responses',
122
);
123

  
124
has statefile => (
125
    isa           => 'Str',
126
    is            => 'ro',
127
    default       => $ENV{MUNIN_STATEFILE},
128
    documentation => 'Where we store state between invocations',
129
);
130

  
131
sub START {
132
    my ($self) = @_;
133

  
134
    die "You must supply some hosts" unless @{ $self->hosts } > 0;
135

  
136
    if ($self->should_config) {
137
        $self->print_config;
138
        return;
139
    }
140

  
141
    for ($self->hosts) {
142
        POE::Quickie->new->run(
143
            Program     => [ 'ping', '-c', $self->times, '-W', $self->timeout, => $_ ],
144
            StdoutEvent => 'stdout',
145
            ExitEvent   => 'exit',
146
            Context     => $_,
147
        );
148
    }
149
}
150

  
151
event stdout => sub {
152
    my ($self, $output, undef, $context) = @_;
153

  
154
    given ($output) {
155
        my $noslash = qr{[^/]+};
156
        when (m[^rtt min/avg/max/mdev = (?<min>$noslash)/(?<avg>$noslash)/(?<max>$noslash)/]) {
157
            $self->response->{ $context } = $+{avg};
158
        }
159
    }
160
};
161

  
162
event exit => sub {
163
    my ($self, $code, $x, $context) = @_;
164

  
165
    given ($code) {
166
        when (0) {
167
            die "Got no response from $context" unless exists $self->response->{ $context };
168
            $self->yield( print_host => $context => $self->response->{ $context } );
169
        }
170
        default {
171
            # Host down, probably
172
            $self->yield( print_host => $context => 0 );
173
        }
174
    }
175

  
176
    return;
177
};
178

  
179
sub STOP {
180
    my ($self) = @_;
181

  
182
    if (not $self->should_config and my $file = $self->statefile) {
183
        my $res = $self->response;
184
        my $ret = store($res, $file);
185
        # use Data::Dumper;
186
        # say Dumper { gonna_store => $res, ret => $ret, file => $file };
187
    }
188
}
189

  
190
sub print_config {
191
    my ($self) = @_;
192
    my $title = $self->graph_title;
193
    my $times = $self->times;
194
    my $category = $self->category;
195
    print <<GRAPH;
196
graph_title $title
197
graph_args --base 1000 -l 0
198
graph_vlabel milliseconds
199
graph_category $category
200
graph_info Average ping times (over $times pings)
201
GRAPH
202
    for my $host ($self->sorted_hosts) {
203
        my $fieldname = $self->fieldname($host);
204
        print <<HOST;
205
$fieldname.label $host
206
$fieldname.info Average ping time over $times pings for $host
207
$fieldname.draw LINE2
208
HOST
209
    }
210
};
211

  
212
sub sorted_hosts {
213
    my ($self) = @_;
214

  
215
    my @hosts = $self->hosts;
216
    my $state = $self->statefile;
217

  
218
    given ($self->statefile) {
219
        when (-e and -r) {
220
            my $last_res = retrieve($_);
221
            my @sorted = sort { $last_res->{$b} <=> $last_res->{$a} } keys %$last_res;
222
            if ($last_res and @hosts == @sorted) {
223
                return @sorted;
224
            }
225
        }
226
    }
227

  
228
    return @hosts;
229
}
230

  
231
event print_host => sub {
232
    my ($self, $context, $time) = @_;
233

  
234
    my $fieldname = $self->fieldname($context);
235
    my $value = sprintf "%6.6f", $time;
236

  
237
    say "$fieldname.value $value";
238
};
239

  
240
sub fieldname {
241
    my ($self, $name) = @_;
242
    my $sha1 = substr Digest->new("SHA-1")->add($name)->hexdigest, 0, 10;
243
    return clean_fieldname($name) . '_' . $sha1;
244
}
245

  
246
no MooseX::POE;
247
Munin::Plugin::Multiping::Async->new;
248
POE::Kernel->run;

Formats disponibles : Unified diff