mirror of
https://github.com/ntop/ntopng.git
synced 2026-07-28 09:08:08 +00:00
1211 lines
51 KiB
Text
1211 lines
51 KiB
Text
=for changes please consult me first. Thanks, Alex
|
|
|
|
=head1 NAME
|
|
|
|
rrdtutorial - Alex van den Bogaerdt's RRDtool tutorial
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
RRDtool is written by Tobias Oetiker E<lt>tobi@oetiker.chE<gt> with
|
|
contributions from many people all around the world. This document is
|
|
written by Alex van den Bogaerdt E<lt>alex@vandenbogaerdt.nlE<gt> to help you
|
|
understand what RRDtool is and what it can do for you.
|
|
|
|
The documentation provided with RRDtool can be too technical for some
|
|
people. This tutorial is here to help you understand the basics of
|
|
RRDtool. It should prepare you to read the documentation yourself.
|
|
It also explains the general things about statistics with a focus on
|
|
networking.
|
|
|
|
=head1 TUTORIAL
|
|
|
|
=head2 Important
|
|
|
|
Please don't skip ahead in this document! The first part of this
|
|
document explains the basics and may be boring. But if you don't
|
|
understand the basics, the examples will not be as meaningful to you.
|
|
|
|
Sometimes things change. This example used to provide numbers like
|
|
"0.04" in stead of "4.00000e-02". Those are really the same numbers,
|
|
just written down differently. Don't be alarmed if a future version
|
|
of rrdtool displays a slightly different form of output. The examples
|
|
in this document are correct for version 1.2.0 of RRDtool.
|
|
|
|
Also, sometimes bugs do occur. They may also influence the outcome of
|
|
the examples. Example speed4.png was suffering from this (the handling
|
|
of unknown data in an if-statement was wrong). Normal data will be
|
|
just fine (a bug in rrdtool wouldn't last long) but special cases like
|
|
NaN, INF and so on may last a bit longer. Try another version if you
|
|
can, or just live with it.
|
|
|
|
I fixed the speed4.png example (and added a note). There may be other
|
|
examples which suffer from the same or a similar bug. Try to fix it
|
|
yourself, which is a great excercise. But please do not submit your
|
|
result as a fix to the source of this document. Discuss it on the
|
|
user's list, or write to me.
|
|
|
|
=head2 What is RRDtool?
|
|
|
|
RRDtool refers to Round Robin Database tool.
|
|
Round robin is a technique that works with a fixed amount of data, and a
|
|
pointer to the current element. Think of a circle with some dots plotted
|
|
on the edge. These dots are the places where data can be stored. Draw an
|
|
arrow from the center of the circle to one of the dots; this is the pointer.
|
|
When the current data is read or written, the pointer moves to the next
|
|
element. As we are on a circle there is neither a beginning nor an end, you can
|
|
go on and on and on. After a while, all the available places will be used and
|
|
the process automatically reuses old locations. This way, the dataset
|
|
will not grow in size and therefore requires no maintenance.
|
|
RRDtool works with Round Robin Databases (RRDs). It stores and retrieves
|
|
data from them.
|
|
|
|
=head2 What data can be put into an RRD?
|
|
|
|
You name it, it will probably fit as long as it is some sort of
|
|
time-series data. This means you have to be able to measure some value
|
|
at several points in time and provide this information to RRDtool. If
|
|
you can do this, RRDtool will be able to store it. The values must be
|
|
numerical but don't have to be integers, as is the case with MRTG (the
|
|
next section will give more details on this more specialized application).
|
|
|
|
Many examples below talk about SNMP which is an acronym for Simple Network
|
|
Management Protocol. "Simple" refers to the protocol. It does not
|
|
mean it is simple to manage or monitor a network. After working your
|
|
way through this document, you should know enough to be able to
|
|
understand what people are talking about. For now, just realize that
|
|
SNMP can be used to query devices for the values of counters they keep. It
|
|
is the value from those counters that we want to store in the RRD.
|
|
|
|
=head2 What can I do with this tool?
|
|
|
|
RRDtool originated from MRTG (Multi Router Traffic Grapher). MRTG
|
|
started as a tiny little script for graphing the use of a university's
|
|
connection to the Internet. MRTG was later (ab-)used as a tool for
|
|
graphing other data sources including temperature, speed, voltage,
|
|
number of printouts and the like.
|
|
|
|
Most likely you will start to use RRDtool to store and process data
|
|
collected via SNMP. The data will most likely be bytes (or bits)
|
|
transferred from and to a network or a computer. But it can also be
|
|
used to display tidal waves, solar radiation, power consumption,
|
|
number of visitors at an exhibition, noise levels near an airport,
|
|
temperature on your favorite holiday location, temperature in the
|
|
fridge and whatever your imagination can come up with.
|
|
|
|
You only need a sensor to measure the data and be able to feed the
|
|
numbers into RRDtool. RRDtool then lets you create a database, store
|
|
data in it, retrieve that data and create graphs in PNG format for
|
|
display on a web browser. Those PNG images are dependent on the data
|
|
you collected and could be, for instance, an overview of the average
|
|
network usage, or the peaks that occurred.
|
|
|
|
=head2 What if I still have problems after reading this document?
|
|
|
|
First of all: read it again! You may have missed something.
|
|
If you are unable to compile the sources and you have a fairly common
|
|
OS, it will probably not be the fault of RRDtool. There may be pre-compiled
|
|
versions around on the Internet. If they come from trusted sources, get
|
|
one of those.
|
|
|
|
If on the other hand the program works but does not give you the
|
|
expected results, it will be a problem with configuring it. Review
|
|
your configuration and compare it with the examples that follow.
|
|
|
|
There is a mailing list and an archive of it. Read the list for a few
|
|
weeks and search the archive. It is considered rude to just ask
|
|
a question without searching the archives: your problem may already have been
|
|
solved for somebody else! This is true for most, if not all, mailing lists
|
|
and not only for this particular one. Look in the documentation that
|
|
came with RRDtool for the location and usage of the list.
|
|
|
|
I suggest you take a moment to subscribe to the mailing list right now
|
|
by sending an email to E<lt>rrd-users-request@lists.oetiker.chE<gt> with a
|
|
subject of "subscribe". If you ever want to leave this list, just write
|
|
an email to the same address but now with a subject of "unsubscribe".
|
|
|
|
=head2 How will you help me?
|
|
|
|
By giving you some detailed descriptions with detailed examples.
|
|
I assume that following the instructions in the order presented
|
|
will give you enough knowledge of RRDtool to experiment for yourself.
|
|
If it doesn't work the first time, don't give up. Reread the stuff that
|
|
you did understand, you may have missed something.
|
|
|
|
By following the examples you get some hands-on experience and, even
|
|
more important, some background information of how it works.
|
|
|
|
You will need to know something about hexadecimal numbers. If you don't
|
|
then start with reading L<bin_dec_hex> before you continue here.
|
|
|
|
=head2 Your first Round Robin Database
|
|
|
|
In my opinion the best way to learn something is to actually do it.
|
|
Why not start right now? We will create a database, put some values
|
|
in it and extract this data again. Your output should be the same
|
|
as the output that is included in this document.
|
|
|
|
We will start with some easy stuff and compare a car with a router,
|
|
or compare kilometers (miles if you wish) with bits and bytes. It's
|
|
all the same: some number over some time.
|
|
|
|
Assume we have a device that transfers bytes to and from the Internet.
|
|
This device keeps a counter that starts at zero when it is turned on,
|
|
increasing with every byte that is transferred. This counter will probably have
|
|
a maximum value. If this value is reached and an extra byte is counted,
|
|
the counter starts over at zero. This is the same as many counters
|
|
in the world such as the mileage counter in a car.
|
|
|
|
Most discussions about networking talk about bits per second so lets
|
|
get used to that right away. Assume a byte is eight bits and start to
|
|
think in bits not bytes. The counter, however, still counts bytes!
|
|
In the SNMP world most of the counters are 32 bits. That means they are
|
|
counting from 0 to 4294967295. We will use these values in the examples.
|
|
The device, when asked, returns the current value of the counter. We
|
|
know the time that has passes since we last asked so we now know how
|
|
many bytes have been transferred ***on average*** per second. This is
|
|
not very hard to calculate. First in words, then in calculations:
|
|
|
|
=over 3
|
|
|
|
=item 1.
|
|
|
|
Take the current counter, subtract the previous value from it.
|
|
|
|
=item 2.
|
|
|
|
Do the same with the current time and the previous time (in seconds).
|
|
|
|
=item 3.
|
|
|
|
Divide the outcome of (1) by the outcome of (2), the result is
|
|
the amount of bytes per second. Multiply by eight to get the
|
|
number of bits per second (bps).
|
|
|
|
=back
|
|
|
|
bps = (counter_now - counter_before) / (time_now - time_before) * 8
|
|
|
|
For some people it may help to translate this to an automobile example.
|
|
Do not try this example, and if you do, don't blame me for the results!
|
|
|
|
People who are not used to think in kilometers per hour can translate
|
|
most into miles per hour by dividing km by 1.6 (close enough).
|
|
I will use the following abbreviations:
|
|
|
|
m: meter
|
|
km: kilometer (= 1000 meters).
|
|
h: hour
|
|
s: second
|
|
km/h: kilometers per hour
|
|
m/s: meters per second
|
|
|
|
You are driving a car. At 12:05 you read the counter in the dashboard
|
|
and it tells you that the car has moved 12345 km until that moment.
|
|
At 12:10 you look again, it reads 12357 km. This means you have
|
|
traveled 12 km in five minutes. A scientist would translate that
|
|
into meters per second and this makes a nice comparison toward the
|
|
problem of (bytes per five minutes) versus (bits per second).
|
|
|
|
We traveled 12 kilometers which is 12000 meters. We did that in five
|
|
minutes or 300 seconds. Our speed is 12000m / 300s or 40 m/s.
|
|
|
|
We could also calculate the speed in km/h: 12 times 5 minutes
|
|
is an hour, so we have to multiply 12 km by 12 to get 144 km/h.
|
|
For our native English speaking friends: that's 90 mph so don't
|
|
try this example at home or where I live :)
|
|
|
|
Remember: these numbers are averages only. There is no way to figure out
|
|
from the numbers, if you drove at a constant speed. There is an example
|
|
later on in this tutorial that explains this.
|
|
|
|
I hope you understand that there is no difference in calculating m/s or
|
|
bps; only the way we collect the data is different. Even the k from kilo
|
|
is the same as in networking terms k also means 1000.
|
|
|
|
We will now create a database where we can keep all these interesting
|
|
numbers. The method used to start the program may differ slightly from
|
|
OS to OS, but I assume you can figure it out if it works different on
|
|
your's. Make sure you do not overwrite any file on your system when
|
|
executing the following command and type the whole line as one long
|
|
line (I had to split it for readability)
|
|
and skip all of the '\' characters.
|
|
|
|
rrdtool create test.rrd \
|
|
--start 920804400 \
|
|
DS:speed:COUNTER:600:U:U \
|
|
RRA:AVERAGE:0.5:1:24 \
|
|
RRA:AVERAGE:0.5:6:10
|
|
|
|
(So enter: C<rrdtool create test.rrd --start 920804400 DS ...>)
|
|
|
|
=head2 What has been created?
|
|
|
|
We created the round robin database called test (test.rrd) which starts at
|
|
noon the day I started writing this document, 7th of March, 1999 (this date
|
|
translates to 920804400 seconds as explained below). Our database holds
|
|
one data source (DS) named "speed" that represents a counter. This counter
|
|
is read every five minutes (this is the default therefore you don't have to
|
|
put C<--step=300>). In the same database two round robin archives (RRAs)
|
|
are kept, one averages the data every time it is read (e.g., there's nothing
|
|
to average) and keeps 24 samples (24 times 5 minutes is 2 hours). The other
|
|
averages 6 values (half hour) and contains 10 such averages (e.g. 5 hours).
|
|
|
|
RRDtool works with special time stamps coming from the UNIX world.
|
|
This time stamp is the number of seconds that passed since January
|
|
1st 1970 UTC. The time stamp value is translated into local time and
|
|
it will therefore look different for different time zones.
|
|
|
|
Chances are that you are not in the same part of the world as I am.
|
|
This means your time zone is different. In all examples where I talk
|
|
about time, the hours may be wrong for you. This has little effect on
|
|
the results of the examples, just correct the hours while reading.
|
|
As an example: where I will see "12:05" the UK folks will see "11:05".
|
|
|
|
We now have to fill our database with some numbers. We'll pretend to
|
|
have read the following numbers:
|
|
|
|
12:05 12345 km
|
|
12:10 12357 km
|
|
12:15 12363 km
|
|
12:20 12363 km
|
|
12:25 12363 km
|
|
12:30 12373 km
|
|
12:35 12383 km
|
|
12:40 12393 km
|
|
12:45 12399 km
|
|
12:50 12405 km
|
|
12:55 12411 km
|
|
13:00 12415 km
|
|
13:05 12420 km
|
|
13:10 12422 km
|
|
13:15 12423 km
|
|
|
|
We fill the database as follows:
|
|
|
|
rrdtool update test.rrd 920804700:12345 920805000:12357 920805300:12363
|
|
rrdtool update test.rrd 920805600:12363 920805900:12363 920806200:12373
|
|
rrdtool update test.rrd 920806500:12383 920806800:12393 920807100:12399
|
|
rrdtool update test.rrd 920807400:12405 920807700:12411 920808000:12415
|
|
rrdtool update test.rrd 920808300:12420 920808600:12422 920808900:12423
|
|
|
|
This reads: update our test database with the following numbers
|
|
|
|
time 920804700, value 12345
|
|
time 920805000, value 12357
|
|
|
|
etcetera.
|
|
|
|
As you can see, it is possible to feed more than one value into the
|
|
database in one command. I had to stop at three for readability but
|
|
the real maximum per line is OS dependent.
|
|
|
|
We can now retrieve the data from our database using "rrdtool fetch":
|
|
|
|
rrdtool fetch test.rrd AVERAGE --start 920804400 --end 920809200
|
|
|
|
It should return the following output:
|
|
|
|
speed
|
|
|
|
920804700: nan
|
|
920805000: 4.0000000000e-02
|
|
920805300: 2.0000000000e-02
|
|
920805600: 0.0000000000e+00
|
|
920805900: 0.0000000000e+00
|
|
920806200: 3.3333333333e-02
|
|
920806500: 3.3333333333e-02
|
|
920806800: 3.3333333333e-02
|
|
920807100: 2.0000000000e-02
|
|
920807400: 2.0000000000e-02
|
|
920807700: 2.0000000000e-02
|
|
920808000: 1.3333333333e-02
|
|
920808300: 1.6666666667e-02
|
|
920808600: 6.6666666667e-03
|
|
920808900: 3.3333333333e-03
|
|
920809200: nan
|
|
920809500: nan
|
|
|
|
Note that you might get more rows than you expect. The reason for this is
|
|
that you ask for a time range that ends on 920809200. The number that is
|
|
written behind 920809200: in the list above covers the time range from
|
|
920808900 to 920809200, EXCLUDING 920809200. Hence to be on the sure side,
|
|
you receive the entry from 920809200 to 920809500 as well since it INCLUDES
|
|
920809200. You may also see "NaN" instead of "nan" this is OS dependent.
|
|
"NaN" stands for "Not A Number". If your OS writes "U" or "UNKN" or
|
|
something similar that's okay. If something else is wrong, it will probably
|
|
be due to an error you made (assuming that my tutorial is correct of course
|
|
:-). In that case: delete the database and try again.
|
|
|
|
|
|
The meaning of the above output will become clear below.
|
|
|
|
=head2 Time to create some graphics
|
|
|
|
Try the following command:
|
|
|
|
rrdtool graph speed.png \
|
|
--start 920804400 --end 920808000 \
|
|
DEF:myspeed=test.rrd:speed:AVERAGE \
|
|
LINE2:myspeed#FF0000
|
|
|
|
This will create speed.png which starts at 12:00 and ends at 13:00.
|
|
There is a definition of a variable called myspeed, using the data from RRA
|
|
"speed" out of database "test.rrd". The line drawn is 2 pixels high
|
|
and represents the variable myspeed. The color is red (specified by
|
|
its rgb-representation, see below).
|
|
|
|
You'll notice that the start of the graph is not at 12:00 but at 12:05.
|
|
This is because we have insufficient data to tell the average before
|
|
that time. This will only happen when you miss some samples, this will
|
|
not happen a lot, hopefully.
|
|
|
|
If this has worked: congratulations! If not, check what went wrong.
|
|
|
|
|
|
The colors are built up from red, green and blue. For each of the
|
|
components, you specify how much to use in hexadecimal where 00 means
|
|
not included and FF means fully included.
|
|
The "color" white is a mixture of red, green and blue: FFFFFF
|
|
The "color" black is all colors off: 000000
|
|
|
|
red #FF0000
|
|
green #00FF00
|
|
blue #0000FF
|
|
magenta #FF00FF (mixed red with blue)
|
|
gray #555555 (one third of all components)
|
|
|
|
Additionally you can (with a recent RRDtool) add an alpha channel
|
|
(transparency). The default will be "FF" which means non-transparent.
|
|
|
|
The PNG you just created can be displayed using your favorite image
|
|
viewer. Web browsers will display the PNG via the URL
|
|
"file:///the/path/to/speed.png"
|
|
|
|
=head2 Graphics with some math
|
|
|
|
When looking at the image, you notice that the horizontal axis is labeled
|
|
12:10, 12:20, 12:30, 12:40 and 12:50. Sometimes a label doesn't fit (12:00
|
|
and 13:00 would be likely candidates) so they are skipped.
|
|
|
|
The vertical axis displays the range we entered. We provided
|
|
kilometers and when divided by 300 seconds, we get very small
|
|
numbers. To be exact, the first value was 12 (12357-12345) and divided
|
|
by 300 this makes 0.04, which is displayed by RRDtool as "40 m"
|
|
meaning "40/1000". The "m" (milli) has nothing to do with meters (also m),
|
|
kilometers or millimeters! RRDtool doesn't know about the physical
|
|
units of our data, it just works with dimensionless numbers.
|
|
|
|
If we had measured our distances in meters, this would have been
|
|
(12357000-12345000)/300 = 12000/300 = 40.
|
|
|
|
As most people have a better feel for numbers in this range, we'll
|
|
correct that. We could recreate our database and store the correct
|
|
data, but there is a better way: we do some calculations while creating
|
|
the png file!
|
|
|
|
rrdtool graph speed2.png \
|
|
--start 920804400 --end 920808000 \
|
|
--vertical-label m/s \
|
|
DEF:myspeed=test.rrd:speed:AVERAGE \
|
|
CDEF:realspeed=myspeed,1000,\* \
|
|
LINE2:realspeed#FF0000
|
|
|
|
Note: I need to escape the multiplication operator * with a backslash.
|
|
If I don't, the operating system may interpret it and use it for file
|
|
name expansion. You could also place the line within quotation marks
|
|
like so:
|
|
|
|
"CDEF:realspeed=myspeed,1000,*" \
|
|
|
|
It boils down to: it is RRDtool which should see *, not your shell.
|
|
And it is your shell interpreting \, not RRDtool. You may need to
|
|
adjust examples accordingly if you happen to use an operating
|
|
system or shell which behaves differently.
|
|
|
|
After viewing this PNG, you notice the "m" (milli) has
|
|
disappeared. This it what the correct result would be. Also, a label
|
|
has been added to the image. Apart from the things mentioned above,
|
|
the PNG should look the same.
|
|
|
|
The calculations are specified in the CDEF part above and are in
|
|
Reverse Polish Notation ("RPN"). What we requested RRDtool to do is:
|
|
"take the data source myspeed and the number 1000; multiply
|
|
those". Don't bother with RPN yet, it will be explained later on in
|
|
more detail. Also, you may want to read my tutorial on CDEFs and Steve
|
|
Rader's tutorial on RPN. But first finish this tutorial.
|
|
|
|
Hang on! If we can multiply values with 1000, it should also be possible
|
|
to display kilometers per hour from the same data!
|
|
|
|
To change a value that is measured in meters per second:
|
|
|
|
Calculate meters per hour: value * 3600
|
|
Calculate kilometers per hour: value / 1000
|
|
Together this makes: value * (3600/1000) or value * 3.6
|
|
|
|
In our example database we made a mistake and we need to compensate for
|
|
this by multiplying with 1000. Applying that correction:
|
|
|
|
value * 3.6 * 1000 == value * 3600
|
|
|
|
Now let's create this PNG, and add some more magic ...
|
|
|
|
rrdtool graph speed3.png \
|
|
--start 920804400 --end 920808000 \
|
|
--vertical-label km/h \
|
|
DEF:myspeed=test.rrd:speed:AVERAGE \
|
|
"CDEF:kmh=myspeed,3600,*" \
|
|
CDEF:fast=kmh,100,GT,kmh,0,IF \
|
|
CDEF:good=kmh,100,GT,0,kmh,IF \
|
|
HRULE:100#0000FF:"Maximum allowed" \
|
|
AREA:good#00FF00:"Good speed" \
|
|
AREA:fast#FF0000:"Too fast"
|
|
|
|
Note: here we use another means to escape the * operator by enclosing
|
|
the whole string in double quotes.
|
|
|
|
This graph looks much better. Speed is shown in km/h and there is even
|
|
an extra line with the maximum allowed speed (on the road I travel
|
|
on). I also changed the colors used to display speed and changed it
|
|
from a line into an area.
|
|
|
|
The calculations are more complex now. For speed measurements within
|
|
the speed limit they are:
|
|
|
|
Check if kmh is greater than 100 ( kmh,100 ) GT
|
|
If so, return 0, else kmh ((( kmh,100 ) GT ), 0, kmh) IF
|
|
|
|
For values above the speed limit:
|
|
|
|
Check if kmh is greater than 100 ( kmh,100 ) GT
|
|
If so, return kmh, else return 0 ((( kmh,100) GT ), kmh, 0) IF
|
|
|
|
=head2 Graphics Magic
|
|
|
|
I like to believe there are virtually no limits to how RRDtool graph
|
|
can manipulate data. I will not explain how it works, but look at the
|
|
following PNG:
|
|
|
|
rrdtool graph speed4.png \
|
|
--start 920804400 --end 920808000 \
|
|
--vertical-label km/h \
|
|
DEF:myspeed=test.rrd:speed:AVERAGE \
|
|
CDEF:nonans=myspeed,UN,0,myspeed,IF \
|
|
CDEF:kmh=nonans,3600,* \
|
|
CDEF:fast=kmh,100,GT,100,0,IF \
|
|
CDEF:over=kmh,100,GT,kmh,100,-,0,IF \
|
|
CDEF:good=kmh,100,GT,0,kmh,IF \
|
|
HRULE:100#0000FF:"Maximum allowed" \
|
|
AREA:good#00FF00:"Good speed" \
|
|
AREA:fast#550000:"Too fast" \
|
|
STACK:over#FF0000:"Over speed"
|
|
|
|
Remember the note in the beginning? I had to remove unknown data from
|
|
this example. The 'nonans' CDEF is new, and the 6th line (which used to
|
|
be the 5th line) used to read 'CDEF:kmh=myspeed,3600,*'
|
|
|
|
Let's create a quick and dirty HTML page to view the three PNGs:
|
|
|
|
<HTML><HEAD><TITLE>Speed</TITLE></HEAD><BODY>
|
|
<IMG src="speed2.png" alt="Speed in meters per second">
|
|
<BR>
|
|
<IMG src="speed3.png" alt="Speed in kilometers per hour">
|
|
<BR>
|
|
<IMG src="speed4.png" alt="Traveled too fast?">
|
|
</BODY></HTML>
|
|
|
|
Name the file "speed.html" or similar, and look at it in your web browser.
|
|
|
|
Now, all you have to do is measure the values regularly and update the
|
|
database. When you want to view the data, recreate the PNGs and make
|
|
sure to refresh them in your browser. (Note: just clicking reload may
|
|
not be enough, especially when proxies are involved. Try shift-reload
|
|
or ctrl-F5).
|
|
|
|
=head2 Updates in Reality
|
|
|
|
We've already used the C<update> command: it took one or more
|
|
parameters in the form of "<time>:<value>". You'll be glad to know
|
|
that you can specify the current time by filling in a "N" as the time.
|
|
Or you could use the "time" function in Perl (the shortest example in
|
|
this tutorial):
|
|
|
|
perl -e 'print time, "\n" '
|
|
|
|
How to run a program on regular intervals is OS specific. But here is
|
|
an example in pseudo code:
|
|
|
|
- Get the value and put it in variable "$speed"
|
|
- rrdtool update speed.rrd N:$speed
|
|
|
|
(do not try this with our test database, we'll use it in further examples)
|
|
|
|
This is all. Run the above script every five minutes. When you need to know
|
|
what the graphs look like, run the examples above. You could put them
|
|
in a script as well. After running that script, view the page
|
|
index.html we created above.
|
|
|
|
=head2 Some words on SNMP
|
|
|
|
I can imagine very few people that will be able to get real data from
|
|
their car every five minutes. All other people will have to settle for
|
|
some other kind of counter. You could measure the number of pages
|
|
printed by a printer, for example, the cups of coffee made by the
|
|
coffee machine, a device that counts the electricity used,
|
|
whatever. Any incrementing counter can be monitored and graphed using
|
|
the stuff you learned so far. Later on we will also be able to monitor
|
|
other types of values like temperature.
|
|
|
|
Many people interested in RRDtool will use the counter that keeps track
|
|
of octets (bytes) transferred by a network device. So let's do just
|
|
that next. We will start with a description of how to collect data.
|
|
|
|
Some people will make a remark that there are tools which can do this data
|
|
collection for you. They are right! However, I feel it is important that
|
|
you understand they are not necessary. When you have to determine why
|
|
things went wrong you need to know how they work.
|
|
|
|
One tool used in the example has been talked about very briefly in the
|
|
beginning of this document, it is called SNMP. It is a way of talking
|
|
to networked equipment. The tool I use below is called "snmpget" and
|
|
this is how it works:
|
|
|
|
snmpget device password OID
|
|
|
|
or
|
|
|
|
snmpget -v[version] -c[password] device OID
|
|
|
|
For device you substitute the name, or the IP address, of your device.
|
|
For password you use the "community read string" as it is called in the
|
|
SNMP world. For some devices the default of "public" might work, however
|
|
this can be disabled, altered or protected for privacy and security
|
|
reasons. Read the documentation that comes with your device or program.
|
|
|
|
Then there is this parameter, called OID, which means "object identifier".
|
|
|
|
When you start to learn about SNMP it looks very confusing. It isn't
|
|
all that difficult when you look at the Management Information Base
|
|
("MIB"). It is an upside-down tree that describes data, with a single node
|
|
as the root and from there a number of branches. These branches end
|
|
up in another node, they branch out, etc. All the branches have a name
|
|
and they form the path that we follow all the way down. The branches
|
|
that we follow are named: iso, org, dod, internet, mgmt and mib-2.
|
|
These names can also be written down as numbers and are 1 3 6 1 2 1.
|
|
|
|
iso.org.dod.internet.mgmt.mib-2 (1.3.6.1.2.1)
|
|
|
|
There is a lot of confusion about the leading dot that some programs
|
|
use. There is *no* leading dot in an OID. However, some programs
|
|
can use the above part of OIDs as a default. To indicate the difference
|
|
between abbreviated OIDs and full OIDs they need a leading dot when
|
|
you specify the complete OID. Often those programs will leave out
|
|
the default portion when returning the data to you. To make things
|
|
worse, they have several default prefixes ...
|
|
|
|
Ok, lets continue to the start of our OID: we had 1.3.6.1.2.1
|
|
From there, we are especially interested in the branch "interfaces"
|
|
which has number 2 (e.g., 1.3.6.1.2.1.2 or 1.3.6.1.2.1.interfaces).
|
|
|
|
First, we have to get some SNMP program. First look if there is a
|
|
pre-compiled package available for your OS. This is the preferred way.
|
|
If not, you will have to get the sources yourself and compile those.
|
|
The Internet is full of sources, programs etc. Find information using
|
|
a search engine or whatever you prefer.
|
|
|
|
Assume you got the program. First try to collect some data that is
|
|
available on most systems. Remember: there is a short name for the
|
|
part of the tree that interests us most in the world we live in!
|
|
|
|
I will give an example which can be used on Fedora Core 3. If it
|
|
doesn't work for you, work your way through the manual of snmp and
|
|
adapt the example to make it work.
|
|
|
|
snmpget -v2c -c public myrouter system.sysDescr.0
|
|
|
|
The device should answer with a description of itself, perhaps an
|
|
empty one. Until you got a valid answer from a device, perhaps using a
|
|
different "password", or a different device, there is no point in
|
|
continuing.
|
|
|
|
snmpget -v2c -c public myrouter interfaces.ifNumber.0
|
|
|
|
Hopefully you get a number as a result, the number of interfaces.
|
|
If so, you can carry on and try a different program called "snmpwalk".
|
|
|
|
snmpwalk -v2c -c public myrouter interfaces.ifTable.ifEntry.ifDescr
|
|
|
|
If it returns with a list of interfaces, you're almost there.
|
|
Here's an example:
|
|
[user@host /home/alex]$ snmpwalk -v2c -c public cisco 2.2.1.2
|
|
|
|
interfaces.ifTable.ifEntry.ifDescr.1 = "BRI0: B-Channel 1"
|
|
interfaces.ifTable.ifEntry.ifDescr.2 = "BRI0: B-Channel 2"
|
|
interfaces.ifTable.ifEntry.ifDescr.3 = "BRI0" Hex: 42 52 49 30
|
|
interfaces.ifTable.ifEntry.ifDescr.4 = "Ethernet0"
|
|
interfaces.ifTable.ifEntry.ifDescr.5 = "Loopback0"
|
|
|
|
On this cisco equipment, I would like to monitor the "Ethernet0"
|
|
interface and from the above output I see that it is number four. I try:
|
|
|
|
[user@host /home/alex]$ snmpget -v2c -c public cisco 2.2.1.10.4 2.2.1.16.4
|
|
|
|
interfaces.ifTable.ifEntry.ifInOctets.4 = 2290729126
|
|
interfaces.ifTable.ifEntry.ifOutOctets.4 = 1256486519
|
|
|
|
So now I have two OIDs to monitor and they are (in full, this time):
|
|
|
|
1.3.6.1.2.1.2.2.1.10
|
|
|
|
and
|
|
|
|
1.3.6.1.2.1.2.2.1.16
|
|
|
|
both with an interface number of 4.
|
|
|
|
Don't get fooled, this wasn't my first try. It took some time for me too
|
|
to understand what all these numbers mean. It does help a lot when they
|
|
get translated into descriptive text... At least, when people are talking
|
|
about MIBs and OIDs you know what it's all about.
|
|
Do not forget the interface number (0 if it is not interface dependent)
|
|
and try snmpwalk if you don't get an answer from snmpget.
|
|
|
|
If you understand the above section and get numbers from your device, continue
|
|
on with this tutorial. If not, then go back and re-read this part.
|
|
|
|
=head2 A Real World Example
|
|
|
|
Let the fun begin. First, create a new database. It contains data from
|
|
two counters, called input and output. The data is put into archives
|
|
that average it. They take 1, 6, 24 or 288 samples at a time.
|
|
They also go into archives that keep the maximum numbers. This will be
|
|
explained later on. The time in-between samples is 300 seconds, a good
|
|
starting point, which is the same as five minutes.
|
|
|
|
1 sample "averaged" stays 1 period of 5 minutes
|
|
6 samples averaged become one average on 30 minutes
|
|
24 samples averaged become one average on 2 hours
|
|
288 samples averaged become one average on 1 day
|
|
|
|
Lets try to be compatible with MRTG which stores about the following
|
|
amount of data:
|
|
|
|
600 5-minute samples: 2 days and 2 hours
|
|
600 30-minute samples: 12.5 days
|
|
600 2-hour samples: 50 days
|
|
732 1-day samples: 732 days
|
|
|
|
These ranges are appended, so the total amount of data stored in the
|
|
database is approximately 797 days. RRDtool stores the data
|
|
differently, it doesn't start the "weekly" archive where the "daily"
|
|
archive stopped. For both archives the most recent data will be near
|
|
"now" and therefore we will need to keep more data than MRTG does!
|
|
|
|
We will need:
|
|
|
|
600 samples of 5 minutes (2 days and 2 hours)
|
|
700 samples of 30 minutes (2 days and 2 hours, plus 12.5 days)
|
|
775 samples of 2 hours (above + 50 days)
|
|
797 samples of 1 day (above + 732 days, rounded up to 797)
|
|
|
|
rrdtool create myrouter.rrd \
|
|
DS:input:COUNTER:600:U:U \
|
|
DS:output:COUNTER:600:U:U \
|
|
RRA:AVERAGE:0.5:1:600 \
|
|
RRA:AVERAGE:0.5:6:700 \
|
|
RRA:AVERAGE:0.5:24:775 \
|
|
RRA:AVERAGE:0.5:288:797 \
|
|
RRA:MAX:0.5:1:600 \
|
|
RRA:MAX:0.5:6:700 \
|
|
RRA:MAX:0.5:24:775 \
|
|
RRA:MAX:0.5:288:797
|
|
|
|
Next thing to do is to collect data and store it. Here is an example.
|
|
It is written partially in pseudo code, you will have to find out what
|
|
to do exactly on your OS to make it work.
|
|
|
|
while not the end of the universe
|
|
do
|
|
get result of
|
|
snmpget router community 2.2.1.10.4
|
|
into variable $in
|
|
get result of
|
|
snmpget router community 2.2.1.16.4
|
|
into variable $out
|
|
|
|
rrdtool update myrouter.rrd N:$in:$out
|
|
|
|
wait for 5 minutes
|
|
done
|
|
|
|
Then, after collecting data for a day, try to create an image using:
|
|
|
|
rrdtool graph myrouter-day.png --start -86400 \
|
|
DEF:inoctets=myrouter.rrd:input:AVERAGE \
|
|
DEF:outoctets=myrouter.rrd:output:AVERAGE \
|
|
AREA:inoctets#00FF00:"In traffic" \
|
|
LINE1:outoctets#0000FF:"Out traffic"
|
|
|
|
This should produce a picture with one day worth of traffic.
|
|
One day is 24 hours of 60 minutes of 60 seconds: 24*60*60=86400, we
|
|
start at now minus 86400 seconds. We define (with DEFs) inoctets and
|
|
outoctets as the average values from the database myrouter.rrd and draw
|
|
an area for the "in" traffic and a line for the "out" traffic.
|
|
|
|
View the image and keep logging data for a few more days.
|
|
If you like, you could try the examples from the test database and
|
|
see if you can get various options and calculations to work.
|
|
|
|
Suggestion: Display in bytes per second and in bits per second. Make
|
|
the Ethernet graphics go red if they are over four megabits per
|
|
second.
|
|
|
|
=head2 Consolidation Functions
|
|
|
|
A few paragraphs back I mentioned the possibility of keeping
|
|
the maximum values instead of the average values. Let's go
|
|
into this a bit more.
|
|
|
|
Recall all the stuff about the speed of the car. Suppose we drove at 144
|
|
km/h during 5 minutes and then were stopped by the police for 25 minutes.
|
|
At the end of the lecture we would take our laptop and create and view the
|
|
image taken from the database. If we look at the second RRA we did
|
|
create, we would have the average from 6 samples. The samples measured
|
|
would be 144+0+0+0+0+0=144, divided by 30 minutes, corrected for the
|
|
error by 1000, translated into km/h, with a result of 24 km/h.
|
|
I would still get a ticket but not for speeding anymore :)
|
|
|
|
Obviously, in this case we shouldn't look at the averages. In some
|
|
cases they are handy. If you want to know how many km you had traveled,
|
|
the averaged picture would be the right one to look at. On the other hand, for
|
|
the speed that we traveled at, the maximum numbers seen is much more
|
|
interesting. Later we will see more types.
|
|
|
|
It is the same for data. If you want to know the amount, look at the
|
|
averages. If you want to know the rate, look at the maximum.
|
|
Over time, they will grow apart more and more. In the last database
|
|
we have created, there are two archives that keep data per day. The
|
|
archive that keeps averages will show low numbers, the archive that
|
|
shows maxima will have higher numbers.
|
|
|
|
For my car this would translate in averages per day of 96/24=4 km/h
|
|
(as I travel about 94 kilometers on a day) during working days, and
|
|
maxima of 120 km/h (my top speed that I reach every day).
|
|
|
|
Big difference. Do not look at the second graph to estimate the
|
|
distances that I travel and do not look at the first graph to
|
|
estimate my speed. This will work if the samples are close together,
|
|
as they are in five minutes, but not if you average.
|
|
|
|
On some days, I go for a long ride. If I go across Europe and travel
|
|
for 12 hours, the first graph will rise to about 60 km/h. The second
|
|
one will show 180 km/h. This means that I traveled a distance of 60
|
|
km/h times 24 h = 1440 km. I did this with a higher speed and a
|
|
maximum around 180 km/h. However, it probably doesn't mean that I
|
|
traveled for 8 hours at a constant speed of 180 km/h!
|
|
|
|
This is a real example: go with the flow through Germany (fast!) and stop
|
|
a few times for gas and coffee. Drive slowly through Austria and the
|
|
Netherlands. Be careful in the mountains and villages. If you would
|
|
look at the graphs created from the five-minute averages you would
|
|
get a totally different picture. You would see the same values on the
|
|
average and maximum graphs (provided I measured every 300 seconds).
|
|
You would be able to see when I stopped, when I was in top gear, when
|
|
I drove over fast highways etc. The granularity of the data is much
|
|
higher, so you can see more. However, this takes 12 samples per hour,
|
|
or 288 values per day, so it would be a lot of data over a longer
|
|
period of time. Therefore we average it, eventually to one value per
|
|
day. From this one value, we cannot see much detail, of course.
|
|
|
|
Make sure you understand the last few paragraphs. There is no value
|
|
in only a line and a few axis, you need to know what they mean and
|
|
interpret the data in an appropriate way. This is true for all data.
|
|
|
|
The biggest mistake you can make is to use the collected data for
|
|
something that it is not suitable for. You would be better off if
|
|
you didn't have the graph at all.
|
|
|
|
|
|
=head2 Let's review what you now should know
|
|
|
|
You know how to create a database and can put data in it. You can get
|
|
the numbers out again by creating an image, do math on the data from
|
|
the database and view the result instead of the raw data. You know
|
|
about the difference between averages and maximum, and when to use
|
|
which (or at least you should have an idea).
|
|
|
|
RRDtool can do more than what we have learned up to now. Before you
|
|
continue with the rest of this doc, I recommend that you reread from
|
|
the start and try some modifications on the examples. Make sure you
|
|
fully understand everything. It will be worth the effort and helps
|
|
you not only with the rest of this tutorial, but also in your day to day
|
|
monitoring long after you read this introduction.
|
|
|
|
=head2 Data Source Types
|
|
|
|
All right, you feel like continuing. Welcome back and get ready
|
|
for an increased speed in the examples and explanations.
|
|
|
|
You know that in order to view a counter over time, you have to
|
|
take two numbers and divide the difference of them between the
|
|
time lapsed. This makes sense for the examples I gave you but there
|
|
are other possibilities. For instance, I'm able to retrieve the
|
|
temperature from my router in three places namely the inlet, the
|
|
so called hot-spot and the exhaust. These values are not counters.
|
|
If I take the difference of the two samples and divide that by
|
|
300 seconds I would be asking for the temperature change per second.
|
|
Hopefully this is zero! If not, the computer room is probably on fire :)
|
|
|
|
So, what can we do? We can tell RRDtool to store the values we measure
|
|
directly as they are (this is not entirely true but close enough). The
|
|
graphs we make will look much better, they will show a rather constant
|
|
value. I know when the router is busy (it
|
|
works -> it uses more electricity -> it generates more heat -> the
|
|
temperature rises). I know when the doors are left open (the room is
|
|
air conditioned) -> the warm air from the rest of the building flows into the
|
|
computer room -> the inlet temperature rises). Etc. The data type we
|
|
use when creating the database before was counter, we now have a
|
|
different data type and thus a different name for it. It is called
|
|
GAUGE. There are more such data types:
|
|
|
|
- COUNTER we already know this one
|
|
- GAUGE we just learned this one
|
|
- DERIVE
|
|
- ABSOLUTE
|
|
|
|
The two additional types are DERIVE and ABSOLUTE. Absolute can be used like
|
|
counter with one difference: RRDtool assumes the counter is reset when
|
|
it's read. That is: its delta is known without calculation by RRDtool
|
|
whereas RRDtool needs to calculate it for the counter type.
|
|
Example: our first example (12345, 12357, 12363, 12363) would read:
|
|
unknown, 12, 6, 0. The rest of the calculations stay the same.
|
|
The other one, derive, is like counter. Unlike counter, it can also
|
|
decrease so it can have a negative delta. Again, the rest of the
|
|
calculations stay the same.
|
|
|
|
Let's try them all:
|
|
|
|
rrdtool create all.rrd --start 978300900 \
|
|
DS:a:COUNTER:600:U:U \
|
|
DS:b:GAUGE:600:U:U \
|
|
DS:c:DERIVE:600:U:U \
|
|
DS:d:ABSOLUTE:600:U:U \
|
|
RRA:AVERAGE:0.5:1:10
|
|
rrdtool update all.rrd \
|
|
978301200:300:1:600:300 \
|
|
978301500:600:3:1200:600 \
|
|
978301800:900:5:1800:900 \
|
|
978302100:1200:3:2400:1200 \
|
|
978302400:1500:1:2400:1500 \
|
|
978302700:1800:2:1800:1800 \
|
|
978303000:2100:4:0:2100 \
|
|
978303300:2400:6:600:2400 \
|
|
978303600:2700:4:600:2700 \
|
|
978303900:3000:2:1200:3000
|
|
rrdtool graph all1.png -s 978300600 -e 978304200 -h 400 \
|
|
DEF:linea=all.rrd:a:AVERAGE LINE3:linea#FF0000:"Line A" \
|
|
DEF:lineb=all.rrd:b:AVERAGE LINE3:lineb#00FF00:"Line B" \
|
|
DEF:linec=all.rrd:c:AVERAGE LINE3:linec#0000FF:"Line C" \
|
|
DEF:lined=all.rrd:d:AVERAGE LINE3:lined#000000:"Line D"
|
|
|
|
=head2 RRDtool under the Microscope
|
|
|
|
=over 2
|
|
|
|
=item *
|
|
|
|
Line A is a COUNTER type, so it should continuously increment and RRDtool
|
|
must calculate the differences. Also, RRDtool needs to divide the
|
|
difference by the amount of time lapsed. This should end up as a
|
|
straight line at 1 (the deltas are 300, the time is 300).
|
|
|
|
=item *
|
|
|
|
Line B is of type GAUGE. These are "real" values so they should match
|
|
what we put in: a sort of a wave.
|
|
|
|
=item *
|
|
|
|
Line C is of type DERIVE. It should be a counter that can decrease. It does
|
|
so between 2400 and 0, with 1800 in-between.
|
|
|
|
=item *
|
|
|
|
Line D is of type ABSOLUTE. This is like counter but it works on
|
|
values without calculating the difference. The numbers are the same
|
|
and as you can see (hopefully) this has a different result.
|
|
|
|
=back
|
|
|
|
This translates in the following values, starting at 23:10 and ending
|
|
at 00:10 the next day (where "u" means unknown/unplotted):
|
|
|
|
- Line A: u u 1 1 1 1 1 1 1 1 1 u
|
|
- Line B: u 1 3 5 3 1 2 4 6 4 2 u
|
|
- Line C: u u 2 2 2 0 -2 -6 2 0 2 u
|
|
- Line D: u 1 2 3 4 5 6 7 8 9 10 u
|
|
|
|
If your PNG shows all this, you know you have entered the data correctly,
|
|
the RRDtool executable is working properly, your viewer doesn't fool you,
|
|
and you successfully entered the year 2000 :)
|
|
|
|
You could try the same example four times, each time with only one of
|
|
the lines.
|
|
|
|
Let's go over the data again:
|
|
|
|
=over 2
|
|
|
|
=item *
|
|
|
|
Line A: 300,600,900 and so on. The counter delta is a constant 300 and
|
|
so is the time delta. A number divided by itself is always 1 (except
|
|
when dividing by zero which is undefined/illegal).
|
|
|
|
Why is it that the first point is unknown? We do know what we put into
|
|
the database, right? True, But we didn't have a value to calculate the delta
|
|
from, so we don't know where we started. It would be wrong to assume we
|
|
started at zero so we don't!
|
|
|
|
=item *
|
|
|
|
Line B: There is nothing to calculate. The numbers are as they are.
|
|
|
|
=item *
|
|
|
|
Line C: Again, the start-out value is unknown. The same story is holds
|
|
as for line A. In this case the deltas are not constant, therefore the line
|
|
is not either. If we would put the same numbers in the database as we did for
|
|
line A, we would have gotten the same line. Unlike type counter,
|
|
this type can decrease and I hope to show you later on why
|
|
this makes a difference.
|
|
|
|
=item *
|
|
|
|
Line D: Here the device calculates the deltas. Therefore we DO know the
|
|
first delta and it is plotted. We had the same input as with line A, but
|
|
the meaning of this input is different and thus the line is different.
|
|
In this case the deltas increase each time with 300. The time delta
|
|
stays at a constant 300 and therefore the division of the two gives
|
|
increasing values.
|
|
|
|
=back
|
|
|
|
=head2 Counter Wraps
|
|
|
|
There are a few more basics to show. Some important options are still to
|
|
be covered and we haven't look at counter wraps yet. First the counter wrap:
|
|
In our car we notice that the counter shows 999987. We travel 20 km and
|
|
the counter should go to 1000007. Unfortunately, there are only six digits
|
|
on our counter so it really shows 000007. If we would plot that on a type
|
|
DERIVE, it would mean that the counter was set back 999980 km. It wasn't,
|
|
and there has to be some protection for this. This protection is only
|
|
available for type COUNTER which should be used for this kind of counter
|
|
anyways. How does it work? Type counter should never decrease and
|
|
therefore RRDtool must assume it wrapped if it does decrease!
|
|
If the delta is negative, this can be compensated for by adding the
|
|
maximum value of the counter + 1. For our car this would be:
|
|
|
|
Delta = 7 - 999987 = -999980 (instead of 1000007-999987=20)
|
|
|
|
Real delta = -999980 + 999999 + 1 = 20
|
|
|
|
At the time of writing this document, RRDtool knows of counters that
|
|
are either 32 bits or 64 bits of size. These counters can handle the
|
|
following different values:
|
|
|
|
- 32 bits: 0 .. 4294967295
|
|
- 64 bits: 0 .. 18446744073709551615
|
|
|
|
If these numbers look strange to you, you can view them in
|
|
their hexadecimal form:
|
|
|
|
- 32 bits: 0 .. FFFFFFFF
|
|
- 64 bits: 0 .. FFFFFFFFFFFFFFFF
|
|
|
|
RRDtool handles both counters the same. If an overflow occurs and
|
|
the delta would be negative, RRDtool first adds the maximum of a small
|
|
counter + 1 to the delta. If the delta is still negative, it had to be
|
|
the large counter that wrapped. Add the maximum possible value of the
|
|
large counter + 1 and subtract the erroneously added small value.
|
|
|
|
There is a risk in this: suppose the large counter wrapped while adding
|
|
a huge delta, it could happen, theoretically, that adding the smaller value
|
|
would make the delta positive. In this unlikely case the results would
|
|
not be correct. The increase should be nearly as high as the maximum
|
|
counter value for that to happen, so chances are you would have several
|
|
other problems as well and this particular problem would not even be
|
|
worth thinking about. Even though, I did include an example, so you
|
|
can judge for yourself.
|
|
|
|
The next section gives you some numerical examples for counter-wraps.
|
|
Try to do the calculations yourself or just believe me if your calculator
|
|
can't handle the numbers :)
|
|
|
|
Correction numbers:
|
|
|
|
- 32 bits: (4294967295 + 1) = 4294967296
|
|
- 64 bits: (18446744073709551615 + 1)
|
|
- correction1 = 18446744069414584320
|
|
|
|
Before: 4294967200
|
|
Increase: 100
|
|
Should become: 4294967300
|
|
But really is: 4
|
|
Delta: -4294967196
|
|
Correction1: -4294967196 + 4294967296 = 100
|
|
|
|
Before: 18446744073709551000
|
|
Increase: 800
|
|
Should become: 18446744073709551800
|
|
But really is: 184
|
|
Delta: -18446744073709550816
|
|
Correction1: -18446744073709550816
|
|
+ 4294967296 = -18446744069414583520
|
|
Correction2: -18446744069414583520
|
|
+ 18446744069414584320 = 800
|
|
|
|
Before: 18446744073709551615 ( maximum value )
|
|
Increase: 18446744069414584320 ( absurd increase, minimum for
|
|
Should become: 36893488143124135935 this example to work )
|
|
But really is: 18446744069414584319
|
|
Delta: -4294967296
|
|
Correction1: -4294967296 + 4294967296 = 0
|
|
(not negative -> no correction2)
|
|
|
|
Before: 18446744073709551615 ( maximum value )
|
|
Increase: 18446744069414584319 ( one less increase )
|
|
Should become: 36893488143124135934
|
|
But really is: 18446744069414584318
|
|
Delta: -4294967297
|
|
Correction1: -4294967297 + 4294967296 = -1
|
|
Correction2: -1 + 18446744069414584320 = 18446744069414584319
|
|
|
|
As you can see from the last two examples, you need strange numbers
|
|
for RRDtool to fail (provided it's bug free of course), so this should
|
|
not happen. However, SNMP or whatever method you choose to collect the
|
|
data, might also report wrong numbers occasionally. We can't prevent all
|
|
errors, but there are some things we can do. The RRDtool "create" command
|
|
takes two special parameters for this. They define
|
|
the minimum and maximum allowed values. Until now, we used "U", meaning
|
|
"unknown". If you provide values for one or both of them and if RRDtool
|
|
receives data points that are outside these limits, it will ignore those
|
|
values. For a thermometer in degrees Celsius, the absolute minimum is
|
|
just under -273. For my router, I can assume this minimum is much higher
|
|
so I would set it to 10, where as the maximum temperature I would
|
|
set to 80. Any higher and the device would be out of order.
|
|
|
|
For the speed of my car, I would never expect negative numbers and
|
|
also I would not expect a speed higher than 230. Anything else,
|
|
and there must have been an error. Remember: the opposite is not true,
|
|
if the numbers pass this check, it doesn't mean that they are
|
|
correct. Always judge the graph with a healthy dose of suspicion if it
|
|
seems weird to you.
|
|
|
|
=head2 Data Resampling
|
|
|
|
One important feature of RRDtool has not been explained yet: it is
|
|
virtually impossible to collect data and feed it into RRDtool on exact
|
|
intervals. RRDtool therefore interpolates the data, so they are stored
|
|
on exact intervals. If you do not know what this means or how it
|
|
works, then here's the help you seek:
|
|
|
|
Suppose a counter increases by exactly one for every second. You want
|
|
to measure it in 300 seconds intervals. You should retrieve values
|
|
that are exactly 300 apart. However, due to various circumstances you
|
|
are a few seconds late and the interval is 303. The delta will also be
|
|
303 in that case. Obviously, RRDtool should not put 303 in the database
|
|
and make you believe that the counter increased by 303 in 300 seconds.
|
|
This is where RRDtool interpolates: it alters the 303 value as if it
|
|
would have been stored earlier and it will be 300 in 300 seconds.
|
|
Next time you are at exactly the right time. This means that the current
|
|
interval is 297 seconds and also the counter increased by 297. Again,
|
|
RRDtool interpolates and stores 300 as it should be.
|
|
|
|
in the RRD in reality
|
|
|
|
time+000: 0 delta="U" time+000: 0 delta="U"
|
|
time+300: 300 delta=300 time+300: 300 delta=300
|
|
time+600: 600 delta=300 time+603: 603 delta=303
|
|
time+900: 900 delta=300 time+900: 900 delta=297
|
|
|
|
Let's create two identical databases. I've chosen the time range 920805000
|
|
to 920805900 as this goes very well with the example numbers.
|
|
|
|
rrdtool create seconds1.rrd \
|
|
--start 920804700 \
|
|
DS:seconds:COUNTER:600:U:U \
|
|
RRA:AVERAGE:0.5:1:24
|
|
|
|
Make a copy
|
|
|
|
for Unix: cp seconds1.rrd seconds2.rrd
|
|
for Dos: copy seconds1.rrd seconds2.rrd
|
|
for vms: how would I know :)
|
|
|
|
Put in some data
|
|
|
|
rrdtool update seconds1.rrd \
|
|
920805000:000 920805300:300 920805600:600 920805900:900
|
|
rrdtool update seconds2.rrd \
|
|
920805000:000 920805300:300 920805603:603 920805900:900
|
|
|
|
Create output
|
|
|
|
rrdtool graph seconds1.png \
|
|
--start 920804700 --end 920806200 \
|
|
--height 200 \
|
|
--upper-limit 1.05 --lower-limit 0.95 --rigid \
|
|
DEF:seconds=seconds1.rrd:seconds:AVERAGE \
|
|
CDEF:unknown=seconds,UN \
|
|
LINE2:seconds#0000FF \
|
|
AREA:unknown#FF0000
|
|
rrdtool graph seconds2.png \
|
|
--start 920804700 --end 920806200 \
|
|
--height 200 \
|
|
--upper-limit 1.05 --lower-limit 0.95 --rigid \
|
|
DEF:seconds=seconds2.rrd:seconds:AVERAGE \
|
|
CDEF:unknown=seconds,UN \
|
|
LINE2:seconds#0000FF \
|
|
AREA:unknown#FF0000
|
|
|
|
View both images together (add them to your index.html file)
|
|
and compare. Both graphs should show the same, despite the
|
|
input being different.
|
|
|
|
=head1 WRAPUP
|
|
|
|
It's time now to wrap up this tutorial. We covered all the basics for
|
|
you to be able to work with RRDtool and to read the additional
|
|
documentation available. There is plenty more to discover about
|
|
RRDtool and you will find more and more uses for this package. You can
|
|
easily create graphs using just the examples provided and using only
|
|
RRDtool. You can also use one of the front ends to RRDtool that are
|
|
available.
|
|
|
|
=head1 MAILINGLIST
|
|
|
|
Remember to subscribe to the RRDtool mailing list. Even if you are not
|
|
answering to mails that come by, it helps both you and the rest of the
|
|
users. A lot of the stuff that I know about MRTG (and therefore about
|
|
RRDtool) I've learned while just reading the list without posting to
|
|
it. I did not need to ask the basic questions as they are answered in
|
|
the FAQ (read it!) and in various mails by other users. With
|
|
thousands of users all over the world, there will always be people who
|
|
ask questions that you can answer because you read this and other
|
|
documentation and they didn't.
|
|
|
|
=head1 SEE ALSO
|
|
|
|
The RRDtool manpages
|
|
|
|
=head1 AUTHOR
|
|
|
|
I hope you enjoyed the examples and their descriptions. If you do, help
|
|
other people by pointing them to this document when they are asking
|
|
basic questions. They will not only get their answers, but at the same
|
|
time learn a whole lot more.
|
|
|
|
Alex van den Bogaerdt
|
|
E<lt>alex@vandenbogaerdt.nlE<gt>
|
|
|