Fawkes API  Fawkes Development Version
rrd_descriptions.cpp
00001 
00002 /***************************************************************************
00003  *  rrd_descriptions.cpp - Fawkes RRD descriptions
00004  *
00005  *  Created: Sat Dec 18 11:41:32 2010
00006  *  Copyright  2006-2011  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009 
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023 
00024 #include <plugins/rrd/aspect/rrd_descriptions.h>
00025 #include <plugins/rrd/aspect/rrd_manager.h>
00026 #include <core/exceptions/software.h>
00027 #include <core/exceptions/system.h>
00028 #include <utils/misc/string_conversions.h>
00029 
00030 #include <cstring>
00031 #include <cstdlib>
00032 #include <cstdio>
00033 #include <cfloat>
00034 
00035 namespace fawkes {
00036 #if 0 /* just to make Emacs auto-indent happy */
00037 }
00038 #endif
00039 
00040 /** @class RRDDataSource <plugins/rrd/aspect/rrd_descriptions.h>
00041  * Class to represent a RRD data source.
00042  * @author Tim Niemueller
00043  */
00044 
00045 /** Use for unknown min or max values */
00046 const float RRDDataSource::UNKNOWN = FLT_MIN;
00047 
00048 /** Constructor for regular data source.
00049  * @param name name of the data source
00050  * @param type type of the data source, may not be COMPUTE.
00051  * @param heartbeat Number of seconds after which a new value must be received
00052  * before the value is considered to be unknown.
00053  * @param min minimum value, use UNKNOWN constant if not known
00054  * @param max maximum value, use UNKNOWN constant if not known
00055  */
00056 RRDDataSource::RRDDataSource(const char *name, Type type, unsigned int heartbeat,
00057                              float min, float max)
00058   : __name(strdup(name)), __type(type), __heartbeat(heartbeat),
00059     __min(min), __max(max), __rpn_expression(NULL), __string(NULL)
00060 {
00061   if (__type == COMPUTE) {
00062     throw IllegalArgumentException("Non-compute data source ctor used with "
00063                                    "COMPUTE type for DS %s", name);
00064   }
00065 }
00066 
00067 
00068 /** Constructor for expression RRDs.
00069  * @param name name of the data source
00070  * @param rpn_expression RPN expression
00071  */
00072 RRDDataSource::RRDDataSource(const char *name, const char *rpn_expression)
00073   : __name(strdup(name)), __type(COMPUTE), __heartbeat(300), __min(UNKNOWN),
00074     __max(UNKNOWN), __rpn_expression(strdup(rpn_expression)), __string(NULL)
00075 {
00076 }
00077 
00078 /** Copy constructor.
00079  * @param other other instance to copy
00080  */
00081 RRDDataSource::RRDDataSource(const RRDDataSource &other)
00082   : __name(strdup(other.__name)), __type(other.__type),
00083     __heartbeat(other.__heartbeat),
00084     __min(other.__min), __max(other.__max),
00085     __rpn_expression(other.__rpn_expression ? strdup(other.__rpn_expression) : 0),
00086     __string(NULL)
00087 {
00088 }
00089 
00090 /** Destructor. */
00091 RRDDataSource::~RRDDataSource()
00092 {
00093   if (__string) free(__string);
00094   if (__name)  free(__name);
00095   if (__rpn_expression)  free(__rpn_expression);
00096 }
00097 
00098 /** Assignment operator.
00099  * @param other Instance to copy data from.
00100  * @return reference to this instance
00101  */
00102 RRDDataSource &
00103 RRDDataSource::operator=(const RRDDataSource &other)
00104 {
00105   if (__string) free(__string);
00106   if (__name)  free(__name);
00107   if (__rpn_expression)  free(__rpn_expression);
00108   __string = NULL;
00109   __rpn_expression = NULL;
00110   __name = strdup(other.__name);
00111   __type = other.__type;
00112   __heartbeat = other.__heartbeat;
00113   __min = other.__min;
00114   __max = other.__max;
00115   if (other.__rpn_expression)  __rpn_expression = strdup(other.__rpn_expression);
00116 
00117   return *this;
00118 }
00119 
00120 
00121 /** Get string reprensetation.
00122  * @return string representation suitable to be bassed to rrd_create().
00123  */
00124 const char *
00125 RRDDataSource::to_string() const
00126 {
00127   if (! __string) {
00128     if (__type == COMPUTE) {
00129       if (asprintf(&__string, "DS:%s:COMPUTE:%s", __name, __rpn_expression) == -1) {
00130         throw OutOfMemoryException("Failed to create DS string for %s", __name);
00131       }
00132     } else {
00133       const char *type_string;
00134       switch (__type) {
00135       case COUNTER:  type_string = "COUNTER";  break;
00136       case DERIVE:   type_string = "DERIVE";   break;
00137       case ABSOLUTE: type_string = "ABSOLUTE"; break;
00138       default:       type_string = "GAUGE";    break;
00139       }
00140       char min_s[32];
00141       char max_s[32];
00142       if (__min == UNKNOWN) {
00143         strcpy(min_s, "U");
00144       } else {
00145         snprintf(min_s, 32, "%f", __min);
00146       }
00147       if (__max == UNKNOWN) {
00148         strcpy(max_s, "U");
00149       } else {
00150         snprintf(max_s, 32, "%f", __max);
00151       }
00152       if (asprintf(&__string, "DS:%s:%s:%u:%s:%s", __name, type_string,
00153                    __heartbeat, min_s, max_s) == -1) {
00154         throw OutOfMemoryException("Failed to create DS string for %s", __name);
00155       }
00156     }
00157   }
00158 
00159   return __string;
00160 }
00161 
00162 
00163 /** @class RRDArchive <plugins/rrd/aspect/rrd_descriptions.h>
00164  * RRD Archive description.
00165  * @author Tim Niemueller
00166  */
00167 
00168 /** Constructor.
00169  * @param cf consolidation function
00170  * @param xff The xfiles factor defines what part of a consolidation interval
00171  * may be made up from *UNKNOWN* data while the consolidated value is still
00172  * regarded as known. It is given as the ratio of allowed *UNKNOWN* PDPs to
00173  * the number of PDPs in the interval. Thus, it ranges from 0 to 1 (exclusive).
00174  * @param steps defines how many of these primary data points are used to build
00175  * a consolidated data point which then goes into the archive.
00176  * @param rows defines how many generations of data values are kept in an RRA.
00177  * Obviously, this has to be greater than zero.
00178  */
00179 RRDArchive::RRDArchive(ConsolidationFunction cf, float xff,
00180                        unsigned int steps, unsigned int rows)
00181   : __cf(cf), __xff(xff), __steps(steps), __rows(rows), __string(NULL)
00182 {
00183 }
00184 
00185 
00186 /** Copy constructor.
00187  * @param rra instance to copy
00188  */
00189 RRDArchive::RRDArchive(const RRDArchive &rra)
00190   : __cf(rra.__cf), __xff(rra.__xff), __steps(rra.__steps), __rows(rra.__rows),
00191     __string(NULL)
00192 {
00193 }
00194 
00195 
00196 /** Destructor. */
00197 RRDArchive::~RRDArchive()
00198 {
00199   if (__string) free(__string);
00200 }
00201 
00202 /** Assignment operator.
00203  * @param rra instance to copy from
00204  * @return reference to this instance
00205  */
00206 RRDArchive &
00207 RRDArchive::operator=(const RRDArchive &rra)
00208 {
00209   if (__string) free(__string);
00210   __string = NULL;
00211   __cf     = rra.__cf;
00212   __xff    = rra.__xff;
00213   __steps  = rra.__steps;
00214   __rows   = rra.__rows;
00215   return *this;
00216 }
00217 
00218 /** Get string representation.
00219  * @return string representation suitable to be passed to rrd_create().
00220  */
00221 const char *
00222 RRDArchive::to_string() const
00223 {
00224   if (! __string) {
00225     const char *cf_string;
00226     switch (__cf) {
00227     case MIN:  cf_string = "MIN";  break;
00228     case MAX:  cf_string = "MAX";   break;
00229     case LAST: cf_string = "LAST"; break;
00230     default:   cf_string = "AVERAGE";    break;
00231     }
00232     if (asprintf(&__string, "RRA:%s:%f:%u:%u", cf_string,
00233                  __xff, __steps, __rows) == -1) {
00234       throw OutOfMemoryException("Failed to create RRA string");
00235     }
00236   }
00237 
00238   return __string;
00239 }
00240 
00241 /** Convert consolidation function type to string.
00242  * @param cf consolidation function type
00243  * @return string representation of @p cf, suitable for RRA lines.
00244  */
00245 const char *
00246 RRDArchive::cf_to_string(ConsolidationFunction cf)
00247 {
00248   switch (cf) {
00249   case RRDArchive::MIN:  return "MIN";     break;
00250   case RRDArchive::MAX:  return "MAX";     break;
00251   case RRDArchive::LAST: return "LAST";    break;
00252   default:               return "AVERAGE"; break;
00253   }
00254 }
00255 
00256 /** @class RRDDefinition <plugins/rrd/aspect/rrd_descriptions.h>
00257  * RRD Definition.
00258  * This class describes everything required to create an RRD file.
00259  * It does not represent all the options rrdtool provides, but a reasonable
00260  * subset.
00261  * @author Tim Niemueller
00262  */
00263 
00264 /** Constructor with default RRAs.
00265  * This creates the RRD definition with the default RRAs produced by
00266  * get_default_rra().
00267  * @param name RRD name
00268  * @param ds data sources
00269  * @param step_sec Specifies the base interval in seconds with which data
00270  * will be fed into the RRD.
00271  * @param recreate if true existing RRD files will be overwritten, otherwise
00272  * data is appended.
00273  */
00274 RRDDefinition::RRDDefinition(const char *name, std::vector<RRDDataSource> &ds,
00275                              unsigned int step_sec, bool recreate)
00276   : __name(strdup(name)), __step_sec(step_sec), __recreate(recreate),
00277     __ds(ds), __rra(get_default_rra()), __filename(NULL), __rrd_manager(NULL)
00278 {
00279 }
00280 
00281 /** Constructor.
00282  * @param name RRD name
00283  * @param ds data sources
00284  * @param rra RRAs for this RRD.
00285  * @param step_sec Specifies the base interval in seconds with which data
00286  * will be fed into the RRD.
00287  * @param recreate if true existing RRD files will be overwritten, otherwise
00288  * data is appended.
00289  */
00290 RRDDefinition::RRDDefinition(const char *name,
00291                              std::vector<RRDDataSource> &ds,
00292                              std::vector<RRDArchive> &rra,
00293                              unsigned int step_sec, bool recreate)
00294   : __name(strdup(name)), __step_sec(step_sec), __recreate(recreate), __ds(ds),
00295     __rra(rra), __filename(NULL), __rrd_manager(NULL)
00296 {
00297 }
00298 
00299 
00300 /** Copy constructor.
00301  * @param other instance to clone
00302  */
00303 RRDDefinition::RRDDefinition(const RRDDefinition &other)
00304   : __name(strdup(other.__name)), __step_sec(other.__step_sec),
00305     __recreate(other.__recreate), __ds(other.__ds), __rra(other.__rra),
00306     __filename(other.__filename ? strdup(other.__filename) : 0),
00307     __rrd_manager(NULL)
00308 {
00309 }
00310 
00311 /** Assignment operator.
00312  * @param other other instance to copy from
00313  * @return reference to this instance.
00314  */
00315 RRDDefinition &
00316 RRDDefinition::operator=(const RRDDefinition &other)
00317 {
00318   if (__name)  free(__name);
00319   if (__filename) free(__filename);
00320   if (__rrd_manager)  __rrd_manager->remove_rrd(this);
00321   __filename    = NULL;
00322   __rrd_manager = NULL;
00323   __name        = strdup(other.__name);
00324   __step_sec    = other.__step_sec;
00325   __recreate    = other.__recreate;
00326   __ds          = other.__ds;
00327   __rra         = other.__rra;
00328   if (other.__filename) __filename=strdup(other.__filename);
00329   return *this;
00330 }
00331 
00332 /** Destructor. */
00333 RRDDefinition::~RRDDefinition()
00334 {
00335   if (__rrd_manager)  __rrd_manager->remove_rrd(this);
00336 
00337   if (__name)  free(__name);
00338   if (__filename)  free(__filename);
00339 }
00340 
00341 /** Get default RRAs. They correspond to the following and assume a
00342  * 10 second step size.
00343  * @code
00344  * "RRA:AVERAGE:0.5:1:720"    #  2 hours of 10 sec  averages
00345  * "RRA:AVERAGE:0.5:3:1680"   # 12 hours of 30 sec  averages
00346  * "RRA:AVERAGE:0.5:30:456"   #  1 day   of  5 min  averages
00347  * "RRA:AVERAGE:0.5:180:412"  #  7 days  of 30 min  averages
00348  * "RRA:AVERAGE:0.5:720:439"  #  4 weeks of  2 hour averages
00349  * "RRA:AVERAGE:0.5:8640:402" #  1 year  of  1 day averages
00350  * "RRA:MIN:0.5:1:720"
00351  * "RRA:MIN:0.5:3:1680"
00352  * "RRA:MIN:0.5:30:456"
00353  * "RRA:MIN:0.5:180:412"
00354  * "RRA:MIN:0.5:720:439"
00355  * "RRA:MIN:0.5:8640:402"
00356  * "RRA:MAX:0.5:1:720"
00357  * "RRA:MAX:0.5:3:1680"
00358  * "RRA:MAX:0.5:30:456"
00359  * "RRA:MAX:0.5:180:412"
00360  * "RRA:MAX:0.5:720:439"
00361  * "RRA:MAX:0.5:8640:402"
00362  * @endcode
00363  * @return vector of RRDArchive representing the described RRAs.
00364  */
00365 const std::vector<RRDArchive>
00366 RRDDefinition::get_default_rra()
00367 {
00368   std::vector<RRDArchive> rv;
00369   rv.push_back(RRDArchive(RRDArchive::AVERAGE, 0.5,    1,  720));
00370   rv.push_back(RRDArchive(RRDArchive::AVERAGE, 0.5,    3, 1680));
00371   rv.push_back(RRDArchive(RRDArchive::AVERAGE, 0.5,   30,  456));
00372   rv.push_back(RRDArchive(RRDArchive::AVERAGE, 0.5,  180,  412));
00373   rv.push_back(RRDArchive(RRDArchive::AVERAGE, 0.5,  720,  439));
00374   rv.push_back(RRDArchive(RRDArchive::AVERAGE, 0.5, 8640,  402));
00375   rv.push_back(RRDArchive(RRDArchive::MIN,     0.5,    1,  720));
00376   rv.push_back(RRDArchive(RRDArchive::MIN,     0.5,    3, 1680));
00377   rv.push_back(RRDArchive(RRDArchive::MIN,     0.5,   30,  456));
00378   rv.push_back(RRDArchive(RRDArchive::MIN,     0.5,  180,  412));
00379   rv.push_back(RRDArchive(RRDArchive::MIN,     0.5,  720,  439));
00380   rv.push_back(RRDArchive(RRDArchive::MIN,     0.5, 8640,  402));
00381   rv.push_back(RRDArchive(RRDArchive::MAX,     0.5,    1,  720));
00382   rv.push_back(RRDArchive(RRDArchive::MAX,     0.5,    3, 1680));
00383   rv.push_back(RRDArchive(RRDArchive::MAX,     0.5,   30,  456));
00384   rv.push_back(RRDArchive(RRDArchive::MAX,     0.5,  180,  412));
00385   rv.push_back(RRDArchive(RRDArchive::MAX,     0.5,  720,  439));
00386   rv.push_back(RRDArchive(RRDArchive::MAX,     0.5, 8640,  402));
00387   return rv;
00388 }
00389 
00390 
00391 /** Find data source index.
00392  * @param ds_name name of the data source
00393  * @return index of found data source
00394  * @exception Exception thrown if the data source could not be found
00395  */
00396 size_t
00397 RRDDefinition::find_ds_index(const char *ds_name) const
00398 {
00399   for (size_t i = 0; i < __ds.size(); ++i) {
00400     if (strcmp(__ds[i].get_name(), ds_name) == 0) return i;
00401   }
00402 
00403   throw Exception("Data source name %s not found", ds_name);
00404 }
00405 
00406 /** Set filename.
00407  * This can be done only once. Do not do this manually, rather let the RRDManager
00408  * handle this!
00409  * @param filename new filename, should be absolute, otherwise considered
00410  * relative to current working directory.
00411  */
00412 void
00413 RRDDefinition::set_filename(const char *filename)
00414 {
00415   if (__filename) {
00416     throw Exception("Graph definition %s: filename has already been set!", __name);
00417   }
00418   __filename = strdup(filename);
00419 }
00420 
00421 
00422 /** Set RRD manager.
00423  * This can be done only once. Do not do this manually, rather let the RRDManager
00424  * handle this! The RRD manager is used to unregister this RRD if it is deleted.
00425  * This is a precaution to avoid dangling RRDs.
00426  * @param rrd_manager RRD manager to use
00427  */
00428 void
00429 RRDDefinition::set_rrd_manager(RRDManager *rrd_manager)
00430 {
00431   if (__rrd_manager) {
00432     throw Exception("RRD definition %s: RRD manager has already been set", __name);
00433   }
00434   __rrd_manager = rrd_manager;
00435 }
00436 
00437 
00438 
00439 /** @class RRDGraphDataDefinition <plugins/rrd/aspect/rrd_descriptions.h>
00440  * Represent data definition in graph arguments.
00441  * @author Tim Niemueller
00442  * Currently supports only DEF and CDEF definitions.
00443  */
00444 
00445 /** DEF constructor.
00446  * @param name name of the graph data source
00447  * @param cf consolidation function to apply if needed
00448  * @param rrd_def RRD definition to use
00449  * @param ds_name data source name in RRD, @p rrd_def will be queried for the
00450  * data source. If ds_name is NULL, @p name will be used as the data source name.
00451  */
00452 RRDGraphDataDefinition::RRDGraphDataDefinition(const char *name,
00453                                                RRDArchive::ConsolidationFunction cf,
00454                                                const RRDDefinition *rrd_def,
00455                                                const char *ds_name)
00456   : __name(strdup(name)), __rrd_def(rrd_def),
00457     __ds_name(ds_name ? strdup(ds_name) : strdup(name)),
00458     __rpn_expression(NULL), __cf(cf), __string(NULL)
00459 {
00460 }
00461 
00462 
00463 /** CDEF constructor.
00464  * @param name name of the graph data source
00465  * @param rpn_expression RPN expression
00466  */
00467 RRDGraphDataDefinition::RRDGraphDataDefinition(const char *name,
00468                                                const char *rpn_expression)
00469   : __name(strdup(name)), __rrd_def(0), __ds_name(NULL),
00470     __rpn_expression(strdup(rpn_expression)),
00471     __cf(RRDArchive::AVERAGE), __string(NULL)
00472 {
00473 }
00474 
00475 
00476 /** Copy constructor.
00477  * @param other instance to clone
00478  */
00479 RRDGraphDataDefinition::RRDGraphDataDefinition(const RRDGraphDataDefinition &other)
00480   : __name(strdup(other.__name)), __rrd_def(other.__rrd_def),
00481     __ds_name(other.__ds_name ? strdup(other.__ds_name) : NULL),
00482     __rpn_expression(other.__rpn_expression ? strdup(other.__rpn_expression) : 0),
00483     __cf(other.__cf), __string(NULL)
00484 {
00485 }
00486 
00487 
00488 /** Destructor. */
00489 RRDGraphDataDefinition::~RRDGraphDataDefinition()
00490 {
00491   if (__name)  free(__name);
00492   if (__ds_name)  free(__ds_name);
00493   if (__rpn_expression)  free(__rpn_expression);
00494   if (__string)   free(__string);
00495 }
00496 
00497 /** Assignment operator.
00498  * @param other instance to copy from
00499  * @return reference to this instance
00500  */
00501 RRDGraphDataDefinition &
00502 RRDGraphDataDefinition::operator=(const RRDGraphDataDefinition &other)
00503 {
00504   if (__string)  free(__string);
00505   if (__ds_name) free(__ds_name);
00506   if (__name)  free(__name);
00507   if (__rpn_expression) free(__rpn_expression);
00508 
00509   __string         = NULL;
00510   __rpn_expression = NULL;
00511   __name           = strdup(other.__name);
00512   __rrd_def        = other.__rrd_def;
00513   if (other.__ds_name)  __ds_name = strdup(other.__ds_name);
00514   if (other.__rpn_expression)  __rpn_expression = other.__rpn_expression;
00515   __cf             = other.__cf;
00516 
00517   return *this;
00518 }
00519 
00520 
00521 /** Create string representation.
00522  * @return string representation suitable for rrd_graph_v().
00523  */
00524 const char *
00525 RRDGraphDataDefinition::to_string() const
00526 {
00527   if (! __string) {
00528     if (__rpn_expression) {
00529       if (asprintf(&__string, "CDEF:%s=%s", __name, __rpn_expression) == -1) {
00530         throw OutOfMemoryException("Failed to create RRA string");
00531       }
00532     } else {
00533       size_t ds_index = __rrd_def->find_ds_index(__ds_name);
00534 
00535       if (asprintf(&__string, "DEF:%s=%s:%s:%s", __name, __rrd_def->get_filename(),
00536                    __rrd_def->get_ds(ds_index).get_name(),
00537                    RRDArchive::cf_to_string(__cf)) == -1) {
00538         throw OutOfMemoryException("Failed to create RRA string");
00539       }
00540     }
00541   }
00542 
00543   return __string;
00544 }
00545 
00546 /** @class RRDGraphElement <plugins/rrd/aspect/rrd_descriptions.h>
00547  * Interface for graph elements.
00548  * This super class provides the general interface for the different
00549  * existing graph elements.
00550  * @author Tim Niemueller
00551  *
00552  * @fn RRDGraphElement * RRDGraphElement::clone() const
00553  * Clone this element.
00554  * The clone function is needed to copy an object without knowing its type and
00555  * therefore without calling its copy constructor.
00556  * @return new copied instance
00557  */
00558 
00559 /** Create string representation.
00560  * @return string suitable for rrd_graph_v().
00561  */
00562 const char *
00563 RRDGraphElement::to_string() const
00564 {
00565   throw NotImplementedException("Invalid graph element");
00566 }
00567 
00568 
00569 
00570 /** @class RRDGraphGPrint <plugins/rrd/aspect/rrd_descriptions.h>
00571  * Print string inside graph.
00572  * @author Tim Niemueller
00573  */
00574 
00575 /** Constructor.
00576  * @param def_name Data definition for this graph element.
00577  * @param cf consolidation function to use
00578  * @param format Format string, cf. man rrdgraph_graph(1).
00579  */
00580 RRDGraphGPrint::RRDGraphGPrint(const char *def_name,
00581                                RRDArchive::ConsolidationFunction cf,
00582                                const char *format)
00583   : __def_name(strdup(def_name)), __cf(cf), __format(strdup(format)),
00584     __string(NULL)
00585 {
00586 }
00587 
00588 /** Copy constructor.
00589  * @param other instance to copy
00590  */
00591 RRDGraphGPrint::RRDGraphGPrint(const RRDGraphGPrint &other)
00592   : __def_name(strdup(other.__def_name)), __cf(other.__cf),
00593     __format(strdup(other.__format)), __string(NULL)
00594 {
00595 }
00596 
00597 
00598 /** Destructor. */
00599 RRDGraphGPrint::~RRDGraphGPrint()
00600 {
00601   if (__def_name)  free(__def_name);
00602   if (__format) free(__format);
00603   if (__string) free(__string);
00604 }
00605 
00606 /** Assignment operator.
00607  * @param g matching graph element to assign
00608  * @return reference to this instance
00609  */
00610 RRDGraphGPrint &
00611 RRDGraphGPrint::operator=(const RRDGraphGPrint &g)
00612 {
00613   if (__def_name)  free(__def_name);
00614   if (__format) free(__format);
00615   if (__string) free(__string);
00616 
00617   __string   = NULL;
00618   __def_name = strdup(g.__def_name);
00619   __cf       = g.__cf;
00620   __format   = strdup(g.__format);
00621 
00622   return *this;
00623 }
00624 
00625 
00626 const char *
00627 RRDGraphGPrint::to_string() const
00628 {
00629   if (! __string) {
00630     if (asprintf(&__string, "GPRINT:%s:%s:%s", __def_name,
00631                  RRDArchive::cf_to_string(__cf), __format) == -1) {
00632       throw OutOfMemoryException("Failed to create RRD graph GPRINT string");
00633     }
00634   }
00635 
00636   return __string;
00637 }
00638 
00639 
00640 /** @class RRDGraphLine <plugins/rrd/aspect/rrd_descriptions.h>
00641  * Print graph line.
00642  * @author Tim Niemueller
00643  */
00644 
00645 /** Constructor.
00646  * @param def_name Data definition for this graph element.
00647  * @param width line width
00648  * @param color color hash string (HTML style, e.g. FF0000)
00649  * @param legend legend string
00650  * @param stacked true to stack on previous graph element
00651  */
00652 RRDGraphLine::RRDGraphLine(const char *def_name, float width, const char *color,
00653                            const char *legend, bool stacked)
00654   : __def_name(strdup(def_name)), __width(width), __color(strdup(color)),
00655     __legend(strdup(legend)), __stacked(stacked), __string(NULL)
00656 {
00657 }
00658 
00659 /** Copy ctor.
00660  * @param other instance to copy
00661  */
00662 RRDGraphLine::RRDGraphLine(const RRDGraphLine &other)
00663   : __def_name(strdup(other.__def_name)), __width(other.__width),
00664     __color(strdup(other.__color)),
00665     __legend(strdup(other.__legend)), __stacked(other.__stacked), __string(NULL)
00666 {
00667 }
00668 
00669 
00670 /** Destructor. */
00671 RRDGraphLine::~RRDGraphLine()
00672 {
00673   if (__def_name)  free(__def_name);
00674   if (__color)  free(__color);
00675   if (__legend)  free(__legend);
00676   if (__string) free(__string);
00677 }
00678 
00679 
00680 /** Assignment operator.
00681  * @param g matching graph element to assign
00682  * @return reference to this instance
00683  */
00684 RRDGraphLine &
00685 RRDGraphLine::operator=(const RRDGraphLine &g)
00686 {
00687   if (__def_name)  free(__def_name);
00688   if (__color)  free(__color);
00689   if (__legend)  free(__legend);
00690   if (__string) free(__string);
00691 
00692   __string   = NULL;
00693   __def_name = strdup(g.__def_name);
00694   __width    = g.__width;
00695   __color    = strdup(g.__color);
00696   __legend   = strdup(g.__legend);
00697   __stacked  = g.__stacked;
00698 
00699   return *this;
00700 }
00701 
00702 
00703 const char *
00704 RRDGraphLine::to_string() const
00705 {
00706   if (! __string) {
00707     if (asprintf(&__string, "LINE%f:%s#%s:%s%s", __width, __def_name, __color,
00708                  __legend, __stacked ? ":STACK" : "") == -1) {
00709       throw OutOfMemoryException("Failed to create RRD graph LINE string");
00710     }
00711   }
00712 
00713   return __string;
00714 }
00715 
00716 
00717 /** @class RRDGraphArea <plugins/rrd/aspect/rrd_descriptions.h>
00718  * Print graph area.
00719  * @author Tim Niemueller
00720  */
00721 
00722 /** Constructor.
00723  * @param def_name Data definition for this graph element.
00724  * @param color color hash string (HTML style, e.g. FF0000)
00725  * @param legend legend string
00726  * @param stacked true to stack on previous graph element
00727  */
00728 RRDGraphArea::RRDGraphArea(const char *def_name,const char *color,
00729                            const char *legend, bool stacked)
00730   : __def_name(strdup(def_name)), __color(strdup(color)),
00731     __legend(strdup(legend)), __stacked(stacked), __string(NULL)
00732 {
00733 }
00734 
00735 
00736 /** Copy ctor.
00737  * @param other instance to copy
00738  */
00739 RRDGraphArea::RRDGraphArea(const RRDGraphArea &other)
00740   : __def_name(strdup(other.__def_name)), __color(strdup(other.__color)),
00741     __legend(strdup(other.__legend)), __stacked(other.__stacked), __string(NULL)
00742 {
00743 }
00744 
00745 
00746 /** Destructor. */
00747 RRDGraphArea::~RRDGraphArea()
00748 {
00749   if (__def_name)  free(__def_name);
00750   if (__color)  free(__color);
00751   if (__legend)  free(__legend);
00752   if (__string) free(__string);
00753 }
00754 
00755 
00756 /** Assignment operator.
00757  * @param g matching graph element to assign
00758  * @return reference to this instance
00759  */
00760 RRDGraphArea &
00761 RRDGraphArea::operator=(const RRDGraphArea &g)
00762 {
00763   if (__def_name)  free(__def_name);
00764   if (__color)  free(__color);
00765   if (__legend)  free(__legend);
00766   if (__string) free(__string);
00767 
00768   __string   = NULL;
00769   __def_name = strdup(g.__def_name);
00770   __color    = strdup(g.__color);
00771   __legend   = strdup(g.__legend);
00772   __stacked  = g.__stacked;
00773 
00774   return *this;
00775 }
00776 
00777 
00778 const char *
00779 RRDGraphArea::to_string() const
00780 {
00781   if (! __string) {
00782     if (asprintf(&__string, "AREA:%s#%s:%s%s", __def_name, __color, __legend,
00783                  __stacked ? ":STACK" : "") == -1) {
00784       throw OutOfMemoryException("Failed to create RRD graph AREA string");
00785     }
00786   }
00787 
00788   return __string;
00789 }
00790 
00791 
00792 /** @class RRDGraphDefinition <plugins/rrd/aspect/rrd_descriptions.h>
00793  * Class representing a graph definition.
00794  * This graph definition is used to generate all required parameters to create
00795  * a graph from an RRD.
00796  * @author Tim Niemueller
00797  */
00798 
00799 /** Constructor.
00800  * @param name name of this graph definition, used internally, name must be
00801  * unique among all registered graphs.
00802  * @param rrd_def pointer to definition of the RRD to graph
00803  * @param start time from where to start graphing. Maybe an absolute time or
00804  * a negative number for relative times, e.g. "-300" for 5 minutes back from now.
00805  * @param end time where to end graphing. Maybe an absolute time or a negative
00806  * number for relative times, e.g. "-300" for 5 minutes back from now.
00807  * @param step step size in seconds
00808  * @param title Graph title to print on top of graph
00809  * @param vertical_label string printed rotated by 90° counter-clockwise besides
00810  * the vertical axis. Usually should carry description of the Y axis units.
00811  * @param update_interval The interval at which the graph should be generated.
00812  * @param slope_mode true to enable slope mode when graphing
00813  * @param def data definitions for the graph
00814  * @param elements elements to print in the graph. This graph definition takes
00815  * ownership of the graph elemenets and will delete them in its dtor.
00816  */
00817 RRDGraphDefinition::RRDGraphDefinition(const char *name, RRDDefinition *rrd_def,
00818                                        const char *title,
00819                                        const char *vertical_label,
00820                                        std::vector<RRDGraphDataDefinition> &def,
00821                                        std::vector<RRDGraphElement *> &elements,
00822                                        time_t start, time_t end, unsigned int step,
00823                                        unsigned int update_interval,
00824                                        bool slope_mode)
00825   : __name(strdup(name)), __rrd_def(rrd_def),
00826     __start(start), __end(end), __step(step),
00827     __title(strdup(title)), __vertical_label(strdup(vertical_label)),
00828     __update_interval(update_interval), __slope_mode(slope_mode),
00829     __defs(def), __elements(elements)
00830 {
00831   __filename = NULL;
00832   __argv = NULL;
00833   __argc = 0;
00834   __fonts.push_back("LEGEND:10:");
00835   __fonts.push_back("UNIT:8:");
00836   __fonts.push_back("TITLE:12:");
00837   __fonts.push_back("AXIS:8:");
00838   __width = 560;
00839   __width_s = strdup(StringConversions::to_string(__width).c_str());
00840   __start_s = strdup(StringConversions::to_string(__start).c_str());
00841   __end_s   = strdup(StringConversions::to_string(__end).c_str());
00842   __step_s  = strdup(StringConversions::to_string(__step).c_str());
00843 }
00844 
00845 /** Copy constructor.
00846  * @param other instance to copy
00847  */
00848 RRDGraphDefinition::RRDGraphDefinition(const RRDGraphDefinition &other)
00849   : __name(strdup(other.__name)), __rrd_def(other.__rrd_def),
00850     __start(other.__start), __end(other.__end), __step(other.__step),
00851     __title(strdup(other.__title)),
00852     __vertical_label(strdup(other.__vertical_label)),
00853     __update_interval(other.__update_interval),
00854     __slope_mode(other.__slope_mode), __defs(other.__defs),
00855     __width(other.__width), __fonts(other.__fonts),
00856     __filename(strdup(other.__filename))
00857 {
00858   std::vector<RRDGraphElement *>::const_iterator i;
00859   for (i = other.__elements.begin(); i != other.__elements.end(); ++i) {
00860     __elements.push_back((*i)->clone());
00861   }
00862 
00863   __argv = NULL;
00864   __argc = 0;
00865   __width_s = strdup(StringConversions::to_string(__width).c_str());
00866   __start_s = strdup(StringConversions::to_string(__start).c_str());
00867   __end_s   = strdup(StringConversions::to_string(__end).c_str());
00868   __step_s  = strdup(StringConversions::to_string(__step).c_str());
00869 }
00870 
00871 
00872 /** Destructor. */
00873 RRDGraphDefinition::~RRDGraphDefinition()
00874 {
00875   if (__filename) free(__filename);
00876   if (__argv)  free(__argv);
00877   if (__name)  free(__name);
00878   if (__title)  free(__title);
00879   if (__vertical_label)  free(__vertical_label);
00880 
00881   free(__width_s);
00882   free(__start_s);
00883   free(__end_s);
00884   free(__step_s);
00885 
00886   std::vector<RRDGraphElement *>::iterator i;
00887   for (i = __elements.begin(); i != __elements.end(); ++i) {
00888     delete *i;
00889   }
00890 }
00891 
00892 /** Set filename.
00893  * This can be done only once. Do not do this manually, rather let the RRDManager
00894  * handle this!
00895  * @param filename new filename, should be absolute, otherwise considered
00896  * relative to current working directory.
00897  */
00898 void
00899 RRDGraphDefinition::set_filename(const char *filename)
00900 {
00901   if (__filename) {
00902     throw Exception("Graph definition for RRD %s: filename has already been set!",
00903                     __rrd_def->get_name());
00904   }
00905   __filename = strdup(filename);
00906 }
00907 
00908 /** Get argument array and size.
00909  * @param argc upon completion contains the number of arguments in the
00910  * return value.
00911  * @return argument array suitable for rrd_create_v().
00912  */
00913 const char **
00914 RRDGraphDefinition::get_argv(size_t &argc) const
00915 {
00916   if (__argv == NULL) {
00917     // "graph" filename --disable-rrdtool-tag --width ... --start ... --end ...
00918     // [fonts] --title ... --vertical-label ... [--slope-mode] DEFS... ELEMS...
00919     __argc = 16 + __fonts.size() * 2 + __defs.size() + __elements.size();
00920     __argv = (const char **)malloc(__argc * sizeof(char *));
00921     size_t i = 0;
00922     __argv[i++] = "graph";
00923     __argv[i++] = __filename;
00924     __argv[i++] = "--disable-rrdtool-tag";
00925     __argv[i++] = "--width";
00926     __argv[i++] = __width_s;
00927     __argv[i++] = "--start";
00928     __argv[i++] = __start_s;
00929     __argv[i++] = "--end";
00930     __argv[i++] = __end_s;
00931     __argv[i++] = "--step";
00932     __argv[i++] = __step_s;
00933     __argv[i++] = "--title";
00934     __argv[i++] = __title;
00935     __argv[i++] = "--vertical-label";
00936 
00937     if (strcmp(__vertical_label, "") == 0) {
00938       __argv[i++] = " ";
00939     } else {
00940       __argv[i++] = __vertical_label;
00941     }
00942 
00943     if (__slope_mode) __argv[i++] = "--slope-mode";
00944 
00945     std::vector<const char *>::const_iterator f;
00946     for (f = __fonts.begin(); f != __fonts.end(); ++f) {
00947       __argv[i++] = "--font";
00948       __argv[i++] = *f;
00949     }
00950 
00951     std::vector<RRDGraphDataDefinition>::const_iterator d;
00952     for (d = __defs.begin(); d != __defs.end(); ++d) {
00953       __argv[i++] = d->to_string();
00954     }
00955 
00956     std::vector<RRDGraphElement *>::const_iterator e;
00957     for (e = __elements.begin(); e != __elements.end(); ++e) {
00958       __argv[i++] = (*e)->to_string();
00959     }
00960 
00961     __argc = i;
00962   }
00963 
00964   argc = __argc;
00965   return __argv;
00966 }
00967 
00968 
00969 } // end namespace fawkes