Click here to Skip to main content
15,896,606 members
Articles / Programming Languages / C#

"C# Hooks For RRDtool"

Rate me:
Please Sign up or sign in to vote.
4.79/5 (26 votes)
26 May 2010GPL35 min read 240.5K   3.1K   37  
C# (.NET and Mono) library provider for RRDtool
/* 
Copyright (C) 2008 Michael Corley  
All rights reserved.

Copyright (c) 1997-2008 Tobias Oetiker
All rights reserved.

                                            
NHAWK GPL License Info.
======================

This file is part of the NHAWK project.
NHAWK 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 3 of the License, or                    
(at your option) any later version.                                                  
                                                                                         
NHAWK 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 NHAWK; if not, write to the Free Software Foundation, Inc.,               
59 Temple Place - Suite 330, Boston, MA  02111-1307, USA  
                           
                                                                                        
RRDTool GPL License Info.
========================

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 this RRDTool; 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/2.1
*/

///////////////////////////////////////////////////////////////////////////////////////////////////////////
//File       : DS.cs   --  C# abstraction for RRDTool DS (Data Source) construct                         //
//Application: NHawk: Open Source Project Support                                                        // 
//Language   : C# .Net 3.5, Visual Studio 2008                                                           //
//Author     : Mike Corley, Syracuse University                                                          //
//             mwcorley@syr.edu                                                                          //
///////////////////////////////////////////////////////////////////////////////////////////////////////////

/* Module Operations
 * =================
 * This module provides a C# .Net interface to the RRDTool DS (Data Source) component of the RRDTool database 
 * structure.  This class seeks to encapsulate the DS semantics in the C# .Net object model, while retaining
 * intuitive structure of RRDTool syntax. The DS class is equipt with appropriate exception (error) handling 
 * for enforces both .Net code correctness and semantically use related RRDTool constructs. The goal of the 
 * NHawk project is to provide the RRDTool facility (natively) in the .Net paradigm while promoting loose coupling
 * between the two paradigms and preserving RRDTool syntax and semantics.  This help enable .Net developers to rapidy 
 * gain development productivity, in that usability (for the more part) be infered intuitively for the RRDTool doc.
 * Note: the manual page described herein while NOT seek to explain, disclose, or exemplify the
 * RRDTool construct semantics and typical usage scenarios.  That is done quite well by the RRDTool author 
 * (Tobi Oetiker), and his supporters.  The goal of the NHawk project is to allow .Net / Mono (C#) developers 
 * to leverage RRDTool natively from .Net by refering (intuitively) directly to the RRDTool main doc. page:
 * http://oss.oetiker.ch/rrdtool/doc/rrdcreate.en.html.
 * 
 * We will however, provide as many examples, and tutorials as time allows, and depending on the success of the 
 * project, we hope a large user base will contribute to ehancements, tutorials, and general support.  We feel 
 * the HNawk is gret way to benefit .Net and Mono FCL (which currently lacks support for time series visualization), 
 * and RRDTool by unleasing its potential by integrating it with the abundance and power of the .Net FCL. 
 * 
 * 
 * Public Interface
 * ================
 * 
 * public DS(string n, TYPE t)
 *    -- constructs a basic data source (DS) entity, accepts name, and TYPE (GAUGE, COUNTER, DERIVE, etc.)
 *       sets default heartbeat=600 secs., min=Unknown, max=Unknown
 *    
 * public DS(string name, TYPE t, long heart_beat, double min, double max)
 *    -- constructs a fully defined data source (DS) entity
 *    
 * public DS(string data_source)
 *    -- constructs a fully defined data source (DS) entity from a serialized DS string
 *       note: if data_source cannot be deserialzed a DSFormatException() is thrown
 * 
 * public TYPE type
 *    -- gets or sets the type of the data source: GAUGE, COUNTER, DERIVE, ABSOLUTE 
 *    
 * public static double U        
 *    -- gets Unknown limit specifier (for min and max values of an DS)
 *    
 * public double heartbeat
 *    -- gets or sets the heartbeat... 
 *     *** heartbeat defines the maximum number of seconds that may pass between 
 *         updates of this data source before the value of the data source is assumed to be *UNKNOWN* 
 *         Source document: http://oss.oetiker.ch/rrdtool/doc/rrdcreate.en.html 
 * 
 * public double min       
 *    -- gets or sets the min range value
 *    *** min and max define the expected range values for data supplied by a data source. 
 *        If min and/or max any value outside the defined range will be regarded as *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. 
 *        Source document: http://oss.oetiker.ch/rrdtool/doc/rrdcreate.en.html 
 * 
 * public double max
 *    -- gets or sets the max range value (see discussion for min)
 *        
 * Example Usage
 * =============
 * See Test stub below
 * 
 * Build Process
 * ============= 
 * This module can be compiled stand alone for testing purposes: 
 * Note: some modules have additional assembly dependencies which
 * are needed for compilation of the test stub.  The required files section
 * shows true dependency structure. i.e when the test stub is not compiled.
 *
 * Compiler Command:
 * Visual Studio 2008 (.Net 3.5): csc  /define:TEST_DS  DS.cs 
 * Win32 Mono (1.9.1)           : gmcs -define:TEST_DS  DS.cs 
 * SUSE Linux 10.3 Mono 1.9.1   : gmcs -define:TEST_DS  DS.cs 
 *                                                                  
 * Required Files: DS.cs
 *
 * Maintanence History
 * ===================
 * version 1.0 : 01 August 08 
 *     -- first release: (no support for COMPUTE DS type)
 *     
*/

using System;
using System.Text;

namespace NHAWK
{
    [Serializable]
    public class DSFormatException : Exception
    {
        public DSFormatException(string message)
            : base(message)
        { }

        public DSFormatException(string message, Exception ex)
            : base(message, ex)
        { }
    };
 
    [Serializable]
    public class DS
    {
        private const long  DEF_HEARTBEAT = 600;
        private const int   MAX_LEN = 19;
        private const int   MAX_TOKEN_COUNT = 6;
        private string     _name;
        private TYPE       _type;
        private long       _heart_beat;
        private double     _min;
        private double     _max;
        
        //--< Data source types as defined by RRDTool >--
        public enum TYPE
        {
            GAUGE=0, COUNTER=1, DERIVE=2, ABSOLUTE=3
        };

        //--< Unknown limit specifier (min and max values of an DS) >--
        public static double U
        {
           get {return Double.NaN;}
        }

        //--<constructs a basic data source (DS) entity >--
        public DS(string n, TYPE t)
        {
            name = n;
            DSType = t;
            heartbeat = DEF_HEARTBEAT;
            min = double.NaN;
            max = double.NaN;
        }

        //--<constructs a fully defined data source (DS) entity >--
        public DS(string name, TYPE t, long heart_beat, double min, double max): this(name, t)
        {
            this.heartbeat = heart_beat;
            this.min = min;
            this.max = max;
        }

        //--<constructs a fully defined data source (DS) entity from a serialized DS string >--
        public DS(string data_source)
        {
            //deserializes DS here
            try
            {
                string[] ds_tokens = data_source.Split(new char[] { ':' });
                if (ds_tokens.Length != MAX_TOKEN_COUNT)
                    throw new DSFormatException("Bad DS format");

                //remove any whitespace (shouldn't be any)
                RemovePadding(ds_tokens);
                name = ds_tokens[1];
                _type = StringToType(ds_tokens[2]);
                heartbeat = long.Parse(ds_tokens[3]);
                min = (ds_tokens[4] != "U") ? Double.Parse(ds_tokens[4]) : Double.NaN;
                max = (ds_tokens[5] != "U") ? Double.Parse(ds_tokens[5]) : Double.NaN;
            }
            catch (Exception ex)
            {
                if (ex is DSFormatException)
                    throw;
                else
                    throw new DSFormatException("bad data source format:  could not deserialize: " + data_source, ex);
            }
        }

        //--< get or set the type of the data source: GAUGE, COUNTER DERIVE, etc >--
        public TYPE DSType
        {
            get { return _type; }
            set { _type = value; }
        }

        //--< get or set the heartbeat... 
        /*  heartbeat defines the maximum number of seconds that may pass between 
            two updates of this data source before the value of the data source is assumed to be *UNKNOWN* 
            Source document: http://oss.oetiker.ch/rrdtool/doc/rrdcreate.en.html 
         */
        public long heartbeat
        {
            get { return _heart_beat; }
            set
            {
                if (value < 0)
                    throw new DSFormatException("HeartBeat cannot be negative");
                
                _heart_beat = value;
            }
        }

       /* --< get or set the min range value >--
        * min and max define the expected range values for data supplied by a data source. 
        * If min and/or max any value outside the defined range will be regarded as *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. 
        * Source document: http://oss.oetiker.ch/rrdtool/doc/rrdcreate.en.html 
        */
        public double max
        {
            get { return _max; }
            set
            {
                //if (value == Double.NaN ||  value > _min)
                    _max = value;    
            }
        }
        
        //--< get or set the max range value >--
        public double min
        {
            get { return _min; }
            set
            {
                //if (value == Double.NaN || value < _min)
                    _min = value;
            }
        }

        // --< get or set the DS name >--
        public string name
        {
            get { return _name; }
            set
            {
                if (check_format(value.Trim()))
                    _name = value.Trim();
                else
                    throw new DSFormatException("Bad name for RRD Data Source: use [a-zA-Z0-9_] up to " + MAX_LEN.ToString() + " characters");
            }
        }

        // --< performs and returns a deep clone of the ds object passed .e.g. a completely different oject on the managed heap >-- 
        public static DS DeepClone(DS ds)
        {
            return new DS((new StringBuilder().Append(ds._name)).ToString(), ds.DSType, ds.heartbeat, ds.min, ds.max);
        }

        // --< serializes the data source to a string >--
        public override string ToString()
        {
            string local_min = (min.ToString().ToLower() != "nan") ? min.ToString() : "U";
            string local_max = (max.ToString().ToLower() != "nan") ? max.ToString() : "U";
        
            return "DS:" + name + ":" + DSType.ToString() + ":" + heartbeat + ":" + local_min + ":" + local_max;
        }

        private void RemovePadding(String[] vals)
        {
            for (int i = 0; i < vals.Length; i++)
                vals[i] = vals[i].Trim();
        }

        public static TYPE StringToType(String type)
        {
            switch (type)
            {
                case "COUNTER":
                    return TYPE.COUNTER;
                case "ABSOLUTE":
                    return TYPE.ABSOLUTE;
                case "DERIVE":
                    return TYPE.DERIVE;
                case "GAUGE":
                    return TYPE.GAUGE;
                default:
                    throw new DSFormatException("Bad DS type: " + type);
            };
        }

        private bool check_format(string val)
        {
            if (val.Length > MAX_LEN || val.Length == 0)
                return false;

            foreach (char ch in val)
                if (!Char.IsLetter(ch) && !Char.IsDigit(ch) && !(ch == '_'))
                    return false;

            return true;
        }

#if TEST_DS
        static void Main(string[] args)
        {
            Console.WriteLine("Testing Data Source class");
            Console.WriteLine("=========================");

            Console.WriteLine("Constructing ds1 (simple construction)");
            DS ds1 = new DS("bandwidth", DS.TYPE.COUNTER);

            Console.WriteLine("Name         : {0}", ds1.name);
            Console.WriteLine("Type         : {0}", ds1.DSType);
            Console.WriteLine("Heartbeart   : {0}", ds1.heartbeat);
            Console.WriteLine("Max value    : {0}", ds1.max);
            Console.WriteLine("Min value    : {0}", ds1.min);
            Console.WriteLine("Serialization: {0}", ds1.ToString());

            Console.WriteLine("\nConstructing ds2... (complete construction)");
            DS ds2 = new DS("speed", DS.TYPE.GAUGE, 300, -34.5, 212.0);

            Console.WriteLine("Name         : {0}", ds2.name);
            Console.WriteLine("Type         : {0}", ds2.DSType);
            Console.WriteLine("Heartbeart   : {0}", ds2.heartbeat);
            Console.WriteLine("Max value    : {0}", ds2.max);
            Console.WriteLine("Min value    : {0}", ds2.min);
            Console.WriteLine("Serialization: {0}", ds2.ToString());

            try
            {
                Console.WriteLine("\nConstructing ds3 *** Testing DSFormatException for illegal name");
                DS ds3 = new DS("speed$", DS.TYPE.ABSOLUTE, 600, 0, DS.U);
            }
            catch (DSFormatException ex)
            {
                Console.WriteLine("In exception handler: {0}", ex.Message);
            }

            Console.WriteLine("\nTest Deserialization:");
            DS ds4 = new DS(ds2.ToString());
            Console.WriteLine("ds4 instance hash code: {0}", ds4.GetHashCode());
            Console.WriteLine("Name         : {0}", ds4.name);
            Console.WriteLine("Type         : {0}", ds4.DSType);
            Console.WriteLine("Heartbeart   : {0}", ds4.heartbeat);
            Console.WriteLine("Max value    : {0}", ds4.max);
            Console.WriteLine("Min value    : {0}", ds4.min);
            Console.WriteLine("Serialization: {0}", ds4.ToString());

            Console.WriteLine("\nTesting deep cloning... ds5(ds4)  notice different codes for ds4 and ds5");
            Console.WriteLine("\nTesting mutators: i.e. ds4 and ds5 will have different values");
            DS ds5 = DS.DeepClone(ds4);

            ds5.name = "new_speed";
            ds5.DSType = DS.TYPE.COUNTER;
            ds5.heartbeat = 120;
            ds5.min = -1.5;
            ds5.max = 2.5;

            Console.WriteLine("ds5 instance hash code: {0}", ds5.GetHashCode());
            Console.WriteLine("Name         : {0}", ds5.name);
            Console.WriteLine("Type         : {0}", ds5.DSType);
            Console.WriteLine("Heartbeart   : {0}", ds5.heartbeat);
            Console.WriteLine("Max value    : {0}", ds5.max);
            Console.WriteLine("Min value    : {0}", ds5.min);
            Console.WriteLine("Serialization: {0}", ds5.ToString());

            Console.WriteLine("Testing exception handling with mutator properties"); 
            try
            {
                //ds5.name = "new_speed$_";
                ds5.DSType = DS.TYPE.COUNTER;
                ds5.heartbeat = -1;
                ds5.min = -1.5;
                ds5.max = 2.5;
            }
            catch (DSFormatException ex)
            {
                Console.WriteLine("In exception handler: {0} ", ex.Message);
            }

            Console.WriteLine("\nFinally...  this is shallow copy (notice hashcodes are same for ds4 and ds6}");
            DS ds6 = ds4;

            Console.WriteLine("ds6 instance hash code: {0}", ds6.GetHashCode());
            Console.WriteLine("Name         : {0}", ds6.name);
            Console.WriteLine("Type         : {0}", ds6.DSType);
            Console.WriteLine("Heartbeart   : {0}", ds6.heartbeat);
            Console.WriteLine("Max value    : {0}", ds6.max);
            Console.WriteLine("Min value    : {0}", ds6.min);
            Console.WriteLine("Serialization: {0}", ds6.ToString());
        }
#endif
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Software Developer (Senior)
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions