Merge branch 'mg/jitter'
[collectd.git] / contrib / collection3 / bin / graph.cgi
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5 use lib ('../lib');
6 use utf8;
7
8 use FindBin ('$RealBin');
9 use Carp (qw(confess cluck));
10 use CGI (':cgi');
11 use RRDs ();
12
13 use Collectd::Graph::Config (qw(gc_read_config gc_get_scalar));
14 use Collectd::Graph::TypeLoader (qw(tl_load_type));
15
16 use Collectd::Graph::Common (qw(sanitize_type get_selected_files
17       epoch_to_rfc1123 flush_files));
18 use Collectd::Graph::Type ();
19
20 our $Debug = param ('debug');
21 our $Begin = param ('begin');
22 our $End = param ('end');
23 our $GraphWidth = param ('width');
24 our $GraphHeight = param ('height');
25 our $Index = param ('index') || 0;
26 our $OutputFormat = 'PNG';
27 our $ContentType = 'image/png';
28
29 if (param ('format'))
30 {
31   my $temp = param ('format') || '';
32   $temp = uc ($temp);
33
34   if ($temp =~ m/^(PNG|SVG|EPS|PDF)$/)
35   {
36     $OutputFormat = $temp;
37
38     if ($OutputFormat eq 'SVG') { $ContentType = 'image/svg+xml'; }
39     elsif ($OutputFormat eq 'EPS') { $ContentType = 'image/eps'; }
40     elsif ($OutputFormat eq 'PDF') { $ContentType = 'application/pdf'; }
41   }
42 }
43
44 if ($Debug)
45 {
46   print <<HTTP;
47 Content-Type: text/plain
48
49 HTTP
50 }
51
52 gc_read_config ("$RealBin/../etc/collection.conf");
53
54 if ($GraphWidth)
55 {
56   $GraphWidth =~ s/\D//g;
57 }
58
59 if (!$GraphWidth)
60 {
61   $GraphWidth = gc_get_scalar ('GraphWidth', 400);
62 }
63
64 if ($GraphHeight)
65 {
66   $GraphHeight =~ s/\D//g;
67 }
68
69 if (!$GraphHeight)
70 {
71   $GraphHeight = gc_get_scalar ('GraphHeight', 100);
72 }
73
74 { # Sanitize begin and end times
75   $End ||= 0;
76   $Begin ||= 0;
77
78   if ($End =~ m/\D/)
79   {
80     $End = 0;
81   }
82
83   if (!$Begin || !($Begin =~ m/^-?([1-9][0-9]*)$/))
84   {
85     $Begin = -86400;
86   }
87
88   if ($Begin < 0)
89   {
90     if ($End)
91     {
92       $Begin = $End + $Begin;
93     }
94     else
95     {
96       $Begin = time () + $Begin;
97     }
98   }
99
100   if ($Begin < 0)
101   {
102     $Begin = time () - 86400;
103   }
104
105   if (($End > 0) && ($Begin > $End))
106   {
107     my $temp = $End;
108     $End = $Begin;
109     $Begin = $temp;
110   }
111 }
112
113 my $type = param ('type') or die;
114 my $obj;
115
116 $obj = tl_load_type ($type);
117 if (!$obj)
118 {
119   confess ("tl_load_type ($type) failed");
120 }
121
122 $type = ucfirst (lc ($type));
123 $type =~ s/_([A-Za-z])/\U$1\E/g;
124 $type = sanitize_type ($type);
125
126 my $files = get_selected_files ();
127 if ($Debug)
128 {
129   require Data::Dumper;
130   print STDOUT Data::Dumper->Dump ([$files], ['files']);
131 }
132 for (@$files)
133 {
134   $obj->addFiles ($_);
135 }
136
137 my $expires = time ();
138 # IF (End is `now')
139 #    OR (Begin is before `now' AND End is after `now')
140 if (($End == 0) || (($Begin <= $expires) && ($End >= $expires)))
141 {
142   # 400 == width in pixels
143   my $timespan;
144
145   if ($End == 0)
146   {
147     $timespan = $expires - $Begin;
148   }
149   else
150   {
151     $timespan = $End - $Begin;
152   }
153   $expires += int ($timespan / 400.0);
154 }
155 # IF (End is not `now')
156 #    AND (End is before `now')
157 # ==> Graph will never change again!
158 elsif (($End > 0) && ($End < $expires))
159 {
160   $expires += (366 * 86400);
161 }
162 elsif ($Begin > $expires)
163 {
164   $expires = $Begin;
165 }
166
167 # Send FLUSH command to the daemon if necessary and possible.
168 flush_files ($files,
169     begin => $Begin,
170     end => $End,
171     addr => gc_get_scalar ('UnixSockAddr', undef),
172     interval => gc_get_scalar ('Interval', 10));
173
174 print STDOUT header (-Content_type => $ContentType,
175   -Last_Modified => epoch_to_rfc1123 ($obj->getLastModified ()),
176   -Expires => epoch_to_rfc1123 ($expires));
177
178 if ($Debug)
179 {
180   print "\$expires = $expires;\n";
181 }
182
183 my $args = $obj->getRRDArgs (0 + $Index);
184
185 if ($Debug)
186 {
187   require Data::Dumper;
188   print STDOUT Data::Dumper->Dump ([$obj], ['obj']);
189   print STDOUT join (",\n", @$args) . "\n";
190   print STDOUT "Last-Modified: " . epoch_to_rfc1123 ($obj->getLastModified ()) . "\n";
191 }
192 else
193 {
194   my @timesel = ();
195
196   if ($End) # $Begin is always true
197   {
198     @timesel = ('-s', $Begin, '-e', $End);
199   }
200   else
201   {
202     @timesel = ('-s', $Begin); # End is implicitely `now'.
203   }
204
205   $| = 1;
206   RRDs::graph ('-', '-a', $OutputFormat, '--width', $GraphWidth, '--height', $GraphHeight, @timesel, @$args);
207   if (my $err = RRDs::error ())
208   {
209     print STDERR "RRDs::graph failed: $err\n";
210     exit (1);
211   }
212 }
213
214 exit (0);
215
216 # vim: set shiftwidth=2 softtabstop=2 tabstop=8 :