From: oetiker Date: Wed, 23 May 2007 16:08:14 +0000 (+0000) Subject: new trunk based on current 1.2 X-Git-Url: https://git.octo.it/?p=rrdtool.git;a=commitdiff_plain;h=5fc7ff89bdbced9c593c566fea9840a269935dcd;hp=8a16a11b3b30dfb937ed42fa69c9e5442d4eca3c new trunk based on current 1.2 git-svn-id: svn://svn.oetiker.ch/rrdtool/trunk/program@1073 a5681a0c-68f1-0310-ab6d-d61299d08faa --- diff --git a/00README b/00README index 7c5753b..5f197b3 100644 --- a/00README +++ b/00README @@ -1,6 +1,6 @@ Title: RRDtool -Date: 2000-01-10 -Owner: Tobias Oetiker +Date: 2005-04-04 +Owner: Tobias Oetiker Group: Software Round Robin Database Tool diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 77178f6..aaf7718 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -1,116 +1,74 @@ I would like to thank to following people for helping to bring RRDtool into existence. -Planning and Inspiration - - Daniel Wesemann - Krister Karlson - Simon Leinen - -Debugging and code contributions - - Andreas Kroomaa - Andrew Turner (LAST consolidator) - Bernard Fischer 64bit stuff and --alt-autoscale-max - Bill Fenner - Blair Zajac - Dan Dunn - Hermann Hueni (SunOS porting) - Jeff R. Allen (autoconfigure, portability) - Joel Becker AIX - Joey Miller php3 and php4 bindings - Jost.Krieger - Larry Leszczynski - Otmar Lendl (lots of bugfixes) - Paul Joslin - Philippe.Simonet (NT porting) - Poul-Henning Kamp CDEF enhancements - REIBENSCHUH Alfred AIX - Roman Hoogant - Russ Wright - Simon Leinen - Stefan Mueller HPUX 11 - Steve Rader (rrd_cgi debugging and LAST) - Terminator rAT - Christophe VG - Shane O'Donnell - Tuc - Mike Mitchell - Ulrich Schilling AIX - Wrolf Courtney (HP-UX) - Alan Lichty - Alex van den Bogaerdt (rrd_resize.c and more) - Frank Strauss TCL bindings - Jakob Ilves HPUX 11 - Jeremy Fischer (Makefile changes & RPM builds) - Oleg Cherevko - Rainer Bawidamann - Selena M Brewington add_ds - Steen Linden - Steve Harris AIX portability - Tom Crawley (GCC&HP configuration) - Albert Chin-A-Young - Sean McCreary mccreary@xoanon.colorado.edu - Bruce Campbell - Sean Summers (RPM .spec) - Christophe Van Ginneken (--no-legend) - Wolfgang Schrimm xport function - Travis Brown - Peter Stamfest initial multi-thread support - David L. Barker xport function bug fixes - Mike Slifcak many rrdtool-1.1.x fixes - Peter Speck eps/svg/pdf file format code in rrdtool-1.x - David Grimes SQRT/SORT/REV/SHIFT/TREND - Henrik Storner make rrd_graph() provide the min/max values of data in graph - Radoslaw Karas - -Documentation - - Alan Lichty - Alex van den Bogaerdt - Amos Shapira - Kai Siering - Russ Wright - Steve Rader - Wrolf Courtney - Tobias Weingartner - hendrik visage - Steve Rader - Jesús Couto Fandiño - -Packaging - Henri GOMEZ -- Redhat RPMs - Philippe Simonet -- NT Binaries - - -Internet Resources - LAN Services AG (www.lan.ch) - for the http://rrdtool.eu.org domain reflector - - Alexander Lucke (lucke@dns-net.de) - and DNS:NET Internet Services (www.dns-net.de) - for http://rrdtool.org - -Further I would like to note, that RRDtool would not exist without -the following free software products: - - Perl by Larry Wall - libart by Raph Levien - freetype by David Turner, Robert Wilhelm, and Werner Lemberg - libpng by Glenn Randers-Pehrson / Andreas Eric Dilger / Guy Eric Schalnat - cgilib by Martin Schulze - zlib by Jean-loup Gailly and Mark Adler - SNMP Perl-Module by Simon Leinen - - and last but not least - - Linux by Linus Torvalds - -I would also like to thank the Department of Electrical Engineering -at the Swiss Federal Institute of Technology who allow me to -use their network resources to publish RRDtool ... - -During Summer 1999 CAIDA (www.caida.org) has supported me in working full -time on RRDtool ... A big thank you to them as well. - -Tobias Oetiker +Alan Lichty +Alan Milligan Python bindings +Alex van den Bogaerdt (rrd_resize.c and more) +Amos Shapira +Andreas Kroomaa +Andrew Turner (LAST consolidator) +Bernard Fischer 64bit stuff and --alt-autoscale-max +Bill Fenner +Blair Zajac +Bruce Campbell +Chin-A-Young +Christophe VG +Christophe Van Ginneken (--no-legend) +Dan Dunn +Dave Bodenstab AT style time in update, tclfixes +David Grimes SQRT/SORT/REV/SHIFT/TREND +David L. Barker xport function bug fixes +Frank Strauss TCL bindings +Henrik Storner functions for min/max values of data in graph +Hermann Hueni (SunOS porting) +Jakob Ilves HPUX 11 +Jeff R. Allen (autoconfigure, portability) +Jeremy Fischer (Makefile changes & RPM builds) +Jesús Couto Fandiño +Joel Becker AIX +Joey Miller php3 and php4 bindings +Jost.Krieger +Kai Siering +Larry Leszczynski +McCreary mccreary with xoanon.colorado.edu +Mike Mitchell +Mike Slifcak many rrdtool-1.1.x fixes +Oleg Cherevko +Otmar Lendl (lots of bugfixes) +Paul Joslin +Peter Speck eps/svg/pdf file format code in rrdtool-1.x +Peter Stamfest initial multi-thread support +Peter Breitenlohner many patches for rrdtool 1.2.x +Philippe.Simonet (NT porting) +Poul-Henning Kamp CDEF enhancements +REIBENSCHUH Alfred AIX +Radoslaw Karas +Rainer Bawidamann +Roman Hoogant +Ronan Mullally +Roger J. Meier (arbitrary linelength in rrdtool) +Russ Wright +Sean Summers (RPM .spec) +Selena M Brewington add_ds +Shane O'Donnell +Simon Leinen +Steen Linden +Stefan Mueller HPUX 11 +Steve Harris AIX portability +Steve Rader (rrd_cgi debugging and LAST) +Terminator rAT +Tobias Weingartner +Tom Crawley (GCC&HP configuration) +Travis Brown +Tuc +Ulf Lilleengen Python binding for 'rrdtool first' +Ulrich Schilling AIX +Wim Heirman --units=si option +Wolfgang Schrimm xport function +Wrolf Courtney (HP-UX) +hendrik visage +Philippe Simonet (Windows Binaries) +Alexander Lucke (lucke with dns-net.de) + of DNS:NET Internet Services (www.dns-net.de) http://rrdtool.org +Hedley Simons +Nicola Worthington diff --git a/COPYRIGHT b/COPYRIGHT index 89f1289..ab5c695 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -2,8 +2,11 @@ A tool for fast logging of numerical data graphical display of this data. - Copyright (c) 1998, 1999 Tobias Oetiker + Copyright (c) 1998-2006 Tobias Oetiker All rights reserved. + + GNU GPL License + =============== This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -18,3 +21,70 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + + FLOSS License Exception + ======================= + (Adapted from http://www.mysql.com/company/legal/licensing/foss-exception.html) + + I want specified Free/Libre and Open Source Software ("FLOSS") + applications to be able to use specified GPL-licensed RRDtool + libraries (the "Program") despite the fact that not all FLOSS licenses are + compatible with version 2 of the GNU General Public License (the "GPL"). + + As a special exception to the terms and conditions of version 2.0 of the GPL: + + You are free to distribute a Derivative Work that is formed entirely from + the Program and one or more works (each, a "FLOSS Work") licensed under one + or more of the licenses listed below, as long as: + + 1. You obey the GPL in all respects for the Program and the Derivative + Work, except for identifiable sections of the Derivative Work which are + not derived from the Program, and which can reasonably be considered + independent and separate works in themselves, + + 2. all identifiable sections of the Derivative Work which are not derived + from the Program, and which can reasonably be considered independent and + separate works in themselves, + + 1. are distributed subject to one of the FLOSS licenses listed + below, and + + 2. the object code or executable form of those sections are + accompanied by the complete corresponding machine-readable source + code for those sections on the same medium and under the same FLOSS + license as the corresponding object code or executable forms of + those sections, and + + 3. any works which are aggregated with the Program or with a Derivative + Work on a volume of a storage or distribution medium in accordance with + the GPL, can reasonably be considered independent and separate works in + themselves which are not derivatives of either the Program, a Derivative + Work or a FLOSS Work. + + If the above conditions are not met, then the Program may only be copied, + modified, distributed or used under the terms and conditions of the GPL. + + FLOSS License List + ================== + License name Version(s)/Copyright Date + Academic Free License 2.0 + Apache Software License 1.0/1.1/2.0 + Apple Public Source License 2.0 + Artistic license From Perl 5.8.0 + BSD license "July 22 1999" + Common Public License 1.0 + GNU Library or "Lesser" General Public License (LGPL) 2.0/2.1 + IBM Public License, Version 1.0 + Jabber Open Source License 1.0 + MIT License (As listed in file MIT-License.txt) - + Mozilla Public License (MPL) 1.0/1.1 + Open Software License 2.0 + OpenSSL license (with original SSLeay license) "2003" ("1998") + PHP License 3.0 + Python license (CNRI Python License) - + Python Software Foundation License 2.1.1 + Sleepycat License "1999" + W3C License "2001" + X11 License "2001" + Zlib/libpng License - + Zope Public License 2.0 diff --git a/MakeMakefile b/MakeMakefile index 26cc005..c936d00 100755 --- a/MakeMakefile +++ b/MakeMakefile @@ -3,6 +3,9 @@ # Run this script after the first cvs checkout to build # makefiles and friends +PATH="/usr/sepp/bin:$PATH" +export PATH + vcheck (){ perl < - Ripped out all foreign libraries and adapted - Configure and Makefiles and accordingly. +* rewritten graphics generation based on libart. + - anti-aliased output + - alpha transparency support + - truetype fonts + +* additional graphics formats: EPS, PDF, SVG -2002/03/26 Peter Speck - Contribution of an svg output routine for the new gfx graphing part +* extended multi-part documentation -2002/03/23 Alex van den Bogaerdt - Several visible changes made to rrd_graph - * Pie chart support workable - * Elements that are not used do not take up space on the img - * Hack for the missing rotated text (see --vertical-label) - * Tiny boxes in front of labels now scale with the text +* VDEF support; define and use variables. Find, and use, the + maximum rate seen by rrdtool; compute and show the average -2002/01/15 Tobias Oetiker - The BIG graph update - * Replace libgd with libart - * Added freetype - * Updated zlib and libpng - * rrd_gfx.c intrduced as libart wrapper - * LINE takes now a float as argument - * RRDtool uses truetype for fonts - * thanks to libart there is now full alpha transparenc - and antialiasing. - * the new option --font lets customize the font - and size for various graph elements - * Updated to -> libtool 1.4.2 automake 2.12 autoconf 2.52 - * new --zoom commandline option for zoom ans shrinking - ---- Still missing is rotatet text for the yaxis description - ---- Still missing is tab support in the text rendere - ---- Still missing is autoconf support for a default truetype font +* Sliding window (trend) analysis + Compute a smoother average, for instance over the last 6 CDPs -2001/07/26 Alex van den Bogaerdt - Added TOTAL to the VDEF functions. +* percentile (95th or other) + Remove peaks, 95 percent of all rates are at or below the + returned value -2001/07/19 Alex van den Bogaerdt - VDEF support. This is a variable containing one value - and a time component. This type of variable can hold - the result of a function over a complete time series - of data (DEF or CDEF) such as the maximum seen, and when. +Logging +------- +* a second logging interface: rrdtool updatev + Verbose updating of the database; show CPDs being created -2001/03/10 Jake Brutlag - Support for COMPUTE data sources (CDEF data sources). Removes the RPN - parser and calculator from rrd_graph and puts then in a new file, - rrd_rpncalc.c. Changes to core files rrd_create and rrd_update. Some - clean-up of aberrant behavior stuff, including a bug fix. - Documentation update (rrdcreate.pod, rrdupdate.pod). Change xml format. - -2001/03/07 Tobias Oetiker - Integrated complete rewrite - of rrdgraph documentation by Alex van den Bogaerdt - . This also contains info on his planned - changes to the rrdgraph module +* Aberrant Behavior Detection with Holt-Winters Forecasting + Compare current data with expected data, detect and log when + the rates are outside expected levels -2001/03/02 Tobias Oetiker - Added Aberrant Patch from Jake Brutlag - From now one, new rrd files use version tag 0002. They can - NOT be read by the old 1.0.x RRDtools. +* COMPUTE data type for artificial data-sources calculating their + input using RPN math and data from the other data-sources. - Jake: - Aberrant Behavior Detection support. A brief overview added to - rrdtool.pod. Major updates to rrd_update.c, rrd_create.c. Minor update to - other core files. Updated documentation: rrdcreate.pod, rrdgraph.pod, - rrdtune.pod. This is backwards compatible (i.e. new tool can read and will - leave the binary header unchanged for old files). - See http://cricket.sourceforge.net/aberrant/rrd_hw.htm +Incompatibilities +----------------- +* Colons in COMMENT arguments to rrdtool graph must be escaped with a backslash + +* the --alt-y-mrtg option is gone or rather since 1.2.7 it is back but + without functionality. + +* In pipe mode, rrdtool answers with OK only if it was successful with the + command. Otherwhise the answer will be ERROR... + + +Behind the Scenes +----------------- +* In order to support Holt-Winters and Calculated Datasources, + the rrdtool data format has changed. While the new version of rrdtool can + read files created with rrdtool 1.0.x. It is not possible to read files + created by rrdtool-1.2.x with rrdtool-1.0.x + +* External libraries are not included with rrdtool anymore. This is in line + with todays trend of using shared libraries everywhere. With the exception + of the cgi library most things required by rrdtool will be found on every recent + system. + +* Memory Mapped IO support for faster logging. diff --git a/NT-BUILD-TIPS.txt b/NT-BUILD-TIPS.txt deleted file mode 100644 index 5fa5e7f..0000000 --- a/NT-BUILD-TIPS.txt +++ /dev/null @@ -1,212 +0,0 @@ -Compiling RRDtool 1.1.x on Win32 with Microsoft Visual C++: ---------------------------------------------------------------- -7/29/04 Jake Brutlag - -As of Jan 2004, code for libraries utilized by rrdtool -(png, libart, freetype, and zlib) is no longer distributed with -rrdtool. This requires some changes to the compile process on -Win32. The solution described here is to compile rrdtool to -link against these libraries dynamically. There is an advantage -to this approach: namely the rrdtool distribution doesn't have to -worry about how to compile these libraries on Win32. In theory, -since others already provide and maintain Win32 binaries for these -libraries the users don't have to worry about how to compile them -either. The disadvantage of this approach is that the DLLs for -these libraries must be available on the hosts where rrdtool will run. - -Here are step by step instructions for compiling rrdtool.exe and -the perl shared library (RRDS.dll) with Microsoft Visual C++ 6.0. -(1) Download libraries rrdtool depends on from GnuWin32: -http://gnuwin32.sourceforge.net/ -For freetype, libpng, and zlib download the "Complete Package"; each of -these will be a self-extracting self-installing executable. -For libart, download both the "Binaries" and "Developer Files" packages. -Unfortunately at this time GnuWin32 doesn't provide the "Complete Package" -installer for libart. Perhaps by the time you are following these -instructions GnuWin32 will have a "Complete Package" for libart. -(2) Install the GnuWin32 libraries by running the executables for freetype, -libpng, and zlib. These instructions and the Visual C++ project files -distributed with rrdtool assume that you will use the default install -location: C:\Program Files\GnuWin32. Extract the two zip files for libart, -libart-2.3.3-bin.zip and libart-2.3.3-1-lib.zip into the GnuWin32 directory; -the appropriate libart files will be added to the include, lib, and bin -subdirectories. -(3) Add C:\Program Files\GnuWin32\bin to the PATH (Control Panel -> -System -> Advanced -> Environment Variables). -(4) Start Microsoft Visual C++ 6.0. Load the workspace file, rrdtool.dsw, -from the src subdirectory of your rrdtool code directory. -(5) Compile the Release build of the rrdtool project (since rrdtool depends -on the rrd project, the rrd library will also be compiled). At this -time, the compile will fail in zconf.h, a zlib header file. The problem -is a preprocessor directive that loads unistd.h. Open zconf.h in VC++ -(this file is in C:\Program Files\GnuWin32\include) and find the following -code block: - -#if 1 /* HAVE_UNISTD_H -- this line is updated by ./configure */ -# include /* for off_t */ -# include /* for SEEK_* and off_t */ -# ifdef VMS -# include /* for off_t */ -# endif -# define z_off_t off_t -#endif - -Change it to reads as follows (this is code from zlib-1.1.4): - -#if HAVE_UNISTD_H -# include /* for off_t */ -# include /* for SEEK_* and off_t */ -# ifdef VMS -# include /* for off_t */ -# endif -# define z_off_t off_t -#endif - -Note that it is actually just a one line change. Save the file and -recompile rrdtool. By the time you are following these instructions -this issue with zconf.h may be resolved. -(6) At this point, you can run the executable rrdtool.exe in the -src\toolrelease subdirectory. Note that if you wish to run rrdtool -on other machines, you will need the following DLLs installed (on the -path) on those machines: -zlib1.dll -libpng12.dll -libart_lgpl.dll -freetype6.dll -msvcrt.dll -The names of the first four DLLs might vary from what is listed here -depending on the versions of the packages you downloaded from GnuWin32. -The fifth DLL, msvcrt.dll, is a system DLL for most versions of Windows. -If you are running on old version of Windows, you can install/upgrade to -IE4.0 to get this DLL. -(7) To compile the perl-shared library, open a Command Prompt (DOS box) -and cd to the bindings\perl-shared subdirectory. -(8) Run vcvars32.bat; this batch file, in your vc98\bin directory will -set necessary environment options for command line compiling. -(9) In bindings\perl-shared, run -perl ntmake.pl -nmake -nmake test -If nmake test succeeds, you are good to go. RRDs.dll is in -blib\arch\auto\RRDs. If you plan to install via the Active State ppm -tool, tar and gzip the blib directory. You can use the RRDs.ppd file -in bindings\perl-shared directory. Remember that as in the case of -rrdtool.exe you will need the DLLs listed in (6) on the machine where -you are going to use RRDs.dll. - -Microsoft Visual C++ 7.1 (.NET 2003): - -Unfortunately, this is more difficult than with VC++ 6.0. The problem -is that by default the C runtime dll for VC++ 7.1 is msvcr71.dll rather -than msvcrt.dll. The GnuWin32 library binaries are all compiled -to use msvcrt.dll and you can't mix msvcr71.dll and msvcrt.dll in the -same process. One option is to download the source code for the libraries -(available from http://gnuwin32.sourceforge.net) recompile them with -VC++ 7.l. Then all the components will use msvcr71.dll. Once you are -going to go this route, you can also use static multi-threaded libraries -and use static linking between rrdtool (or RRDs.dll) and its dependencies. - -To use the GnuWin32 library binaries, you need to trick VC++ 7.1 into -compiling rrdtool to use the older msvcrt.dll. Follow steps (1) - (3) -as above, then: -(4) Obtain a different version of the msvcrt.lib import library that -is compatible with vc7 and points to msvcrt.dll: -msvcrtlib_for_vc7.zip from http://xchat.org/win32/testing -Backup msvcrt.lib in your vc7\lib directory -(\Program Files\Microsoft Visual Studio .NET 2003\vc7\lib) -Then extract the msvcrt.lib from the zip file into the vc7\lib directory. -WARNING: Use this msvcrt.lib at your own risk! This is not a Microsoft -supplied file nor a file supported by anyone associated with rrdtool. -(5) Start Microsoft Visual C++ 7.1. Load the solution file, rrdtool.sln, -from the src subdirectory of your rrdtool code directory. Edit zconf.h, -as needed, as described under (5) above. Compile the release build of -the rrdtool project. -Proceed with steps (6) - (9) as above, if you are using/picking up -the wrong msvcrt.lib import library then nmake test for perl-shared -will fail. - -Note: it is possible in the future that GnuWin32 will provide Win32 -binaries that utilize msvcr71.dll rather than msvcrt.dll. - -5/14/02 Jake Brutlag - -These notes share some insight I gained compiling 1.1.x with -MS Visual C++ 6.0 (using project files). This information may or -may not be accurate at the time you are reading this. - -(1) freetype and rrdtool cannot use precompiled headers (which are -enabled by default for MSVC++ projects). MSVC++ 6.0 does not -support precompiled headers if #include directives contain MACROS. -(2) Compile Release build with Default optimization, not the -Maximize Speed optimization. I encountered some strange errors -(related to argument processing for complex commands like graph-- -perhaps the getopt stuff is too blame) with Maximize Speed. -(3) libart relies upon config.h (ostensibly generated by the -configure script-- but of course not on Win32 platforms). ..\..\confignt -(which contains a static Win32 version of config.h) should be on -the include path. -(4) Fonts are located in the %windir%\fonts, so the default font -is c:\winnt\fonts\cour.ttf. (6/19/02) At Kerry Calvert's suggestion -this setting was moved to confignt\config.h. -(5) libart requires a custom build step to generate art_config.h; this -is done manually via the commands: -cl -I..\..\confignt gen_art_config.c -gen_art_config.exe > art_config.h - -Currently, to compile rrd.lib and rrdtool.exe using -the MSVC++ project files, first start MSVC++ 6.0. Open the rrdtool -workspace (rrdtool.dsw in the src directory). The active project/ -configuration should be rrdtool-Win32 Release. Select Rebuild All -from the Build menu. The static link library (rrd.lib) will -be generated in src\release directory and executable will be generated -in the src\toolrelease directory. - -Compiling RRDtool on NT ... work in progress ---------------------------------------------------------------- - by Tamas Kovacshazy (khazy@mit.bme.hu) - -Persisting Problems with the current NT port: - -Unfortunately, the RRD perl modules does not work with Perl -(ActivePerl) using the current distribution. - -The RRD shared perl module can be compiled after some -modification... - -Follow these steps: - -0. Install perl if you do not have it! - Visit http://www.ActiveState.com/pw32/ for a complete distribution. - -1. Copy ..\gd1.2\release\gd.lib to ..\gd1.2\ -2. Copy ..\src\release\rrd.lib to ..\src -3. perl Makefile.pl - -In this step the system complains about something I do not -understand. The error message is the following: - -Note (probably harmless): No library found for '-lm' - -Is a library missing? But it does not stop with an error... - -4. nmake test (You must have Visual C++ on the machine!) - -After these steps it generates the test files (svgs and rrds), -and they seem to be good. - -The real problem in the shared perl modul is the following: - -I do not know how this installation stuff works. The problem is -that the installation stuff looks for the gd.lib and the -rrd.lib in the ..\gd1.2 and ..\src directory. The UNIX compile -puts the files into these directories, but the NT compile does -not. - -It is all for today, - -khazy - -Tamas Kovacshazy E-mail: khazy@mit.bme.hu -WWW: http://www.mit.bme.hu/~khazy -Technical University of Budapest -Department of Measurement and Information Systems diff --git a/PROJECTS b/PROJECTS index dbba94b..68a5fcf 100644 --- a/PROJECTS +++ b/PROJECTS @@ -3,12 +3,9 @@ NEW RRD DATAFORMAT with Accessor Functions Interested: -Tobias Oetiker +Tobias Oetiker Jake Brutlag - updating rrd_update to use accessor fks -Karl Schilke -- changeing data access to mmap - Plan: diff --git a/README b/README index d28600c..cba88fd 100644 --- a/README +++ b/README @@ -14,75 +14,7 @@ values collected over a definable time period. To compile: ----------- -you need the following libraries installed on your system. - - cgilib-0.5.tar.gz - freetype-2.1.5.tar.gz - libart_lgpl-2.3.16.tar.gz - libpng-1.2.5.tar.gz - zlib-1.2.1.tar.gz - -you can either get these libraries directly from their original sites -or you can get copies from - - http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/pub/libs - -the configure program will try to use the libraries with out adding any extra -flags apart from the ones defined in CPPFLAGS and LDFLAGS. If this does not -work it will try to get information from pkgconfig. - -If your libraries are not installed in standard places and you do not have -pkgconfig support, then you may want to set CPPFLAGS and LDFLAGS to help -configure while it tries to find the libraries. - - env CPPFLAGS="-I/scratch/oetiker/cgilib-0.5 \ - -I/scratch/oetiker/libs/include/libart-2.0 \ - -I/scratch/oetiker/libs/include \ - -I/scratch/oetiker/libs/include/freetype2" \ - LDFLAGS="-L/scratch/oetiker/libs/lib -R/scratch/oetiker/libs/lib \ - -L/scratch/oetiker/cgilib-0.5" ./configure - - make <------ GNU make - - make install <------ GNU make - -This will configure, compile and install RRDtool in -/usr/local/rrdtool-VERSION. If you prefer to install RRDtool in some other -place, use - - ./configure --prefix=/some/other/RRDtool-dir - -The configure script will try to find your perl installation (5.008 -preferred). If it does not find it, you can still build RRDtool but no perl -modules will be generated. - -By default the perl modules will be installed under the RRDtool install -directory. This will require you to use a 'use lib' statement in your -RRDtool perl programs. If you do not care what happens to your site-perl -directory, you can also use - - --enable-perl-site-install - -when running configure to have the RRD perl modules installed wherever you -keep your local perl modules. Doing this reliefs you from using 'use lib' in -your scripts. - -Configure will also look for an TCL installation on your system. If it finds -one it will build a TCL interface for RRDtool. If you keep tcl in a non -standard location you can use - - sh configure --with-tcllib=/sw/tcl-8.3/lib - -to indicte the right version (note, this must point to the directory where -tclConfig.sh is located). Note that install will integrate the tcl bindings -into your tcl installation. It will use a separate directory for each -version though, so this is not much of a problem. Nevertheless the Tcl -module will not get intalled by default as Tcl wants its module in the base -tcl installation where you might not be able to write to. So if you want the -tcl stuff installed, type - - make site-tcl-install - +check out the instructions in doc/rrdbuild.txt Getting Started: ---------------- @@ -107,7 +39,7 @@ How to make Tobi happy: ----------------------- If you want to show your appreciation for RRDtool you could make me happy -by going to ee-staff.ethz.ch/~oetiker/wish and ordering a CD from +by going to http://tobi.oetiker.ch/wish and ordering a CD from my CD wish list ... @@ -121,7 +53,7 @@ rrd-users For discussion amongst people who use RRDtool in their applicati rrd-developers For people who actually HACK RRDtool code To subscribe to send a message with the subject 'subscribe' -to -request@list.ee.ethz.ch. +to -request@lists.oetiker.ch Note, that postings to rrd-announce will always be cross-posted to rrd-users and rrd-developers as well. @@ -137,7 +69,7 @@ Use GNU diff --unified --recursive olddir newdir to build your patches. The latest Version: ------------------- -Is available from http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/ +Is available from http://oss.oetiker.ch/rrdtool/ -Tobias Oetiker +Tobias Oetiker diff --git a/TODO b/TODO index 350f2b8..baa64f7 100644 --- a/TODO +++ b/TODO @@ -1,12 +1,5 @@ What has to be done before the 1.2.0 Release -------------------------------------------- -* Add tab support so that it becomes possible to use proportional - fonts in the legend - -* Polish up the looks of the generated graphs. - -* Remove all unfinished code like the PIE chart stuff. - * Sync Docs with reality (there are things described which have not been implemented) @@ -37,7 +30,7 @@ Let the user define the base resolution of the graph independently of the pixel resolution. If it is smaller than one pixel it will simply be ignored -allow sub second presition for step definition +allow sub second precision for the step definition modularise consolidation and acquisition functions @@ -53,8 +46,6 @@ add axis on the right and on top of the graph ... add configurable counter wrap -95th percentile plotting - build derivatives while plotting show trend by building moving average and represent it as an arrow @@ -75,4 +66,3 @@ have configurable role-over limits for counters align data points not to GMT but some free offset allow starting through symlinks called rrdcreate rrdtune and the like - diff --git a/WIN32-BUILD-TIPS.txt b/WIN32-BUILD-TIPS.txt new file mode 100644 index 0000000..7d731c8 --- /dev/null +++ b/WIN32-BUILD-TIPS.txt @@ -0,0 +1,335 @@ +Compiling RRDtool 1.1.x on Win32 with Microsoft Visual C++: +--------------------------------------------------------------- +5/1/05 Tobi +to help windows deal with the reentrant versions of many unix +calls link with win32comp.c + +4/10/05 Tobi +The windows implementation of strftime does not seem to support +the ISO 8601 week number (%V) I have therfore included the file +strftime.[ch] which provides strftime_ ... if you compile rrdtool +with -Dstrftime=_strftime and link strftime.o then you will +get propper support for %V. + +7/29/04 Jake Brutlag + +As of Jan 2004, code for libraries utilized by rrdtool +(png, libart, freetype, and zlib) is no longer distributed with +rrdtool. This requires some changes to the compile process on +Win32. The solution described here is to compile rrdtool to +link against these libraries dynamically. There is an advantage +to this approach: namely the rrdtool distribution doesn't have to +worry about how to compile these libraries on Win32. In theory, +since others already provide and maintain Win32 binaries for these +libraries the users don't have to worry about how to compile them +either. The disadvantage of this approach is that the DLLs for +these libraries must be available on the hosts where rrdtool will run. + +Here are step by step instructions for compiling rrdtool.exe and +the perl shared library (RRDS.dll) with Microsoft Visual C++ 6.0. +(1) Download libraries rrdtool depends on from GnuWin32: +http://gnuwin32.sourceforge.net/ +For freetype, libpng, and zlib download the "Complete Package"; each of +these will be a self-extracting self-installing executable. +For libart, download both the "Binaries" and "Developer Files" packages. +Unfortunately at this time GnuWin32 doesn't provide the "Complete Package" +installer for libart. Perhaps by the time you are following these +instructions GnuWin32 will have a "Complete Package" for libart. +(2) Install the GnuWin32 libraries by running the executables for freetype, +libpng, and zlib. These instructions and the Visual C++ project files +distributed with rrdtool assume that you will use the default install +location: C:\Program Files\GnuWin32. Extract the two zip files for libart, +libart-2.3.3-bin.zip and libart-2.3.3-1-lib.zip into the GnuWin32 directory; +the appropriate libart files will be added to the include, lib, and bin +subdirectories. +(3) Add C:\Program Files\GnuWin32\bin to the PATH (Control Panel -> +System -> Advanced -> Environment Variables). +(4) Start Microsoft Visual C++ 6.0. Load the workspace file, rrdtool.dsw, +from the src subdirectory of your rrdtool code directory. +(5) Compile the Release build of the rrdtool project (since rrdtool depends +on the rrd project, the rrd library will also be compiled). At this +time, the compile will fail in zconf.h, a zlib header file. The problem +is a preprocessor directive that loads unistd.h. Open zconf.h in VC++ +(this file is in C:\Program Files\GnuWin32\include) and find the following +code block: + +#if 1 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif + +Change it to reads as follows (this is code from zlib-1.1.4): + +#if HAVE_UNISTD_H +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif + +Note that it is actually just a one line change. Save the file and +recompile rrdtool. By the time you are following these instructions +this issue with zconf.h may be resolved. +(6) At this point, you can run the executable rrdtool.exe in the +src\toolrelease subdirectory. Note that if you wish to run rrdtool +on other machines, you will need the following DLLs installed (on the +path) on those machines: +zlib1.dll +libpng12.dll +libart_lgpl.dll +freetype6.dll +msvcrt.dll +The names of the first four DLLs might vary from what is listed here +depending on the versions of the packages you downloaded from GnuWin32. +The fifth DLL, msvcrt.dll, is a system DLL for most versions of Windows. +If you are running on old version of Windows, you can install/upgrade to +IE4.0 to get this DLL. +(7) To compile the perl-shared library, open a Command Prompt (DOS box) +and cd to the bindings\perl-shared subdirectory. +(8) Run vcvars32.bat; this batch file, in your vc98\bin directory will +set necessary environment options for command line compiling. +(9) In bindings\perl-shared, run +perl ntmake.pl +nmake +nmake test +If nmake test succeeds, you are good to go. RRDs.dll is in +blib\arch\auto\RRDs. If you plan to install via the Active State ppm +tool, tar and gzip the blib directory. You can use the RRDs.ppd file +in bindings\perl-shared directory. Remember that as in the case of +rrdtool.exe you will need the DLLs listed in (6) on the machine where +you are going to use RRDs.dll. + +Microsoft Visual C++ 7.1 (.NET 2003): + +Unfortunately, this is more difficult than with VC++ 6.0. The problem +is that by default the C runtime dll for VC++ 7.1 is msvcr71.dll rather +than msvcrt.dll. The GnuWin32 library binaries are all compiled +to use msvcrt.dll and you can't mix msvcr71.dll and msvcrt.dll in the +same process. One option is to download the source code for the libraries +(available from http://gnuwin32.sourceforge.net) recompile them with +VC++ 7.l. Then all the components will use msvcr71.dll. Once you are +going to go this route, you can also use static multi-threaded libraries +and use static linking between rrdtool (or RRDs.dll) and its dependencies. + +To use the GnuWin32 library binaries, you need to trick VC++ 7.1 into +compiling rrdtool to use the older msvcrt.dll. Follow steps (1) - (3) +as above, then: +(4) Obtain a different version of the msvcrt.lib import library that +is compatible with vc7 and points to msvcrt.dll: +msvcrtlib_for_vc7.zip from http://xchat.org/win32/testing +Backup msvcrt.lib in your vc7\lib directory +(\Program Files\Microsoft Visual Studio .NET 2003\vc7\lib) +Then extract the msvcrt.lib from the zip file into the vc7\lib directory. +WARNING: Use this msvcrt.lib at your own risk! This is not a Microsoft +supplied file nor a file supported by anyone associated with rrdtool. +(5) Start Microsoft Visual C++ 7.1. Load the solution file, rrdtool.sln, +from the src subdirectory of your rrdtool code directory. Edit zconf.h, +as needed, as described under (5) above. Compile the release build of +the rrdtool project. +Proceed with steps (6) - (9) as above, if you are using/picking up +the wrong msvcrt.lib import library then nmake test for perl-shared +will fail. + +Note: it is possible in the future that GnuWin32 will provide Win32 +binaries that utilize msvcr71.dll rather than msvcrt.dll. + +5/14/02 Jake Brutlag + +These notes share some insight I gained compiling 1.1.x with +MS Visual C++ 6.0 (using project files). This information may or +may not be accurate at the time you are reading this. + +(1) freetype and rrdtool cannot use precompiled headers (which are +enabled by default for MSVC++ projects). MSVC++ 6.0 does not +support precompiled headers if #include directives contain MACROS. +(2) Compile Release build with Default optimization, not the +Maximize Speed optimization. I encountered some strange errors +(related to argument processing for complex commands like graph-- +perhaps the getopt stuff is too blame) with Maximize Speed. +(3) libart relies upon config.h (ostensibly generated by the +configure script-- but of course not on Win32 platforms). ..\..\confignt +(which contains a static Win32 version of config.h) should be on +the include path. +(4) Fonts are located in the %windir%\fonts, so the default font +is c:\winnt\fonts\cour.ttf. (6/19/02) At Kerry Calvert's suggestion +this setting was moved to confignt\config.h. +(5) libart requires a custom build step to generate art_config.h; this +is done manually via the commands: +cl -I..\..\confignt gen_art_config.c +gen_art_config.exe > art_config.h + +Currently, to compile rrd.lib and rrdtool.exe using +the MSVC++ project files, first start MSVC++ 6.0. Open the rrdtool +workspace (rrdtool.dsw in the src directory). The active project/ +configuration should be rrdtool-Win32 Release. Select Rebuild All +from the Build menu. The static link library (rrd.lib) will +be generated in src\release directory and executable will be generated +in the src\toolrelease directory. + +Compiling RRDtool on NT ... work in progress +--------------------------------------------------------------- + by Tamas Kovacshazy (khazy@mit.bme.hu) + +Persisting Problems with the current NT port: + +Unfortunately, the RRD perl modules does not work with Perl +(ActivePerl) using the current distribution. + +The RRD shared perl module can be compiled after some +modification... + +Follow these steps: + +0. Install perl if you do not have it! + Visit http://www.ActiveState.com/pw32/ for a complete distribution. + +1. Copy ..\gd1.2\release\gd.lib to ..\gd1.2\ +2. Copy ..\src\release\rrd.lib to ..\src +3. perl Makefile.pl + +In this step the system complains about something I do not +understand. The error message is the following: + +Note (probably harmless): No library found for '-lm' + +Is a library missing? But it does not stop with an error... + +4. nmake test (You must have Visual C++ on the machine!) + +After these steps it generates the test files (svgs and rrds), +and they seem to be good. + +The real problem in the shared perl modul is the following: + +I do not know how this installation stuff works. The problem is +that the installation stuff looks for the gd.lib and the +rrd.lib in the ..\gd1.2 and ..\src directory. The UNIX compile +puts the files into these directories, but the NT compile does +not. + +It is all for today, + +khazy + +Tamas Kovacshazy E-mail: khazy@mit.bme.hu +WWW: http://www.mit.bme.hu/~khazy +Technical University of Budapest +Department of Measurement and Information Systems + + +Compiling RRDtool 1.2.x on Win32 with MingW32 gcc: +--------------------------------------------------------------- + +1. Obtain and install the current version of the MingW package. + + http://www.mingw.org/download.shtml + + In the MinGW set you will need the gcc and binutils as a minimum. + +2. Obtain either of the following awk versions and install in a directory + on your System Path: + + - awk.exe + + http://cm.bell-labs.com/cm/cs/awkbook/index.html + + Note: This version has no dependencies to other libs. + + - gawk.exe (GnuWin32 version) + + http://gnuwin32.sourceforge.net/packages/gawk.htm + + Note: Also fetch the dependant libraries for it from the same page. + +3. If you plan to create a 'distribution' release of the RRD Tools, the + Makefile.Win32 will copy all the needed files to an output directory and + then zip the entire directory. A suitable zip utility can be obtained here: + + http://www.info-zip.org/ + + Install in a directory on your System Path. + +4. Obtain the following libraries, ideally install them all under a common + directory: + + = zlib + + http://oss.oetiker.ch/rrdtool/pub/libs/zlib-1.2.3.tar.gz + http://www.zlib.net/ + + = libpng + + http://oss.oetiker.ch/rrdtool/pub/libs/libpng-1.2.12.tar.gz + http://libpng.sourceforge.net/ + + = freetype + + http://oss.oetiker.ch/rrdtool/pub/libs/freetype-2.2.1.tar.gz + http://freetype.sourceforge.net/index2.html + + = libart_lgpl + + http://oss.oetiker.ch/rrdtool/pub/libs/libart_lgpl-2.3.17.tar.gz + http://www.levien.com/libart/ + + Note: libart_lgpl needs a special tweak because the archive contains + only the base directory, but the libart headers are usually included with + a directory prefix; therefore create a subfolder 'libart_lgpl' and move + all files into this subfolder. + +5. Set up for DOS environment. + + Add MingW\bin and MSYS\bin directories to your System path. + + If the libraries share a common directory set the following environment var: + + set LIBBASE= + e.g set LIBBASE=C:\Libraries + + If the libraries are scattered, set the following environment vers: + + set ZLIBSDK= + e.g set ZLIBSDK=C:\mytest\zlib-1.2.3 + set LIBPNG= + set LIBFT2= + set LIBART= + + If using the Gnu Awk (gawk.exe), edit the Makefile.Win32 and change the line: + + AWK = awk + + to + + AWK = gawk + +6. Compile the project. + + All dependent libs are statically linked in. This has the benefit that the + binaries do not depend on any other DLLs. + In order to build the static freetype lib enter the freetype base directory + and type 'make'. If everything is fine a message appears that gcc is detected, + and that you should again type 'make'. Follow that in order to build freetype. + All other libs are build from the sources with the RRDTool Makefile.Win32. + + Switch to the RRDTOOL .\src directory. Then: + + make -f Makefile.Win32 help + + to see the build options, or + + make -f Makefile.Win32 all + + should build the entire package. + +6. Happy Graphing! + + +written by normw & gk. + + diff --git a/acinclude.m4 b/acinclude.m4 index 062216a..b71fe8e 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -9,8 +9,8 @@ dnl if this check fails set the environment variable EX_CHECK_ALL_ERR to YES dnl and prints out a helful message dnl dnl -dnl EX_CHECK_ALL(library, function, header, pkgconf name, tested-version, homepage) -dnl $1 $2 $3 $4 $5 $6 +dnl EX_CHECK_ALL(library, function, header, pkgconf name, tested-version, homepage, cppflags) +dnl $1 $2 $3 $4 $5 $6 $7 dnl dnl AC_DEFUN([EX_CHECK_ALL], @@ -19,7 +19,10 @@ AC_DEFUN([EX_CHECK_ALL], EX_CHECK_STATE=NO ex_check_save_LIBS=${LIBS} ex_check_save_CPPFLAGS=${CPPFLAGS} - ex_check_save_LDFLAGS=${LDPFLAGS} + ex_check_save_LDFLAGS=${LDFLAGS} + if test "x$7" != "x"; then + CPPFLAGS="$CPPFLAGS -I$7" + fi dnl try compiling naked first AC_CHECK_LIB($1,$2, [ AC_CHECK_HEADER($3,[LIBS="-l$1 ${LIBS}";EX_CHECK_STATE=YES],[])],[]) @@ -34,7 +37,10 @@ AC_DEFUN([EX_CHECK_ALL], LIBS=${LIBS}" "`$PKGCONFIG --libs-only-l $4` dnl remove the cached value and test again unset ac_cv_lib_$1_$2 - AC_CHECK_LIB($1,$2,[ AC_CHECK_HEADER($3,[EX_CHECK_STATE=YES],[])],[]) + AC_CHECK_LIB($1,$2,[ + unset ac_cv_header_`echo $3 | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']` + AC_CHECK_HEADER($3,[EX_CHECK_STATE=YES],[]) + ],[]) else AC_MSG_WARN([ ---------------------------------------------------------------------------- @@ -59,7 +65,7 @@ AC_DEFUN([EX_CHECK_ALL], You can find also find an archive copy on - http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/pub/libs + http://oss.oetiker.ch/rrdtool/pub/libs The last tested version of $4 is $5. @@ -77,6 +83,7 @@ AC_DEFUN([EX_CHECK_ALL], AC_LANG_POP(C) ] ) + dnl dnl Ptherad check from http://autoconf-archive.cryp.to/acx_pthread.m4 dnl @@ -282,6 +289,12 @@ if test "x$acx_pthread_ok" = xyes; then case "${host_cpu}-${host_os}" in *-aix* | *-freebsd* | *-darwin*) x_rflag="-D_THREAD_SAFE";; *solaris* | *-osf* | *-hpux*) x_rflag="-D_REENTRANT";; + *-linux*) + if test x"$PTHREAD_CFLAGS" = "x-pthread"; then + # For Linux/gcc "-pthread" implies "-lpthread". We need, however, to make this explicit + # in PTHREAD_LIBS such that a shared library to be built properly depends on libpthread. + PTHREAD_LIBS="-lpthread $PTHREAD_LIBS" + fi;; esac AC_MSG_RESULT(${x_rflag}) if test "x$x_rflag" != xno; then @@ -349,6 +362,12 @@ AC_CACHE_VAL([rd_cv_ieee_$2], # define isinf(a) (fpclass(a) == FP_NINF || fpclass(a) == FP_PINF) #endif +/* solaris 10 it defines isnan such that only forte can compile it ... bad bad */ +#if (defined(HAVE_ISNAN) && defined(isnan) && defined(HAVE_FPCLASS)) +# undef isnan +# define isnan(a) (fpclass(a) == FP_SNAN || fpclass(a) == FP_QNAN) +#endif + /* Digital UNIX */ #if (! defined(HAVE_ISINF) && defined(HAVE_FP_CLASS) && defined(HAVE_FP_CLASS_H)) # define HAVE_ISINF 1 @@ -373,21 +392,21 @@ AC_CACHE_VAL([rd_cv_ieee_$2], #include int main(void){ - double nan,inf,c,zero; + double rrdnan,rrdinf,rrdc,rrdzero; $4; /* some math to see if we get a floating point exception */ - zero=sin(0.0); /* don't let the compiler optimize us away */ - nan=0.0/zero; /* especially here */ - inf=1.0/zero; /* and here. I want to know if it can do the magic */ + rrdzero=sin(0.0); /* don't let the compiler optimize us away */ + rrdnan=0.0/rrdzero; /* especially here */ + rrdinf=1.0/rrdzero; /* and here. I want to know if it can do the magic */ /* at run time without sig fpe */ - c = inf + nan; - c = inf / nan; - if (! isnan(nan)) {printf ("not isnan(NaN) ... "); return 1;} - if (nan == nan) {printf ("nan == nan ... "); return 1;} - if (! isinf(inf)) {printf ("not isinf(oo) ... "); return 1;} - if (! isinf(-inf)) {printf ("not isinf(-oo) ... "); return 1;} - if (! inf > 0) {printf ("not inf > 0 ... "); return 1;} - if (! -inf < 0) {printf ("not -inf < 0 ... "); return 1;} + rrdc = rrdinf + rrdnan; + rrdc = rrdinf / rrdnan; + if (! isnan(rrdnan)) {printf ("not isnan(NaN) ... "); return 1;} + if (rrdnan == rrdnan) {printf ("nan == nan ... "); return 1;} + if (! isinf(rrdinf)) {printf ("not isinf(oo) ... "); return 1;} + if (! isinf(-rrdinf)) {printf ("not isinf(-oo) ... "); return 1;} + if (! rrdinf > 0) {printf ("not inf > 0 ... "); return 1;} + if (! -rrdinf < 0) {printf ("not -inf < 0 ... "); return 1;} return 0; }]])],[rd_cv_ieee_$2=yes],[rd_cv_ieee_$2=no],[:])]) dnl these we run regardles is cached or not @@ -430,10 +449,100 @@ AC_IEEE([out of the box], works, , , , PERLFLAGS="CCFLAGS=-DMUST_DISABLE_SIGFPE"], AC_MSG_ERROR([ Your Compiler does not do propper IEEE math ... Please find out how to -make IEEE math work with your compiler and let me know (oetiker@ee.ethz.ch). +make IEEE math work with your compiler and let me know (tobi@oetiker.ch). Check config.log to see what went wrong ... ]))])])])])])])])])]) AC_LANG_POP(C) ]) + + +dnl a macro to check for ability to create python extensions +dnl AM_CHECK_PYTHON_HEADERS([ACTION-IF-POSSIBLE], [ACTION-IF-NOT-POSSIBLE]) +dnl function also defines PYTHON_INCLUDES +AC_DEFUN([AM_CHECK_PYTHON_HEADERS], +[AC_REQUIRE([AM_PATH_PYTHON]) +AC_MSG_CHECKING(for headers required to compile python extensions) +dnl deduce PYTHON_INCLUDES +py_prefix=`$PYTHON -c "import sys; print sys.prefix"` +py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"` +PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}" +if test "$py_prefix" != "$py_exec_prefix"; then + PYTHON_INCLUDES="$PYTHON_INCLUDES -I${py_exec_prefix}/include/python${PYTHON_VERSION}" +fi +AC_SUBST(PYTHON_INCLUDES) +dnl check if the headers exist: +save_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES" +AC_TRY_CPP([#include ],dnl +[AC_MSG_RESULT(found) +$1],dnl +[AC_MSG_RESULT(not found) +$2]) +CPPFLAGS="$save_CPPFLAGS" +]) + +dnl a macro to add some color to the build process. +dnl CONFIGURE_PART(MESSAGE) + +AC_DEFUN([CONFIGURE_PART],[ +case $TERM in + # for the most important terminal types we directly know the sequences + xterm|xterm*|vt220|vt220*) + T_MD=`awk 'BEGIN { printf("%c%c%c%c", 27, 91, 49, 109); }' /dev/null` + T_ME=`awk 'BEGIN { printf("%c%c%c", 27, 91, 109); }' /dev/null` + ;; + vt100|vt100*|cygwin) + T_MD=`awk 'BEGIN { printf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0); }' /dev/null` + T_ME=`awk 'BEGIN { printf("%c%c%c%c%c", 27, 91, 109, 0, 0); }' /dev/null` + ;; + *) + T_MD='' + T_ME='' + ;; +esac + AC_MSG_RESULT() + AC_MSG_RESULT([${T_MD}$1${T_ME}]) +]) + + +dnl --------------------------------------------------------------------------- +dnl CF_DISABLE_ECHO version: 10 updated: 2003/04/17 22:27:11 +dnl --------------- +dnl stolen from xterm aclocal.m4 +dnl +dnl You can always use "make -n" to see the actual options, but it's hard to +dnl pick out/analyze warning messages when the compile-line is long. +dnl +dnl Sets: +dnl ECHO_LT - symbol to control if libtool is verbose +dnl ECHO_LD - symbol to prefix "cc -o" lines +dnl RULE_CC - symbol to put before implicit "cc -c" lines (e.g., .c.o) +dnl SHOW_CC - symbol to put before explicit "cc -c" lines +dnl ECHO_CC - symbol to put before any "cc" line +dnl +AC_DEFUN([CF_DISABLE_ECHO],[ +AC_MSG_CHECKING(if you want to see long compiling messages) +CF_ARG_DISABLE(echo, + [ --disable-echo display "compiling" commands], + [ + ECHO_LT='--silent' + ECHO_LD='@echo linking [$]@;' + RULE_CC=' @echo compiling [$]<' + SHOW_CC=' @echo compiling [$]@' + ECHO_CC='@' +],[ + ECHO_LT='' + ECHO_LD='' + RULE_CC='# compiling' + SHOW_CC='# compiling' + ECHO_CC='' +]) +AC_MSG_RESULT($enableval) +AC_SUBST(ECHO_LT) +AC_SUBST(ECHO_LD) +AC_SUBST(RULE_CC) +AC_SUBST(SHOW_CC) +AC_SUBST(ECHO_CC) +])dnl diff --git a/bindings/Makefile.am b/bindings/Makefile.am index 48a7508..a0e0907 100644 --- a/bindings/Makefile.am +++ b/bindings/Makefile.am @@ -1,13 +1,36 @@ -SUBDIRS = tcl +.PHONY: python ruby + +if BUILD_TCL +SUB_tcl = tcl +endif + +SUBDIRS = $(SUB_tcl) + # the following files are not mentioned in any other Makefile -EXTRA_DIST = $(shell for A in perl-*; do cat $$A/MANIFEST | sed -e s,^,$$A/, ; done) +EXTRA_DIST = perl-piped/MANIFEST perl-piped/README perl-piped/Makefile.PL perl-piped/RRDp.pm perl-piped/t/base.t \ + perl-shared/ntmake.pl perl-shared/MANIFEST perl-shared/README perl-shared/Makefile.PL perl-shared/RRDs.pm perl-shared/RRDs.xs perl-shared/t/base.t \ + ruby/CHANGES ruby/README ruby/extconf.rb ruby/main.c ruby/test.rb \ + python/ACKNOWLEDGEMENT python/AUTHORS python/COPYING python/README python/rrd_extra.h python/rrdtoolmodule.c python/setup.py + # add the following to the all target -all-local: @COMP_PERL@ +all-local: @COMP_PERL@ @COMP_RUBY@ @COMP_PYTHON@ install-data-local: - cd perl-piped && test -f Makefile && $(MAKE) install || true - cd perl-shared && test -f Makefile && $(MAKE) install || true + test -f perl-piped/Makefile && cd perl-piped && $(MAKE) install || true + test -f perl-shared/Makefile && cd perl-shared && $(MAKE) install || true + test -f ruby/Makefile && cd ruby && $(MAKE) EPREFIX=$(DESTDIR)$(exec_prefix) $(RUBY_MAKE_OPTIONS) install || true + test -d python/build && cd python && env BUILDLIBDIR=../../src/.libs $(PYTHON) setup.py install --skip-build --prefix=$(DESTDIR)$(prefix) --exec-prefix=$(DESTDIR)$(exec_prefix) || true + +# rules for buildung the ruby module +# RUBYARCHDIR= is to work around in a makefile quirk not sure +# it is is the right thing todo, but it makes rrdtool build on freebsd as well +ruby: + cd ruby && $(RUBY) extconf.rb && $(MAKE) EPREFIX=$(exec_prefix) $(RUBY_MAKE_OPTIONS) RUBYARCHDIR= + +# rules for buildung the pyton module +python: + cd python && env BUILDLIBDIR=../../src/.libs $(PYTHON) setup.py build_ext --rpath=$(libdir) && env LIBDIR=../../src/.libs $(PYTHON) setup.py build # rules for building the perl module perl_piped: perl-piped/Makefile @@ -17,13 +40,17 @@ perl-piped/Makefile: perl-piped/Makefile.PL cd perl-piped && $(PERL) Makefile.PL $(PERL_MAKE_OPTIONS) perl_shared: perl-shared/Makefile - cd perl-shared && $(MAKE) RPATH=$(exec_prefix)/lib + cd perl-shared && $(MAKE) perl-shared/Makefile: perl-shared/Makefile.PL - cd perl-shared && $(PERL) Makefile.PL $(PERLFLAGS) $(PERL_MAKE_OPTIONS) + cd perl-shared && $(PERL) Makefile.PL $(PERLFLAGS) $(PERL_MAKE_OPTIONS) RPATH=$(libdir) +# LIBS="$(LDFLAGS) $(LIBS)" $(PERLFLAGS) $(PERL_MAKE_OPTIONS) clean-local: - cd perl-piped && test -f Makefile && $(MAKE) clean || true - cd perl-shared && test -f Makefile && $(MAKE) clean || true - + test -f perl-piped/Makefile && cd perl-piped && $(MAKE) clean || true + test -f perl-piped/Makefile && rm perl-piped/Makefile || true + test -f perl-shared/Makefile && cd perl-shared && $(MAKE) clean || true + test -f perl-shared/Makefile && rm -f perl-shared/Makefile || true + test -f ruby/Makefile && cd ruby && $(MAKE) clean && rm Makefile || true + test -d python/build && cd python && rm -rf build || true ##END## diff --git a/bindings/perl-piped/RRDp.pm b/bindings/perl-piped/RRDp.pm index 89b168e..e61a28b 100644 --- a/bindings/perl-piped/RRDp.pm +++ b/bindings/perl-piped/RRDp.pm @@ -16,7 +16,7 @@ $answer = B $status = B -B<$RRDp::user>, B<$RRDp::sys>, B<$RRDp::real> +B<$RRDp::user>, B<$RRDp::sys>, B<$RRDp::real>, B<$RRDp::error_mode>, B<$RRDp::error> =head1 DESCRIPTION @@ -69,6 +69,16 @@ The difference between user + system and real is the time spent waiting for things like the hard disk and new input from the perl script. +=item B<$RRDp::error_mode> and B<$RRDp::error> + +If you set the variable $RRDp::error_mode to the value 'catch' before you run RRDp::read a potential +ERROR message will not cause the program to abort but will be returned in this variable. If no error +occurs the variable will be empty. + + $RRDp::error_mode = 'catch'; + RRDp::cmd qw(info file.rrd); + print $RRDp::error if $RRDp::error; + =back @@ -89,7 +99,7 @@ For more information on how to use RRDtool, check the manpages. =head1 AUTHOR -Tobias Oetiker +Tobias Oetiker =cut #' this is to make cperl.el happy @@ -110,7 +120,7 @@ sub cmd (@); sub end (); sub read (); -$VERSION = 1.000331 ; +$VERSION=1.2023; sub start ($){ croak "rrdtool is already running" @@ -128,6 +138,7 @@ sub start ($){ sub read () { croak "RRDp::read can only be called after RRDp::cmd" unless $Sequence eq 'C'; + $RRDp::error = undef; $Sequence = 'R'; my $inmask = 0; my $srbuf; @@ -148,9 +159,10 @@ sub read () { $minibuf .= $srbuf; while ($minibuf =~ s|^(.+?)\n||s) { my $line = $1; - # print $line,"\n"; - if ($line =~ m|^ERROR|) { - croak $line; + # print $line,"\n"; + $RRDp::error = undef; + if ($line =~ m|^ERROR|) { + $RRDp::error_mode eq 'catch' ? $RRDp::error = $line : croak $line; $ERR = 1; } elsif ($line =~ m|^OK u:([\d\.]+) s:([\d\.]+) r:([\d\.]+)|){ diff --git a/bindings/perl-piped/t/base.t b/bindings/perl-piped/t/base.t index b7de1f5..5f0b2ae 100755 --- a/bindings/perl-piped/t/base.t +++ b/bindings/perl-piped/t/base.t @@ -23,7 +23,7 @@ $ok_count = 1; print "ok 1 module load\n"; -ok("RRDp::start", RRDp::start "../src/rrdtool" > 0); +ok("RRDp::start", RRDp::start "../../src/rrdtool" > 0); $now=time(); RRDp::cmd qw(create demo.rrd --start ), $now, qw(--step 100 ), diff --git a/bindings/perl-shared/Makefile.PL b/bindings/perl-shared/Makefile.PL index 598fc99..863444c 100644 --- a/bindings/perl-shared/Makefile.PL +++ b/bindings/perl-shared/Makefile.PL @@ -3,18 +3,35 @@ use Config; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. -# Specify the location of the archive containing PIC compiled object files. -my $R = $^O eq 'Linux' ? "-Wl,--rpath -Wl," : "-R" ; -my $librrd = "-L../../src/.libs/ $R\$(RPATH) -lrrd"; +# if the last argument when calling Makefile.PL is RPATH=/... and ... is the +# path to librrd.so then the Makefile will be written such that RRDs.so knows +# where to find librrd.so later on ... +my $R=""; +if ($ARGV[-1] =~ /RPATH=(\S+)/){ + pop @ARGV; + my $rp = $1; + for ($^O){ + /linux/ && do{ $R = "-Wl,--rpath -Wl,$rp"}; + /hpux/ && do{ $R = "+b$rp"}; + /solaris/ && do{ $R = "-R$rp"}; + /aix/ && do{ $R = "-Wl,-blibpath:$rp"}; + } +} + +# darwin works without this because librrd contains its +# install_name which will includes the final location of the +# library after it is installed. This install_name gets transfered +# to the perl shared object. + +my $librrd = "-L../../src/.libs/ $R -lrrd"; WriteMakefile( 'NAME' => 'RRDs', 'VERSION_FROM' => 'RRDs.pm', # finds $VERSION 'DEFINE' => "-DPERLPATCHLEVEL=$Config{PATCHLEVEL}", - 'INC' => '-I../../src -I../../libraries/gd1.3', - # where to look for the necessary libraries + 'INC' => '-I../../src', # Perl will figure out which one is valid - 'depend' => {'RRDs.c' => "../../src/.libs/librrd.a"}, 'dynamic_lib' => {'OTHERLDFLAGS' => "$librrd -lm"}, 'realclean' => {FILES => 't/demo?.rrd t/demo?.png' } ); + diff --git a/bindings/perl-shared/RRDs.pm b/bindings/perl-shared/RRDs.pm index b0d6b7e..9542421 100644 --- a/bindings/perl-shared/RRDs.pm +++ b/bindings/perl-shared/RRDs.pm @@ -7,7 +7,7 @@ use vars qw(@ISA $VERSION); require DynaLoader; -$VERSION = 1.100001; +$VERSION=1.2023; bootstrap RRDs $VERSION; @@ -26,10 +26,13 @@ RRDs - Access RRDtool as a shared module RRDs::info ... RRDs::create ... RRDs::update ... + RRDs::updatev ... RRDs::graph ... RRDs::fetch ... RRDs::tune ... RRDs::times(start, end) + RRDs::dump ... + RRDs::restore ... =head1 DESCRIPTION @@ -137,6 +140,6 @@ operating in the timezone of your choice. =head1 AUTHOR -Tobias Oetiker Eoetiker@ee.ethz.chE +Tobias Oetiker Etobi@oetiker.chE =cut diff --git a/bindings/perl-shared/RRDs.ppd b/bindings/perl-shared/RRDs.ppd index e44f6d3..3a28cd9 100755 --- a/bindings/perl-shared/RRDs.ppd +++ b/bindings/perl-shared/RRDs.ppd @@ -1,7 +1,7 @@ RRDs Round Robin Database Tool - Tobias Oetiker (oetiker@ee.ethz.ch) + Tobias Oetiker (tobi@oetiker.ch) diff --git a/bindings/perl-shared/RRDs.xs b/bindings/perl-shared/RRDs.xs index 217482c..f84efef 100644 --- a/bindings/perl-shared/RRDs.xs +++ b/bindings/perl-shared/RRDs.xs @@ -10,7 +10,25 @@ extern "C" { } #endif +/* + * rrd_tool.h includes config.h, but at least on Ubuntu Breezy Badger + * 5.10 with gcc 4.0.2, the C preprocessor picks up Perl's config.h + * which is included from the Perl includes and never reads rrdtool's + * config.h. Without including rrdtool's config.h, this module does + * not compile, so include it here with an explicit path. + * + * Because rrdtool's config.h redefines VERSION which is originally + * set via Perl's Makefile.PL and passed down to the C compiler's + * command line, save the original value and reset it after the + * includes. + */ +#define VERSION_SAVED VERSION +#undef VERSION +#include "../../rrd_config.h" #include "../../src/rrd_tool.h" +#undef VERSION +#define VERSION VERSION_SAVED +#undef VERSION_SAVED /* perl 5.004 compatibility */ #if PERLPATCHLEVEL < 5 @@ -29,7 +47,6 @@ extern "C" { argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char)); \ strcpy(argv[i+1],handle); \ } \ - optind=0; opterr=0; \ rrd_clear_error();\ RETVAL=name(items+1,argv); \ for (i=0; i < items; i++) {\ @@ -53,7 +70,6 @@ extern "C" { argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char)); \ strcpy(argv[i+1],handle); \ } \ - optind=0; opterr=0; \ rrd_clear_error(); \ data=name(items+1, argv); \ for (i=0; i < items; i++) { \ @@ -203,7 +219,6 @@ rrd_graph(...) argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char)); strcpy(argv[i+1],handle); } - optind=0; opterr=0; rrd_clear_error(); rrd_graph(items+1,argv,&calcpr,&xsize,&ysize,NULL,&ymin,&ymax); for (i=0; i < items; i++) { @@ -251,7 +266,6 @@ rrd_fetch(...) argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char)); strcpy(argv[i+1],handle); } - optind=0; opterr=0; rrd_clear_error(); rrd_fetch(items+1,argv,&start,&end,&step,&ds_cnt,&ds_namv,&data); for (i=0; i < items; i++) { @@ -330,7 +344,6 @@ rrd_xport(...) argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char)); strcpy(argv[i+1],handle); } - optind=0; opterr=0; rrd_clear_error(); rrd_xport(items+1,argv,&xsize,&start,&end,&step,&col_cnt,&legend_v,&data); for (i=0; i < items; i++) { diff --git a/bindings/perl-shared/ntmake.pl b/bindings/perl-shared/ntmake.pl index e3fd3c2..047b76f 100644 --- a/bindings/perl-shared/ntmake.pl +++ b/bindings/perl-shared/ntmake.pl @@ -19,7 +19,7 @@ WriteMakefile( 'LIBS' => '../../src/release/rrd.lib "/Program Files/GnuWin32/lib/libart_lgpl.lib" "/Program Files/GnuWin32/lib/libz.lib" "/Program Files/GnuWin32/lib/libpng.lib" "/Program Files/GnuWin32/lib/libfreetype.lib"', 'realclean' => {FILES => 't/demo?.rrd t/demo?.png' }, ($] ge '5.005') ? ( - 'AUTHOR' => 'Tobias Oetiker (oetiker@ee.ethz.ch)', + 'AUTHOR' => 'Tobias Oetiker (tobi@oetiker.ch)', 'ABSTRACT' => 'Round Robin Database Tool', ) : () diff --git a/bindings/python/ACKNOWLEDGEMENT b/bindings/python/ACKNOWLEDGEMENT new file mode 100644 index 0000000..8cf3658 --- /dev/null +++ b/bindings/python/ACKNOWLEDGEMENT @@ -0,0 +1,7 @@ +ACKNOWLEDGMENT +============== + +This is a list of people who have made contributions to py-rrdtool. + +Matthew W. Samsonoff +Brian E. Gallew diff --git a/bindings/python/AUTHORS b/bindings/python/AUTHORS new file mode 100644 index 0000000..b3b5713 --- /dev/null +++ b/bindings/python/AUTHORS @@ -0,0 +1 @@ +Hye-Shik Chang diff --git a/bindings/python/COPYING b/bindings/python/COPYING new file mode 100644 index 0000000..b1e3f5a --- /dev/null +++ b/bindings/python/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/bindings/python/README b/bindings/python/README new file mode 100644 index 0000000..265244f --- /dev/null +++ b/bindings/python/README @@ -0,0 +1,28 @@ +Python-RRDtool 0.2.1 +-------------------- + +The python-rrdtool provides a interface to rrdtool, the wonderful +graphing and logging utility. This wrapper implementation has +worked from the scratch (without SWIG), and it's under LGPL. + +This module have not documented yet. Please refer pydoc. + + +Project +------- + +Homepage: http://www.nongnu.org/py-rrdtool/ + +Mailing Lists: + + CVS Checkins py-rrdtool-cvs@nongnu.org + Users & Hackers py-rrdtool-users@nongnu.org + + +Author +------ + +Hye-Shik Chang + +Any comments, suggestions, and/or patches are very welcome. +Thank you for using py-rrdtool! diff --git a/bindings/python/rrd_extra.h b/bindings/python/rrd_extra.h new file mode 100644 index 0000000..99b5aa0 --- /dev/null +++ b/bindings/python/rrd_extra.h @@ -0,0 +1,61 @@ +/* + * This file is part of RRDtool. + * + * RRDtool is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * RRDtool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/***************************************************************************** + * RRDtool 1.0.37 Copyright Tobias Oetiker, 1997 - 2000 + ***************************************************************************** + * rrd_tool.h Common Header File + ***************************************************************************** + * Id: rrd_tool.h,v 1.1.1.1 2002/02/26 10:21:37 oetiker Exp + * Log: rrd_tool.h,v + * Revision 1.1.1.1 2002/02/26 10:21:37 oetiker + * Intial Import + * + *****************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _RRD_EXTRA_H +#define _RRD_EXTRA_H + +#include "rrd_format.h" + +#ifndef WIN32 +#ifndef isnan /* POSIX */ +int isnan(double value); +#endif +#else /* Windows only */ +#include +#define isnan _isnan +#endif + +void rrd_free(rrd_t *rrd); +void rrd_init(rrd_t *rrd); + +int rrd_open(char *file_name, FILE **in_file, rrd_t *rrd, int rdwr); +int readfile(char *file, char **buffer, int skipfirst); + +#define RRD_READONLY 0 +#define RRD_READWRITE 1 + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/bindings/python/rrdtoolmodule.c b/bindings/python/rrdtoolmodule.c new file mode 100644 index 0000000..6f5b36c --- /dev/null +++ b/bindings/python/rrdtoolmodule.c @@ -0,0 +1,542 @@ +/* + * rrdtoolmodule.c + * + * RRDTool Python binding + * + * Author : Hye-Shik Chang + * Date : $Date: 2003/02/22 07:41:19 $ + * Created : 23 May 2002 + * + * $Revision: 1.14 $ + * + * ========================================================================== + * This file is part of py-rrdtool. + * + * py-rrdtool is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * py-rrdtool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Foobar; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifdef UNUSED +#elif defined(__GNUC__) +# define UNUSED(x) x __attribute__((unused)) +#elif defined(__LCLINT__) +# define UNUSED(x) /*@unused@*/ x +#else +# define UNUSED(x) x +#endif + +static const char *__version__ = "$Revision: 1.14 $"; + +#include "Python.h" +#include "rrd.h" +#include "rrd_extra.h" + +static PyObject *ErrorObject; +extern int optind; +extern int opterr; + +/* forward declaration to keep compiler happy */ +void initrrdtool(void); + +static int +create_args(char *command, PyObject *args, int *argc, char ***argv) +{ + PyObject *o; + int size, i; + + size = PyTuple_Size(args); + *argv = PyMem_New(char *, size + 1); + if (*argv == NULL) + return -1; + + for (i = 0; i < size; i++) { + o = PyTuple_GET_ITEM(args, i); + if (PyString_Check(o)) + (*argv)[i + 1] = PyString_AS_STRING(o); + else { + PyMem_Del(*argv); + PyErr_Format(PyExc_TypeError, "argument %d must be string", i); + return -1; + } + } + (*argv)[0] = command; + *argc = size + 1; + + /* reset getopt state */ + opterr = optind = 0; + + return 0; +} + +static void +destroy_args(char ***argv) +{ + PyMem_Del(*argv); + *argv = NULL; +} + +static char PyRRD_create__doc__[] = +"create(args..): Set up a new Round Robin Database\n\ + create filename [--start|-b start time] \ +[--step|-s step] [DS:ds-name:DST:heartbeat:min:max] \ +[RRA:CF:xff:steps:rows]"; + +static PyObject * +PyRRD_create(PyObject UNUSED(*self), PyObject *args) +{ + PyObject *r; + char **argv; + int argc; + + if (create_args("create", args, &argc, &argv) < 0) + return NULL; + + if (rrd_create(argc, argv) == -1) { + PyErr_SetString(ErrorObject, rrd_get_error()); + rrd_clear_error(); + r = NULL; + } else { + Py_INCREF(Py_None); + r = Py_None; + } + + destroy_args(&argv); + return r; +} + +static char PyRRD_update__doc__[] = +"update(args..): Store a new set of values into the rrd\n" +" update filename [--template|-t ds-name[:ds-name]...] " +"N|timestamp:value[:value...] [timestamp:value[:value...] ...]"; + +static PyObject * +PyRRD_update(PyObject UNUSED(*self), PyObject *args) +{ + PyObject *r; + char **argv; + int argc; + + if (create_args("update", args, &argc, &argv) < 0) + return NULL; + + if (rrd_update(argc, argv) == -1) { + PyErr_SetString(ErrorObject, rrd_get_error()); + rrd_clear_error(); + r = NULL; + } else { + Py_INCREF(Py_None); + r = Py_None; + } + + destroy_args(&argv); + return r; +} + +static char PyRRD_fetch__doc__[] = +"fetch(args..): fetch data from an rrd.\n" +" fetch filename CF [--resolution|-r resolution] " +"[--start|-s start] [--end|-e end]"; + +static PyObject * +PyRRD_fetch(PyObject UNUSED(*self), PyObject *args) +{ + PyObject *r; + rrd_value_t *data, *datai; + unsigned long step, ds_cnt; + time_t start, end; + int argc; + char **argv, **ds_namv; + + if (create_args("fetch", args, &argc, &argv) < 0) + return NULL; + + if (rrd_fetch(argc, argv, &start, &end, &step, + &ds_cnt, &ds_namv, &data) == -1) { + PyErr_SetString(ErrorObject, rrd_get_error()); + rrd_clear_error(); + r = NULL; + } else { + /* Return : + ((start, end, step), (name1, name2, ...), [(data1, data2, ..), ...]) */ + PyObject *range_tup, *dsnam_tup, *data_list, *t; + unsigned long i, j, row; + rrd_value_t dv; + + row = ((end - start) / step + 1); + + r = PyTuple_New(3); + range_tup = PyTuple_New(3); + dsnam_tup = PyTuple_New(ds_cnt); + data_list = PyList_New(row); + PyTuple_SET_ITEM(r, 0, range_tup); + PyTuple_SET_ITEM(r, 1, dsnam_tup); + PyTuple_SET_ITEM(r, 2, data_list); + + datai = data; + + PyTuple_SET_ITEM(range_tup, 0, PyInt_FromLong((long)start)); + PyTuple_SET_ITEM(range_tup, 1, PyInt_FromLong((long)end)); + PyTuple_SET_ITEM(range_tup, 2, PyInt_FromLong((long)step)); + + for (i = 0; i < ds_cnt; i++) + PyTuple_SET_ITEM(dsnam_tup, i, PyString_FromString(ds_namv[i])); + + for (i = 0; i < row; i ++) { + t = PyTuple_New(ds_cnt); + PyList_SET_ITEM(data_list, i, t); + + for (j = 0; j < ds_cnt; j++) { + dv = *(datai++); + if (isnan(dv)) { + PyTuple_SET_ITEM(t, j, Py_None); + Py_INCREF(Py_None); + } else { + PyTuple_SET_ITEM(t, j, PyFloat_FromDouble((double)dv)); + } + } + } + + for (i = 0; i < ds_cnt; i++) + free(ds_namv[i]); + free(ds_namv); /* rrdtool don't use PyMem_Malloc :) */ + free(data); + } + + destroy_args(&argv); + return r; +} + +static char PyRRD_graph__doc__[] = +"graph(args..): Create a graph based on data from one or several RRD\n" +" graph filename [-s|--start seconds] " +"[-e|--end seconds] [-x|--x-grid x-axis grid and label] " +"[-y|--y-grid y-axis grid and label] [--alt-y-grid] [--alt-y-mrtg] " +"[--alt-autoscale] [--alt-autoscale-max] [--units-exponent] value " +"[-v|--vertical-label text] [-w|--width pixels] [-h|--height pixels] " +"[-i|--interlaced] " +"[-f|--imginfo formatstring] [-a|--imgformat GIF|PNG|GD] " +"[-B|--background value] [-O|--overlay value] " +"[-U|--unit value] [-z|--lazy] [-o|--logarithmic] " +"[-u|--upper-limit value] [-l|--lower-limit value] " +"[-g|--no-legend] [-r|--rigid] [--step value] " +"[-b|--base value] [-c|--color COLORTAG#rrggbb] " +"[-t|--title title] [DEF:vname=rrd:ds-name:CF] " +"[CDEF:vname=rpn-expression] [PRINT:vname:CF:format] " +"[GPRINT:vname:CF:format] [COMMENT:text] " +"[HRULE:value#rrggbb[:legend]] [VRULE:time#rrggbb[:legend]] " +"[LINE{1|2|3}:vname[#rrggbb[:legend]]] " +"[AREA:vname[#rrggbb[:legend]]] " +"[STACK:vname[#rrggbb[:legend]]]"; + +static PyObject * +PyRRD_graph(PyObject UNUSED(*self), PyObject *args) +{ + PyObject *r; + char **argv, **calcpr; + int argc, xsize, ysize, i; + double ymin, ymax; + if (create_args("graph", args, &argc, &argv) < 0) + return NULL; + + if (rrd_graph(argc, argv, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) == -1) { + PyErr_SetString(ErrorObject, rrd_get_error()); + rrd_clear_error(); + r = NULL; + } else { + r = PyTuple_New(3); + + PyTuple_SET_ITEM(r, 0, PyInt_FromLong((long)xsize)); + PyTuple_SET_ITEM(r, 1, PyInt_FromLong((long)ysize)); + + if (calcpr) { + PyObject *e, *t; + + e = PyList_New(0); + PyTuple_SET_ITEM(r, 2, e); + + for(i = 0; calcpr[i]; i++) { + t = PyString_FromString(calcpr[i]); + PyList_Append(e, t); + Py_DECREF(t); + free(calcpr[i]); + } + free(calcpr); + } else { + Py_INCREF(Py_None); + PyTuple_SET_ITEM(r, 2, Py_None); + } + } + + destroy_args(&argv); + return r; +} + +static char PyRRD_tune__doc__[] = +"tune(args...): Modify some basic properties of a Round Robin Database\n" +" tune filename [--heartbeat|-h ds-name:heartbeat] " +"[--minimum|-i ds-name:min] [--maximum|-a ds-name:max] " +"[--data-source-type|-d ds-name:DST] [--data-source-rename|-r old-name:new-name]"; + +static PyObject * +PyRRD_tune(PyObject UNUSED(*self), PyObject *args) +{ + PyObject *r; + char **argv; + int argc; + + if (create_args("tune", args, &argc, &argv) < 0) + return NULL; + + if (rrd_tune(argc, argv) == -1) { + PyErr_SetString(ErrorObject, rrd_get_error()); + rrd_clear_error(); + r = NULL; + } else { + Py_INCREF(Py_None); + r = Py_None; + } + + destroy_args(&argv); + return r; +} + +static char PyRRD_first__doc__[] = +"first(filename): Return the timestamp of the first data sample in an RRD"; + +static PyObject * +PyRRD_first(PyObject UNUSED(*self), PyObject *args) +{ + PyObject *r; + int argc, ts; + char **argv; + + if (create_args("first", args, &argc, &argv) < 0) + return NULL; + + if ((ts = rrd_first(argc, argv)) == -1) { + PyErr_SetString(ErrorObject, rrd_get_error()); + rrd_clear_error(); + r = NULL; + } else + r = PyInt_FromLong((long)ts); + + destroy_args(&argv); + return r; +} + +static char PyRRD_last__doc__[] = +"last(filename): Return the timestamp of the last data sample in an RRD"; + +static PyObject * +PyRRD_last(PyObject UNUSED(*self), PyObject *args) +{ + PyObject *r; + int argc, ts; + char **argv; + + if (create_args("last", args, &argc, &argv) < 0) + return NULL; + + if ((ts = rrd_last(argc, argv)) == -1) { + PyErr_SetString(ErrorObject, rrd_get_error()); + rrd_clear_error(); + r = NULL; + } else + r = PyInt_FromLong((long)ts); + + destroy_args(&argv); + return r; +} + +static char PyRRD_resize__doc__[] = +"resize(args...): alters the size of an RRA.\n" +" resize filename rra-num GROW|SHRINK rows"; + +static PyObject * +PyRRD_resize(PyObject UNUSED(*self), PyObject *args) +{ + PyObject *r; + char **argv; + int argc, ts; + + if (create_args("resize", args, &argc, &argv) < 0) + return NULL; + + if ((ts = rrd_resize(argc, argv)) == -1) { + PyErr_SetString(ErrorObject, rrd_get_error()); + rrd_clear_error(); + r = NULL; + } else { + Py_INCREF(Py_None); + r = Py_None; + } + + destroy_args(&argv); + return r; +} + +static char PyRRD_info__doc__[] = +"info(filename): extract header information from an rrd"; + +static PyObject * +PyRRD_info(PyObject UNUSED(*self), PyObject *args) +{ + PyObject *r, *t, *ds; + rrd_t rrd; + FILE *in_file; + char *filename; + unsigned long i, j; + + if (! PyArg_ParseTuple(args, "s:info", &filename)) + return NULL; + + if (rrd_open(filename, &in_file, &rrd, RRD_READONLY) == -1) { + PyErr_SetString(ErrorObject, rrd_get_error()); + rrd_clear_error(); + return NULL; + } + fclose(in_file); + +#define DICTSET_STR(dict, name, value) \ + t = PyString_FromString(value); \ + PyDict_SetItemString(dict, name, t); \ + Py_DECREF(t); + +#define DICTSET_CNT(dict, name, value) \ + t = PyInt_FromLong((long)value); \ + PyDict_SetItemString(dict, name, t); \ + Py_DECREF(t); + +#define DICTSET_VAL(dict, name, value) \ + t = isnan(value) ? (Py_INCREF(Py_None), Py_None) : \ + PyFloat_FromDouble((double)value); \ + PyDict_SetItemString(dict, name, t); \ + Py_DECREF(t); + + r = PyDict_New(); + + DICTSET_STR(r, "filename", filename); + DICTSET_STR(r, "rrd_version", rrd.stat_head->version); + DICTSET_CNT(r, "step", rrd.stat_head->pdp_step); + DICTSET_CNT(r, "last_update", rrd.live_head->last_up); + + ds = PyDict_New(); + PyDict_SetItemString(r, "ds", ds); + Py_DECREF(ds); + + for (i = 0; i < rrd.stat_head->ds_cnt; i++) { + PyObject *d; + + d = PyDict_New(); + PyDict_SetItemString(ds, rrd.ds_def[i].ds_nam, d); + Py_DECREF(d); + + DICTSET_STR(d, "ds_name", rrd.ds_def[i].ds_nam); + DICTSET_STR(d, "type", rrd.ds_def[i].dst); + DICTSET_CNT(d, "minimal_heartbeat", rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt); + DICTSET_VAL(d, "min", rrd.ds_def[i].par[DS_min_val].u_val); + DICTSET_VAL(d, "max", rrd.ds_def[i].par[DS_max_val].u_val); + DICTSET_STR(d, "last_ds", rrd.pdp_prep[i].last_ds); + DICTSET_VAL(d, "value", rrd.pdp_prep[i].scratch[PDP_val].u_val); + DICTSET_CNT(d, "unknown_sec", rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt); + } + + ds = PyList_New(rrd.stat_head->rra_cnt); + PyDict_SetItemString(r, "rra", ds); + Py_DECREF(ds); + + for (i = 0; i < rrd.stat_head->rra_cnt; i++) { + PyObject *d, *cdp; + + d = PyDict_New(); + PyList_SET_ITEM(ds, i, d); + + DICTSET_STR(d, "cf", rrd.rra_def[i].cf_nam); + DICTSET_CNT(d, "rows", rrd.rra_def[i].row_cnt); + DICTSET_CNT(d, "pdp_per_row", rrd.rra_def[i].pdp_cnt); + DICTSET_VAL(d, "xff", rrd.rra_def[i].par[RRA_cdp_xff_val].u_val); + + cdp = PyList_New(rrd.stat_head->ds_cnt); + PyDict_SetItemString(d, "cdp_prep", cdp); + Py_DECREF(cdp); + + for (j = 0; j < rrd.stat_head->ds_cnt; j++) { + PyObject *cdd; + + cdd = PyDict_New(); + PyList_SET_ITEM(cdp, j, cdd); + + DICTSET_VAL(cdd, "value", + rrd.cdp_prep[i*rrd.stat_head->ds_cnt+j].scratch[CDP_val].u_val); + DICTSET_CNT(cdd, "unknown_datapoints", + rrd.cdp_prep[i*rrd.stat_head->ds_cnt+j].scratch[CDP_unkn_pdp_cnt].u_cnt); + } + } + + rrd_free(&rrd); + + return r; +} + +/* List of methods defined in the module */ +#define meth(name, func, doc) {name, (PyCFunction)func, METH_VARARGS, doc} + +static PyMethodDef _rrdtool_methods[] = { + meth("create", PyRRD_create, PyRRD_create__doc__), + meth("update", PyRRD_update, PyRRD_update__doc__), + meth("fetch", PyRRD_fetch, PyRRD_fetch__doc__), + meth("graph", PyRRD_graph, PyRRD_graph__doc__), + meth("tune", PyRRD_tune, PyRRD_tune__doc__), + meth("first", PyRRD_first, PyRRD_first__doc__), + meth("last", PyRRD_last, PyRRD_last__doc__), + meth("resize", PyRRD_resize, PyRRD_resize__doc__), + meth("info", PyRRD_info, PyRRD_info__doc__), + {NULL, NULL,0,NULL} +}; + +#define SET_INTCONSTANT(dict, value) \ + t = PyInt_FromLong((long)value); \ + PyDict_SetItemString(dict, #value, t); \ + Py_DECREF(t); +#define SET_STRCONSTANT(dict, value) \ + t = PyString_FromString(value); \ + PyDict_SetItemString(dict, #value, t); \ + Py_DECREF(t); + +/* Initialization function for the module */ +void +initrrdtool(void) +{ + PyObject *m, *d, *t; + + /* Create the module and add the functions */ + m = Py_InitModule("rrdtool", _rrdtool_methods); + + /* Add some symbolic constants to the module */ + d = PyModule_GetDict(m); + + SET_STRCONSTANT(d, __version__); + ErrorObject = PyErr_NewException("rrdtool.error", NULL, NULL); + PyDict_SetItemString(d, "error", ErrorObject); + + /* Check for errors */ + if (PyErr_Occurred()) + Py_FatalError("can't initialize the rrdtool module"); +} + +/* + * $Id: _rrdtoolmodule.c,v 1.14 2003/02/22 07:41:19 perky Exp $ + * ex: ts=8 sts=4 et + */ diff --git a/bindings/python/setup.py b/bindings/python/setup.py new file mode 100644 index 0000000..7a41a11 --- /dev/null +++ b/bindings/python/setup.py @@ -0,0 +1,55 @@ +#! /usr/bin/env python +# +# setup.py +# +# py-rrdtool distutil setup +# +# Author : Hye-Shik Chang +# Date : $Date: 2003/02/14 02:38:16 $ +# Created : 24 May 2002 +# +# $Revision: 1.7 $ +# +# ========================================================================== +# This file is part of py-rrdtool. +# +# py-rrdtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# py-rrdtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Foobar; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +from distutils.core import setup, Extension +import sys, os + +RRDBASE = os.environ.get('LOCALBASE', '../../src') +library_dir = os.environ.get('BUILDLIBDIR', os.path.join(RRDBASE, 'lib')) +include_dir = os.environ.get('INCDIR', RRDBASE) + +setup(name = "py-rrdtool", + version = "0.2.1", + description = "Python Interface to RRDTool", + author = "Hye-Shik Chang", + author_email = "perky@fallin.lv", + license = "LGPL", + url = "http://oss.oetiker.ch/rrdtool", + #packages = ['rrdtool'], + ext_modules = [ + Extension( + "rrdtoolmodule", + ["rrdtoolmodule.c"], + libraries=['rrd'], + library_dirs=[library_dir], + include_dirs=[include_dir], + ) + ] +) diff --git a/bindings/ruby/CHANGES b/bindings/ruby/CHANGES new file mode 100644 index 0000000..c84ff29 --- /dev/null +++ b/bindings/ruby/CHANGES @@ -0,0 +1,3 @@ +2006-07-25 Loïs Lherbier + add y_min and y_max parameters to rrd_graph + update test.rb to send only strings to RRD.fetch diff --git a/bindings/ruby/README b/bindings/ruby/README new file mode 100644 index 0000000..888a062 --- /dev/null +++ b/bindings/ruby/README @@ -0,0 +1,22 @@ +# +# ruby librrd bindings +# author: Miles Egan +# + +- Introduction + +This module provides ruby bindings for librrd, with functionality +comparable to the native perl bindings. See test.rb for a script that +exercises all ruby-librrd functionality. + +- Installation + +Installation is standard. Simply run: + +ruby extconf.rb +make +make install + +I hope this works for you. Please let me know if you have any +problems or suggestions. Someday when I'm feeling less lazy I'll +actually document this thing. Thanks to Tobi for rrdtool! diff --git a/bindings/ruby/extconf.rb b/bindings/ruby/extconf.rb new file mode 100644 index 0000000..2045e5a --- /dev/null +++ b/bindings/ruby/extconf.rb @@ -0,0 +1,18 @@ +# $Id: extconf.rb,v 1.2 2001/11/28 18:30:16 miles Exp $ +# Lost ticket pays maximum rate. + +require 'mkmf' + +if /linux/ =~ RUBY_PLATFORM + $LDFLAGS += '-Wl,--rpath -Wl,$(EPREFIX)/lib' +elsif /solaris/ =~ RUBY_PLATFORM + $LDFLAGS += '-R$(EPREFIX)/lib' +elsif /hpux/ =~ RUBY_PLATFORM + $LDFLAGS += '+b$(EPREFIX)/lib' +elsif /aix/ =~ RUBY_PLATFORM + $LDFLAGS += '-Wl,-blibpath:$(EPREFIX)/lib' +end + +dir_config("rrd","../../src","../../src/.libs") +have_library("rrd", "rrd_create") +create_makefile("RRD") diff --git a/bindings/ruby/main.c b/bindings/ruby/main.c new file mode 100644 index 0000000..b2eaa68 --- /dev/null +++ b/bindings/ruby/main.c @@ -0,0 +1,259 @@ +/* $Id$ + * Substantial penalty for early withdrawal. + */ + +#include +#include +#include + +typedef struct string_arr_t { + int len; + char **strings; +} string_arr; + +VALUE mRRD; +VALUE rb_eRRDError; + +typedef int (*RRDFUNC)(int argc, char ** argv); +#define RRD_CHECK_ERROR \ + if (rrd_test_error()) \ + rb_raise(rb_eRRDError, rrd_get_error()); \ + rrd_clear_error(); + +string_arr string_arr_new(VALUE rb_strings) +{ + string_arr a; + char buf[64]; + int i; + + Check_Type(rb_strings, T_ARRAY); + a.len = RARRAY(rb_strings)->len + 1; + + a.strings = malloc(a.len * sizeof(char *)); + a.strings[0] = "dummy"; /* first element is a dummy element */ + + for (i = 0; i < a.len - 1; i++) { + VALUE v = rb_ary_entry(rb_strings, i); + switch (TYPE(v)) { + case T_STRING: + a.strings[i + 1] = strdup(STR2CSTR(v)); + break; + case T_FIXNUM: + snprintf(buf, 63, "%d", FIX2INT(v)); + a.strings[i + 1] = strdup(buf); + break; + default: + rb_raise(rb_eTypeError, "invalid argument"); + break; + } + } + + return a; +} + +void string_arr_delete(string_arr a) +{ + int i; + + /* skip dummy first entry */ + for (i = 1; i < a.len; i++) { + free(a.strings[i]); + } + + free(a.strings); +} + +void reset_rrd_state() +{ + optind = 0; + opterr = 0; + rrd_clear_error(); +} + +VALUE rrd_call(RRDFUNC func, VALUE args) +{ + string_arr a; + + a = string_arr_new(args); + reset_rrd_state(); + func(a.len, a.strings); + string_arr_delete(a); + + RRD_CHECK_ERROR + + return Qnil; +} + +VALUE rb_rrd_create(VALUE self, VALUE args) +{ + return rrd_call(rrd_create, args); +} + +VALUE rb_rrd_dump(VALUE self, VALUE args) +{ + return rrd_call(rrd_dump, args); +} + +VALUE rb_rrd_fetch(VALUE self, VALUE args) +{ + string_arr a; + unsigned long i, j, k, step, ds_cnt; + rrd_value_t *raw_data; + char **raw_names; + VALUE data, names, result; + time_t start, end; + + a = string_arr_new(args); + reset_rrd_state(); + rrd_fetch(a.len, a.strings, &start, &end, &step, &ds_cnt, &raw_names, &raw_data); + string_arr_delete(a); + + RRD_CHECK_ERROR + + names = rb_ary_new(); + for (i = 0; i < ds_cnt; i++) { + rb_ary_push(names, rb_str_new2(raw_names[i])); + free(raw_names[i]); + } + free(raw_names); + + k = 0; + data = rb_ary_new(); + for (i = start; i <= end; i += step) { + VALUE line = rb_ary_new2(ds_cnt); + for (j = 0; j < ds_cnt; j++) { + rb_ary_store(line, j, rb_float_new(raw_data[k])); + k++; + } + rb_ary_push(data, line); + } + free(raw_data); + + result = rb_ary_new2(4); + rb_ary_store(result, 0, INT2FIX(start)); + rb_ary_store(result, 1, INT2FIX(end)); + rb_ary_store(result, 2, names); + rb_ary_store(result, 2, data); + return result; +} + +VALUE rb_rrd_graph(VALUE self, VALUE args) +{ + string_arr a; + char **calcpr, **p; + VALUE result, print_results; + int xsize, ysize; + double ymin, ymax; + + a = string_arr_new(args); + reset_rrd_state(); + rrd_graph(a.len, a.strings, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax); + string_arr_delete(a); + + RRD_CHECK_ERROR + + result = rb_ary_new2(3); + print_results = rb_ary_new(); + p = calcpr; + for (p = calcpr; p && *p; p++) { + rb_ary_push(print_results, rb_str_new2(*p)); + free(*p); + } + free(calcpr); + rb_ary_store(result, 0, print_results); + rb_ary_store(result, 1, INT2FIX(xsize)); + rb_ary_store(result, 2, INT2FIX(ysize)); + return result; +} + +/* +VALUE rb_rrd_info(VALUE self, VALUE args) +{ + string_arr a; + info_t *p; + VALUE result; + + a = string_arr_new(args); + data = rrd_info(a.len, a.strings); + string_arr_delete(a); + + RRD_CHECK_ERROR + + result = rb_hash_new(); + while (data) { + VALUE key = rb_str_new2(data->key); + switch (data->type) { + case RD_I_VAL: + if (isnan(data->u_val)) { + rb_hash_aset(result, key, Qnil); + } + else { + rb_hash_aset(result, key, rb_float_new(data->u_val)); + } + break; + case RD_I_CNT: + rb_hash_aset(result, key, INT2FIX(data->u_cnt)); + break; + case RD_I_STR: + rb_hash_aset(result, key, rb_str_new2(data->u_str)); + free(data->u_str); + break; + } + p = data; + data = data->next; + free(p); + } + return result; +} +*/ + +VALUE rb_rrd_last(VALUE self, VALUE args) +{ + string_arr a; + time_t last; + + a = string_arr_new(args); + reset_rrd_state(); + last = rrd_last(a.len, a.strings); + string_arr_delete(a); + + RRD_CHECK_ERROR + + return rb_funcall(rb_cTime, rb_intern("at"), 1, INT2FIX(last)); +} + +VALUE rb_rrd_resize(VALUE self, VALUE args) +{ + return rrd_call(rrd_resize, args); +} + +VALUE rb_rrd_restore(VALUE self, VALUE args) +{ + return rrd_call(rrd_restore, args); +} + +VALUE rb_rrd_tune(VALUE self, VALUE args) +{ + return rrd_call(rrd_tune, args); +} + +VALUE rb_rrd_update(VALUE self, VALUE args) +{ + return rrd_call(rrd_update, args); +} + +void Init_RRD() +{ + mRRD = rb_define_module("RRD"); + rb_eRRDError = rb_define_class("RRDError", rb_eStandardError); + + rb_define_module_function(mRRD, "create", rb_rrd_create, -2); + rb_define_module_function(mRRD, "dump", rb_rrd_dump, -2); + rb_define_module_function(mRRD, "fetch", rb_rrd_fetch, -2); + rb_define_module_function(mRRD, "graph", rb_rrd_graph, -2); + rb_define_module_function(mRRD, "last", rb_rrd_last, -2); + rb_define_module_function(mRRD, "resize", rb_rrd_resize, -2); + rb_define_module_function(mRRD, "restore", rb_rrd_restore, -2); + rb_define_module_function(mRRD, "tune", rb_rrd_tune, -2); + rb_define_module_function(mRRD, "update", rb_rrd_update, -2); +} diff --git a/bindings/ruby/test.rb b/bindings/ruby/test.rb new file mode 100755 index 0000000..4853326 --- /dev/null +++ b/bindings/ruby/test.rb @@ -0,0 +1,52 @@ +#!/usr/bin/env ruby +# $Id: test.rb,v 1.2 2002/10/22 17:34:00 miles Exp $ +# Driver does not carry cash. + +$: << '/scratch/rrd12build/lib/ruby/1.8/i386-linux/' + +require "RRD" + +name = "test" +rrd = "#{name}.rrd" +start = Time.now.to_i + +puts "creating #{rrd}" +RRD.create( + rrd, + "--start", "#{start - 1}", + "--step", "300", + "DS:a:GAUGE:600:U:U", + "DS:b:GAUGE:600:U:U", + "RRA:AVERAGE:0.5:1:300") +puts + +puts "updating #{rrd}" +start.to_i.step(start.to_i + 300 * 300, 300) { |i| + RRD.update(rrd, "#{i}:#{rand(100)}:#{Math.sin(i / 800) * 50 + 50}") +} +puts + +puts "fetching data from #{rrd}" +(fstart, fend, data) = RRD.fetch(rrd, "--start", start.to_s, "--end", (start + 300 * 300).to_s, "AVERAGE") +puts "got #{data.length} data points from #{fstart} to #{fend}" +puts + +puts "generating graph #{name}.png" +RRD.graph( + "#{name}.png", + "--title", " RubyRRD Demo", + "--start", "#{start+3600}", + "--end", "start + 1000 min", + "--interlace", + "--imgformat", "PNG", + "--width=450", + "DEF:a=#{rrd}:a:AVERAGE", + "DEF:b=#{rrd}:b:AVERAGE", + "CDEF:line=TIME,2400,%,300,LT,a,UNKN,IF", + "AREA:b#00b6e4:beta", + "AREA:line#0022e9:alpha", + "LINE3:line#ff0000") +puts + +print "This script has created #{name}.png in the current directory\n"; +print "This demonstrates the use of the TIME and % RPN operators\n"; diff --git a/bindings/tcl/Makefile.am b/bindings/tcl/Makefile.am index 7fd7012..c73a6e2 100644 --- a/bindings/tcl/Makefile.am +++ b/bindings/tcl/Makefile.am @@ -1,47 +1,56 @@ -EXTRA_DIST = README ifOctets.tcl tclrrd.c -CLEANFILES = tclrrd.o tclrrd.so +EXTRA_DIST = README tclrrd.c VERSION = @VERSION@ -CFLAGS = @CFLAGS@ +AM_CFLAGS = @CFLAGS@ + TCL_PREFIX = @TCL_PREFIX@ TCL_SHLIB_LD = @TCL_SHLIB_LD@ TCL_SHLIB_CFLAGS = @TCL_SHLIB_CFLAGS@ TCL_SHLIB_SUFFIX = @TCL_SHLIB_SUFFIX@ -TCL_PACKAGE_PATH = $(DESTDIR)@TCL_PACKAGE_PATH@ +TCL_PACKAGE_PATH = @TCL_PACKAGE_PATH@ TCL_LD_SEARCH_FLAGS = @TCL_LD_SEARCH_FLAGS@ -GD_LIB_DIR = $(top_srcdir)/@GD_LIB_DIR@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ + +CLEANFILES = tclrrd.o tclrrd.so SRC_DIR = $(top_srcdir)/src -AM_CPPFLAGS = -I$(TCL_PREFIX)/include -I$(SRC_DIR) -I$(GD_LIB_DIR) -LIBDIRS = -L$(libdir) -L$(SRC_DIR) -L../src/.libs +AM_CPPFLAGS = -I$(TCL_PREFIX)/include -I$(SRC_DIR) -DUSE_TCL_STUBS +LIBDIRS = -L$(top_builddir)/src/.libs -L$(top_builddir)/src -L$(libdir) LIB_RUNTIME_DIR = $(libdir) -if COMP_TCL - -tclrrd$(TCL_SHLIB_SUFFIX): tclrrd.o - $(TCL_SHLIB_LD) $(LIBDIRS) $< -o $@ -lrrd_private -lm +if BUILD_TCL_SITE +tclpkgdir = @TCL_PACKAGE_DIR@ +tclpkg_DATA = pkgIndex.tcl +tclpkg_SCRIPTS = ifOctets.tcl +else +pkglib_DATA = pkgIndex.tcl +pkglib_SCRIPTS = ifOctets.tcl +endif -tclrrd.o: tclrrd.c - $(CC) $(CFLAGS) $(TCL_SHLIB_CFLAGS) $(INCLUDES) -c $< -DVERSION=\"$(VERSION)\" +# Automake doen't like `tclrrd$(VERSION)$(TCL_SHLIB_SUFFIX)' as +# library name. So we build and install this library `by hand'. +# +# We do, however, specify a lib_LIBRARIES target such that +# automake creates the directory (if neecessary). +# +TCL_RRD_LIB = tclrrd$(VERSION)$(TCL_SHLIB_SUFFIX) -all-local: tclrrd$(TCL_SHLIB_SUFFIX) +lib_LIBRARIES = -tcl-install: tclrrd$(TCL_SHLIB_SUFFIX) - cp tclrrd$(TCL_SHLIB_SUFFIX) $(TCL_PACKAGE_PATH)/tclrrd$(VERSION)$(TCL_SHLIB_SUFFIX) - if [ ! -d $(TCL_PACKAGE_PATH)/tclrrd$(VERSION) ] ; then \ - mkdir $(TCL_PACKAGE_PATH)/tclrrd$(VERSION) ; \ - fi - echo "package ifneeded Rrd $(VERSION) [list load [file join \$$dir .. tclrrd$(VERSION)$(TCL_SHLIB_SUFFIX)]]" > $(TCL_PACKAGE_PATH)/tclrrd$(VERSION)/pkgIndex.tcl +all-local: $(TCL_RRD_LIB) -else +$(TCL_RRD_LIB): tclrrd.o + $(TCL_SHLIB_LD) $(TCL_LD_SEARCH_FLAGS) $(LIBDIRS) $< -o $@ -lrrd_th -lm $(TCL_STUB_LIB_SPEC) $(LDFLAGS) $(LIBS) -all-local: +tclrrd.o: tclrrd.c + $(CC) $(AM_CFLAGS) $(CFLAGS) $(TCL_SHLIB_CFLAGS) $(AM_CPPFLAGS) -c $< -DVERSION=\"$(VERSION)\" -endif +pkgIndex.tcl: + echo "package ifneeded Rrd $(VERSION) \"load $(libdir)/tclrrd$(VERSION)[info sharedlibextension]\"" > $@ -diff: - cd .. ; diff -c -u -r -N --exclude Makefile --exclude html --exclude doc --exclude Makefile.in --exclude Makefile.old --exclude perl --exclude aclocal.m4 --exclude configure rrdtool-1.0.13 rrdtool-1.0.13-ibr > rrdtool-1.0.13-ibr.patch - +install-exec-local: $(TCL_RRD_LIB) + @$(NORMAL_INSTALL) + $(INSTALL_PROGRAM) $(TCL_RRD_LIB) $(DESTDIR)$(libdir)/$(TCL_RRD_LIB) diff --git a/bindings/tcl/ifOctets.tcl b/bindings/tcl/ifOctets.tcl deleted file mode 100644 index 34185b2..0000000 --- a/bindings/tcl/ifOctets.tcl +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh -# the next line restarts using tclsh -*- tcl -*- \ -exec tclsh8.2 "$0" "$@" - -#package require Tnm 3.0 -package require Rrd 1.0.13 - -set rrdfile "[lindex $argv 0]-[lindex $argv 1].rrd" - -# create rrdfile if not yet existent -if {[file exists $rrdfile] == 0} { - Rrd::create $rrdfile --step 5 \ - DS:inOctets:COUNTER:10:U:U DS:outOctets:COUNTER:10:U:U \ - RRA:AVERAGE:0.5:1:12 -} - -# get an snmp session context -set session [Tnm::snmp generator -address [lindex $argv 0]] - -# walk through the ifDescr column to find the right interface -$session walk descr IF-MIB!ifDescr { - - # is this the right interface? - if {"[Tnm::snmp value $descr 0]" == "[lindex $argv 1]"} { - - # get the instance part of this table row - set inst [lindex [Tnm::mib split [Tnm::snmp oid $descr 0]] 1] - - # get the two interface's octet counter values - set in [lindex [lindex [$session get IF-MIB!ifInOctets.$inst] 0] 2] - set out [lindex [lindex [$session get IF-MIB!ifOutOctets.$inst] 0] 2] - - # write the values to the rrd - puts "$in $out" - Rrd::update $rrdfile --template inOctets:outOctets N:$in:$out - - Rrd::graph gaga.png --title "gaga" \ - DEF:in=$rrdfile:inOctets:AVERAGE \ - DEF:out=$rrdfile:outOctets:AVERAGE \ - AREA:in#0000FF:inOctets \ - LINE2:out#00C000:outOctets - - #puts [Rrd::fetch $rrdfile AVERAGE] - } -} diff --git a/bindings/tcl/ifOctets.tcl.in b/bindings/tcl/ifOctets.tcl.in new file mode 100644 index 0000000..7a36397 --- /dev/null +++ b/bindings/tcl/ifOctets.tcl.in @@ -0,0 +1,45 @@ +#!/bin/sh +# the next line restarts using tclsh -*- tcl -*- \ +exec tclsh@TCL_VERSION@ "$0" "$@" + +#package require Tnm 3.0 +package require Rrd @VERSION@ + +set rrdfile "[lindex $argv 0]-[lindex $argv 1].rrd" + +# create rrdfile if not yet existent +if {[file exists $rrdfile] == 0} { + Rrd::create $rrdfile --step 5 \ + DS:inOctets:COUNTER:10:U:U DS:outOctets:COUNTER:10:U:U \ + RRA:AVERAGE:0.5:1:12 +} + +# get an snmp session context +set session [Tnm::snmp generator -address [lindex $argv 0]] + +# walk through the ifDescr column to find the right interface +$session walk descr IF-MIB!ifDescr { + + # is this the right interface? + if {"[Tnm::snmp value $descr 0]" == "[lindex $argv 1]"} { + + # get the instance part of this table row + set inst [lindex [Tnm::mib split [Tnm::snmp oid $descr 0]] 1] + + # get the two interface's octet counter values + set in [lindex [lindex [$session get IF-MIB!ifInOctets.$inst] 0] 2] + set out [lindex [lindex [$session get IF-MIB!ifOutOctets.$inst] 0] 2] + + # write the values to the rrd + puts "$in $out" + Rrd::update $rrdfile --template inOctets:outOctets N:$in:$out + + Rrd::graph gaga.png --title "gaga" \ + DEF:in=$rrdfile:inOctets:AVERAGE \ + DEF:out=$rrdfile:outOctets:AVERAGE \ + AREA:in#0000FF:inOctets \ + LINE2:out#00C000:outOctets + + #puts [Rrd::fetch $rrdfile AVERAGE] + } +} diff --git a/bindings/tcl/tclrrd.c b/bindings/tcl/tclrrd.c index 3cc1711..11d25df 100644 --- a/bindings/tcl/tclrrd.c +++ b/bindings/tcl/tclrrd.c @@ -3,6 +3,8 @@ * * Copyright (c) 1999,2000 Frank Strauss, Technical University of Braunschweig. * + * Thread-safe code copyright (c) 2005 Oleg Derevenetz, CenterTelecom Voronezh ISP. + * * See the file "COPYING" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * @@ -11,31 +13,35 @@ +#include +#include #include +#include #include -#include -#include +#include "../../src/rrd_tool.h" +#include "../../src/rrd_format.h" +/* support pre-8.4 tcl */ +#ifndef CONST84 +# define CONST84 +#endif -extern int __getopt_initialized; +extern int Tclrrd_Init(Tcl_Interp *interp); +extern int Tclrrd_SafeInit(Tcl_Interp *interp); /* - * some rrd_XXX() functions might modify the argv strings passed to it. - * Furthermore, they use getopt() without initializing getopt's optind - * variable themselves. Hence, we need to do some preparation before + * some rrd_XXX() and new thread-safe versions of Rrd_XXX() + * functions might modify the argv strings passed to it. + * Hence, we need to do some preparation before * calling the rrd library functions. */ -static char ** getopt_init(argc, argv) - int argc; - char *argv[]; +static char ** getopt_init(int argc, CONST84 char *argv[]) { char **argv2; int i; - optind = 0; - argv2 = calloc(argc, sizeof(char *)); for (i = 0; i < argc; i++) { argv2[i] = strdup(argv[i]); @@ -43,31 +49,128 @@ static char ** getopt_init(argc, argv) return argv2; } -static void getopt_cleanup(argc, argv2) - int argc; - char *argv2[]; +static void getopt_cleanup(int argc, char **argv2) { int i; for (i = 0; i < argc; i++) { - free(argv2[i]); + if (argv2[i] != NULL) { + free(argv2[i]); + } } free(argv2); } +static void getopt_free_element(argv2, argn) + char *argv2[]; + int argn; +{ + if (argv2[argn] != NULL) { + free(argv2[argn]); + argv2[argn] = NULL; + } +} +static void getopt_squieeze(argc, argv2) + int *argc; + char *argv2[]; +{ + int i, null_i = 0, argc_tmp = *argc; + for (i = 0; i < argc_tmp; i++) { + if (argv2[i] == NULL) { + (*argc)--; + } else { + argv2[null_i++] = argv2[i]; + } + } +} + + + +/* Thread-safe version */ static int -Rrd_Create(clientData, interp, argc, argv) - ClientData clientData; - Tcl_Interp *interp; - int argc; - char *argv[]; +Rrd_Create(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char *argv[]) { - char **argv2; + int argv_i; + char **argv2; + char *parsetime_error = NULL; + time_t last_up = time(NULL) - 10; + long int long_tmp; + unsigned long int pdp_step = 300; + struct rrd_time_value last_up_tv; argv2 = getopt_init(argc, argv); - rrd_create(argc, argv2); + + for (argv_i = 1; argv_i < argc; argv_i++) { + if (!strcmp(argv2[argv_i], "--start") || !strcmp(argv2[argv_i], "-b")) { + if (argv_i++>=argc) { + Tcl_AppendResult(interp, "RRD Error: option '", + argv2[argv_i - 1], "' needs an argument", (char *) NULL); + getopt_cleanup(argc, argv2); + return TCL_ERROR; + } + if ((parsetime_error = parsetime(argv2[argv_i], &last_up_tv))) { + Tcl_AppendResult(interp, "RRD Error: invalid time format: '", + argv2[argv_i], "'", (char *) NULL); + getopt_cleanup(argc, argv2); + return TCL_ERROR; + } + if (last_up_tv.type == RELATIVE_TO_END_TIME || + last_up_tv.type == RELATIVE_TO_START_TIME) { + Tcl_AppendResult(interp, "RRD Error: specifying time relative to the 'start' ", + "or 'end' makes no sense here", (char *) NULL); + getopt_cleanup(argc, argv2); + return TCL_ERROR; + } + last_up = mktime(&last_up_tv.tm) + last_up_tv.offset; + if (last_up < 3600*24*365*10) { + Tcl_AppendResult(interp, "RRD Error: the first entry to the RRD should be after 1980", + (char *) NULL); + getopt_cleanup(argc, argv2); + return TCL_ERROR; + } + getopt_free_element(argv2, argv_i - 1); + getopt_free_element(argv2, argv_i); + } else if (!strcmp(argv2[argv_i], "--step") || !strcmp(argv2[argv_i], "-s")) { + if (argv_i++>=argc) { + Tcl_AppendResult(interp, "RRD Error: option '", + argv2[argv_i - 1], "' needs an argument", (char *) NULL); + getopt_cleanup(argc, argv2); + return TCL_ERROR; + } + long_tmp = atol(argv2[argv_i]); + if (long_tmp < 1) { + Tcl_AppendResult(interp, "RRD Error: step size should be no less than one second", + (char *) NULL); + getopt_cleanup(argc, argv2); + return TCL_ERROR; + } + pdp_step = long_tmp; + getopt_free_element(argv2, argv_i - 1); + getopt_free_element(argv2, argv_i); + } else if (!strcmp(argv2[argv_i], "--")) { + getopt_free_element(argv2, argv_i); + break; + } else if (argv2[argv_i][0]=='-') { + Tcl_AppendResult(interp, "RRD Error: unknown option '", + argv2[argv_i], "'", (char *) NULL); + getopt_cleanup(argc, argv2); + return TCL_ERROR; + } + } + + getopt_squieeze(&argc, argv2); + + if (argc < 2) { + Tcl_AppendResult(interp, "RRD Error: needs rrd filename", + (char *) NULL); + getopt_cleanup(argc, argv2); + return TCL_ERROR; + } + + rrd_create_r(argv2[1], pdp_step, last_up, argc - 2, argv2 + 2); + getopt_cleanup(argc, argv2); if (rrd_test_error()) { @@ -82,18 +185,17 @@ Rrd_Create(clientData, interp, argc, argv) +/* Thread-safe version */ static int -Rrd_Dump(clientData, interp, argc, argv) - ClientData clientData; - Tcl_Interp *interp; - int argc; - char *argv[]; +Rrd_Dump(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char *argv[]) { - char **argv2; - - argv2 = getopt_init(argc, argv); - rrd_dump(argc, argv2); - getopt_cleanup(argv, argv2); + if (argc < 2) { + Tcl_AppendResult(interp, "RRD Error: needs rrd filename", + (char *) NULL); + return TCL_ERROR; + } + + rrd_dump_r(argv[1], NULL); /* NOTE: rrd_dump() writes to stdout. No interaction with TCL. */ @@ -109,20 +211,19 @@ Rrd_Dump(clientData, interp, argc, argv) +/* Thread-safe version */ static int -Rrd_Last(clientData, interp, argc, argv) - ClientData clientData; - Tcl_Interp *interp; - int argc; - char *argv[]; +Rrd_Last(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char *argv[]) { time_t t; - char **argv2; - argv2 = getopt_init(argc, argv); - t = rrd_last(argc, argv2); - getopt_cleanup(argv, argv2); + if (argc < 2) { + Tcl_AppendResult(interp, "RRD Error: needs rrd filename", + (char *) NULL); + return TCL_ERROR; + } + t = rrd_last_r(argv[1]); if (rrd_test_error()) { Tcl_AppendResult(interp, "RRD Error: ", @@ -138,18 +239,64 @@ Rrd_Last(clientData, interp, argc, argv) +/* Thread-safe version */ static int -Rrd_Update(clientData, interp, argc, argv) - ClientData clientData; - Tcl_Interp *interp; - int argc; - char *argv[]; +Rrd_Update(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char *argv[]) { - char **argv2; + int argv_i; + char **argv2, *template = NULL; argv2 = getopt_init(argc, argv); - rrd_update(argc, argv2); - getopt_cleanup(argv, argv2); + + for (argv_i = 1; argv_i < argc; argv_i++) { + if (!strcmp(argv2[argv_i], "--template") || !strcmp(argv2[argv_i], "-t")) { + if (argv_i++>=argc) { + Tcl_AppendResult(interp, "RRD Error: option '", + argv2[argv_i - 1], "' needs an argument", (char *) NULL); + if (template != NULL) { + free(template); + } + getopt_cleanup(argc, argv2); + return TCL_ERROR; + } + if (template != NULL) { + free(template); + } + template = strdup(argv2[argv_i]); + getopt_free_element(argv2, argv_i - 1); + getopt_free_element(argv2, argv_i); + } else if (!strcmp(argv2[argv_i], "--")) { + getopt_free_element(argv2, argv_i); + break; + } else if (argv2[argv_i][0]=='-') { + Tcl_AppendResult(interp, "RRD Error: unknown option '", + argv2[argv_i], "'", (char *) NULL); + if (template != NULL) { + free(template); + } + getopt_cleanup(argc, argv2); + return TCL_ERROR; + } + } + + getopt_squieeze(&argc, argv2); + + if (argc < 2) { + Tcl_AppendResult(interp, "RRD Error: needs rrd filename", + (char *) NULL); + if (template != NULL) { + free(template); + } + getopt_cleanup(argc, argv2); + return TCL_ERROR; + } + + rrd_update_r(argv2[1], template, argc - 2, argv2 + 2); + + if (template != NULL) { + free(template); + } + getopt_cleanup(argc, argv2); if (rrd_test_error()) { Tcl_AppendResult(interp, "RRD Error: ", @@ -161,16 +308,49 @@ Rrd_Update(clientData, interp, argc, argv) return TCL_OK; } - +static int +Rrd_Lastupdate(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char *argv[]) +{ + time_t last_update; + char **argv2; + char **ds_namv; + char **last_ds; + char s[30]; + Tcl_Obj *listPtr; + unsigned long ds_cnt, i; + + argv2 = getopt_init(argc, argv); + if (rrd_lastupdate(argc-1, argv2, &last_update, + &ds_cnt, &ds_namv, &last_ds) == 0) { + listPtr = Tcl_GetObjResult(interp); + for (i=0; iis< a Tcl fileID + */ + if (!(mode & TCL_WRITABLE)) { + Tcl_AppendResult(interp, "channel \"", argv[1], + "\" wasn't opened for writing", (char *) NULL); + return TCL_ERROR; + } + /* + * Must flush channel to make sure any buffered data is written before + * rrd_graph() writes to the stream + */ + if (Tcl_Flush(channel) != TCL_OK) { + Tcl_AppendResult(interp, "flush failed for \"", argv[1], "\": ", + strerror(Tcl_GetErrno()), (char *) NULL); + return TCL_ERROR; + } + if (Tcl_GetChannelHandle(channel, TCL_WRITABLE, &fd1) != TCL_OK) { + Tcl_AppendResult(interp, "cannot get file descriptor associated with \"", + argv[1], "\"", (char *) NULL); + return TCL_ERROR; + } + /* + * Must dup() file descriptor so we can fclose(stream), otherwise the fclose() + * would close Tcl's file descriptor + */ + if ((fd2 = dup((int)fd1)) == -1) { + Tcl_AppendResult(interp, "dup() failed for file descriptor associated with \"", + argv[1], "\": ", strerror(errno), (char *) NULL); + return TCL_ERROR; + } + /* + * rrd_graph() wants a FILE* + */ + if ((stream = fdopen(fd2, "wb")) == NULL) { + Tcl_AppendResult(interp, "fdopen() failed for file descriptor associated with \"", + argv[1], "\": ", strerror(errno), (char *) NULL); + close(fd2); /* plug potential file descriptor leak */ + return TCL_ERROR; + } - argv2 = getopt_init(argc, argv); - if (rrd_graph(argc, argv2, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) != -1 ) { - listPtr = Tcl_GetObjResult(interp); - Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewIntObj(xsize)); - Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewIntObj(ysize)); + save = argv[1]; + argv[1] = "-"; + argv2 = getopt_init(argc, argv); + argv[1] = save; + } else { + Tcl_ResetResult(interp); /* clear error from Tcl_GetChannel() */ + argv2 = getopt_init(argc, argv); + } + + rc = rrd_graph(argc, argv2, &calcpr, &xsize, &ysize, stream, &ymin, &ymax); + getopt_cleanup(argc, argv2); + + if (stream != NULL) + fclose(stream); /* plug potential malloc & file descriptor leak */ + + if (rc != -1) { + sprintf(dimensions, "%d %d", xsize, ysize); + Tcl_AppendResult(interp, dimensions, (char *) NULL); if (calcpr) { #if 0 int i; @@ -240,7 +478,6 @@ Rrd_Graph(clientData, interp, argc, argv) free(calcpr); } } - getopt_cleanup(argv, argv2); if (rrd_test_error()) { Tcl_AppendResult(interp, "RRD Error: ", @@ -255,17 +492,13 @@ Rrd_Graph(clientData, interp, argc, argv) static int -Rrd_Tune(clientData, interp, argc, argv) - ClientData clientData; - Tcl_Interp *interp; - int argc; - char *argv[]; +Rrd_Tune(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char *argv[]) { char **argv2; argv2 = getopt_init(argc, argv); rrd_tune(argc, argv2); - getopt_cleanup(argv, argv2); + getopt_cleanup(argc, argv2); if (rrd_test_error()) { Tcl_AppendResult(interp, "RRD Error: ", @@ -280,17 +513,13 @@ Rrd_Tune(clientData, interp, argc, argv) static int -Rrd_Resize(clientData, interp, argc, argv) - ClientData clientData; - Tcl_Interp *interp; - int argc; - char *argv[]; +Rrd_Resize(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char *argv[]) { char **argv2; argv2 = getopt_init(argc, argv); rrd_resize(argc, argv2); - getopt_cleanup(argv, argv2); + getopt_cleanup(argc, argv2); if (rrd_test_error()) { Tcl_AppendResult(interp, "RRD Error: ", @@ -305,17 +534,13 @@ Rrd_Resize(clientData, interp, argc, argv) static int -Rrd_Restore(clientData, interp, argc, argv) - ClientData clientData; - Tcl_Interp *interp; - int argc; - char *argv[]; +Rrd_Restore(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char *argv[]) { char **argv2; argv2 = getopt_init(argc, argv); rrd_restore(argc, argv2); - getopt_cleanup(argv, argv2); + getopt_cleanup(argc, argv2); if (rrd_test_error()) { Tcl_AppendResult(interp, "RRD Error: ", @@ -336,35 +561,46 @@ Rrd_Restore(clientData, interp, argc, argv) typedef struct { char *name; /* Name of the command. */ Tcl_CmdProc *proc; /* Procedure for command. */ + int hide; /* Hide if safe interpreter */ } CmdInfo; static CmdInfo rrdCmds[] = { - { "Rrd::create", Rrd_Create }, - { "Rrd::dump", Rrd_Dump }, - { "Rrd::last", Rrd_Last }, - { "Rrd::update", Rrd_Update }, - { "Rrd::fetch", Rrd_Fetch }, - { "Rrd::graph", Rrd_Graph }, - { "Rrd::tune", Rrd_Tune }, - { "Rrd::resize", Rrd_Resize }, - { "Rrd::restore", Rrd_Restore }, - { (char *) NULL, (Tcl_CmdProc *) NULL } + { "Rrd::create", Rrd_Create, 1 }, /* Thread-safe version */ + { "Rrd::dump", Rrd_Dump, 0 }, /* Thread-safe version */ + { "Rrd::last", Rrd_Last, 0 }, /* Thread-safe version */ + { "Rrd::lastupdate", Rrd_Lastupdate, 0 }, /* Thread-safe version */ + { "Rrd::update", Rrd_Update, 1 }, /* Thread-safe version */ + { "Rrd::fetch", Rrd_Fetch, 0 }, + { "Rrd::graph", Rrd_Graph, 1 }, /* Due to RRD's API, a safe + interpreter cannot create + a graph since it writes to + a filename supplied by the + caller */ + { "Rrd::tune", Rrd_Tune, 1 }, + { "Rrd::resize", Rrd_Resize, 1 }, + { "Rrd::restore", Rrd_Restore, 1 }, + { (char *) NULL, (Tcl_CmdProc *) NULL, 0 } }; -int -Tclrrd_Init(interp, safe) - Tcl_Interp *interp; - int safe; +static int +init(Tcl_Interp *interp, int safe) { CmdInfo *cmdInfoPtr; Tcl_CmdInfo info; + if ( Tcl_InitStubs(interp,TCL_VERSION,0) == NULL ) + return TCL_ERROR; + if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 1) == NULL) { return TCL_ERROR; } + /* + * Why a global array? In keeping with the Rrd:: namespace, why + * not simply create a normal variable Rrd::version and set it? + */ Tcl_SetVar2(interp, "rrd", "version", VERSION, TCL_GLOBAL_ONLY); for (cmdInfoPtr = rrdCmds; cmdInfoPtr->name != NULL; cmdInfoPtr++) { @@ -378,7 +614,41 @@ Tclrrd_Init(interp, safe) "\" already exists", (char *) NULL); return TCL_ERROR; } - Tcl_CreateCommand(interp, cmdInfoPtr->name, cmdInfoPtr->proc, + if (safe && cmdInfoPtr->hide) { +#if 0 + /* + * Turns out the one cannot hide a command in a namespace + * due to a limitation of Tcl, one can only hide global + * commands. Thus, if we created the commands without + * the Rrd:: namespace in a safe interpreter, then the + * "unsafe" commands could be hidden -- which would allow + * an owning interpreter either un-hiding them or doing + * an "interp invokehidden". If the Rrd:: namespace is + * used, then it's still possible for the owning interpreter + * to fake out the missing commands: + * + * # Make all Rrd::* commands available in master interperter + * package require Rrd + * set safe [interp create -safe] + * # Make safe Rrd::* commands available in safe interperter + * interp invokehidden $safe -global load ./tclrrd1.2.11.so + * # Provide the safe interpreter with the missing commands + * $safe alias Rrd::update do_update $safe + * proc do_update {which_interp $args} { + * # Do some checking maybe... + * : + * return [eval Rrd::update $args] + * } + * + * Our solution for now is to just not create the "unsafe" + * commands in a safe interpreter. + */ + if (Tcl_HideCommand(interp, cmdInfoPtr->name, cmdInfoPtr->name) != TCL_OK) + return TCL_ERROR; +#endif + } + else + Tcl_CreateCommand(interp, cmdInfoPtr->name, cmdInfoPtr->proc, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); } @@ -388,3 +658,20 @@ Tclrrd_Init(interp, safe) return TCL_OK; } + +int +Tclrrd_Init(Tcl_Interp *interp) +{ + return init(interp, 0); +} + +/* + * See the comments above and note how few commands are considered "safe"... + * Using rrdtool in a safe interpreter has very limited functionality. It's + * tempting to just return TCL_ERROR and forget about it. + */ +int +Tclrrd_SafeInit(Tcl_Interp *interp) +{ + return init(interp, 1); +} diff --git a/confignt/config.h b/confignt/config.h deleted file mode 100644 index 7b9d68c..0000000 --- a/confignt/config.h +++ /dev/null @@ -1,29 +0,0 @@ -/* config.h.nt: what configure _would_ say, if it ran on NT */ - -#define STDC_HEADERS 1 - -/* Define if you have the strftime function. */ -#define HAVE_STRFTIME 1 - -/* Define if you have the header file. */ -#define HAVE_MATH_H 1 - -#define HAVE_SYS_TYPES_H 1 -#define HAVE_SYS_STAT_H 1 - -#define rrd_realloc(a,b) realloc((a), (b)) - -#define snprintf _snprintf -/* Code in rrd_graph.c:rrd_graph_init() uses the %windir% - * environment variable to override this. This should - * avoid the recompile problem if the system directory is - * c:/windows vs. d:/winnt. - * This #define can't be removed because: - * (1) the constant is used outside of rrd_graph_init() to init a struct - * (2) windir might not be available in all environments - */ -#define RRD_DEFAULT_FONT "c:/windows/fonts/cour.ttf" - -#define RRDGRAPH_YLEGEND_ANGLE 90.0 - -#define HAVE_STRING_H 1 diff --git a/configure.ac b/configure.ac index 72c3a80..09e0260 100644 --- a/configure.ac +++ b/configure.ac @@ -4,12 +4,21 @@ dnl dnl Created by Jeff Allen, Tobi Oetiker, Blair Zajac dnl dnl Inspiration from http://autoconf-archive.cryp.to - + dnl tell automake the this script is for rrdtool -AC_INIT([rrdtool],[1.1.9901]) +dnl the official version number is +dnl a.b.c +AC_INIT([rrdtool],[1.2.23]) +dnl for testing a numberical version number comes handy +dnl the released version are +dnl a.bccc +dnl the devl versions will be something like +dnl a.b999yymmddhh +NUMVERS=1.2023 +AC_SUBST(NUMVERS) AC_CANONICAL_TARGET AM_INIT_AUTOMAKE -AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_HEADERS([rrd_config.h]) dnl all our local stuff like install scripts and include files dnl is in there @@ -17,10 +26,8 @@ dnl is in there dnl determine the type of system we are running on - AC_SUBST(VERSION) -dnl where we install our stuff ... AC_PREFIX_DEFAULT( /usr/local/rrdtool-$PACKAGE_VERSION ) dnl Minimum Autoconf version required. @@ -30,8 +37,8 @@ dnl At the TOP of the HEADER AH_TOP([ -#ifndef CONFIG_H -#define CONFIG_H +#ifndef RRD_CONFIG_H +#define RRD_CONFIG_H /* IEEE can be prevented from raising signals with fpsetmask(0) */ #undef MUST_DISABLE_FPMASK @@ -45,11 +52,16 @@ AH_TOP([ ]) AH_BOTTOM([ +/* enable posix_fadvise on linux */ +#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_FCNTL_H) +#define _XOPEN_SOURCE 600 +#include +#endif /* define strrchr, strchr and memcpy, memmove in terms of bsd funcs make sure you are NOT using bcopy, index or rindex in the code */ -#if STDC_HEADERS +#ifdef STDC_HEADERS # include #else # ifndef HAVE_STRCHR @@ -63,26 +75,29 @@ char *strchr (), *strrchr (); # endif #endif - -#if NO_NULL_REALLOC +#ifdef NO_NULL_REALLOC # define rrd_realloc(a,b) ( (a) == NULL ? malloc( (b) ) : realloc( (a) , (b) )) #else # define rrd_realloc(a,b) realloc((a), (b)) -#endif +#endif + +#ifdef NEED_MALLOC_MALLOC_H +# include +#endif -#if HAVE_MATH_H +#ifdef HAVE_MATH_H # include #endif -#if HAVE_FLOAT_H +#ifdef HAVE_FLOAT_H # include #endif -#if HAVE_IEEEFP_H +#ifdef HAVE_IEEEFP_H # include #endif -#if HAVE_FP_CLASS_H +#ifdef HAVE_FP_CLASS_H # include #endif @@ -92,6 +107,12 @@ char *strchr (), *strrchr (); # define isinf(a) (fpclass(a) == FP_NINF || fpclass(a) == FP_PINF) #endif +/* solaris 10 it defines isnan such that only forte can compile it ... bad bad */ +#if (defined(HAVE_ISNAN) && defined(isnan) && defined(HAVE_FPCLASS)) +# undef isnan +# define isnan(a) (fpclass(a) == FP_SNAN || fpclass(a) == FP_QNAN) +#endif + /* for OSF1 Digital Unix */ #if (! defined(HAVE_ISINF) && defined(HAVE_FP_CLASS) && defined(HAVE_FP_CLASS_H)) # define HAVE_ISINF 1 @@ -132,9 +153,45 @@ char *strchr (), *strrchr (); #error "Can't compile without isinf function" #endif -#endif /* CONFIG_H */ +#endif /* RRD_CONFIG_H */ ]) +dnl Process Special Options +dnl ----------------------------------- + +dnl How the vertical axis label is printed +AC_ARG_VAR(RRDGRAPH_YLEGEND_ANGLE, + [Vertical label angle: 90.0 (default) or 270.0]) +AC_DEFINE_UNQUOTED(RRDGRAPH_YLEGEND_ANGLE,${RRDGRAPH_YLEGEND_ANGLE:-90.0}, + [Vertical label angle: 90.0 (default) or 270.0]) + +AC_ARG_ENABLE(rrdcgi,[ --disable-rrdcgi disable building of rrdcgi], +[],[enable_rrdcgi=yes]) + +dnl Check if we run on a system that has fonts +AC_ARG_WITH(rrd-default-font, +[ --with-rrd-default-font=[OPTIONS] set the full path to your default font.], +[RRD_DEFAULT_FONT=$withval],[ + if test -d ${WINDIR:-nodir}/cour.ttf ; then + RRD_DEFAULT_FONT=`cd $WINDIR;pwd`/cour.ttf + else + RRD_DEFAULT_FONT='$(fontsdir)/$(fonts_DATA)' + fi +]) + +dnl Use mmap in rrd_update instead of seek+write +AC_ARG_ENABLE([mmap], +[ --disable-mmap disable mmap in rrd_update, use seek+write instead], +[], +[enable_mmap=yes]) + + + AC_ARG_ENABLE(pthread,[ --disable-pthread disable multithread support], +[],[enable_pthread=yes]) + + + +CONFIGURE_PART(Audit Compilation Environment) dnl Check for the compiler and static/shared library creation. @@ -142,10 +199,30 @@ AC_PROG_CC AC_PROG_CPP AC_PROG_LIBTOOL +dnl which flags does the compile support? +if test "$GCC" = "yes"; then + for flag in -fno-strict-aliasing -Wall -std=gnu99 -pedantic -Wshadow -Wpointer-arith -Wcast-align -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline -W; do + oCFLAGS=$CFLAGS + CFLAGS="$CFLAGS $flag" + cachename=rd_cv_gcc_flag_`echo $flag|sed 's/[[^A-Za-z]]/_/g'` + AC_CACHE_CHECK([if gcc likes the $flag flag], $cachename, + [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[return 0 ]])],[eval $cachename=yes],[eval $cachename=no])]) + if eval test \$$cachename = no; then + CFLAGS=$oCFLAGS + fi + done +fi + + + +AC_SUBST(RRD_DEFAULT_FONT) + +CONFIGURE_PART(Checking for Header Files) + dnl Checks for header files. AC_HEADER_STDC AC_HEADER_DIRENT -AC_CHECK_HEADERS(sys/stat.h sys/types.h fcntl.h time.h locale.h fp_class.h malloc.h unistd.h ieeefp.h math.h sys/time.h sys/times.h sys/param.h sys/resource.h float.h) +AC_CHECK_HEADERS(sys/stat.h sys/types.h fcntl.h locale.h fp_class.h malloc.h unistd.h ieeefp.h math.h sys/times.h sys/param.h sys/resource.h float.h) dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST @@ -159,6 +236,8 @@ dnl add pic flag in any case this makes sure all our code is relocatable eval `./libtool --config | grep pic_flag` CFLAGS="$CFLAGS $pic_flag" +CONFIGURE_PART(Test Library Functions) + dnl Checks for library functions. AC_FUNC_STRFTIME AC_FUNC_VPRINTF @@ -168,57 +247,67 @@ AC_C_BIGENDIAN dnl for each function found we get a definition in config.h dnl of the form HAVE_FUNCTION -AC_CHECK_FUNCS(tzset opendir readdir chdir chroot getuid setlocale strerror strerror_r snprintf vsnprintf fpclass class fp_class isnan memmove strchr mktime getrusage gettimeofday) +AC_CHECK_FUNCS(tzset mbstowcs opendir readdir chdir chroot getuid setlocale strerror strerror_r snprintf vsnprintf fpclass class fp_class isnan memmove strchr mktime getrusage gettimeofday posix_fadvise madvise) -dnl Use mmap in rrd_update instead of seek+write -AC_ARG_ENABLE([mmap], -[ --disable-mmap disable mmap in rrd_update, use seek+write instead], -[], -[enable_mmap=yes]) +AC_CHECK_DECLS(fdatasync, [], [], [#include ]) +AC_CHECK_DECLS(posix_fadvise, [], [], [#define _XOPEN_SOURCE 600 +#include ]) +AC_CHECK_DECLS(madvise, [], [], [#include ]) if test "x$enable_mmap" = xyes; then - AC_FUNC_MMAP + case "$host" in + *cygwin*) + # the normal mmap test does not work in cygwin + AC_CHECK_FUNCS(mmap) + if [ "x${ac_cv_func_mmap}" = xyes ]; then + ac_cv_func_mmap_fixed_mapped=yes + fi + ;; + *) + AC_FUNC_MMAP + ;; + esac fi + +CONFIGURE_PART(IEEE Math Checks) + dnl HP-UX 11.00 does not have finite but does have isfinite as a macro so we need dnl actual code to check if this works AC_CHECK_FUNCS(fpclassify, , [AC_MSG_CHECKING(for fpclassify with ) - AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[float f = 0.0; fpclassify(f)]])],[AC_MSG_RESULT(yes) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include +volatile int x;volatile float f; ]], [[x = fpclassify(f)]])],[AC_MSG_RESULT(yes) AC_DEFINE(HAVE_FPCLASSIFY)],[AC_MSG_RESULT(no)])]) AC_CHECK_FUNCS(finite, , [AC_CHECK_FUNCS(isfinite, , [AC_MSG_CHECKING(for isfinite with ) - AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[float f = 0.0; isfinite(f)]])],[AC_MSG_RESULT(yes) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include +volatile int x;volatile float f; ]], [[x = isfinite(f)]])],[AC_MSG_RESULT(yes) AC_DEFINE(HAVE_ISFINITE)],[AC_MSG_RESULT(no)])])]) AC_CHECK_FUNCS(isinf, , [AC_MSG_CHECKING(for isinf with ) - AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[float f = 0.0; isinf(f)]])],[AC_MSG_RESULT(yes) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include +volatile int x;volatile float f; ]], [[x = isinf(f)]])],[AC_MSG_RESULT(yes) AC_DEFINE(HAVE_ISINF)],[AC_MSG_RESULT(no)])]) AC_FULL_IEEE -dnl How the vertical axis label is printed -AC_ARG_VAR(RRDGRAPH_YLEGEND_ANGLE, - [Vertical label angle: 90.0 (default) or 270.0]) -AC_DEFINE_UNQUOTED(RRDGRAPH_YLEGEND_ANGLE,${RRDGRAPH_YLEGEND_ANGLE:-90.0}, - [Vertical label angle: 90.0 (default) or 270.0]) +CONFIGURE_PART(Resolve Portability Issues) +dnl what does realloc do if it gets called with a NULL pointer -AC_ARG_ENABLE(rrdcgi,[ --disable-rrdcgi disable building of rrdcgi], -[],[enable_rrdcgi=yes]) -AM_CONDITIONAL(BUILD_RRDCGI,[test $enable_rrdcgi != no]) - -if test $enable_rrdcgi != no; then -EX_CHECK_ALL(cgi, cgiInit, cgi.h, cgilib, 0.5, http://www.infodrom.org/projects/cgilib) -fi -EX_CHECK_ALL(art_lgpl_2, art_vpath_add_point, libart_lgpl/libart.h, libart-2.0, 2.3.17, ftp://ftp.gnome.org/pub/GNOME/sources/libart_lgpl/2.3/) -EX_CHECK_ALL(z, zlibVersion, zlib.h, zlib, 1.2.1, http://www.gzip.org/zlib/) -EX_CHECK_ALL(png, png_access_version_number, png.h, libpng, 1.2.8, http://prdownloads.sourceforge.net/libpng/) -EX_CHECK_ALL(freetype, FT_Init_FreeType, ft2build.h, freetype2, 2.1.9, http://prdownloads.sourceforge.net/freetype/) +AC_CACHE_CHECK([if realloc can deal with NULL], rd_cv_null_realloc, +[AC_RUN_IFELSE([AC_LANG_SOURCE([[#include + int main(void){ + char *x = NULL; + x = realloc (x,10); + if (x==NULL) return 1; + return 0; + }]])],[rd_cv_null_realloc=yes],[rd_cv_null_realloc=nope],[:])]) -if test "$EX_CHECK_ALL_ERR" = "YES"; then - AC_MSG_ERROR([Please fix the library issues listed above and try again.]) +if test x"$rd_cv_null_realloc" = xnope; then +AC_DEFINE(NO_NULL_REALLOC) fi AC_LANG_PUSH(C) @@ -244,7 +333,7 @@ AC_LINK_IFELSE( [[#include ]], [[ctime_r(NULL,NULL)]] ), - [AC_MSG_RESULT(yes)], + [AC_MSG_RESULT(no)], [AC_MSG_ERROR([Can't figure how to compile ctime_r])] ) ] @@ -257,11 +346,6 @@ dnl http://autoconf-archive.cryp.to/acx_pthread.m4 AC_SUBST(MULTITHREAD_CFLAGS) AC_SUBST(MULTITHREAD_LDFLAGS) - -AC_ARG_ENABLE(pthread,[ --disable-pthread disable multithread support], -[],[enable_pthread=yes]) - - if test $enable_pthread != no; then ACX_PTHREAD([ MULTITHREAD_CFLAGS=$PTHREAD_CFLAGS @@ -277,40 +361,103 @@ if test "x$x_rflag" != "xno"; then CPPFLAGS="$CPPFLAGS $x_rflag" fi - AM_CONDITIONAL(BUILD_MULTITHREAD,[test $enable_pthread != no]) + +AC_LANG_PUSH(C) +dnl see if we have to include malloc/malloc.h +AC_MSG_CHECKING([do we need malloc/malloc.h]) +AC_LINK_IFELSE( + AC_LANG_PROGRAM( + [[#include ]], + [[malloc(1)]] + ), + [ AC_MSG_RESULT([nope, works out of the box]) ], + [ AC_LINK_IFELSE( + AC_LANG_PROGRAM( + [[#include + #include ]], + [[malloc(1)]] + ), + [AC_DEFINE(NEED_MALLOC_MALLOC_H) + AC_MSG_RESULT([yes we do])], + [AC_MSG_ERROR([Can not figure how to compile malloc])] + ) + ] +) +AC_LANG_POP(C) + +CONFIGURE_PART(Find 3rd-Party Libraries) + + +AM_CONDITIONAL(BUILD_RRDCGI,[test $enable_rrdcgi != no]) + +CORE_LIBS="$LIBS" + +EX_CHECK_ALL(art_lgpl_2, art_vpath_add_point, libart_lgpl/libart.h, libart-2.0, 2.3.17, ftp://ftp.gnome.org/pub/GNOME/sources/libart_lgpl/2.3/, /usr/include/libart-2.0) +EX_CHECK_ALL(z, zlibVersion, zlib.h, zlib, 1.2.3, http://www.gzip.org/zlib/, "") +EX_CHECK_ALL(png, png_access_version_number, png.h, libpng, 1.2.10, http://prdownloads.sourceforge.net/libpng/, "") +EX_CHECK_ALL(freetype, FT_Init_FreeType, ft2build.h, freetype2, 2.1.10, http://prdownloads.sourceforge.net/freetype/, /usr/include/freetype2) + +if test "$EX_CHECK_ALL_ERR" = "YES"; then + AC_MSG_ERROR([Please fix the library issues listed above and try again.]) +fi + +ALL_LIBS="$LIBS" +LIBS= + +AC_SUBST(CORE_LIBS) +AC_SUBST(ALL_LIBS) + +CONFIGURE_PART(Prep for Building Language Bindings) dnl Check for Perl. AC_PATH_PROG(PERL, perl, no) -if test "x$PERL" = "xno"; then + +AC_ARG_ENABLE(perl,[ --disable-perl do not build the perl modules], +[],[enable_perl=yes]) + + +AC_ARG_VAR(PERLCC, [[] C compiler for Perl modules]) +AC_ARG_VAR(PERLCCFLAGS, [[] CC flags for Perl modules]) +AC_ARG_VAR(PERLLD, [[same as PERLCC] Linker for Perl modules]) +AC_ARG_VAR(PERLLDFLAGS, [[] LD flags for Perl modules]) + +if test "x$PERL" = "xno" -o x$enable_perl = xno; then COMP_PERL= else COMP_PERL="perl_piped perl_shared" AC_MSG_CHECKING(for the perl version you are running) PERL_VERSION=`$PERL -MConfig -e 'print $Config{version}'` AC_MSG_RESULT($PERL_VERSION) - AC_MSG_CHECKING(for the C compiler perl wants to use to build its modules) - perlcc=`$PERL -MConfig -e 'print $Config{cc}'` - AC_MSG_RESULT($perlcc) - if test ! -x $perlcc; then - AC_PATH_PROG(PERLCC, ${perlcc}, no) - if test -x $"x$PERLCC" = "xno"; then - AC_MSG_WARN([ -I would not find the Compiler ($perlcc) that was originally used to compile your -perl binary. You should either make sure that this compiler is available on your -system, or use a different perl setup that was compiled with $CC. - -I will disable the compilation of the RRDs perl module. + if test -z "$PERLCC"; then + AC_MSG_CHECKING(for the C compiler perl wants to use to build its modules) + perlcc=`$PERL -MConfig -e 'print $Config{cc}'` + AC_MSG_RESULT($perlcc) + if test ! -x "$perlcc"; then + AC_PATH_PROG(PERL_CC, ${perlcc}, no) + if test "$PERL_CC" = "no"; then + AC_MSG_WARN([ +I would not find the Compiler ($perlcc) that was originally used to compile +your perl binary. You should either make sure that this compiler is +available on your system, pick an other compiler and set PERLCC +appropriately, or use a different perl setup that was compiled locally. + +I will disable the compilation of the RRDs perl module for now. ]) - COMP_PERL="perl_piped" - fi + COMP_PERL="perl_piped" + fi + fi fi fi + AC_MSG_CHECKING(Perl Modules to build) AC_MSG_RESULT(${COMP_PERL:-No Perl Modules will be built}) # Options to pass when configuring perl module -PERL_MAKE_OPTIONS="PREFIX=$prefix LIB=$prefix/lib/perl/$PERL_VERSION" +ppref=$prefix +test "$ppref" = "NONE" && ppref=$ac_default_prefix + +PERL_MAKE_OPTIONS="PREFIX=$ppref LIB=$ppref/lib/perl/$PERL_VERSION" dnl pass additional perl options when generating Makefile from Makefile.PL AC_ARG_ENABLE(perl-site-install, @@ -322,6 +469,23 @@ AC_ARG_ENABLE(perl-site-install, your perl setup thinks it is best.], [PERL_MAKE_OPTIONS=],[]) +if test ! -z "$PERLCC"; then + PERL_MAKE_OPTIONS="$PERL_MAKE_OPTIONS CC=$PERLCC" + + if test ! -z "$PERLCCFLAGS"; then + PERL_MAKE_OPTIONS="$PERL_MAKE_OPTIONS CCFLAGS=$PERLCCFLAGS" + fi + + if test -z "$PERLLD"; then + PERLLD=$PERLCC + fi + PERL_MAKE_OPTIONS="$PERL_MAKE_OPTIONS LD=$PERLLD" + + if test ! -z "$PERLLDFLAGS"; then + PERL_MAKE_OPTIONS="$PERL_MAKE_OPTIONS LDFLAGS=$PERLLDFLAGS" + fi +fi + AC_ARG_WITH(perl-options, [ --with-perl-options=[OPTIONS] options to pass on command-line when generating Makefile from Makefile.PL. If you set this @@ -334,29 +498,84 @@ AC_SUBST(PERL) AC_SUBST(COMP_PERL) AC_SUBST(PERL_VERSION) +dnl Check for Ruby. +AC_PATH_PROG(RUBY, ruby, no) + +AC_ARG_ENABLE(ruby,[ --disable-ruby do not build the ruby modules], +[],[enable_ruby=yes]) + +AC_MSG_CHECKING(if ruby modules can be built) + +if test "x$RUBY" = "xno" -o x$enable_ruby = xno; then + COMP_RUBY= + AC_MSG_RESULT(No .. Ruby not found or disabled) +else + if $RUBY -e 'require "mkmf"' >/dev/null 2>&1; then + COMP_RUBY="ruby" + AC_MSG_RESULT(YES) + else + COMP_RUBY= + AC_MSG_RESULT(Ruby found but mkmf is missing! Install the -dev package) + fi +fi + -dnl Check for Tcl. -withval="" -AC_ARG_WITH(tcllib,[ --with-tcllib=DIR location of the tclConfig.sh]) -found=0 -AC_MSG_CHECKING(for tclConfig.sh in $withval) -if test -f "$withval/tclConfig.sh" ; then - tcl_config=$withval/tclConfig.sh - found=1 +dnl pass additional ruby options when generating Makefile from Makefile.PL +AC_ARG_ENABLE(ruby-site-install, +[ --enable-ruby-site-install by default the rrdtool ruby modules are installed + together with rrdtool in $prefix/lib/ruby. You have to + add $prefix/lib/ruby/$ruby_version/$sitearch to you $: variable + for ruby to find the RRD.so file.], +[RUBY_MAKE_OPTIONS=],[RUBY_MAKE_OPTIONS="sitedir=$prefix/lib/ruby"]) + + +AC_ARG_WITH(ruby-options, +[ --with-ruby-options=[OPTIONS] options to pass on command-line when + generating Makefile from extconf.rb. If you set this + option, interesting things may happen unless you know + what you are doing!], +[RUBY_MAKE_OPTIONS=$withval]) + +AC_SUBST(RUBY_MAKE_OPTIONS) +AC_SUBST(RUBY) +AC_SUBST(COMP_RUBY) + + +enable_tcl_site=no + +AC_ARG_ENABLE(tcl,[ --disable-tcl do not build the tcl modules], +[],[enable_tcl=yes]) + +if test "$enable_tcl" = "yes"; then + dnl Check for Tcl. + withval="" + AC_ARG_WITH(tcllib,[ --with-tcllib=DIR location of the tclConfig.sh]) + enable_tcl=no + for dir in $withval /usr/lib /usr/local/lib; do + AC_MSG_CHECKING(for tclConfig.sh in $dir) + if test -f "$dir/tclConfig.sh" ; then + tcl_config=$dir/tclConfig.sh + enable_tcl=yes AC_MSG_RESULT(yes) break -else + else AC_MSG_RESULT(no) -fi + fi + done -if test $found -eq 0 ; then + if test "$enable_tcl" = "no"; then AC_MSG_WARN([tclConfig.sh not found - Tcl interface won't be built]) -else + else . $tcl_config -fi + TCL_PACKAGE_DIR="$TCL_PACKAGE_PATH/tclrrd$VERSION" + fi + AC_ARG_ENABLE(tcl,[ --enable-tcl-site install the tcl extension in the tcl tree], + [],[enable_tcl_site=yes]) +fi -AM_CONDITIONAL(COMP_TCL, test x$found = x1 ) +AM_CONDITIONAL(BUILD_TCL, test "$enable_tcl" = "yes" ) +AM_CONDITIONAL(BUILD_TCL_SITE, test "$enable_tcl_site" = "yes" ) AC_SUBST(TCL_PREFIX) AC_SUBST(TCL_SHLIB_CFLAGS) @@ -364,62 +583,60 @@ AC_SUBST(TCL_SHLIB_LD) AC_SUBST(TCL_SHLIB_SUFFIX) AC_SUBST(TCL_PACKAGE_PATH) AC_SUBST(TCL_LD_SEARCH_FLAGS) +AC_SUBST(TCL_STUB_LIB_SPEC) +AC_SUBST(TCL_VERSION) +AC_SUBST(TCL_PACKAGE_DIR) + +AC_ARG_ENABLE(python,[ --disable-python do not build the python modules], +[],[enable_python=yes]) +if test "$enable_python" = "yes"; then +dnl Check for python +AM_PATH_PYTHON(2.3,[],[enable_python=no]) +AM_CHECK_PYTHON_HEADERS(,[enable_python=no;AC_MSG_WARN(could not find Python headers)]) +fi + +if test x$enable_python = xno; then + COMP_PYTHON= +else + COMP_PYTHON="python" +fi +AC_SUBST(COMP_PYTHON) dnl Check for nroff AC_PATH_PROGS(NROFF, gnroff nroff) AC_PATH_PROGS(TROFF, groff troff) -dnl Does the compiler like -Wall and -pedantic? -if test "x$GCC" = "xyes"; then - oCFLAGS=$CFLAGS - CFLAGS="$CFLAGS -Wall -pedantic -Wshadow -Wpointer-arith -Wcast-align -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline -W" - AC_CACHE_CHECK(if we can use GCC-specific compiler options, rd_cv_gcc_opt, - [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[return 0 ]])],[rd_cv_gcc_opt=yes],[rd_cv_gcc_opt=no ]) - ] - ) - if test $rd_cv_gcc_opt = no; then - CFLAGS=$oCFLAGS - fi -fi +AC_ARG_VAR(RRDDOCDIR, [[DATADIR/doc/PACKAGE-VERSION] Documentation directory]) +if test -z "$RRDDOCDIR"; then + RRDDOCDIR='${datadir}/doc/${PACKAGE}-${VERSION}'; fi -dnl what does realloc do if it gets called with a NULL pointer -AC_CACHE_CHECK([if realloc can deal with NULL], rd_cv_null_realloc, -[AC_RUN_IFELSE([AC_LANG_SOURCE([[#include - int main(void){ - char *x = NULL; - x = realloc (x,10); - if (x==NULL) return 1; - return 0; - }]])],[rd_cv_null_realloc=yes],[rd_cv_null_realloc=nope],[:])]) - -if test x"$rd_cv_null_realloc" = xnope; then -AC_DEFINE(NO_NULL_REALLOC) -fi - -AC_CONFIG_FILES([examples/shared-demo.pl \ - examples/piped-demo.pl \ - examples/stripes.pl \ - examples/bigtops.pl \ - examples/minmax.pl \ - examples/cgi-demo.cgi \ - examples/4charts.pl \ - examples/Makefile \ - doc/Makefile \ - src/Makefile \ - bindings/Makefile \ - bindings/tcl/Makefile \ - Makefile]) -AC_CONFIG_COMMANDS([default],[[\ - chmod +x examples/*.cgi examples/*.pl]],[[]]) +CONFIGURE_PART(Apply Configuration Information) + +AC_CONFIG_FILES([examples/shared-demo.pl]) +AC_CONFIG_FILES([examples/piped-demo.pl]) +AC_CONFIG_FILES([examples/stripes.pl]) +AC_CONFIG_FILES([examples/bigtops.pl]) +AC_CONFIG_FILES([examples/minmax.pl]) +AC_CONFIG_FILES([examples/4charts.pl]) +AC_CONFIG_FILES([examples/perftest.pl]) +AC_CONFIG_FILES([examples/Makefile]) +AC_CONFIG_FILES([doc/Makefile]) +AC_CONFIG_FILES([src/Makefile]) +AC_CONFIG_FILES([bindings/Makefile]) +AC_CONFIG_FILES([bindings/tcl/Makefile]) +AC_CONFIG_FILES([bindings/tcl/ifOctets.tcl]) +AC_CONFIG_FILES([Makefile]) + +AC_CONFIG_COMMANDS([default],[[ chmod +x examples/*.pl]],[[]]) AC_OUTPUT AC_MSG_CHECKING(in) AC_MSG_RESULT(and out again) -echo $ECHO_N "ordering CD from http://people.ee.ethz.ch/~oetiker/wish $ECHO_C" 1>&6 +echo $ECHO_N "ordering CD from http://tobi.oetiker.ch/wish $ECHO_C" 1>&6 sleep 1 echo $ECHO_N ".$ECHO_C" 1>&6 sleep 1 @@ -434,21 +651,25 @@ echo echo "----------------------------------------------------------------" echo "Config is DONE!" echo -echo " With MMAP IO: $ac_cv_func_mmap_fixed_mapped" -echo " Perl Modules: $COMP_PERL" -echo " Perl Binary: $PERL" -echo " Perl Version: $PERL_VERSION" -echo " Perl Options: $PERL_MAKE_OPTIONS" -echo " Tcl Config: $tcl_config" -echo " Build rrdcgi: $enable_rrdcgi" -echo " Build librrd MT: $enable_pthread" +echo " With MMAP IO: $ac_cv_func_mmap_fixed_mapped" +echo " Perl Modules: $COMP_PERL" +echo " Perl Binary: $PERL" +echo " Perl Version: $PERL_VERSION" +echo " Perl Options: $PERL_MAKE_OPTIONS" +echo " Ruby Modules: $COMP_RUBY" +echo " Ruby Binary: $RUBY" +echo " Ruby Options: $RUBY_MAKE_OPTIONS" +echo " Build Tcl Bindings: $enable_tcl" +echo " Build Python Bindings: $enable_python" +echo " Build rrdcgi: $enable_rrdcgi" +echo " Build librrd MT: $enable_pthread" +echo echo -ech echo "Type 'make' to compile the software and use 'make install' to " echo "install everything to: $prefix." echo echo " ... that wishlist is NO JOKE. If you find RRDtool useful" -echo "make me happy. Go to http://people.ee.ethz.ch/oetiker/wish and" +echo "make me happy. Go to http://tobi.oetiker.ch/wish and" echo "place an order." echo echo " -- Tobi Oetiker " diff --git a/debian/copyright b/debian/copyright index a6f32a9..4af7fb0 100644 --- a/debian/copyright +++ b/debian/copyright @@ -4,9 +4,9 @@ Fri, 10 Sep 1999 10:53:19 -0700. Copied from 1.0.46 to 1.1.0 snapshot by Mike Slifcak on Wed May 12 20:53:16 EDT 2004 The source package was downloaded from - http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/pub/beta/ + http://oss.oetiker.ch/rrdtool/pub/ -Upstream Author(s): Tobias Oetiker +Upstream Author(s): Tobias Oetiker Modifications to upstream source: - Build and install shared libraries diff --git a/debian/watch b/debian/watch index 9792b1f..bf1b626 100644 --- a/debian/watch +++ b/debian/watch @@ -1 +1 @@ -http://people.ee.ethz.ch /~oetiker/webtools/rrdtool/pub rrdtool-(.*)\.tar\.gz debian +http://oss.oetiker.ch /rrdtool/pub rrdtool-(.*)\.tar\.gz debian diff --git a/doc/Makefile.am b/doc/Makefile.am index d23f49f..70f456c 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,38 +1,34 @@ ## Process this file with automake to produce Makefile.in -SUFFIXES = .pod .1 .man .html .txt .pm .pdf .src .inc +SUFFIXES = .pod .1 .man .html .txt .pm .pdf .inc #AUTOMAKE_OPTIONS = foreign #ACLOCAL_M4 = $(top_srcdir)/config/aclocal.m4 -CLEANFILES = *.1 *.html *.txt *-dircache *.pm *.pdf *~ core *itemcache *.rej *.orig rrdgraph_*.pod *.tmp rrdgraph.pod +CLEANFILES = *.1 *.html *.txt *-dircache RRD?.pod *.pdf *~ core *itemcache *.rej *.orig *.tmp -SRC = rrdgraph.src rrdgraph_examples.src rrdgraph_rpn.src \ - rrdgraph_data.src rrdgraph_graph.src +POD = bin_dec_hex.pod rrddump.pod rrdgraph_examples.pod rrdrestore.pod rrdupdate.pod \ + cdeftutorial.pod rrdfetch.pod rrdgraph_graph.pod rrdthreads.pod rrdxport.pod \ + rpntutorial.pod rrdfirst.pod rrdgraph_rpn.pod rrdtool.pod \ + rrd-beginners.pod rrdinfo.pod rrdtune.pod rrdbuild.pod \ + rrdcgi.pod rrdgraph.pod rrdlast.pod rrdlastupdate.pod \ + rrdcreate.pod rrdgraph_data.pod rrdresize.pod rrdtutorial.pod -PODOLD = rrdgraph-old.pod -POD = rrdtool.pod rrdlast.pod rrdfirst.pod rrdcreate.pod rrdupdate.pod rrdtutorial.es.pod \ - cdeftutorial.pod rpntutorial.pod rrdthreads.pod bin_dec_hex.pod \ - rrdfetch.pod rrdrestore.pod rrddump.pod rrdtune.pod rrdresize.pod \ - rrdcgi.pod rrdtutorial.pod rrdinfo.pod rrdxport.pod rrd-beginners.pod \ - $(SRC:.src=.pod) +PMP = RRDs.pod RRDp.pod -PMP = RRDs.pm RRDp.pm - -MAN = $(POD:.pod=.1) $(PMP:.pm=.1) +MAN = $(POD:.pod=.1) TXT = $(MAN:.1=.txt) -HTML = $(POD:.pod=.html) $(PMP:.pm=.html) +HTML = $(POD:.pod=.html) $(PMP:.pod=.html) PDF = $(MAN:.1=.pdf) # what should go into the distribution -EXTRA_DIST= $(POD) $(HTML) $(TXT) rrdtool-dump.dtd rrdtool-xport.dtd +EXTRA_DIST= $(POD) $(HTML) $(MAN) $(TXT) rrdtool-dump.dtd rrdtool-xport.dtd -# some install rules -idocdir = $(prefix)/doc +idocdir = $(RRDDOCDIR)/txt idoc_DATA = $(POD) $(TXT) -ihtmldir = $(prefix)/html +ihtmldir = $(RRDDOCDIR)/html ihtml_DATA = $(HTML) imandir = $(mandir)/man1 iman_DATA = $(MAN) @@ -46,7 +42,7 @@ all-local: link txt man html-local pod2man --release=$(VERSION) --center=rrdtool $< > $@ .1.txt: - @NROFF@ -man -Tlp $< > $@ + GROFF_NO_SGR=1 @NROFF@ -man -Tlp $< > $@ .1.pdf: @TROFF@ -man $< | ps2pdf - $@ @@ -54,16 +50,13 @@ all-local: link txt man html-local .pm.html .pod.html .pl.html: pod2html --infile=$< --outfile=$@ --noindex --htmlroot=. --podpath=. --title=$* -RRDs.pm: - ln -s ../bindings/perl-shared/RRDs.pm . - -RRDp.pm: - ln -s ../bindings/perl-piped/RRDp.pm . +RRDs.pod: + $(LN_S) $(top_srcdir)/bindings/perl-shared/RRDs.pm RRDs.pod -index.html: - rm -f index.html; ln -s rrdtool.html index.html +RRDp.pod: + $(LN_S) $(top_srcdir)/bindings/perl-piped/RRDp.pm RRDp.pod -link: RRDp.pm RRDs.pm index.html +link: RRDp.pod RRDs.pod man: $(MAN) @@ -73,3 +66,7 @@ txt: $(TXT) pdf-local: $(PDF) +pod: $(POD) + +install-data-hook: + cd $(DESTDIR)$(ihtmldir) && rm -f index.html && $(LN_S) rrdtool.html index.html diff --git a/doc/bin_dec_hex.pod b/doc/bin_dec_hex.pod index 3a2f2fb..7a2adf5 100644 --- a/doc/bin_dec_hex.pod +++ b/doc/bin_dec_hex.pod @@ -1,6 +1,6 @@ =head1 NAME -Binary Decimal Hexadecimal - How does it work +bin_dec_hex - How to use binary, decimal, and hexadecimal notation. =for html
PDF version.
@@ -8,11 +8,11 @@ Binary Decimal Hexadecimal - How does it work Most people use the decimal numbering system. This system uses ten symbols to represent numbers. When those ten symbols are used up, they -start all over again and increment the position just before this. The +start all over again and increment the position to the left. The digit 0 is only shown if it is the only symbol in the sequence, or if it is not the first one. -If this sounds cryptic to you, this is what I've said in numbers: +If this sounds cryptic to you, this is what I've just said in numbers: 0 1 @@ -31,17 +31,21 @@ If this sounds cryptic to you, this is what I've said in numbers: and so on. -Each time the digit nine should be incremented, it is reset to 0 and the -position before is incremented. Then number 9 can be seen as "00009" and -when we should increment 9, we reset it to zero and increment the digit -just before the 9 so the number becomes "00010". For zero's we write a -space if it is not the only digit (so: number 0) and if it is the first -digit: "00010" -> " 0010" -> " 010" -> " 10". It is not " 1 ". +Each time the digit nine is incremented, it is reset to 0 and the +position before (to the left) is incremented (from 0 to 1). Then +number 9 can be seen as "00009" and when we should increment 9, we +reset it to zero and increment the digit just before the 9 so the +number becomes "00010". Leading zeros we don't write except if it is +the only digit (number 0). And of course, we write zeros if they occur +anywhere inside or at the end of a number: -This was pretty basic, you already knew this. Why did I tell it ? -Well, computers do not represent numbers with 10 different digits. They -know of only two different symbols, being 0 and 1. Apply the same rules -to this set of digits and you get the binary numbering system: + "00010" -> " 0010" -> " 010" -> " 10", but not " 1 ". + +This was pretty basic, you already knew this. Why did I tell it? +Well, computers usually do not represent numbers with 10 different +digits. They only use two different symbols, namely "0" and "1". Apply +the same rules to this set of digits and you get the binary numbering +system: 0 1 @@ -61,42 +65,47 @@ to this set of digits and you get the binary numbering system: and so on. If you count the number of rows, you'll see that these are again 14 -different numbers. The numbers are the same and mean the same. It is -only a different representation. This means that you have to know the -representation used, or as it is called the numbering system or base. -Normally if we do not speak about the numbering system used, we're -using the decimal system. If we are talking about another numbering -system, we'll have to make that clear. There are a few wide-spread -methods to do so. One common form is to write 1010(2) which means that -you wrote down a number in the binary form. It is the number ten. -If you would write 1010 it means the number one thousand and ten. - -In books, another form is most used. It uses subscript (little chars, -more or less in between two rows). You can leave out the parentheses -in that case and write down the number in normal characters followed -with a little two just behind it. - -The numbering system used is also called the base. We talk of the number -1100 base 2, the number 12 base 10. - -For the binary system, is is common to write leading zero's. The numbers -are written down in series of four, eight or sixteen depending on the -context. - -We can use the binary form when talking to computers (...programming...) -but the numbers will have large representations. The number 65535 would -be written down as 1111111111111111(2) which is 16 times the digit 1. -This is difficult and prone to errors. Therefore we normally would use +different numbers. The numbers are the same and mean the same as in +the first list, we just used a different representation. This means +that you have to know the representation used, or as it is called the +numbering system or base. Normally, if we do not explicitly specify +the numbering system used, we implicitly use the decimal system. If we +want to use any other numbering system, we'll have to make that +clear. There are a few widely adopted methods to do so. One common +form is to write 1010(2) which means that you wrote down a number in +its binary representation. It is the number ten. If you would write +1010 without specifying the base, the number is interpreted as one +thousand and ten using base 10. + +In books, another form is common. It uses subscripts (little +characters, more or less in between two rows). You can leave out the +parentheses in that case and write down the number in normal +characters followed by a little two just behind it. + +As the numbering system used is also called the base, we talk of the +number 1100 base 2, the number 12 base 10. + +Within the binary system, it is common to write leading zeros. The +numbers are written down in series of four, eight or sixteen depending +on the context. + +We can use the binary form when talking to computers +(...programming...), but the numbers will have large +representations. The number 65'535 (often in the decimal system a ' is +used to separate blocks of three digits for readability) would be +written down as 1111111111111111(2) which is 16 times the digit 1. +This is difficult and prone to errors. Therefore, we usually would use another base, called hexadecimal. It uses 16 different symbols. First the symbols from the decimal system are used, thereafter we continue -with the alphabetic characters. We get 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, -B, C, D, E and F. This system is chosen because the hexadecimal form -can be converted into the binary system very easy (and back). +with alphabetic characters. We get 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, +A, B, C, D, E and F. This system is chosen because the hexadecimal +form can be converted into the binary system very easily (and back). There is yet another system in use, called the octal system. This was -more common in the old days but not anymore. You will find it in use -on some places so get used to it. The same story applies, but now with -only eight different symbols. +more common in the old days, but is not used very often anymore. As +you might find it in use sometimes, you should get used to it and +we'll show it below. It's the same story as with the other +representations, but with eight different symbols. Binary (2) Octal (8) @@ -106,7 +115,7 @@ only eight different symbols. (2) (8) (10) (16) 00000 0 0 0 00001 1 1 1 - 00010 2 2 2 + 00010 2 2 2 00011 3 3 3 00100 4 4 4 00101 5 5 5 @@ -129,7 +138,7 @@ only eight different symbols. Most computers used nowadays are using bytes of eight bits. This means that they store eight bits at a time. You can see why the octal system -is not the most preferred for that: You'd need three digits to represent +is not the most practical for that: You'd need three digits to represent the eight bits and this means that you'd have to use one complete digit to represent only two bits (2+3+3=8). This is a waste. For hexadecimal digits, you need only two digits which are used completely: @@ -137,29 +146,28 @@ digits, you need only two digits which are used completely: (2) (8) (10) (16) 11111111 377 255 FF -You can see why binary and hexadecimal can be converted quickly: -For each hexadecimal digit there are exactly four binary digits. -Take a binary number. Each time take four digits from the right and make -a hexadecimal digit from it (see the table above). Stop when there are -no more digits. -Other way around: Take a hexadecimal number. For each digit, write down -its binary equivalent. - -Computers (or rather the parsers running on them) would have a hard time -converting a number like 1234(16). Therefore hexadecimal numbers get a -prefix. This prefix depends on the language you're writing in. Some of -the prefixes are "0x" for C, "$" for Pascal, "#" for HTML. -It is common to assume that if a number starts with a zero, it is octal. -It does not matter what is used as long as you know what it is. -I will use "0x" for hexadecimal, "%" for binary and "0" for octal. -The following numbers are all the same, just the way they are written is -different: 021 0x11 17 %00010001 +You can see why binary and hexadecimal can be converted quickly: For +each hexadecimal digit there are exactly four binary digits. Take a +binary number: take four digits from the right and make a hexadecimal +digit from it (see the table above). Repeat this until there are no +more digits. And the other way around: Take a hexadecimal number. For +each digit, write down its binary equivalent. + +Computers (or rather the parsers running on them) would have a hard +time converting a number like 1234(16). Therefore hexadecimal numbers +are specified with a prefix. This prefix depends on the language +you're writing in. Some of the prefixes are "0x" for C, "$" for +Pascal, "#" for HTML. It is common to assume that if a number starts +with a zero, it is octal. It does not matter what is used as long as +you know what it is. I will use "0x" for hexadecimal, "%" for binary +and "0" for octal. The following numbers are all the same, just their represenatation (base) is different: 021 0x11 17 %00010001 To do arithmetics and conversions you need to understand one more thing. It is something you already know but perhaps you do not "see" it yet: -If you write down 1234, (so it is decimal) you are talking about the -number one thousand, two hundred and thirty four. In sort of a formula: +If you write down 1234, (no prefix, so it is decimal) you are talking +about the number one thousand, two hundred and thirty four. In sort of +a formula: 1 * 1000 = 1000 2 * 100 = 200 @@ -197,7 +205,7 @@ It is the same in all other representations: 3 * 8^1 4 * 8^0 -This example can not be done for binary as that system can only use two +This example can not be done for binary as that system only uses two symbols. Another example: %1010 would be @@ -207,69 +215,68 @@ symbols. Another example: 1 * 2^1 0 * 2^0 -It would have been more easy to convert it to its hexadecimal form and +It would have been easier to convert it to its hexadecimal form and just translate %1010 into 0xA. After a while you get used to it. You will -not need to do any calculations anymore but just know that 0xA means 10. +not need to do any calculations anymore, but just know that 0xA means 10. -To convert a decimal number into a hexadecimal one you could use the next -method. It will take some time to be able to do the estimates but it will -be more and more easy when you use the system more frequent. Another way -is presented to you thereafter. +To convert a decimal number into a hexadecimal you could use the next +method. It will take some time to be able to do the estimates, but it +will be easier when you use the system more frequently. We'll look at +yet another way afterwards. -First you will need to know how many positions will be used in the other -system. To do so, you need to know the maximum numbers. Well, that's not -so hard as it looks. In decimal, the maximum number that you can form -with two digits is "99". The maximum for three: "999". The next number -would need an extra position. Reverse this idea and you will see that -the number can be found by taking 10^3 (10*10*10 is 1000) minus 1 or -10^2 minus one. +First you need to know how many positions will be used in the other +system. To do so, you need to know the maximum numbers you'll be +using. Well, that's not as hard as it looks. In decimal, the maximum +number that you can form with two digits is "99". The maximum for +three: "999". The next number would need an extra position. Reverse +this idea and you will see that the number can be found by taking 10^3 +(10*10*10 is 1000) minus 1 or 10^2 minus one. -This can be done for hexadecimal too: +This can be done for hexadecimal as well: 16^4 = 0x10000 = 65536 16^3 = 0x1000 = 4096 16^2 = 0x100 = 256 16^1 = 0x10 = 16 -If a number is smaller than 65536 it will thus fit in four positions. -If the number is bigger than 4095, you will need to use position 4. -How many times can you take 4096 from the number without going below +If a number is smaller than 65'536 it will fit in four positions. +If the number is bigger than 4'095, you must use position 4. +How many times you can subtract 4'096 from the number without going below zero is the first digit you write down. This will always be a number from 1 to 15 (0x1 to 0xF). Do the same for the other positions. -Number is 41029. It is smaller than 16^4 but bigger than 16^3-1. This +Let's try with 41'029. It is smaller than 16^4 but bigger than 16^3-1. This means that we have to use four positions. -We can subtract 16^3 from 41029 ten times without going below zero. -The leftmost digit will be "A" so we have 0xA????. -The number is reduced to 41029 - 10*4096 = 41029-40960 = 69. +We can subtract 16^3 from 41'029 ten times without going below zero. +The left-most digit will therefore be "A", so we have 0xA????. +The number is reduced to 41'029 - 10*4'096 = 41'029-40'960 = 69. 69 is smaller than 16^3 but not bigger than 16^2-1. The second digit -is therefore "0" and we know 0xA0??. +is therefore "0" and we now have 0xA0??. 69 is smaller than 16^2 and bigger than 16^1-1. We can subtract 16^1 (which is just plain 16) four times and write down "4" to get 0xA04?. -Take 64 from 69 (69 - 4*16) and the last digit is 5 --> 0xA045. +Subtract 64 from 69 (69 - 4*16) and the last digit is 5 --> 0xA045. -The other method builds the number from the right. Take again 41029. -Divide by 16 and do not use fractions (only whole numbers). +The other method builds ub the number from the right. Let's try 41'029 +again. Divide by 16 and do not use fractions (only whole numbers). - 41029 / 16 is 2564 with a remainder of 5. Write down 5. - 2564 / 16 is 160 with a remainder of 4. Write the 4 before the 5. + 41'029 / 16 is 2'564 with a remainder of 5. Write down 5. + 2'564 / 16 is 160 with a remainder of 4. Write the 4 before the 5. 160 / 16 is 10 with no remainder. Prepend 45 with 0. 10 / 16 is below one. End here and prepend 0xA. End up with 0xA045. -Which method to use is up to you. Use whatever works for you. Personally -I use them both without being able to tell what method I use in each -case, it just depends on the number, I think. Fact is, some numbers -will occur frequently while programming, if the number is close then -I will use the first method (like 32770, translate into 32768 + 2 and -just know that it is 0x8000 + 0x2 = 0x8002). - +Which method to use is up to you. Use whatever works for you. I use +them both without being able to tell what method I use in each case, +it just depends on the number, I think. Fact is, some numbers will +occur frequently while programming. If the number is close to one I am +familiar with, then I will use the first method (like 32'770 which is +into 32'768 + 2 and I just know that it is 0x8000 + 0x2 = 0x8002). For binary the same approach can be used. The base is 2 and not 16, and the number of positions will grow rapidly. Using the second method -has the advantage that you can see very simple if you should write down +has the advantage that you can see very easily if you should write down a zero or a one: if you divide by two the remainder will be zero if it -was an even number and one if it was an odd number: - +is an even number and one if it is an odd number: + 41029 / 2 = 20514 remainder 1 20514 / 2 = 10257 remainder 0 10257 / 2 = 5128 remainder 1 @@ -317,10 +324,10 @@ Group %1010000001000101 by three and convert into octal: At first while adding numbers, you'll convert them to their decimal form and then back into their original form after doing the addition. If you use the other numbering system often, you will see that you'll -be able to do arithmetics in the base that is used. +be able to do arithmetics directly in the base that is used. In any representation it is the same, add the numbers on the right, -write down the rightmost digit from the result, remember the other -digits and use them in the next round. Continue with the second digits +write down the right-most digit from the result, remember the other +digits and use them in the next round. Continue with the second digit from the right and so on: %1010 + %0111 --> 10 + 7 --> 17 --> %00010001 @@ -338,16 +345,16 @@ will become -------- %10001 is the result, I like to write it as %00010001 -For low values, try to do the calculations yourself, check them with -a calculator. The more you do the calculations yourself, the more you +For low values, try to do the calculations yourself, then check them with +a calculator. The more you do the calculations yourself, the more you'll find that you didn't make mistakes. In the end, you'll do calculi in -other bases as easy as you do in decimal. +other bases as easily as you do them in decimal. When the numbers get bigger, you'll have to realize that a computer is -not called a computer just to have a nice name. There are many different -calculators available. Use them. For Unix you could use "bc" which is -called so as it is short for Binary Calculator. It calculates not only -in decimal, but in all bases you'll ever use (among them Binary). +not called a computer just to have a nice name. There are many +different calculators available, use them. For Unix you could use "bc" +which is short for Binary Calculator. It calculates not only in +decimal, but in all bases you'll ever want to use (among them Binary). For people on Windows: Start the calculator (start->programs->accessories->calculator) @@ -358,8 +365,7 @@ calculator and can compute in binary or hexadecimal. 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 answer but at the same +basic questions. They will not only get their answer, but at the same time learn a whole lot more. -Alex van den Bogaerdt - +Alex van den Bogaerdt Ealex@ergens.op.het.netE diff --git a/doc/cdeftutorial.pod b/doc/cdeftutorial.pod index fb33770..6a45ef4 100644 --- a/doc/cdeftutorial.pod +++ b/doc/cdeftutorial.pod @@ -2,21 +2,22 @@ cdeftutorial - Alex van den Bogaerdt's CDEF tutorial -=for html
PDF version.
- =head1 DESCRIPTION -B. B - -I +Intention of this document: to provide some examples of the commonly +used parts of RRDtool's CDEF language. -Alex van den Bogaerdt Ealex@ergens.op.het.netE +If you think some important feature is not explained properly, and if +adding it to this document would benefit most users, please do ask me +to add it. I will then try to provide an answer in the next release +of this tutorial. No feedback equals no changes! Additions to +this document are also welcome. -- Alex van den Bogaerdt +Ealex@ergens.op.het.netE -=head2 Why this tutorial ? +=head2 Why this tutorial? One of the powerful parts of RRDtool is its ability to do all sorts -of calculations on the data retrieved from it's databases. However +of calculations on the data retrieved from its databases. However, RRDtool's many options and syntax make it difficult for the average user to understand. The manuals are good at explaining what these options do; however they do not (and should not) explain in detail @@ -25,14 +26,14 @@ simple document in simple language you should read this tutorial. If you are happy with the official documentation, you may find this document too simple or even boring. If you do choose to read this tutorial, I also expect you to have read and fully understand my -other tutorial. +other tutorial. =head2 More reading If you have difficulties with the way I try to explain it please read Steve Rader's L. It may help you understand how this all works. -=head1 What are CDEFs ? +=head1 What are CDEFs? When retrieving data from an RRD, you are using a "DEF" to work with that data. Think of it as a variable that changes over time (where @@ -62,12 +63,12 @@ instead of the original: CDEF:inbits=inbytes,8,* -It tells to multiply inbytes by eight to get inbits. I'll explain later -how this works. In the graphing or printing functions, you can now use -inbits where you would use inbytes otherwise. +This tells RRDtool to multiply inbytes by eight to get inbits. I'll +explain later how this works. In the graphing or printing functions, +you can now use inbits where you would use inbytes otherwise. -Note that variable in the CDEF (inbits) must not be the same as the -variable (inbytes) in the DEF! +Note that the variable name used in the CDEF (inbits) must not be the +same as the variable named in the DEF (inbytes)! =head1 RPN-expressions @@ -137,20 +138,20 @@ inbytes would have value 10, the stack would be: || -=back +=back Processing the stack (step 5) will retrieve one value from the stack (from the right at step 4). This is the operation multiply and this takes two values off the stack as input. The result is put back on the stack (the value 80 in this case). For multiplication the order doesn't -matter but for other operations like subtraction and division it does. +matter, but for other operations like subtraction and division it does. Generally speaking you have the following order: y = A - B --> y=minus(A,B) --> CDEF:y=A,B,- This is not very intuitive (at least most people don't think so). For -the function f(A,B) you reverse the position of "f" but you do not -reverse the order of the variables. +the function f(A,B) you reverse the position of "f", but you do not +reverse the order of the variables. =head1 Converting your wishes to RPN @@ -178,7 +179,7 @@ RRD router1.rrd) router1.rrd:link2in router2.rrd:link1in router3.rrd:link1in - router3.rrd:link2in + router3.rrd:link2in -------------------- + (outcome of the sum) @@ -216,7 +217,7 @@ This is correct but it can be made more clear to humans. It does not matter if you add a to b and then add c to the result or first add b to c and then add a to the result. This makes it possible to rewrite the RPN into C which is -evaluated differently: +evaluated differently: push value of variable a on the stack: a push value of variable b on the stack: a b @@ -233,17 +234,17 @@ evaluated differently: and process it: S (where S == a+R) As you can see the RPN expression C will evaluate in -C<((((d+e)+c)+b)+a)> and it has the same outcome as C -According to Steve Rader this is called the commutative law of addition +C<((((d+e)+c)+b)+a)> and it has the same outcome as C. +This is called the commutative law of addition, but you may forget this right away, as long as you remember what it -represents. +means. Now look at an expression that contains a multiplication: First in normal math: C. In this case you can't choose the order yourself, you have to start with the multiplication -and then add a to it. You may alter the position of b and c, you may -not alter the position of a and b. +and then add a to it. You may alter the position of b and c, you must +not alter the position of a and b. You have to take this in consideration when converting this expression into RPN. Read it as: "Add the outcome of b*c to a" and then it is @@ -257,8 +258,8 @@ easy to write it in RPN: C. Note that this is very similar to one of the expressions in the previous paragraph, only the multiplication and the addition changed places. -When you have problems with RPN or when RRDtool is complaining, it's -usually a Good Thing to write down the stack on a piece of paper +When you have problems with RPN or when RRDtool is complaining, it's +usually a good thing to write down the stack on a piece of paper and see what happens. Have the manual ready and pretend to be RRDtool. Just do all the math by hand to see what happens, I'm sure this will solve most, if not all, problems you encounter. @@ -269,7 +270,7 @@ solve most, if not all, problems you encounter. Sometimes collecting your data will fail. This can be very common, especially when querying over busy links. RRDtool can be configured -to allow for one (or even more) unknown value and calculate the missing +to allow for one (or even more) unknown value(s) and calculate the missing update. You can, for instance, query your device every minute. This is creating one so called PDP or primary data point per minute. If you defined your RRD to contain an RRA that stores 5-minute values, you need @@ -280,7 +281,7 @@ These PDPs can become unknown in two cases: =item 1. -The updates are too far apart. This is tuned using the "heartbeat" setting +The updates are too far apart. This is tuned using the "heartbeat" setting. =item 2. @@ -299,12 +300,12 @@ Suppose the counter increments with one per second and you retrieve it every minute: counter value resulting rate - 10000 - 10060 1; (10060-10000)/60 == 1 - 10120 1; (10120-10060)/60 == 1 - unknown unknown; you don't know the last value - 10240 unknown; you don't know the previous value - 10300 1; (10300-10240)/60 == 1 + 10'000 + 10'060 1; (10'060-10'000)/60 == 1 + 10'120 1; (10'120-10'060)/60 == 1 + unknown unknown; you don't know the last value + 10'240 unknown; you don't know the previous value + 10'300 1; (10'300-10'240)/60 == 1 If the CDP was to be calculated from the last five updates, it would get two unknown PDPs and three known PDPs. If xff would have been set to 0.5 @@ -340,14 +341,14 @@ data into zero. The counters of the device were unknown (after all, it wasn't installed yet!) but you know that the data rate through the device had to be zero (because of the same reason: it was not installed). -There are some examples further on that make this change. +There are some examples below that make this change. =head2 Infinity -Infinite data is another form of a special number. It cannot be graphed -because by definition you would never reach the infinite value. You could -think of positive and negative infinity (I'm not sure if mathematicians -will agree) depending on the position relative to zero. +Infinite data is another form of a special number. It cannot be +graphed because by definition you would never reach the infinite +value. You can think of positive and negative infinity depending on +the position relative to zero. RRDtool is capable of representing (-not- graphing!) infinity by stopping at its current maximum (for positive infinity) or minimum (for negative @@ -389,14 +390,14 @@ the other database. =item * -Alternately you could use CDEF and alter unknown data to zero. +Alternatively, you could use CDEF and alter unknown data to zero. =back Both methods have their pros and cons. The first method is troublesome and if you want to do that you have to figure it out yourself. It is not possible to create a database filled with zeros, you have to put them in -on purpose. Implementing the second method is described next: +manually. Implementing the second method is described next: What we want is: "if the value is unknown, replace it with zero". This could be written in pseudo-code as: if (value is unknown) then (zero) @@ -448,7 +449,7 @@ to remove this rule so that unknown data is properly displayed. =head2 Example: better handling of unknown data, by using time -Above example has one drawback. If you do log unknown data in +The above example has one drawback. If you do log unknown data in your database after installing your new equipment, it will also be translated into zero and therefore you won't see that there was a problem. This is not good and what you really want to do is: @@ -457,28 +458,28 @@ problem. This is not good and what you really want to do is: =item * -If there is unknown data, look at the time that this sample was taken +If there is unknown data, look at the time that this sample was taken. =item * -If the unknown value is before time xxx, make it zero +If the unknown value is before time xxx, make it zero. =item * -If it is after time xxx, leave it as unknown data +If it is after time xxx, leave it as unknown data. =back This is doable: you can compare the time that the sample was taken to some known time. Assuming you started to monitor your device on -Friday September 17, 00:35:57 MET DST. Translate this time in seconds -since 1970-01-01 and it becomes 937521357. If you process unknown values +Friday September 17, 1999, 00:35:57 MET DST. Translate this time in seconds +since 1970-01-01 and it becomes 937'521'357. If you process unknown values that were received after this time, you want to leave them unknown and if they were "received" before this time, you want to translate them into zero (so you can effectively ignore them while adding them to your other routers counters). -Translating Friday September 17, 00:35:57 MET DST into 937521357 can +Translating Friday September 17, 1999, 00:35:57 MET DST into 937'521'357 can be done by, for instance, using gnu date: date -d "19990917 00:35:57" +%s @@ -494,11 +495,11 @@ This is a three step process: =item 1. -If the timestamp of the value is after 937521357, leave it as is +If the timestamp of the value is after 937'521'357, leave it as is. =item 2. -If the value is a known value, leave it as is +If the value is a known value, leave it as is. =item 3. @@ -529,7 +530,7 @@ so lets do it quick: where x represents "time>937521357" where a represents the original value where b represents the outcome of the previous example - + time>937521357 --> TIME,937521357,GT if (x) then a else b --> x,a,b,IF @@ -540,13 +541,13 @@ so lets do it quick: We end up with: C -This looks very complex however as you can see it was not too hard to +This looks very complex, however, as you can see, it was not too hard to come up with. =head2 Example: Pretending weird data isn't there Suppose you have a problem that shows up as huge spikes in your graph. -You know this happens and why so you decide to work around the problem. +You know this happens and why, so you decide to work around the problem. Perhaps you're using your network to do a backup at night and by doing so you get almost 10mb/s while the rest of your network activity does not produce numbers higher than 100kb/s. @@ -558,11 +559,11 @@ There are two options: =item 1. If the number exceeds 100kb/s it is wrong and you want it masked out -by changing it into unknown +by changing it into unknown. =item 2. -You don't want the graph to show more than 100kb/s +You don't want the graph to show more than 100kb/s. =back @@ -578,7 +579,7 @@ the numbers to display maxima they will be set to 100kb/s. We use "IF" and "GT" again. "if (x) then (y) else (z)" is written down as "CDEF:result=x,y,z,IF"; now fill in x, y and z. For x you fill in "number greater than 100kb/s" becoming -"number,100000,GT" (kilo is 1000 and b/s is what we measure!). +"number,100000,GT" (kilo is 1'000 and b/s is what we measure!). The "z" part is "number" in both cases and the "y" part is either "UNKN" for unknown or "100000" for 100kb/s. @@ -590,7 +591,7 @@ The two CDEF expressions would be: =head2 Example: working on a certain time span If you want a graph that spans a few weeks, but would only want to -see some routers data for one week, you need to "hide" the rest of +see some routers' data for one week, you need to "hide" the rest of the time frame. Don't ask me when this would be useful, it's just here for the example :) @@ -700,11 +701,11 @@ if you like. But there are good reasons for writing two CDEFS: =item * -It improves the readability of the script +It improves the readability of the script. =item * -It can be used inside GPRINT to display the total number of users +It can be used inside GPRINT to display the total number of users. =back @@ -725,9 +726,12 @@ If you do so, you won't be able to use these next GPRINTs: =head2 Degrees Celsius vs. Degrees Fahrenheit +To convert Celsius into Fahrenheit use the formula +F=9/5*C+32 + rrdtool graph demo.png --title="Demo Graph" \ DEF:cel=demo.rrd:exhaust:AVERAGE \ - CDEF:far=cel,32,-,0.55555,* \ + CDEF:far=9,5,/,cel,*,32,+ \ LINE2:cel#00a000:"D. Celsius" \ LINE2:far#ff0000:"D. Fahrenheit\c" @@ -735,19 +739,17 @@ This example gets the DS called "exhaust" from database "demo.rrd" and puts the values in variable "cel". The CDEF used is evaluated as follows: - CDEF:far=cel,32,-,0.5555,* - 1. push variable "cel" - 2. push 32 - 3. push function "minus" and process it - The stack now contains values that are 32 less than "cel" - 4. push 0.5555 - 5. push function "multiply" and process it - 6. the resulting value is now "(cel-32)*0.55555" - -Note that if you take the Celsius to Fahrenheit function you should -be doing "5/9*(cel-32)" so 0.55555 is not exactly correct. It is close -enough for this purpose and it saves a calculation. - + CDEF:far=9,5,/,cel,*,32,+ + 1. push 9, push 5 + 2. push function "divide" and process it + the stack now contains 9/5 + 3. push variable "cel" + 4. push function "multiply" and process it + the stack now contains 9/5*cel + 5. push 32 + 6. push function "plus" and process it + the stack contains now the temperature in Fahrenheit + =head2 Changing unknown into zero rrdtool graph demo.png --title="Demo Graph" \ @@ -760,13 +762,15 @@ enough for this purpose and it saves a calculation. AREA:agginput#00cc00:Input Aggregate \ LINE1:aggoutput#0000FF:Output Aggregate -These two CDEFs are built from several functions. It helps to -split them when viewing what they do. -Starting with the first CDEF we would get: - idat1,UN --> a - 0 --> b - idat1 --> c - if (a) then (b) else (c) +These two CDEFs are built from several functions. It helps to split +them when viewing what they do. Starting with the first CDEF we would +get: + + idat1,UN --> a + 0 --> b + idat1 --> c + if (a) then (b) else (c) + The result is therefore "0" if it is true that "idat1" equals "UN". If not, the original value of "idat1" is put back on the stack. Lets call this answer "d". The process is repeated for the next @@ -802,10 +806,10 @@ to see what happens in the "background" CDEF. This RPN takes the value of "val4" as input and then immediately removes it from the stack using "POP". The stack is now empty but -as a side result we now know the time that this sample was taken. +as a side effect we now know the time that this sample was taken. This time is put on the stack by the "TIME" function. -"TIME,7200,%" takes the modulo of time and 7200 (which is two hours). +"TIME,7200,%" takes the modulo of time and 7'200 (which is two hours). The resulting value on the stack will be a number in the range from 0 to 7199. @@ -826,7 +830,8 @@ won't do that here. Now you can draw the different layers. Start with the background that is either unknown (nothing to see) or infinite (the whole positive part of the graph gets filled). -Next you draw the data on top of this background. It will overlay + +Next you draw the data on top of this background, it will overlay the background. Suppose one of val1..val4 would be unknown, in that case you end up with only three bars stacked on top of each other. You don't want to see this because the data is only valid when all @@ -837,7 +842,7 @@ If your data can also have negative values you also need to overwrite the other half of your graph. This can be done in a relatively simple way: what you need is the "wipeout" variable and place a negative sign before it: "CDEF:wipeout2=wipeout,-1,*" - + =head2 Filtering data You may do some complex data filtering: @@ -866,10 +871,11 @@ You may do some complex data filtering: =head1 Out of ideas for now -This document was created from questions asked by either myself or -by other people on the list. Please let me know if you find errors -in it or if you have trouble understanding it. If you think there -should be an addition, mail me: Ealex@ergens.op.het.netE +This document was created from questions asked by either myself or by +other people on the RRDtool mailing list. Please let me know if you +find errors in it or if you have trouble understanding it. If you +think there should be an addition, mail me: +Ealex@ergens.op.het.netE Remember: B diff --git a/doc/name.inc b/doc/name.inc index 056f27f..dffcae4 100644 --- a/doc/name.inc +++ b/doc/name.inc @@ -8,11 +8,4 @@ WARNING: DO NOT EDIT THE POD FILES. THEY ARE AUTO-GENERATED rrdtool graph - Round Robin Database tool grapher functions -WARNING: This is for version 1.1.x which is B> software. -The software may contain serious bugs. Some of the items -described in here may not yet exist (although this should -be mentioned) or still be in the alpha stage. As with every -other RRDtool release: use at your own risk. In contrast with -the stable version of RRDtool, this release may contain bugs -known to the authors. It is highly recommended that you subscribe -to the mailing list. +Documentation for version 1.2.0 diff --git a/doc/rpntutorial.pod b/doc/rpntutorial.pod index 13ee0ec..b3beac1 100644 --- a/doc/rpntutorial.pod +++ b/doc/rpntutorial.pod @@ -2,8 +2,6 @@ rpntutorial - Reading RRDtool RPN Expressions by Steve Rader -=for html
PDF version.
- =head1 DESCRIPTION This tutorial should help you get to grips with RRDtool RPN expressions @@ -15,18 +13,18 @@ The LT, LE, GT, GE and EQ RPN logic operators are not as tricky as they appear. These operators act on the two values on the stack preceding them (to the left). Read these two values on the stack from left to right inserting the operator in the middle. If the -resulting statement is true, the replace the three values from the +resulting statement is true, then replace the three values from the stack with "1". If the statement if false, replace the three values with "0". -For example think about "2,1,GT". This RPN expression could be +For example, think about "2,1,GT". This RPN expression could be read as "is two greater than one?" The answer to that question is "true". So the three values should be replaced with "1". Thus the RPN expression 2,1,GT evaluates to 1. -Now also consider "2,1,LE". This RPN expression could be read as "is +Now consider "2,1,LE". This RPN expression could be read as "is two less than or equal to one?". The natural response is "no" -and thus the RPN expression 2,1,LE evaluates to 0. +and thus the RPN expression 2,1,LE evaluates to 0. =head1 Reading the IF Operator @@ -58,14 +56,14 @@ GT, GE and EQ operators. While compound expressions can look overly complex, they can be considered elegantly simple. To quickly comprehend RPN expressions, you must know the the algorithm for evaluating RPN expressions: -iterate searches from the left to the right looking for an operator, -when it's found, apply that operator by popping the operator and some +iterate searches from the left to the right looking for an operator. +When it's found, apply that operator by popping the operator and some number of values (and by definition, not operators) off the stack. For example, the stack "1,2,3,+,+" gets "2,3,+" evaluated (as "2+3") -during the first iteration which is replaced by 5. This results in +during the first iteration and is replaced by 5. This results in the stack "1,5,+". Finally, "1,5,+" is evaluated resulting in the -answer 6. For convenience sake, it's useful to write this set of +answer 6. For convenience, it's useful to write this set of operations as: 1) 1,2,3,+,+ eval is 2,3,+ = 5 result is 1,5,+ @@ -78,7 +76,7 @@ with multiple logic operators: 1) 20,10,GT,10,20,IF eval is 20,10,GT = 1 result is 1,10,20,IF read the eval as pop "20 is greater than 10" so push 1 - + 2) 1,10,20,IF eval is 1,10,20,IF = 10 result is 10 read pop "if 1 then 10 else 20" so push 10. Only 10 is left so @@ -93,23 +91,23 @@ multiplication operator: 4) 0,7000,1024,IF result is 1024 -Now let's go back to the first example of multiple logic operators +Now let's go back to the first example of multiple logic operators, but replace the value 20 with the variable "input": - 1) input,10,GT,10,input,IF eval is input,10,GT result is A + 1) input,10,GT,10,input,IF eval is input,10,GT ( lets call this A ) Read eval as "if input > 10 then true" and replace "input,10,GT" -with "A: - +with "A": + 2) A,10,input,IF eval is A,10,input,IF -read "if A then 10 else input". Now replace A it's verbose -description and--voila!--you have a easily readable description +read "if A then 10 else input". Now replace A with it's verbose +description againg and--voila!--you have a easily readable description of the expression: if input > 10 then 10 else input -Lastly, let's to back the first most complex example and replace +Finally, let's go back to the first most complex example and replace the value 128 with "input": 1) input,8,*,7000,GT,7000,input,8,*,IF eval input,8,* result is A @@ -141,7 +139,7 @@ traditional notation. Explain why they have different answers. Answer 1: 3*2+1 = 7 and 3*(2+1) = 9. These expressions have - different answers because the altering of the plus and + different answers because the altering of the plus and times operators alter the order of their evaluation. @@ -155,8 +153,8 @@ by removing the redundant use of "input,8,*" like so: input,56000,GT,56000,input,IF,8,* -Use tradition notation to show these expressions are not the same. -Write an expression that's equivalent to the first expression but +Use traditional notation to show these expressions are not the same. +Write an expression that's equivalent to the first expression, but uses the LE and DIV operators. Answer 2: @@ -183,7 +181,7 @@ Answer 3: Exercise 4: -Explain why it is desirable for the RRDtool developers to implement +Explain why it was desirable for the RRDtool developers to implement RPN notation instead of traditional mathematical notation. Answer 4: diff --git a/doc/rrd-beginners.pod b/doc/rrd-beginners.pod index 363cc2e..5ac7997 100644 --- a/doc/rrd-beginners.pod +++ b/doc/rrd-beginners.pod @@ -1,6 +1,6 @@ -=head1 NAME +=head1 NAME -rrd-beginners - Beginners guide +rrd-beginners - RRDtool Beginners' Guide =head1 SYNOPSIS @@ -10,35 +10,35 @@ Helping new RRDtool users to understand the basics of RRDtool This manual is an attempt to assist beginners in understanding the concepts of RRDtool. It sheds a light on differences between RRDtool and other -databases. With help of an example, it explains structure of RRDtool +databases. With help of an example, it explains the structure of RRDtool database. This is followed by an overview of the "graph" feature of RRDtool. -At the end, it has sample scripts that illustrates the +At the end, it has sample scripts that illustrate the usage/wrapping of RRDtool within Shell or Perl scripts. =head2 What makes RRDtool so special? RRDtool is GNU licensed software developed by Tobias Oetiker, a system manager at the Swiss Federal Institute of Technology. Though it is a -database, there are distinct differences between RRDtool database and other +database, there are distinct differences between RRDtool databases and other databases as listed below: =over =item * -RRDtool stores data; that makes it a back end tool. The RRDtool command set -allows the creation of graphs; that makes it a front end tool as well. Other -databases just stores data and can not create graphs. +RRDtool stores data; that makes it a back-end tool. The RRDtool command set +allows the creation of graphs; that makes it a front-end tool as well. Other +databases just store data and can not create graphs. =item * In case of linear databases, new data gets appended at the bottom of -the database table. Thus its size keeps on increasing, whereas size of an RRDtool -database is determined at creation time. Imagine an RRDtool database as the -perimeter of a circle. Data is added along the perimeter. When new data -reaches the starting point, it overwrites existing data. This way, the size of -an RRDtool database always remains constant. The name "Round Robin" stems from this -attribute. +the database table. Thus its size keeps on increasing, whereas the size of +an RRDtool database is determined at creation time. Imagine an RRDtool +database as the perimeter of a circle. Data is added along the +perimeter. When new data reaches the starting point, it overwrites +existing data. This way, the size of an RRDtool database always +remains constant. The name "Round Robin" stems from this behavior. =item * @@ -52,24 +52,25 @@ Other databases get updated when values are supplied. The RRDtool database is structured in such a way that it needs data at predefined time intervals. If it does not get a new value during the interval, it stores an UNKNOWN value for that interval. So, when using the RRDtool database, it is -imperative to use scripts that runs at regular intervals to ensure a constant +imperative to use scripts that run at regular intervals to ensure a constant data flow to update the RRDtool database. =back - -RRDtool has a lot to do with time. With every data update, it also needs to -know the time when that update occurred. Time is always expressed in -seconds passed since epoch (01-01-1971). RRDtool can be installed on Unix as -well as Windows. It has command set to carry out various -operations on RRD database. This command set can be accessed from the command line, -and from Shell or Perl scripts. The scripts -act as wrappers for accessing data stored in RRDtool database. - + +RRDtool is designed to store time series of data. With every data +update, an associated time stamp is stored. Time is always expressed +in seconds passed since epoch (01-01-1970). RRDtool can be installed +on Unix as well as Windows. It comes with a command set to carry out +various operations on RRD databases. This command set can be accessed +from the command line, as well as from Shell or Perl scripts. The +scripts act as wrappers for accessing data stored in RRDtool +databases. + =head2 Understanding by an example The structure of an RRD database is different than other linear databases. Other databases define tables with columns, and many other parameters. These -definitions sometime are very complex, especially in large databases. +definitions sometimes are very complex, especially in large databases. RRDtool databases are primarily used for monitoring purposes and hence are very simple in structure. The parameters that need to be defined are variables that hold values and archives of those @@ -83,143 +84,152 @@ terminologies related to RRDtool databases. The structure of a database and the terminology associated with it can be best explained with an example. - rrdtool create target.rrd - --start 1023654125 - --step 300 - DS:mem:GAUGE:600:0:671744 - RRA:AVERAGE:0.5:12:24 + rrdtool create target.rrd \ + --start 1023654125 \ + --step 300 \ + DS:mem:GAUGE:600:0:671744 \ + RRA:AVERAGE:0.5:12:24 \ RRA:AVERAGE:0.5:288:31 -This example creates a database named F. Start time (1023654125) is -specified in total number of seconds since epoch (time in seconds since -01-01-1970). While updating the database, update time is also specified. -This update time MUST occur after start time and MUST be in seconds since -epoch. +This example creates a database named F. Start time +(1'023'654'125) is specified in total number of seconds since epoch +(time in seconds since 01-01-1970). While updating the database, the +update time is also specified. This update time MUST be large (later) +then start time and MUST be in seconds since epoch. The step of 300 seconds indicates that database expects new values every 300 seconds. The wrapper script should be scheduled to run every B seconds so that it updates the database every B seconds. DS (Data Source) is the actual variable which relates to the parameter on -the device that has to be monitored. Its syntax is +the device that is monitored. Its syntax is DS:variable_name:DST:heartbeat:min:max B is a key word. C is a name under which the parameter is -saved in database. There can be as many DSs in a database as needed. After +saved in the database. There can be as many DSs in a database as needed. After every step interval, a new value of DS is supplied to update the database. -This value is also called as Primary Data Point B<(PDP)>. In our example +This value is also called Primary Data Point B<(PDP)>. In our example mentioned above, a new PDP is generated every 300 seconds. Note, that if you do NOT supply new datapoints exactly every 300 seconds, -this is not problem, RRDtool will interpolate the data accordingly. - -B (Data Source Type) defines type of DS. It can be COUNTER, DERIVE, -ABSOLUTE, GAUGE. A DS declared as COUNTER will save the rate of change of -the value over a step period. This assumes that the value is always -increasing (difference between last two values is more than 0). Traffic -counters on a router is an ideal candidate for using COUNTER as DST. DERIVE -is same as COUNTER but it allows negative values as well. If you want to see -the rate of I in free diskspace on your server, then you might want to -use the DERIVE data type. ABSOLUTE also saves the rate of change but it assumes -that previous value is set to 0. The difference between current and previous -value is always equal to the current value. So, it stores the current value divided -by step interval (300 seconds in our example). GAUGE does not save the rate of -change. It saves the actual value itself. There are no -divisions/calculations. Memory consumption in a server is an ideal -example of gauge. Difference among different types DSTs can be explained -better with following example: +this is not a problem, RRDtool will interpolate the data accordingly. + +B (Data Source Type) defines the type of the DS. It can be +COUNTER, DERIVE, ABSOLUTE, GAUGE. A DS declared as COUNTER will save +the rate of change of the value over a step period. This assumes that +the value is always increasing (the difference between the current and +the previous value is greater than 0). Traffic counters on a router +are an ideal candidate for using COUNTER as DST. DERIVE is the same as +COUNTER, but it allows negative values as well. If you want to see the +rate of I in free diskspace on your server, then you might +want to use the DERIVE data type. ABSOLUTE also saves the rate of +change, but it assumes that the previous value is set to 0. The +difference between the current and the previous value is always equal +to the current value. Thus it just stores the current value divided by +the step interval (300 seconds in our example). GAUGE does not save +the rate of change. It saves the actual value itself. There are no +divisions or calculations. Memory consumption in a server is a typical +example of gauge. The difference between the different types DSTs can be +explained better with the following example: Values = 300, 600, 900, 1200 Step = 300 seconds - COUNTER DS = 1, 1, 1, 1 + COUNTER DS = 1, 1, 1, 1 DERIVE DS = 1, 1, 1, 1 - ABSOLUTE DS = 1, 2, 3, 4 + ABSOLUTE DS = 1, 2, 3, 4 GAUGE DS = 300, 600, 900, 1200 The next parameter is B. In our example, heartbeat is 600 -seconds. If database does not get a new PDP within 300 -seconds, it will wait for another 300 seconds (total 600 seconds). -If it doesn't receive any PDP with in 600 seconds, it will save an UNKNOWN value -into database. This UNKNOWN value is a special feature of RRDtool - it is -much better than to assume a missing value was 0 (zero). -For example, the traffic flow counter on a router -keeps on increasing. Lets say, a value is missed for an interval and 0 is stored -instead of UNKNOWN. Now when next value becomes available, it will calculate -difference between current value and previous value (0) which is not -correct. So, inserting value UNKNOWN makes much more sense here. - -The next two parameters are the minimum and maximum value respectively. If variable -to be stored has predictable maximum and minimum value, this should be -specified here. Any update value falling out of this range will be saved as -UNKNOWN. - -The next line declares a round robin archive (RRA). The syntax for declaring an RRA is +seconds. If the database does not get a new PDP within 300 seconds, it +will wait for another 300 seconds (total 600 seconds). If it doesn't +receive any PDP within 600 seconds, it will save an UNKNOWN value into +the database. This UNKNOWN value is a special feature of RRDtool - it +is much better than to assume a missing value was 0 (zero) or any +other number which might also be a valid data value. For example, the +traffic flow counter on a router keeps increasing. Lets say, a value +is missed for an interval and 0 is stored instead of UNKNOWN. Now when +the next value becomes available, it will calculate the difference +between the current value and the previous value (0) which is not +correct. So, inserting the value UNKNOWN makes much more sense here. + +The next two parameters are the minimum and maximum value, +respectively. If the variable to be stored has predictable maximum and +minimum values, this should be specified here. Any update value +falling out of this range will be stored as UNKNOWN. + +The next line declares a round robin archive (RRA). The syntax for +declaring an RRA is RRA:CF:xff:step:rows -RRA is the keyword to declare RRAs. The consolidation function (CF) can be -AVERAGE, MINIMUM, MAXIMUM, and LAST. The concept of the consolidated data point (CDP) -comes into the picture here. A CDP is CFed (averaged, maximum/minimum value or -last value) from I number of PDPs. This RRA will hold I CDPs. - -Lets have a look at the example above. For the first RRA, 12 (steps) PDPs -(DS variables) are AVERAGEed (CF) to form one CDP. 24 (rows) of theses CDPs -are archived. Each PDP occurs at 300 seconds. 12 PDPs represent 12 times 300 -seconds which is 1 hour. It means 1 CDP (which is equal to 12 PDPs) -represents data worth 1 hour. 24 such CDPs represent 1 day (1 hour times 24 -CDPs). It means, this RRA is an archive for one day. After 24 CDPs, CDP -number 25 will replace the 1st CDP. Second RRA saves 31 CDPs; each CPD -represents an AVERAGE value for a day (288 PDPs, each covering 300 seconds = -24 hours). Therefore this RRA is an archive for one month. A single database -can have many RRAs. If there are multiple DSs, each individual RRA will save -data for all the DSs in the database. For example, if a database has 3 DSs; -and daily, weekly, monthly, and yearly RRAs are declared, then each RRA will -hold data from all 3 data sources. +RRA is the keyword to declare RRAs. The consolidation function (CF) +can be AVERAGE, MINIMUM, MAXIMUM, and LAST. The concept of the +consolidated data point (CDP) comes into the picture here. A CDP is +CFed (averaged, maximum/minimum value or last value) from I +number of PDPs. This RRA will hold I CDPs. + +Lets have a look at the example above. For the first RRA, 12 (steps) +PDPs (DS variables) are AVERAGEed (CF) to form one CDP. 24 (rows) of +theses CDPs are archived. Each PDP occurs at 300 seconds. 12 PDPs +represent 12 times 300 seconds which is 1 hour. It means 1 CDP (which +is equal to 12 PDPs) represents data worth 1 hour. 24 such CDPs +represent 1 day (1 hour times 24 CDPs). This means, this RRA is an +archive for one day. After 24 CDPs, CDP number 25 will replace the 1st +CDP. The second RRA saves 31 CDPs; each CPD represents an AVERAGE +value for a day (288 PDPs, each covering 300 seconds = 24 +hours). Therefore this RRA is an archive for one month. A single +database can have many RRAs. If there are multiple DSs, each +individual RRA will save data for all the DSs in the database. For +example, if a database has 3 DSs and daily, weekly, monthly, and +yearly RRAs are declared, then each RRA will hold data from all 3 data +sources. =head2 Graphical Magic -Another important feature of RRDtool is its ability to create graphs. The -"graph" command uses "fetch" command internally to retrieve values from the -database. With the retrieved values, it draws graphs as defined by the -parameters supplied on the command line. A single graph can show different -DS (Data Sources0) from a database. It is also possible to show the -values from more than one databases into a single graph. Often, it is -necessary to perform some math on the values retrieved from database, before -plotting them. For example, in SNMP replies, memory consumption values are -usually specified in KBytes and traffic flow on interfaces is specified in -Bytes. Graphs for these values will be more senseful if values are -represented in MBytes and mbps. the RRDtool graph command allows to define -such conversions. Apart from mathematical calculations, it is also possible -to perform logical operations such as greater than, less than, and if then -else. If a database contains more than one RRA archive, then a question may -arise - how does RRDtool decide which RRA archive to use for retrieving the -values? RRDtool takes looks at several things when making its choice. First -it makes sure that the RRA covers as much of the graphing time frame as -possible. Second it looks at the resolution of the RRA compared to the -resolution of the graph. It tries to find one which has the same or better -resolution. With the "-r" option you can force RRDtool to assume a different -resolution than the one calculated from the pixel width of the graph. - -Values of different variables can be presented in 5 different shapes in a -graph - AREA, LINE1, LINE2, LINE3, and STACK. AREA is represented by a solid -colored area with values as the boundary of this area. LINE1/2/3 (increasing -width) are just plain lines representing the values. STACK is also an area -but it is "stack"ed on AREA or LINE1/2/3. Another important thing to note, -is that variables are plotted in the order they are defined in graph -command. So, care must be taken to define STACK only after defining -AREA/LINE. It is also possible to put formatted comments within the graph. -Detailed instructions be found under graph manual. +Another important feature of RRDtool is its ability to create +graphs. The "graph" command uses the "fetch" command internally to +retrieve values from the database. With the retrieved values it draws +graphs as defined by the parameters supplied on the command line. A +single graph can show different DS (Data Sources) from a database. It +is also possible to show the values from more than one database in a +single graph. Often, it is necessary to perform some math on the +values retrieved from the database before plotting them. For example, +in SNMP replies, memory consumption values are usually specified in +KBytes and traffic flow on interfaces is specified in Bytes. Graphs +for these values will be more meaningful if values are represented in +MBytes and mbps. The RRDtool graph command allows to define such +conversions. Apart from mathematical calculations, it is also possible +to perform logical operations such as greater than, less than, and +if/then/else. If a database contains more than one RRA archive, then a +question may arise - how does RRDtool decide which RRA archive to use +for retrieving the values? RRDtool looks at several things when making +its choice. First it makes sure that the RRA covers as much of the +graphing time frame as possible. Second it looks at the resolution of +the RRA compared to the resolution of the graph. It tries to find one +which has the same or higher better resolution. With the "-r" option +you can force RRDtool to assume a different resolution than the one +calculated from the pixel width of the graph. + +Values of different variables can be presented in 5 different shapes +in a graph - AREA, LINE1, LINE2, LINE3, and STACK. AREA is represented +by a solid colored area with values as the boundary of this +area. LINE1/2/3 (increasing width) are just plain lines representing +the values. STACK is also an area but it is "stack"ed on top AREA or +LINE1/2/3. Another important thing to note is that variables are +plotted in the order they are defined in the graph command. Therefore +care must be taken to define STACK only after defining AREA/LINE. It +is also possible to put formatted comments within the graph. Detailed +instructions can be found in the graph manual. =head2 Wrapping RRDtool within Shell/Perl script -After understanding RRDtool, it is now a time to actually use RRDtool in -scripts. Tasks involved in network management are data collection, data -storage, and data retrieval. In the following example, -the previously created target.rrd database is used. Data collection and data -storage is done using Shell scrip. Data retrieval -and report generation is done using Perl script. These -scripts are as shown below: +After understanding RRDtool it is now a time to actually use RRDtool +in scripts. Tasks involved in network management are data collection, +data storage, and data retrieval. In the following example, the +previously created target.rrd database is used. Data collection and +data storage is done using Shell scripts. Data retrieval and report +generation is done using Perl scripts. These scripts are shown below: =head3 Shell script (collects data, updates database) @@ -241,21 +251,21 @@ scripts are as shown below: =head3 Perl script (retrieves data from database and generates graphs and statistics) #!/usr/bin/perl -w - #This script fetch data from target.rrd, creates graph of memory consumption - on target (Dual P3 Processor 1 GHz, 656 MB RAM) + # This script fetches data from target.rrd, creates a graph of memory + # consumption on the target (Dual P3 Processor 1 GHz, 656 MB RAM) - #calling RRD perl module + # call the RRD perl module use lib qw( /usr/local/rrdtool-1.0.41/lib/perl ../lib/perl ); use RRDs; - my $cur_time = time(); # setting current time - my $end_time = $cur_time - 86400; # setting end time to 24 hours behind current time - my $start_time = $end_time - 2592000; # setting start time to 30 days from end time + my $cur_time = time(); # set current time + my $end_time = $cur_time - 86400; # set end time to 24 hours ago + my $start_time = $end_time - 2592000; # set start 30 days in the past - #fetching average values from RRD database between start and end time - my ($start,$step,$ds_names,$data) = - RRDs::fetch("target.rrd", "AVERAGE", + # fetch average values from the RRD database between start and end time + my ($start,$step,$ds_names,$data) = + RRDs::fetch("target.rrd", "AVERAGE", "-r", "600", "-s", "$start_time", "-e", "$end_time"); - #saving fetched values in 2-dimensional array + # save fetched values in a 2-dimensional array my $rows = 0; my $columns = 0; my $time_variable = $start; @@ -269,19 +279,19 @@ scripts are as shown below: } my $tot_time = 0; my $count = 0; - #saving values from 2-dimensional into 1-dimensional array + # save the values from the 2-dimensional into a 1-dimensional array for $i ( 0 .. $#vals ) { $tot_mem[$count] = $vals[$i][1]; $count++; } my $tot_mem_sum = 0; - #calculating total of all values + # calculate the total of all values for $i ( 0 .. ($count-1) ) { $tot_mem_sum = $tot_mem_sum + $tot_mem[$i]; } - #calculating average of array + # calculate the average of the array my $tot_mem_ave = $tot_mem_sum/($count); - #creating graph + # create the graph RRDs::graph ("/images/mem_$count.png", \ "--title= Memory Usage", \ "--vertical-label=Memory Consumption (MB)", \ @@ -296,16 +306,16 @@ scripts are as shown below: "--rigid", \ "--base=1024", \ "DEF:tot_mem=target.rrd:mem:AVERAGE", \ - "CDEF:correct_tot_mem=tot_mem,0,671744,LIMIT,UN,0,tot_mem,IF,1024,/",\ + "CDEF:tot_mem_cor=tot_mem,0,671744,LIMIT,UN,0,tot_mem,IF,1024,/",\ "CDEF:machine_mem=tot_mem,656,+,tot_mem,-",\ "COMMENT:Memory Consumption between $start_time",\ "COMMENT: and $end_time ",\ "HRULE:656#000000:Maximum Available Memory - 656 MB",\ "AREA:machine_mem#CCFFFF:Memory Unused", \ - "AREA:correct_tot_mem#6699CC:Total memory consumed in MB"); + "AREA:tot_mem_cor#6699CC:Total memory consumed in MB"); my $err=RRDs::error; if ($err) {print "problem generating the graph: $err\n";} - #printing the output + # print the output print "Average memory consumption is "; printf "%5.2f",$tot_mem_ave/1024; print " MB. Graphical representation can be found at /images/mem_$count.png."; diff --git a/doc/rrdbuild.pod b/doc/rrdbuild.pod new file mode 100644 index 0000000..7a24a82 --- /dev/null +++ b/doc/rrdbuild.pod @@ -0,0 +1,205 @@ +=head1 NAME + +rrdbuild - Instructions for building RRDtool + +=head1 DESCRIPTION + +=head2 Overview + +If you downloaded the source of rrdtool you have to compile it. This +document will give some information on how this is done. + +RRDtool relies on services of thrid part libraries. Some of these libraries +may already be installed on your system. You have to compile copies of the other +ones before you can build RRDtool. + +This document will tell you about all the necessary steps to get going. + +=head2 Building + +Before you start to build RRDtool, you have to decide two things: + +=over + +=item 1. + +In which directory you want to build the software. + +=item 2. + +Where you want to install the software. + +=back + +Once you have decided. Save the two locations into environment variables. +Depending on the shell you are using, you can do either (bash,zsh): + + BUILD_DIR=/tmp/rrdbuild + INSTALL_DIR=/usr/local/rrdtool-1.2.23 + +Or if you run tcsh: + + set BUILD_DIR=/tmp/rrdbuild + set INSTALL_DIR=/usr/local/rrdtool-1.2.23 + +If your F is mounted with the option noexec (RHEL seems todo that) you have to choose +a different directory! + +Now make sure the BUILD_DIR exists and go there: + + mkdir -p $BUILD_DIR + cd $BUILD_DIR + +Lets first assume you already have all the necessary libraries +pre-installed. Note that these instructions assume that your copies of +B and B are actually B and B respectively. It +could be that they are installed as B and B on your system. + + wget http://oss.oetiker.ch/rrdtool/pub/rrdtool-1.2.23.tar.gz + tar zxf rrdtool-1.2.23.tar.gz + cd rrdtool-1.2.23 + ./configure --prefix=$INSTALL_DIR && make && make install + +Ok, this was very optimistic. This try will probably have ended with +B complaining about several missing libraries. If you are on a +Linux or *bsd system you may want to just install the missing bits from your +software repository. When you do that, make sure you also get the B<-dev> +package for each library you install. Once you have the missing bits on +board, just re-run the last line of the instructions above. + +But again this may have been too optimistic, and you actually have to +compile your own copies of the required libraries. + +=head3 Build Tipps for AIX + +If you are woking with AIX, you may find the the B<--disable-shared> option +will cause things to break for you. In that case you may have to install the +shared libraries into the rrdtool PREFIX and work with B<--disable-static> +instead. + +Another hint to get rrdtool working on AIX is to use the IBM XL C Compiler: + + export CC=/usr/vac/bin/cc + export PERLCC=$CC + +(Better instructions for AIX welcome!) + +=head2 Building Libraries + +In order to build the libraries you need a compiler on your system. +Unfortunately compilers are not all alike. This has an effect on the CFLAGS +you want to set. The examples below are for the popular GCC compiler suite. +If you have an other compile you have to use the following settings: + +=over + +=item Sun Forte + + CFLAGS="-xO3 -kPIC" + +=back + +=over + +=item Building zlib + + cd $BUILD_DIR + wget http://oss.oetiker.ch/rrdtool/pub/libs/zlib-1.2.3.tar.gz + tar zxf zlib-1.2.3.tar.gz + cd zlib-1.2.3 + env CFLAGS="-O3 -fPIC" ./configure --prefix=$BUILD_DIR/lb + make + make install + +=item Building libpng + +Libpng itself requires zlib to build, so we need to help a bit. If you +already have a copy of zlib on your system (which is very likley) you can +drop the settings of LDFLAGS and CPPFLAGS. Note that the backslash (\) at +the end of line 4 means that line 4 and line 5 are on one line. + + cd $BUILD_DIR + wget http://oss.oetiker.ch/rrdtool/pub/libs/libpng-1.2.10.tar.gz + tar zxvf libpng-1.2.10.tar.gz + cd libpng-1.2.10 + env CPPFLAGS="-I$BUILD_DIR/lb/include" LDFLAGS="-L$BUILD_DIR/lb/lib" CFLAGS="-O3 -fPIC" \ + ./configure --disable-shared --prefix=$BUILD_DIR/lb + make + make install + +=item Building freetype + + cd $BUILD_DIR + wget http://oss.oetiker.ch/rrdtool/pub/libs/freetype-2.1.10.tar.bz2 + tar jxvf freetype-2.1.10.tar.bz2 + cd freetype-2.1.10 + env CPPFLAGS="-I$BUILD_DIR/lb/include" LDFLAGS="-L$BUILD_DIR/lb/lib" CFLAGS="-O3 -fPIC" \ + ./configure --disable-shared --prefix=$BUILD_DIR/lb + make + make install + +If you run into problems building freetype on Solaris, you may want to try to +add the following at the end of the configure line: + + GNUMAKE=gmake EGREP=egrep + +=item Building libart_lgpl + + cd $BUILD_DIR + wget http://oss.oetiker.ch/rrdtool/pub/libs/libart_lgpl-2.3.17.tar.gz + tar zxvf libart_lgpl-2.3.17.tar.gz + cd libart_lgpl-2.3.17 + env CFLAGS="-O3 -fPIC" ./configure --disable-shared --prefix=$BUILD_DIR/lb + make + make install + +=back + +Now all the dependent libraries are built and you can try again. Since these +are static libraries, you may have to use F to make them accessible. +Especially BSD systems like Mac OS X may require this, Linux and Solaris +will do just fine without since their F command does ranlibs job as well. + + ranlib $BUILD_DIR/lb/lib/*.a + +This time you tell configure where it should be looking for libraries and +include files. This is done via environment variables. Depending on the +shell you are running, the syntax for setting environment variables is +different. Under csh/tcsh you use: + + set IR=-I$BUILD_DIR/lb/include + setenv CPPFLAGS "$IR $IR/libart-2.0 $IR/freetype2 $IR/libpng" + setenv LDFLAGS -L$BUILD_DIR/lb/lib + setenv CFLAGS -O3 + +If you are running bash/sh/ash/ksh/zsh use this: + + IR=-I$BUILD_DIR/lb/include + CPPFLAGS="$IR $IR/libart-2.0 $IR/freetype2 $IR/libpng" + LDFLAGS="-L$BUILD_DIR/lb/lib" + CFLAGS=-O3 + export CPPFLAGS LDFLAGS CFLAGS + +And finally try building again. We disable the python and tcl bindings +because it seems that a fair number of people have ill configured python and +tcl setups that would prevent rrdtool from building if they are included in +their current state. + + cd $BUILD_DIR/rrdtool-1.2.23 + ./configure --prefix=$INSTALL_DIR --disable-python --disable-tcl + make clean + make + make install + +SOLARIS HINT: if you want to build the perl module for the native perl (the +one shipping with solaris) you will need the sun forte compiler +installed on your box or you have to hand-tune bindings/perl-shared/Makefile +while building! + +Now go to I<$INSTALL_DIR>B and run them to see if your +build has been successful. + +=head1 AUTHOR + +Tobias Oetiker Etobi@oetiker.chE + diff --git a/doc/rrdcgi.pod b/doc/rrdcgi.pod index 763ab23..4c81e01 100644 --- a/doc/rrdcgi.pod +++ b/doc/rrdcgi.pod @@ -1,13 +1,10 @@ =head1 NAME -rrdcgi - create web pages containing RRD graphs based on templates - -=for html
PDF version.
+rrdcgi - Create web pages containing RRD graphs based on templates =head1 SYNOPSIS -#!/path/to/B -S<[B<--filter>]> +C<#!/path/to/>B S<[B<--filter>]> =head1 DESCRIPTION @@ -17,16 +14,15 @@ ERRD:: tags. B will interpret and act according to these tags. In the end it will printout a web page including the necessary CGI headers. B parses the contents of the template in 3 steps. In each step it looks -only for a subset of tags. This allows to nest tags. +only for a subset of tags. This allows nesting of tags. -The argument parser uses the same semantics as you are used from your c shell. +The argument parser uses the same semantics as you are used from your C-shell. =over 8 - =item B<--filter> -Assume that rrdcgi is being run as a filter and not as a cgi. +Assume that rrdcgi is run as a filter and not as a cgi. =back @@ -42,13 +38,13 @@ Inserts the CGI variable of the given name. Inserts the CGI variable of the given name but quotes it, ready for use as an argument in another RRD:: tag. So even when there are spaces in the -value of the CGI variable it will still be considered as one argument. +value of the CGI variable it will still be considered to be one argument. =item RRD::CV::PATH I Inserts the CGI variable of the given name, quotes it and makes sure -the it starts neither with a '/' nor contains '..'. This is to make -sure that no problematic pathnames can be introduced through the +it starts neither with a '/' nor contains '..'. This is to make +sure that no problematic pathnames can be introduced through the CGI interface. =item RRD::GETENV I @@ -58,18 +54,18 @@ Get the value of an environment variable. might give you the name of the remote user given you are using -some sort of access control on the directory +some sort of access control on the directory. =item RRD::GOODFOR I Specify the number of seconds this page should remain valid. This will prompt the rrdcgi to output a Last-Modified, an Expire and if the number of -seconds is I a Refresh headers. +seconds is I a Refresh header. =item RRD::INCLUDE I -Include the contents of the given file into the page returned from the cgi +Include the contents of the specified file into the page returned from the cgi. =item RRD::SETENV I I @@ -83,11 +79,11 @@ values permitted to TZ depend on your OS. =item RRD::SETVAR I I -Analog to SETENV but for local variables +Analog to SETENV but for local variables. -=item RRD::GETVAR I +=item RRD::GETVAR I -Analog to GETENV but for local variables +Analog to GETENV but for local variables. =item RRD::TIME::LAST I I @@ -99,8 +95,9 @@ time is I-formatted with the string specified in the second argument. This gets replaced by the current time of day. The time is I-formatted with the string specified in the argument. -Note that if you return : from your strftime format you may have to escape -them using \ if the time is to be used as an argument to a GRAPH command. +Note that if you return : (colons) from your strftime format you may +have to escape them using \ if the time is to be used as an argument +to a GRAPH command. =item RRD::TIME::STRFTIME I I I I @@ -111,13 +108,14 @@ must be supplied as either could be relative to the other. This is intended to allow pretty titles on graphs with times that are easier for non RRDtool folks to figure out than "-2weeks". -Note that if you return : from your strftime format you may have to escape -them using \ if the time is to be used as an argument to a GRAPH command. +Note that again, if you return : (colon) from your strftime format, +you may have to escape them using \ if the time is to be used as an +argument to a GRAPH command. =item RRD::GRAPH I -This tag creates the RRD graph defined in its argument and then gets -replaced by an appropriate EIMG tag referring to the graph. +This tag creates the RRD graph defined by its argument and then is +replaced by an appropriate EIMG ... E tag referring to the graph. The B<--lazy> option in RRD graph can be used to make sure that graphs are only regenerated when they are out of date. The arguments to the B tag work as described in the B manual page. @@ -140,6 +138,12 @@ If the preceding B tag contained and B arguments, then you can access their output with this tag. The I argument refers to the number of the B argument. This first B has I 0. +=item RRD::INTERNAL + +This tag gets replaced by an internal var. Currently these vars are known: +VERSION, COMPILETIME. +These vars represent the compiled-in values. + =back =head1 EXAMPLE 1 @@ -162,9 +166,9 @@ The example below creates a web pages with a single RRD graph. =head1 EXAMPLE 2 -This script is slightly more elaborate, it allows you to run it from +This script is slightly more elaborate, it allows you to run it from a form which sets RRD_NAME. RRD_NAME is then used to select which RRD -you want to use a source for your graph. +you want to use as source for your graph. #!/usr/local/bin/rrdcgi @@ -177,7 +181,7 @@ you want to use a source for your graph.

Graph

- .png --lazy + .png --lazy --title "Temperatures for " DEF:cel=.rrd:exhaust:AVERAGE LINE2:cel#00a000:"D. Celsius"> @@ -213,7 +217,7 @@ webserver/browser =head1 AUTHOR -Tobias Oetiker Eoetiker@ee.ethz.chE +Tobias Oetiker Etobi@oetiker.chE diff --git a/doc/rrdcreate.pod b/doc/rrdcreate.pod index 3b7fb68..27ef702 100644 --- a/doc/rrdcreate.pod +++ b/doc/rrdcreate.pod @@ -1,23 +1,20 @@ =head1 NAME -rrdtool create - Set up a new Round Robin Database - -=for html

PDF version.
+rrdcreate - Set up a new Round Robin Database =head1 SYNOPSIS -B B I -S<[B<--start>|B<-b> I]> -S<[B<--step>|B<-s> I]> +B B I +S<[B<--start>|B<-b> I]> +S<[B<--step>|B<-s> I]> S<[BIB<:>IB<:>I]> S<[BIB<:>I]> =head1 DESCRIPTION -The create function of the RRDtool lets you set up new -Round Robin Database (B) files. -The file is created at its final, full size and filled -with I<*UNKNOWN*> data. +The create function of RRDtool lets you set up new Round Robin +Database (B) files. The file is created at its final, full size +and filled with I<*UNKNOWN*> data. =over 8 @@ -34,7 +31,7 @@ value should be added to the B. B will not accept any data timed before or at the time specified. See also AT-STYLE TIME SPECIFICATION section in the -I documentation for more ways to specify time. +I documentation for other ways to specify time. =item B<--step>|B<-s> I (default: 300 seconds) @@ -43,17 +40,17 @@ into the B. =item BIB<:>IB<:>I -A single B can accept input from several data sources (B). -(e.g. Incoming and Outgoing traffic on a specific communication -line). With the B configuration option you must define some basic -properties of each data source you want to use to feed the B. +A single B can accept input from several data sources (B), +for example incoming and outgoing traffic on a specific communication +line. With the B configuration option you must define some basic +properties of each data source you want to store in the B. I is the name you will use to reference this particular data source from an B. A I must be 1 to 19 characters long in the characters [a-zA-Z0-9_]. I defines the Data Source Type. The remaining arguments of a -data source entry depend upon the data source type. For GAUGE, COUNTER, +data source entry depend on the data source type. For GAUGE, COUNTER, DERIVE, and ABSOLUTE the format for a data source entry is: BIB<:>IB<:>IB<:>IB<:>I @@ -62,24 +59,26 @@ For COMPUTE data sources, the format is: BIB<:>IB<:>I -To decide on a data source type, review the definitions that follow. -Consult the section on "HOW TO MEASURE" for further insight. +In order to decide which data source type to use, review the +definitions that follow. Also consult the section on "HOW TO MEASURE" +for further insight. =over 4 -=item B +=item B -is for things like temperatures or number of people in a -room or value of a RedHat share. +is for things like temperatures or number of people in a room or the +value of a RedHat share. =item B -is for continuous incrementing counters like the -ifInOctets counter in a router. The B data source assumes that -the counter never decreases, except when a counter overflows. The update -function takes the overflow into account. The counter is stored as a -per-second rate. When the counter overflows, RRDtool checks if the overflow happened at -the 32bit or 64bit border and acts accordingly by adding an appropriate value to the result. +is for continuous incrementing counters like the ifInOctets counter in +a router. The B data source assumes that the counter never +decreases, except when a counter overflows. The update function takes +the overflow into account. The counter is stored as a per-second +rate. When the counter overflows, RRDtool checks if the overflow +happened at the 32bit or 64bit border and acts accordingly by adding +an appropriate value to the result. =item B @@ -113,72 +112,77 @@ wrap. =back -=item B +=item B is for counters which get reset upon reading. This is used for fast counters which tend to overflow. So instead of reading them normally you reset them -after every read to make sure you have a maximal time available before the +after every read to make sure you have a maximum time available before the next overflow. Another usage is for things you count like number of messages since the last update. =item B -is for storing the result of a formula applied to other data sources in -the B. This data source is not supplied a value on update, but rather -its Primary Data Points (PDPs) are computed from the PDPs of the data sources -according to the rpn-expression that defines the formula. Consolidation -functions are then applied normally to the PDPs of the COMPUTE data source -(that is the rpn-expression is only applied to generate PDPs). In database -software, these are referred to as "virtual" or "computed" columns. +is for storing the result of a formula applied to other data sources +in the B. This data source is not supplied a value on update, but +rather its Primary Data Points (PDPs) are computed from the PDPs of +the data sources according to the rpn-expression that defines the +formula. Consolidation functions are then applied normally to the PDPs +of the COMPUTE data source (that is the rpn-expression is only applied +to generate PDPs). In database software, such data sets are referred +to as "virtual" or "computed" columns. =back I defines the maximum number of seconds that may pass -between two updates of this data source before the value of the +between two updates of this data source before the value of the data source is assumed to be I<*UNKNOWN*>. -I and I are optional entries defining the expected range of -the data supplied by this data source. If I and/or I are -defined, any value outside the defined range will be regarded as -I<*UNKNOWN*>. If you do not know or care about min and max, set them -to U for unknown. Note that min and max always refer to the processed values -of the DS. For a traffic-B type DS this would be the max and min -data-rate expected from the device. +I and I define the expected range values for data supplied by a +data source. If I and/or I any value outside the defined range +will be regarded as I<*UNKNOWN*>. If you do not know or care about min and +max, set them to U for unknown. Note that min and max always refer to the +processed values of the DS. For a traffic-B type DS this would be +the maximum and minimum data-rate expected from the device. I -I defines the formula used to compute the PDPs of a COMPUTE -data source from other data sources in the same . It is similar to defining -a B argument for the graph command. Please refer to that manual page -for a list and description of RPN operations supported. For -COMPUTE data sources, the following RPN operations are not supported: COUNT, PREV, -TIME, and LTIME. In addition, in defining the RPN expression, the COMPUTE -data source may only refer to the names of data source listed previously -in the create command. This is similar to the restriction that Bs must -refer only to Bs and Bs previously defined in the same graph command. +I defines the formula used to compute the PDPs of a +COMPUTE data source from other data sources in the same . It is +similar to defining a B argument for the graph command. Please +refer to that manual page for a list and description of RPN operations +supported. For COMPUTE data sources, the following RPN operations are +not supported: COUNT, PREV, TIME, and LTIME. In addition, in defining +the RPN expression, the COMPUTE data source may only refer to the +names of data source listed previously in the create command. This is +similar to the restriction that Bs must refer only to Bs +and Bs previously defined in the same graph command. =item BIB<:>I The purpose of an B is to store data in the round robin archives -(B). An archive consists of a number of data values or statistics for +(B). An archive consists of a number of data values or statistics for each of the defined data-sources (B) and is defined with an B line. -When data is entered into an B, it is first fit into time slots of -the length defined with the B<-s> option becoming a I. +When data is entered into an B, it is first fit into time slots +of the length defined with the B<-s> option, thus becoming a I. -The data is also processed with the consolidation function (I) -of the archive. There are several consolidation functions that consolidate -primary data points via an aggregate function: B, B, B, B. -The format of B line for these consolidation functions is: +The data is also processed with the consolidation function (I) of +the archive. There are several consolidation functions that +consolidate primary data points via an aggregate function: B, +B, B, B. The format of B line for these +consolidation functions is: BIB<:>IB<:>IB<:>I I The xfiles factor defines what part of a consolidation interval may be made up from I<*UNKNOWN*> data while the consolidated value is still -regarded as known. +regarded as known. It is given as the ratio of allowed I<*UNKNOWN*> PDPs +to the number of PDPs in the interval. Thus, it ranges from 0 to 1 (exclusive). + I defines how many of these I are used to build a I which then goes into the archive. @@ -189,52 +193,60 @@ I defines how many generations of data values are kept in an B. =head1 Aberrant Behavior Detection with Holt-Winters Forecasting -by Jake Brutlag Ejakeb@corp.webtv.netE - In addition to the aggregate functions, there are a set of specialized functions that enable B to provide data smoothing (via the -Holt-Winters forecasting algorithm), confidence bands, and the flagging -aberrant behavior in the data source time series: +Holt-Winters forecasting algorithm), confidence bands, and the +flagging aberrant behavior in the data source time series: -=over 4 +=over -=item BIB<:>IB<:>IB<:>IB<:>IB<:>I +=item * -=item BIB<:>IB<:>IB<:>I +BIB<:>IB<:>IB<:>IB<:>I[B<:>I] -=item BIB<:>IB<:>IB<:>I +=item * + +BIB<:>IB<:>IB<:>I -=item BIB<:>IB<:>I +=item * -=item BIB<:>IB<:>IB<:>IB<:>I +BIB<:>IB<:>IB<:>I + +=item * + +BIB<:>IB<:>I + +=item * + +BIB<:>IB<:>IB<:>IB<:>I =back These B differ from the true consolidation functions in several ways. First, each of the Bs is updated once for every primary data point. Second, these B are interdependent. To generate real-time confidence -bounds, then a matched set of HWPREDICT, SEASONAL, DEVSEASONAL, and +bounds, a matched set of HWPREDICT, SEASONAL, DEVSEASONAL, and DEVPREDICT must exist. Generating smoothed values of the primary data points requires both a HWPREDICT B and SEASONAL B. Aberrant behavior detection requires FAILURES, HWPREDICT, DEVSEASONAL, and SEASONAL. The actual predicted, or smoothed, values are stored in the HWPREDICT -B. The predicted deviations are store in DEVPREDICT (think a standard +B. The predicted deviations are stored in DEVPREDICT (think a standard deviation which can be scaled to yield a confidence band). The FAILURES -B stores binary indicators. A 1 marks the indexed observation a +B stores binary indicators. A 1 marks the indexed observation as failure; that is, the number of confidence bounds violations in the preceding window of observations met or exceeded a specified threshold. An example of using these B to graph confidence bounds and failures appears in L. The SEASONAL and DEVSEASONAL B store the seasonal coefficients for the -Holt-Winters forecasting algorithm and the seasonal deviations respectively. +Holt-Winters forecasting algorithm and the seasonal deviations, respectively. There is one entry per observation time point in the seasonal cycle. For -example, if primary data points are generated every five minutes, and the -seasonal cycle is 1 day, both SEASONAL and DEVSEASONAL with have 288 rows. +example, if primary data points are generated every five minutes and the +seasonal cycle is 1 day, both SEASONAL and DEVSEASONAL will have 288 rows. In order to simplify the creation for the novice user, in addition to -supporting explicit creation the HWPREDICT, SEASONAL, DEVPREDICT, +supporting explicit creation of the HWPREDICT, SEASONAL, DEVPREDICT, DEVSEASONAL, and FAILURES B, the B create command supports implicit creation of the other four when HWPREDICT is specified alone and the final argument I is omitted. @@ -247,7 +259,7 @@ default number of rows is the same as the HWPREDICT I argument. If the FAILURES B is implicitly created, I will be set to the I argument of the HWPREDICT B. Of course, the B I command is available if these defaults are not sufficient and the -create wishes to avoid explicit creations of the other specialized function +creator wishes to avoid explicit creations of the other specialized function B. I specifies the number of primary data points in a seasonal @@ -257,11 +269,11 @@ they are explicitly created, the creator should verify that all three I arguments agree. I is the adaption parameter of the intercept (or baseline) -coefficient in the Holt-Winters forecasting algorithm. See L for a +coefficient in the Holt-Winters forecasting algorithm. See L for a description of this algorithm. I must lie between 0 and 1. A value closer to 1 means that more recent observations carry greater weight in -predicting the baseline component of the forecast. A value closer to 0 mean -that past history carries greater weight in predicted the baseline +predicting the baseline component of the forecast. A value closer to 0 means +that past history carries greater weight in predicting the baseline component. I is the adaption parameter of the slope (or linear trend) coefficient @@ -286,25 +298,26 @@ be the same for both. Note that I can also be changed via the B I command. I provides the links between related B. If HWPREDICT is -specified alone and the other B created implicitly, then there is no -need to worry about this argument. If B are created explicitly, then -pay careful attention to this argument. For each B which includes this -argument, there is a dependency between that B and another B. The -I argument is the 1-based index in the order of B creation -(that is, the order they appear in the I command). The dependent -B for each B requiring the I argument is listed here: +specified alone and the other B are created implicitly, then +there is no need to worry about this argument. If B are created +explicitly, then carefully pay attention to this argument. For each +B which includes this argument, there is a dependency between +that B and another B. The I argument is the 1-based +index in the order of B creation (that is, the order they appear +in the I command). The dependent B for each B +requiring the I argument is listed here: -=over 4 +=over =item * HWPREDICT I is the index of the SEASONAL B. -=item * +=item * SEASONAL I is the index of the HWPREDICT B. -=item * +=item * DEVPREDICT I is the index of the DEVSEASONAL B. @@ -312,7 +325,7 @@ DEVPREDICT I is the index of the DEVSEASONAL B. DEVSEASONAL I is the index of the HWPREDICT B. -=item * +=item * FAILURES I is the index of the DEVSEASONAL B. @@ -335,7 +348,7 @@ It may help you to sort out why all this *UNKNOWN* data is popping up in your databases: RRDtool gets fed samples at arbitrary times. From these it builds Primary -Data Points (PDPs) at exact times every "step" interval. The PDPs are +Data Points (PDPs) at exact times on every "step" interval. The PDPs are then accumulated into RRAs. The "heartbeat" defines the maximum acceptable interval between @@ -350,7 +363,7 @@ The known rates during a PDP's "step" interval are used to calculate an average rate for that PDP. Also, if the total "unknown" time during the "step" interval exceeds the "heartbeat", the entire PDP is marked as "unknown". This means that a mixture of known and "unknown" sample -time in a single PDP "step" may or may not add up to enough "unknown" +times in a single PDP "step" may or may not add up to enough "unknown" time to exceed "heartbeat" and hence mark the whole PDP "unknown". So "heartbeat" is not only the maximum acceptable interval between samples, but also the maximum acceptable amount of "unknown" time per @@ -367,6 +380,44 @@ sample. An extreme example of this might be a "step" of 5 minutes and a result in all the PDPs for that entire day period being set to the same average rate. I<-- Don Baarda Edon.baarda@baesystems.comE> + time| + axis| + begin__|00| + |01| + u|02|----* sample1, restart "hb"-timer + u|03| / + u|04| / + u|05| / + u|06|/ "hbt" expired + u|07| + |08|----* sample2, restart "hb" + |09| / + |10| / + u|11|----* sample3, restart "hb" + u|12| / + u|13| / + step1_u|14| / + u|15|/ "swt" expired + u|16| + |17|----* sample4, restart "hb", create "pdp" for step1 = + |18| / = unknown due to 10 "u" labled secs > "hb" + |19| / + |20| / + |21|----* sample5, restart "hb" + |22| / + |23| / + |24|----* sample6, restart "hb" + |25| / + |26| / + |27|----* sample7, restart "hb" + step2__|28| / + |22| / + |23|----* sample8, restart "hb", create "pdp" for step1, create "cdp" + |24| / + |25| / + +graphics by I. + =head1 HOW TO MEASURE @@ -377,17 +428,17 @@ Here are a few hints on how to measure: =item Temperature -Normally you have some type of meter you can read to get the temperature. +Usually you have some type of meter you can read to get the temperature. The temperature is not really connected with a time. The only connection is that the temperature reading happened at a certain time. You can use the -B data source type for this. RRDtool will the record your reading +B data source type for this. RRDtool will then record your reading together with the time. =item Mail Messages Assume you have a method to count the number of messages transported by -your mailserver in a certain amount of time, this give you data like '5 -messages in the last 65 seconds'. If you look at the count of 5 like and +your mailserver in a certain amount of time, giving you data like '5 +messages in the last 65 seconds'. If you look at the count of 5 like an B data type you can simply update the RRD with the number 5 and the end time of your monitoring period. RRDtool will then record the number of messages per second. If at some later stage you want to know the number of @@ -398,87 +449,91 @@ precision should be acceptable. =item It's always a Rate -RRDtool stores rates in amount/second for COUNTER, DERIVE and ABSOLUTE data. -When you plot the data, you will get on the y axis amount/second which you -might be tempted to convert to absolute amount volume by multiplying by the -delta-time between the points. RRDtool plots continuous data, and as such is -not appropriate for plotting absolute volumes as for example "total bytes" -sent and received in a router. What you probably want is plot rates that you -can scale to for example bytes/hour or plot volumes with another tool that -draws bar-plots, where the delta-time is clear on the plot for each point -(such that when you read the graph you see for example GB on the y axis, -days on the x axis and one bar for each day). +RRDtool stores rates in amount/second for COUNTER, DERIVE and ABSOLUTE +data. When you plot the data, you will get on the y axis +amount/second which you might be tempted to convert to an absolute +amount by multiplying by the delta-time between the points. RRDtool +plots continuous data, and as such is not appropriate for plotting +absolute amounts as for example "total bytes" sent and received in a +router. What you probably want is plot rates that you can scale to +bytes/hour, for example, or plot absolute amounts with another tool +that draws bar-plots, where the delta-time is clear on the plot for +each point (such that when you read the graph you see for example GB +on the y axis, days on the x axis and one bar for each day). =back =head1 EXAMPLE -C + rrdtool create temperature.rrd --step 300 \ + DS:temp:GAUGE:600:-273:5000 \ + RRA:AVERAGE:0.5:1:1200 \ + RRA:MIN:0.5:12:2400 \ + RRA:MAX:0.5:12:2400 \ + RRA:AVERAGE:0.5:12:2400 This sets up an B called F which accepts one temperature value every 300 seconds. If no new data is supplied for more than 600 seconds, the temperature becomes I<*UNKNOWN*>. The -minimum acceptable value is -273 and the maximum is 5000. +minimum acceptable value is -273 and the maximum is 5'000. -A few archives areas are also defined. The first stores the -temperatures supplied for 100 hours (1200 * 300 seconds = 100 +A few archive areas are also defined. The first stores the +temperatures supplied for 100 hours (1'200 * 300 seconds = 100 hours). The second RRA stores the minimum temperature recorded over -every hour (12 * 300 seconds = 1 hour), for 100 days (2400 hours). The +every hour (12 * 300 seconds = 1 hour), for 100 days (2'400 hours). The third and the fourth RRA's do the same for the maximum and average temperature, respectively. =head1 EXAMPLE 2 -C + rrdtool create monitor.rrd --step 300 \ + DS:ifOutOctets:COUNTER:1800:0:4294967295 \ + RRA:AVERAGE:0.5:1:2016 \ + RRA:HWPREDICT:1440:0.1:0.0035:288 This example is a monitor of a router interface. The first B tracks the traffic flow in octets; the second B generates the specialized functions B for aberrant behavior detection. Note that the I -argument of HWPREDICT is missing, so the other B will be implicitly be +argument of HWPREDICT is missing, so the other B will implicitly be created with default parameter values. In this example, the forecasting algorithm baseline adapts quickly; in fact the most recent one hour of -observations (each at 5 minute intervals) account for 75% of the baseline +observations (each at 5 minute intervals) accounts for 75% of the baseline prediction. The linear trend forecast adapts much more slowly. Observations -made in during the last day (at 288 observations per day) account for only +made during the last day (at 288 observations per day) account for only 65% of the predicted linear trend. Note: these computations rely on an -exponential smoothing formula described in a forthcoming LISA 2000 paper. +exponential smoothing formula described in the LISA 2000 paper. The seasonal cycle is one day (288 data points at 300 second intervals), and the seasonal adaption parameter will be set to 0.1. The RRD file will store 5 -days (1440 data points) of forecasts and deviation predictions before wrap +days (1'440 data points) of forecasts and deviation predictions before wrap around. The file will store 1 day (a seasonal cycle) of 0-1 indicators in the FAILURES B. -The same RRD file and B are created with the following command, which explicitly -creates all specialized function B. +The same RRD file and B are created with the following command, +which explicitly creates all specialized function B. -C + rrdtool create monitor.rrd --step 300 \ + DS:ifOutOctets:COUNTER:1800:0:4294967295 \ + RRA:AVERAGE:0.5:1:2016 \ + RRA:HWPREDICT:1440:0.1:0.0035:288:3 \ + RRA:SEASONAL:288:0.1:2 \ + RRA:DEVPREDICT:1440:5 \ + RRA:DEVSEASONAL:288:0.1:2 \ + RRA:FAILURES:288:7:9:5 -Of course, explicit creation need not replicate implicit create, a number of arguments -could be changed. +Of course, explicit creation need not replicate implicit create, a +number of arguments could be changed. =head1 EXAMPLE 3 -C + rrdtool create proxy.rrd --step 300 \ + DS:Total:DERIVE:1800:0:U \ + DS:Duration:DERIVE:1800:0:U \ + DS:AvgReqDur:COMPUTE:Duration,Requests,0,EQ,1,Requests,IF,/ \ + RRA:AVERAGE:0.5:1:2016 -This example is monitoring the average request duration during each 300 sec +This example is monitoring the average request duration during each 300 sec interval for requests processed by a web proxy during the interval. In this case, the proxy exposes two counters, the number of requests processed since boot and the total cumulative duration of all processed @@ -495,4 +550,4 @@ RPN expression handles the divide by zero case. =head1 AUTHOR -Tobias Oetiker Eoetiker@ee.ethz.chE +Tobias Oetiker Etobi@oetiker.chE diff --git a/doc/rrddump.pod b/doc/rrddump.pod index de6b0ec..2e4cd4b 100644 --- a/doc/rrddump.pod +++ b/doc/rrddump.pod @@ -1,20 +1,23 @@ =head1 NAME -rrdtool dump - dump the contents of an B to XML format - -=for html
PDF version.
+rrddump - dump the contents of an RRD to XML format =head1 SYNOPSIS -B B I E I +B B I E I + +or + +B B I I =head1 DESCRIPTION -The B function prints the contents of an B in human -readable (?) XML format. This format can be read by rrdrestore. -Together they allow you to transfer your files from one architecture -to another as well as manipulating the contents of an B file in a -somewhat more convenient manner. +The B function writes the contents of an B in human +readable (?) XML format to a file or to stdout. This format can +be read by rrdrestore. Together they allow you to transfer your +files from one computer architecture to another as well to +manipulate the contents of an B file in a somewhat more +convenient manner. @@ -24,6 +27,11 @@ somewhat more convenient manner. The name of the B you want to dump. +=item I + +The (optional) filename that you want to write the XML output to. +If not specified, the XML will be printed to stdout. + =back =head1 EXAMPLES @@ -37,18 +45,18 @@ To transfer an RRD between architectures, follow these steps: On the same system where the RRD was created, use B B to export the data to XML format. -=item 2. +=item 2. -Transfer the XML dump to the target system +Transfer the XML dump to the target system. =item 3. -Run B B to create a new RRD from the XML dump. See +Run B B to create a new RRD from the XML dump. See B for details. =back =head1 AUTHOR -Tobias Oetiker Eoetiker@ee.ethz.chE +Tobias Oetiker Etobi@oetiker.chE diff --git a/doc/rrdfetch.pod b/doc/rrdfetch.pod index a4e87c5..51b5ccd 100644 --- a/doc/rrdfetch.pod +++ b/doc/rrdfetch.pod @@ -1,62 +1,60 @@ =head1 NAME -rrdtool fetch - fetch data from an RRD. - -=for html
PDF version.
+rrdfetch - Fetch data from an RRD. =head1 SYNOPSIS -B B I I -S<[B<--resolution>|B<-r> I]> -S<[B<--start>|B<-s> I]> -S<[B<--end>|B<-e> I]> +B B I I +S<[B<--resolution>|B<-r> I]> +S<[B<--start>|B<-s> I]> +S<[B<--end>|B<-e> I]> =head1 DESCRIPTION -The B function is normally used internally by the graph function, -to get data from Bs. B will analyze the B and -will try to retrieve the data in the resolution requested. +The B function is normally used internally by the graph +function to get data from Bs. B will analyze the B +and try to retrieve the data in the resolution requested. The data fetched is printed to stdout. I<*UNKNOWN*> data is often represented by the string "NaN" depending on your OS's printf function. =over 8 -=item I +=item I the name of the B you want to fetch the data from. -=item I +=item I -which consolidation function should have been applied to the data you -want to fetch? (AVERAGE,MIN,MAX,LAST) +the consolidation function that is applied to the data you +want to fetch (AVERAGE,MIN,MAX,LAST) =item B<--resolution>|B<-r> I (default is the highest resolution) -what interval should the values have (seconds per value). B will try -to match your request, but it will return data even if no absolute -match is possible. B See note below. +the interval you want the values to have (seconds per +value). B will try to match your request, but it will return +data even if no absolute match is possible. B See note below. =item B<--start>|B<-s> I (default end-1day) -when should the data begin. A time in seconds since epoch (1970-01-01) -is required. Negative numbers are relative to the current time. By default +start of the time series. A time in seconds since epoch (1970-01-01) +is required. Negative numbers are relative to the current time. By default, one day worth of data will be fetched. See also AT-STYLE TIME SPECIFICATION -section for a detailed explanation on ways to specify start time. +section for a detailed explanation on ways to specify the start time. =item B<--end>|B<-e> I (default now) -when should the data end. Time in seconds since epoch. See also -AT-STYLE TIME SPECIFICATION section for a detailed explanation of how to specify -end time. +the end of the time series in seconds since epoch. See also AT-STYLE +TIME SPECIFICATION section for a detailed explanation of how to +specify the end time. =back =head2 RESOLUTION INTERVAL -In order to get RRDtool to fetch anything other than the finest resolution RRA -B the start and end time must be specified on boundaries that are -multiples of the wanted resolution. Consider the following example: +In order to get RRDtool to fetch anything other than the finest resolution RRA +B the start and end time must be specified on boundaries that are +multiples of the desired resolution. Consider the following example: rrdtool create subdata.rrd -s 10 DS:ds0:GAUGE:300:0:U \ RRA:AVERAGE:0.5:30:3600 \ @@ -66,17 +64,19 @@ multiples of the wanted resolution. Consider the following example: RRA:AVERAGE:0.5:8640:600 \ RRA:MAX:0.5:8640:600 -This RRD collects data every 10 seconds and stores its averages over 5 minutes, -15 minutes, 1 hour and 1 day as well as the maxima for 1 hour and 1 day. +This RRD collects data every 10 seconds and stores its averages over 5 +minutes, 15 minutes, 1 hour, and 1 day, as well as the maxima for 1 hour +and 1 day. -Consider now that you want too fetch the 15 minute average data for last hour. -So you might try +Consider now that you want to fetch the 15 minute average data for the +last hour. You might try rrdtool fetch subdata.rrd AVERAGE -r 900 -s -1h -However, this will almost always result in a time series that is B in the 15 -minute RRA. Therefore the highest resolution RRA, i.e. 5 minute averages, will -be chosen which, in this case, is not what you want. +However, this will almost always result in a time series that is +B in the 15 minute RRA. Therefore, the highest resolution RRA, +i.e. 5 minute averages, will be chosen which in this case is not +what you want. Hence, make sure that @@ -88,110 +88,116 @@ both start and end time are a multiple of 900 =item 2. -both start and end time are within the wanted RRA +both start and end time are within the desired RRA =back -So, if time now is called "t", +So, if time now is called "t", do - do end time == int(t/900)*900, - start time == end time -1hour, resolution == 900. + end time == int(t/900)*900, + start time == end time - 1hour, + resolution == 900. -In e.g. bash this could look as: +Using the bash shell, this could look be: - TIME=$(date +%s); RRDRES=900; rrdtool fetch subdata.rrd AVERAGE -r $RRDRES \ - -e $(echo $(($TIME/$RRDRES*$RRDRES))) -s e-1h + TIME=$(date +%s) + RRDRES=900 + rrdtool fetch subdata.rrd AVERAGE -r $RRDRES \ + -e $(($TIME/$RRDRES*$RRDRES)) -s e-1h Or in Perl: - perl -e '$ctime = time; $rrdres = 900; system "rrdtool fetch subdata.rrd AVERAGE \ - -r $rrdres -e @{[int($ctime/$rrdres)*$rrdres]} -s e-1h"' + perl -e '$ctime = time; $rrdres = 900; \ + system "rrdtool fetch subdata.rrd AVERAGE \ + -r $rrdres -e @{[int($ctime/$rrdres)*$rrdres]} -s e-1h"' =head2 AT-STYLE TIME SPECIFICATION Apart from the traditional I, RRDtool does also -understand at-style time specification. The specification is called -"at-style" after Unix command at(1) that has moderately complex ways -to specify time to run your job at. The at-style specification -consists of two parts: B