root / plugins / munin / munin_stats_plugins @ d7f54f3e
Historique | Voir | Annoter | Télécharger (3,92 ko)
| 1 | accb5b10 | ?var Arnfj?r? Bjarmason | #!/usr/bin/env perl |
|---|---|---|---|
| 2 | use 5.010; |
||
| 3 | use strict; |
||
| 4 | use warnings; |
||
| 5 | use autodie; |
||
| 6 | use Munin::Plugin; |
||
| 7 | use File::Temp qw(tempdir tempfile); |
||
| 8 | use Time::HiRes qw(gettimeofday tv_interval); |
||
| 9 | use File::Spec::Functions qw(catfile); |
||
| 10 | use File::Basename qw(basename); |
||
| 11 | |||
| 12 | =head1 NAME |
||
| 13 | |||
| 14 | munin_stats_plugins - Report the time it takes to run all munin plugins |
||
| 15 | |||
| 16 | =head1 SYNOPSIS |
||
| 17 | |||
| 18 | In F</etc/munin/plugin-conf.d/munin-node>, because we invoke plugins |
||
| 19 | with munin-run, some of which may need root privileges: |
||
| 20 | |||
| 21 | [munin_stats_plugins] |
||
| 22 | user root |
||
| 23 | |||
| 24 | Put this in cron somewhere: |
||
| 25 | |||
| 26 | # Refresh the statistics |
||
| 27 | MUNIN_STATS_PLUGINS_RELOAD=1 munin-run munin_stats_plugins |
||
| 28 | |||
| 29 | E.g.: |
||
| 30 | |||
| 31 | 40 4 * * * root MUNIN_STATS_PLUGINS_RELOAD=1 munin-run munin_stats_plugins |
||
| 32 | |||
| 33 | Then run it: |
||
| 34 | |||
| 35 | # Get the statistics |
||
| 36 | munin-run munin_stats_plugins |
||
| 37 | |||
| 38 | =head1 DESCRIPTION |
||
| 39 | |||
| 40 | Runs all the munin plugins in F</etc/munin/plugins> and reports the |
||
| 41 | time it takes to run each one with C<system> and L<Time::HiRes>. Since |
||
| 42 | running all the plugins again on each munin-update run would lead to |
||
| 43 | epic recursive failure, you have to reload the statistics database |
||
| 44 | yourself by reloading it in cron somewhere. |
||
| 45 | |||
| 46 | =head1 AUTHOR |
||
| 47 | |||
| 48 | d7f54f3e | Lars Kruse | Ævar Arnfjörð Bjarmason <avar@cpan.org> |
| 49 | accb5b10 | ?var Arnfj?r? Bjarmason | |
| 50 | =head1 LICENSE |
||
| 51 | |||
| 52 | This program is in the public domain. |
||
| 53 | |||
| 54 | =head1 MAGIC MARKERS |
||
| 55 | |||
| 56 | #%# family=manual |
||
| 57 | |||
| 58 | =cut |
||
| 59 | |||
| 60 | my $statedir = $ENV{MUNIN_PLUGSTATE};
|
||
| 61 | my $statefile = $0; $statefile =~ s[^.*/][]; |
||
| 62 | my $cache = catfile($statedir, $statefile . '-cache'); |
||
| 63 | my $cache_tmp = "$cache.tmp"; |
||
| 64 | |||
| 65 | my @plugins = parse_plugin_time($cache); |
||
| 66 | |||
| 67 | # We should reload our data |
||
| 68 | if (not $ARGV[0] and $ENV{MUNIN_STATS_PLUGINS_RELOAD}) {
|
||
| 69 | $ARGV[0] = 'reload'; |
||
| 70 | } |
||
| 71 | |||
| 72 | given ($ARGV[0]) {
|
||
| 73 | when ("reload") {
|
||
| 74 | # Plugin names |
||
| 75 | my @plugs = plugin_names(); |
||
| 76 | |||
| 77 | # Run all the plugins |
||
| 78 | my $time = plugin_times(@plugs); |
||
| 79 | |||
| 80 | write_plugin_times($cache_tmp, $cache, $time); |
||
| 81 | } |
||
| 82 | when ("config") {
|
||
| 83 | print <<END; |
||
| 84 | graph_title Munin plugin processing time |
||
| 85 | graph_scale yes |
||
| 86 | graph_vlabel seconds |
||
| 87 | graph_category munin |
||
| 88 | graph_info Shows the processing time of munin plugins in seconds |
||
| 89 | END |
||
| 90 | for my $plugin (@plugins) {
|
||
| 91 | my ($time, $name) = @$plugin; |
||
| 92 | my $fieldname = clean_fieldname($name); |
||
| 93 | print <<END; |
||
| 94 | $fieldname.label $name |
||
| 95 | $fieldname.info The processing time of $name |
||
| 96 | $fieldname.draw AREASTACK |
||
| 97 | END |
||
| 98 | } |
||
| 99 | } |
||
| 100 | default {
|
||
| 101 | for my $plugin (@plugins) {
|
||
| 102 | my ($time, $name) = @$plugin; |
||
| 103 | my $fieldname = clean_fieldname($name); |
||
| 104 | print <<END; |
||
| 105 | $fieldname.value $time |
||
| 106 | END |
||
| 107 | } |
||
| 108 | } |
||
| 109 | } |
||
| 110 | |||
| 111 | sub slurp {
|
||
| 112 | do {
|
||
| 113 | local (@ARGV, $/) = shift; |
||
| 114 | scalar <>; |
||
| 115 | }; |
||
| 116 | } |
||
| 117 | |||
| 118 | sub parse_plugin_time |
||
| 119 | {
|
||
| 120 | my ($file) = @_; |
||
| 121 | |||
| 122 | my $cont = slurp($file); |
||
| 123 | |||
| 124 | my @plugins; |
||
| 125 | while ($cont =~ /^ (?<time>[\d.]+) \s+ (?<plugin>.*) $/mgx) {
|
||
| 126 | push @plugins => [ $+{time} => $+{plugin} ];
|
||
| 127 | } |
||
| 128 | |||
| 129 | # Sort by size |
||
| 130 | @plugins = sort { $b->[0] <=> $a->[0] } @plugins;
|
||
| 131 | |||
| 132 | @plugins; |
||
| 133 | } |
||
| 134 | |||
| 135 | sub plugin_names {
|
||
| 136 | map { basename $_ } grep { -x } glob "/etc/munin/plugins/*";
|
||
| 137 | } |
||
| 138 | |||
| 139 | sub plugin_times {
|
||
| 140 | my (@p) = @_; |
||
| 141 | my %time; |
||
| 142 | |||
| 143 | my $dir = tempdir("munin-stats-plugins-XXXX", CLEANUP => 1, TMPDIR => 1);
|
||
| 144 | |||
| 145 | for my $plugin (@p) {
|
||
| 146 | my ($fh, $file) = tempfile(DIR => $dir); |
||
| 147 | my $t0 = [gettimeofday]; |
||
| 148 | if (system qq[MUNIN_STATS_PLUGINS_RELOAD=0 munin-run "$plugin" >"$file" 2>&1]) {
|
||
| 149 | my $cont = slurp($file); |
||
| 150 | die "munin-run: Failed to run plugin $plugin: $?, output: $cont"; |
||
| 151 | } |
||
| 152 | my $t1 = [gettimeofday]; |
||
| 153 | |||
| 154 | my $elapsed = tv_interval($t0, $t1); |
||
| 155 | $time{$plugin} = sprintf "%0.2f", $elapsed;
|
||
| 156 | } |
||
| 157 | |||
| 158 | return \%time; |
||
| 159 | } |
||
| 160 | |||
| 161 | sub write_plugin_times {
|
||
| 162 | my ($tmp, $real, $time) = @_; |
||
| 163 | |||
| 164 | # Write out the runtimes to a tempfile |
||
| 165 | open my $fh, ">", $cache_tmp; |
||
| 166 | while (my ($p, $t) = each %$time) {
|
||
| 167 | say $fh "$t $p"; |
||
| 168 | } |
||
| 169 | close $fh; |
||
| 170 | |||
| 171 | # Rename the temp to the real thing. If we wrote it to begin |
||
| 172 | # with we might have a race condition. |
||
| 173 | rename $cache_tmp, $cache; |
||
| 174 | } |
