ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/experimental/reports/graphing/graph.pl
Revision: 1.7
Committed: Wed Mar 13 20:50:48 2002 UTC (22 years, 2 months ago) by tdb
Content type: text/plain
Branch: MAIN
Changes since 1.6: +4 -1 lines
Log Message:
Added a graph of "the last year". Also fixed a minor bug with the script to
create the rrd's. As an aside, I've noticed the grid on the graphs seems to
differ between the different graphs. I'm sure this is because I've got some
of my numbers a bit silly ;) oh well :)

File Contents

# User Rev Content
1 tdb 1.1 #!/usr/bin/perl -w
2    
3     # -----------------------------------------------------------
4     # i-scream graph generation script
5     # http://www.i-scream.org.uk
6     #
7     # Generates graphs from rrd databases for i-scream data.
8     #
9 tdb 1.4 # $Author: tdb $
10 tdb 1.7 # $Id: graph.pl,v 1.6 2002/03/11 17:06:45 tdb Exp $
11 tdb 1.1 #------------------------------------------------------------
12    
13     ## TODO
14     # possibly make more configurable?
15     # -- allow configurable periods of graphs
16     # -- comments, types, etc
17     # -- move all to external config file
18    
19     $| = 1;
20     use strict;
21     use RRDs;
22    
23     # Base directory for images
24     # (a directory will be constructed for each host under this)
25     my($imgdir) = "/home/tdb/public_html/rrd";
26    
27     # Location of RRD databases
28     my($rrddir) = "/u1/i-scream/rrd";
29    
30     # / converted to a decimal then hex'd
31     my($hex_slash) = "_2f";
32     # _ converted to a decimal then hex'd
33     my($hex_underscore) = "_5f";
34    
35     # Read the contents of the base directory
36     # and pull out the list of subdirectories (except . and .. :)
37     opendir(DIR, $rrddir);
38     my(@rrddirlist) = grep { -d "$rrddir/$_" && !/^\.$/ && !/^\.\.$/ } readdir(DIR);
39     closedir DIR;
40    
41     # look through each directoty, as they might
42     # contain rrds for a particular machine
43     foreach my $machine (@rrddirlist) {
44     # Read the contents of the directory
45     opendir(DIR, "$rrddir/$machine");
46     my(@rrdlist) = grep { /\.rrd$/ && -f "$rrddir/$machine/$_" } readdir(DIR);
47     closedir DIR;
48    
49     # See what rrd we have, and generate the graphs accordingly
50     foreach my $rrd (@rrdlist) {
51     chomp $rrd;
52     if($rrd =~ /^(cpu)\.rrd$/) {
53     my(@data);
54 tdb 1.5 my(@rawdata);
55 tdb 1.3 push @data, "LINE2:$1:idle:idle#00FF00:idle cpu";
56     push @data, "LINE2:$1:user:user#0000FF:user cpu";
57     push @data, "LINE2:$1:kernel:kernel#00FFFF:kernel cpu";
58     push @data, "LINE2:$1:swap:swap#FF00FF:swap cpu";
59     push @data, "LINE2:$1:iowait:iowait#FF0000:iowait cpu";
60 tdb 1.5 push @rawdata, "--upper-limit=100";
61     &makegraph($machine, $1, "CPU Usage for $machine", \@data, \@rawdata);
62 tdb 1.1 }
63     if($rrd =~ /^(mem)\.rrd$/) {
64     my(@data);
65 tdb 1.5 my(@rawdata);
66 tdb 1.6 # we don't actually want to display free memory,
67     # although we need it to do inuse...
68     push @data, "NONE:$1:free:free#CCCCFF:free memory";
69 tdb 1.3 push @data, "LINE2:$1:total:total#0000FF:total memory";
70 tdb 1.6 # calculate inuse
71     push @rawdata, "CDEF:inuse=total,free,-";
72     # and add it to the graph
73     push @rawdata, "AREA:inuse#CCCCFF:memory in use";
74 tdb 1.5 push @rawdata, "--base=1024";
75     &makegraph($machine, $1, "Memory Usage for $machine", \@data, \@rawdata);
76 tdb 1.1 }
77     if($rrd =~ /^(load)\.rrd$/) {
78     my(@data);
79 tdb 1.5 push @data, "LINE2:$1:load1:load1#CCCCFF:1 minute load average";
80     push @data, "LINE2:$1:load5:load5#7777FF:5 minute load average";
81     push @data, "LINE2:$1:load15:load15#0000FF:15 minute load average";
82 tdb 1.1 &makegraph($machine, $1, "Loads for $machine", \@data);
83     }
84     if($rrd =~ /^(proc)\.rrd$/) {
85     my(@data);
86 tdb 1.3 push @data, "LINE2:$1:cpu:cpu#00FF00:cpu processes";
87     push @data, "LINE2:$1:sleeping:sleeping#0000FF:sleeping processes";
88     push @data, "LINE2:$1:stopped:stopped#00FFFF:stopped processes";
89     push @data, "LINE2:$1:total:total#FF00FF:total processes";
90     push @data, "LINE2:$1:zombie:zombie#FF0000:zombie processes";
91 tdb 1.1 &makegraph($machine, $1, "Processes on $machine", \@data);
92     }
93     if($rrd =~ /^(swap)\.rrd$/) {
94     my(@data);
95 tdb 1.5 my(@rawdata);
96 tdb 1.6 # we don't actually want to display free swap,
97     # although we need it to do inuse...
98     push @data, "NONE:$1:free:free#CCCCFF:free swap";
99 tdb 1.3 push @data, "LINE2:$1:total:total#0000FF:total swap";
100 tdb 1.6 # calculate inuse
101     push @rawdata, "CDEF:inuse=total,free,-";
102     # and add it to the graph
103     push @rawdata, "AREA:inuse#CCCCFF:swap in use";
104 tdb 1.5 push @rawdata, "--base=1024";
105     &makegraph($machine, $1, "Swap Usage for $machine", \@data, \@rawdata);
106 tdb 1.1 }
107     if($rrd =~ /^(users)\.rrd$/) {
108     my(@data);
109 tdb 1.5 push @data, "AREA:$1:count:count#CCCCFF:user count";
110 tdb 1.1 &makegraph($machine, $1, "User Count for $machine", \@data);
111     }
112     if($rrd =~ /^(disk)-(\S+).rrd$/) {
113     my(@data);
114 tdb 1.5 my(@rawdata);
115 tdb 1.3 push @data, "LINE2:$1-$2:kbytes:kbytes#0000FF:total size";
116 tdb 1.5 push @data, "AREA:$1-$2:used:used#CCCCFF:used";
117     push @rawdata, "--base=1024";
118 tdb 1.1 my($type) = $1;
119     my($name) = $2;
120     my($nicename) = $2;
121     $nicename =~ s/$hex_slash/\//g;
122     $nicename =~ s/$hex_underscore/_/g;
123 tdb 1.5 &makegraph($machine, "$type-$name", "Disk Usage for $machine on $nicename", \@data, \@rawdata);
124 tdb 1.1 }
125     # probably a queue with a name like this :)
126     if($rrd =~ /^(\d+)_0\.rrd$/) {
127     my(@data);
128     my(@rawdata);
129     my($baserrd) = $1;
130     my($i) = 0;
131     while( -f "$rrddir/$machine/$baserrd\_$i.rrd" ) {
132 tdb 1.3 push @data, "LINE2:$baserrd\_$i:size:size$i" . &get_colour($i) . ":queue$i size ";
133 tdb 1.1 ++$i;
134     }
135 tdb 1.3 push @data, "LINE2:$baserrd\_0:total:total#FF0000:packets/sec - currently";
136 tdb 1.2 push @rawdata, "GPRINT:total:LAST:%lf %spackets/sec";
137 tdb 1.1 my($comment);
138     if(-f "$rrddir/$machine/$baserrd.def") {
139     open(DEF, "$rrddir/$machine/$baserrd.def");
140     $comment = <DEF>;
141     chomp $comment if defined $comment;
142     }
143     $comment = "unknown queue" if not defined $comment;
144     &makegraph($machine, $baserrd, $comment, \@data, \@rawdata);
145     }
146     }
147     }
148    
149     #
150     # subroutine to make some graphs
151     #
152     # $machine = name of the machine
153     # (eg. kernow.ukc.ac.uk)
154     # $type = the type of graph for the machine
155     # (eg. cpu)
156     # $title = the title for the graph
157     # (eg. kernow CPU usage)
158     # $dataref = a reference to an array containing information for the graph
159 tdb 1.3 # elements of format: "gtype:rrdname:dsname:name#colour:comment with spaces"
160 tdb 1.6 # (if gtype is "NONE" only a DEF of 'name' will be defined, no line will be plotted)
161 tdb 1.1 # $rawcmdref = a reference to an array containing raw rrd commands
162     # elements a single command each, no spaces
163     #
164 tdb 1.2
165 tdb 1.1 sub makegraph() {
166     my($machine, $type, $title, $dataref, $rawcmdref) = @_;
167     # pass in these arrays by reference
168     my(@data) = @$dataref if defined $dataref;
169     my(@rawcmd) = @$rawcmdref if defined $rawcmdref;
170     # check if directory exists for images
171     if(! -d "$imgdir/$machine") {
172     # not sure on this umask, but it seems to work?
173     mkdir "$imgdir/$machine", 0777;
174     }
175     my(@rrdcmd);
176     foreach my $dataitem (@data) {
177 tdb 1.3 # dataitem should be: "gtype:rrdname:dsname:name#colour:comment with spaces"
178 tdb 1.6 # (if gtype is "NONE" only a DEF of 'name' will be defined, no line will be plotted)
179 tdb 1.3 if($dataitem =~ /^(\S+):(\S+):(\S+):(\S+)#(.{6}):(.*)$/) {
180 tdb 1.6 push @rrdcmd, "DEF:$4=$rrddir/$machine/$2.rrd:$3:AVERAGE";
181     if($1 ne "NONE") {
182     push @rrdcmd, "$1:$4#$5:$6";
183     }
184 tdb 1.1 }
185     }
186     push @rrdcmd, "--title=$title";
187     push @rrdcmd, "--imgformat=PNG";
188     push @rrdcmd, "--lower-limit=0";
189 tdb 1.5 # not entirely convinced this is good...
190     push @rrdcmd, "--alt-autoscale-max";
191 tdb 1.1 # add any further raw commands
192     push @rrdcmd, @rawcmd;
193     RRDs::graph ("$imgdir/$machine/$type-3h.png", "--start=-10800", @rrdcmd);
194     my($err_3h) = RRDs::error;
195 tdb 1.2 print STDERR "Error generating 3h graph for $machine/$type: $err_3h\n" if $err_3h;
196 tdb 1.1 RRDs::graph ("$imgdir/$machine/$type-1d.png", "--start=-86400", @rrdcmd);
197     my($err_1d) = RRDs::error;
198 tdb 1.2 print STDERR "Error generating 1d graph for $machine/$type: $err_1d\n" if $err_1d;
199 tdb 1.1 RRDs::graph ("$imgdir/$machine/$type-1w.png", "--start=-604800", @rrdcmd);
200     my($err_1w) = RRDs::error;
201 tdb 1.2 print STDERR "Error generating 1w graph for $machine/$type: $err_1w\n" if $err_1w;
202 tdb 1.1 RRDs::graph ("$imgdir/$machine/$type-1m.png", "--start=-2678400", @rrdcmd);
203     my($err_1m) = RRDs::error;
204 tdb 1.2 print STDERR "Error generating 1m graph for $machine/$type: $err_1m\n" if $err_1m;
205 tdb 1.7 RRDs::graph ("$imgdir/$machine/$type-1y.png", "--start=-31536000", @rrdcmd);
206     my($err_1y) = RRDs::error;
207     print STDERR "Error generating 1y graph for $machine/$type: $err_1y\n" if $err_1y;
208 tdb 1.1 return;
209     }
210    
211     # hacky subroutine to return a colour
212     # could be done much better somehow :/
213     sub get_colour {
214     my($col) = @_;
215     if($col == 0) {
216     return "#0000FF";
217     }
218     elsif($col == 1) {
219     return "#00FF00";
220     }
221     elsif($col == 2) {
222     return "#FF00FF";
223     }
224     elsif($col == 3) {
225     return "#FFFF00";
226     }
227     elsif($col == 4) {
228     return "#00FFFF";
229     }
230     else {
231     return "#000066";
232     }
233     }