chiark / gitweb /
navbar things
[rrd-graphs.git] / cgi
1 #!/usr/bin/perl -w
2
3 use strict qw(vars);
4 use CGI qw/:standard/;
5
6 sub fail ($) {
7     print(header(-status=>500),
8           start_html('Error'),
9           h1('Error'),
10           escapeHTML($_[0]),
11           end_html());
12     exit 0;
13 }
14
15 our $R= '/var/lib/collectd/rrd/chiark.greenend.org.uk';
16
17 my $self= url(-relative=>1);
18
19 our (@sections, %sections, %graphs);
20
21 our @timeranges= (3600, map { $_*86400 } qw(1 7 28), 13*7+1);
22
23 sub graph ($$$$) {
24     my ($section, $gname, $basis, $args) = @_;
25     $basis->{Args}= $args;
26     $basis->{Slower}= 0 unless exists $basis->{Slower};
27     $graphs{$section,$gname}= $basis;
28     if (!exists $sections{$section}) {
29         push @sections, $section;
30     }
31     push @{ $sections{$section} }, $gname;
32 }
33
34 graph('General', 'Load', { },
35       [
36        "DEF:load=$R/load/load.rrd:shortterm:AVERAGE",
37        (map { "DEF:$_=$R/processes/ps_state-$_.rrd:value:AVERAGE" }
38             qw(blocked running stopped paging sleeping zombies)),
39        "AREA:running#88f:running processes:STACK",
40        "AREA:blocked#8f8:blocked processes:STACK",
41        "AREA:paging#f88:paging processes:STACK",
42        "LINE:load#000:load",
43        ]);
44
45 graph('General', 'Processes', { },
46       [
47        (map { "DEF:$_=$R/processes/ps_state-$_.rrd:value:AVERAGE" }
48             qw(blocked running stopped paging sleeping zombies)),
49        "CDEF:busy=0".(join '', map { ",$_,+" } qw(running blocked paging)),
50        "AREA:sleeping#ccc:sleeping:STACK",
51        "AREA:stopped#f00:stopped:STACK",
52        "AREA:zombies#0f0:zombie:STACK",
53        "AREA:busy#f00:busy:STACK",
54        ]);
55
56 graph('General', 'CPU', { Units => '[%]' },
57       [
58        (map {
59            my $thing= $_;
60            (map { "DEF:$thing$_=$R/cpu-$_/cpu-$thing.rrd:value:AVERAGE" }
61                 (0..7)),
62            "CDEF:$thing=0".join('', map { ",$thing$_,+" } (0..7)).",8.0,/";
63        } qw(idle interrupt nice softirq steal system user wait)),
64        "AREA:system#00f:system:STACK",
65        "AREA:wait#f88:wait:STACK",
66        "AREA:nice#ccc:nice:STACK",
67        "AREA:user#080:user:STACK",
68        "AREA:softirq#f0f:softirq:STACK",
69        "AREA:interrupt#ff0:interrupt:STACK",
70        "AREA:steal#0ff:steal:STACK",
71        ]);
72
73 foreach my $src (<$R/df/df-*.rrd>) {
74     my $vol= $src;
75     $vol =~ s,.*/,,;
76     $vol =~ s,^df-,,;
77     $vol =~ s,\.rrd$,,;
78     graph('Disk space', $vol, {
79              Slower => 1,
80           },
81           [
82            qw(-b 1024 -l 0),
83            (map { "DEF:$_=$src:$_:AVERAGE" } qw(free used)),
84            "AREA:used#000:used:STACK",
85            "AREA:free#88f:free:STACK",
86            ]);
87 }
88
89 if (param('debug')) {
90     print "Content-Type: text/plain\n\n";
91 }
92
93 our @navsettings;
94
95 sub navsetting ($) {
96     my ($nav) = @_;
97     my $var= $nav->{Variable};
98     $$var= param($nav->{Param});
99     $$var= $nav->{Default} if !defined $$var;
100     die $nav->{Param} unless grep { $_ eq $$var } @{ $nav->{Values} };
101     push @navsettings, $nav;
102 }
103
104 our $section;
105
106 navsetting({
107     Desc => 'Section',
108     Param => 'section',
109     Variable => \$section,
110     Default => $sections[0],
111     Values => [@sections],
112     Show => sub { return $_[0]; }
113 });
114
115
116 my $gname= param('graph');
117
118 if ($gname) {
119     my $g= $graphs{$section,$gname};
120     die unless $g;
121
122     my @args= @{ $g->{Args} };
123
124     my $end= param('end');
125     if (defined $end) {
126         $end =~ m/^(\d+)$/ or die;
127         unshift @args, qw(--end now --start), "end-${end}s";
128     }
129     if (param('debug')) {
130         print((join "\n",@args),"\n"); exit 0;
131     }
132     print "Content-Type: image/png\n\n";
133
134     my $title= $gname;
135     $title .= " $g->{Units}" if $g->{Units};
136     unshift @args, '-t', $title;
137     
138     exec qw(rrdtool graph - -a PNG --full-size-mode -w 370 -h 200), @args;
139     die $!;
140 }
141
142 sub start_page ($) {
143     my ($title) = @_;
144     print header(), start_html($title);
145     my $outerdelim= '';
146     foreach my $nav (@navsettings) {
147         print $outerdelim;
148         print $nav->{Desc}, ": ";
149         my $delim= '';
150         my $current= $nav->{Variable};  $current= $$current;
151         foreach my $couldbe (@{ $nav->{Values} }) {
152             print $delim;
153             my $show= $nav->{Show}($couldbe);
154             if ($couldbe eq $current) {
155                 print "<b>$show</b>";
156             } else {
157                 print "<a href=\"$self";
158                 my $delim2= '?';
159                 foreach my $nav2 (@navsettings) {
160                     my $current2= $nav2->{Variable};  $current2= $$current2;
161                     $current2= $couldbe if $nav2->{Param} eq $nav->{Param};
162                     next if $current2 eq $nav2->{Default};
163                     print $delim2, "$nav2->{Param}=$current2";
164                     $delim2= '&';
165                 }
166                 print "\">$show</a>";
167             }
168             $delim= ' | ';
169         }
170         $outerdelim= "<br>\n";
171     }
172     print "\n";
173
174     print h1("$title");
175 }
176
177 my $detail= param('detail');
178 if ($detail) {
179     my $g= $graphs{$section,$detail};
180     die unless $g;
181     start_page("$detail graphs");
182     foreach my $end (@timeranges[$g->{Slower}..$g->{Slower}+3]) {
183         print "<img src=\"$self?graph=$detail&section=$section&end=$end\">\n";
184     }
185     print end_html();
186     exit 0;
187 }
188
189 our $sloth;
190
191 navsetting({
192     Desc => 'Time interval',
193     Param => 'sloth',
194     Variable => \$sloth,
195     Default => 1,
196     Values => [0..2],
197     Show => sub {
198         my ($sl) = @_;
199         return ('Narrower', 'Normal', 'Wider')[$sl];
200     }
201 });
202
203 if (param('debug')) {
204     use Data::Dumper;
205     print Dumper(\%graphs);
206     exit 0;
207 }
208
209 start_page("$section graphs");
210
211 foreach my $gname (@{ $sections{$section} }) {
212     my $g= $graphs{$section,$gname};
213     print "<a href=\"$self?detail=$gname&section=$section\">";
214     my $end= $timeranges[$g->{Slower}+$sloth];
215     my $imgurl= "$self?graph=$gname&section=$section&end=$end";
216     print "<img src=\"$imgurl\"></a>\n";
217 }
218