/*****************************************************************************
* RRDLIB .NET Binding
*****************************************************************************
* Created 2010/06/29 by Chris Larsen
*
* This .NET interface allows the use of Tobias Oetiker's awesome RRDtool
* functions in .NET projects using the PInvoke method to load the rrdlib.dll
* To use, please make sure that you place the rrdlib.dll in the same
* directory as this dll, or change the "const string dll" to point to the
* proper location. For documentation, please see the RRDtool website at:
* http://oss.oetiker.ch/rrdtool/
* For useage examples, please see the rrd_binding_test project.
****************************************************************************/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
///
/// Contains data structures and methods for working with round robin databases.
///
namespace dnrrdlib
{
///
/// Information about a particular RRD parameter. The key is the name of the parameter,
/// type determines what kind of value we have, value is the value, and next is a
/// pointer to another info object.
///
[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct rrd_info_t
{
[FieldOffset(0), MarshalAs(UnmanagedType.LPStr)]
public string key;
[FieldOffset(4)] // for 64 bit, set this to 8 and increment everyone else by 4
public rrd_info_type_t type;
[FieldOffset(8)]
public rrd_infoval_t value;
[FieldOffset(16)]
public IntPtr next;
}
///
/// This is a chunk of data returned from an RRD object
///
[StructLayout(LayoutKind.Sequential)]
public struct rrd_blob_t
{
public UInt32 size; /* size of the blob */
public IntPtr ptr; /* pointer */
};
///
/// This contains the actual data values for an rrd_info_t structure.
/// NOTE: Only one of these will be valid per instance. Use the containing info_t's
/// type field to deteremine which of these to read.
/// NOTE: If the type is RD_I_STR, you have to marshal the string value yourself
///
[StructLayout(LayoutKind.Explicit)]
public struct rrd_infoval_t
{
[FieldOffset(0)]
public UInt32 u_cnt;
[FieldOffset(0)]
public double u_val;
[FieldOffset(0)]
public IntPtr u_str;
[FieldOffset(0)]
public Int32 u_int;
[FieldOffset(0)]
public rrd_blob_t u_blo;
};
///
/// Different rrd_info_t value types
///
public enum rrd_info_type_t
{
RD_I_VAL = 0,
RD_I_CNT,
RD_I_STR,
RD_I_INT,
RD_I_BLO
};
///
/// Direct bindings to the RRD Library for .NET applications. Uses the PInvoke method
/// of accessing the rrdlib.dll file.
///
public class rrd
{
// Set this path to the location of your "rrdlib.dll" file
const string dll = @"C:\Programming\RRDTool\SVN\win32\DebugDLL\rrdlib.dll";
// IMPORTS - Main methods
[DllImport(dll)] static extern Int32 rrd_create(Int32 argc, string[] argv);
[DllImport(dll)] static extern Int32 rrd_create_r([MarshalAs(UnmanagedType.LPStr)] string filename,
UInt32 pdp_step, Int32 last_up, Int32 argc, [MarshalAs(UnmanagedType.LPArray)] string[] argv);
[DllImport(dll)] static extern IntPtr rrd_info_r(string filename);
[DllImport(dll)] static extern void rrd_info_print(IntPtr data);
[DllImport(dll)] static extern Int32 rrd_update(Int32 argc, string[] argv);
[DllImport(dll)] static extern IntPtr rrd_update_v(Int32 argc, string[] argv);
[DllImport(dll)] static extern Int32 rrd_update_r(string filename, string template, Int32 argc,
string[] argv);
/* Do not use this until someone adds the FILE structure */
[DllImport(dll)] static extern Int32 rrd_graph(Int32 argc, string[] argv, ref string[] prdata,
ref Int32 xsize, ref Int32 ysize, /* TODO - FILE, */ ref double ymin, ref double ymax);
[DllImport(dll)] static extern Int32 rrd_graph_v(Int32 argc, string[] argv);
[DllImport(dll)] static extern Int32 rrd_fetch(Int32 argc, string[] argv, ref Int32 start,
ref Int32 end, ref UInt32 step, [Out] out UInt32 ds_cnt, [Out] out IntPtr ds_namv, [Out] out IntPtr data);
[DllImport(dll)] static extern Int32 rrd_first(Int32 argc, string[] argv);
[DllImport(dll)] static extern Int32 rrd_first_r(string filename, Int32 rraindex);
[DllImport(dll)] static extern Int32 rrd_last(Int32 argc, string[] argv);
[DllImport(dll)] static extern Int32 rrd_last_r(string filename, Int32 rraindex);
[DllImport(dll)] static extern Int32 rrd_lastupdate(Int32 argc, string[] argv);
[DllImport(dll)] static extern Int32 rrd_lastupdate_r(string filename, ref Int32 ret_last_update,
ref UInt32 ret_ds_count, [Out] out IntPtr ret_ds_names, [Out] out IntPtr ret_last_ds);
[DllImport(dll)] static extern Int32 rrd_dump(Int32 argc, string[] argv);
[DllImport(dll)] static extern Int32 rrd_dump_r(string filename, string outname);
[DllImport(dll)] static extern Int32 rrd_xport(Int32 argc, string[] argv, Int32 unused,
ref Int32 start, ref Int32 end, ref UInt32 step, ref UInt32 col_cnt,
[Out] out IntPtr leggend_v, [Out] out IntPtr data);
[DllImport(dll)] static extern Int32 rrd_restore(Int32 argc, string[] argv);
[DllImport(dll)] static extern Int32 rrd_resize(Int32 argc, string[] argv);
[DllImport(dll)] static extern Int32 rrd_tune(Int32 argc, string[] argv);
// IMPORTS - Utility methods
[DllImport(dll)] static extern string rrd_strversion();
[DllImport(dll)] static extern Int32 rrd_random();
[DllImport(dll)] static extern IntPtr rrd_get_error();
// MAIN FUNCTIONS
///
/// The create function of RRDtool lets you set up new Round Robin Database (RRD) files.
/// The file is created at its final, full size and filled with *UNKNOWN* data.
///
/// String array of command line arguments
/// 0 if successful, -1 if an error occurred
public static int Create(string[] argv)
{
return rrd_create(argv.GetUpperBound(0) + 1, argv);
}
///
/// The create function of RRDtool lets you set up new Round Robin Database (RRD) files.
/// The file is created at its final, full size and filled with *UNKNOWN* data.
///
/// A full path to the location where you want the rrd to reside
/// Specifies the base interval in seconds with which data will be fed into the RRD
/// Timestamp of the last update
/// String array of command line arguments
/// 0 if successful, -1 if an error occurred
public static int Create(string filename, UInt32 pdp_step, Int32 last_up, string[] argv)
{
return rrd_create_r(filename, pdp_step, last_up, argv.GetUpperBound(0)+1, argv);
}
///
/// Returns a linked list of rrd_info_t objects that describe the rrd file.
///
/// Full path to the rrd file
/// An rrd_info_t object
public static rrd_info_t Info(string filename)
{
if (filename.Length < 1)
throw new Exception("Empty filename");
IntPtr ptr = rrd_info_r(filename);
if (ptr == IntPtr.Zero || (int)ptr < 1)
throw new Exception("Unable to extract information from rrd");
return (rrd_info_t)Marshal.PtrToStructure(ptr, typeof(rrd_info_t));
}
///
/// The update function feeds new data values into an RRD. The data is time aligned (interpolated)
/// according to the properties of the RRD to which the data is written.
///
/// String array of command line arguments
/// 0 if successful, -1 if an error occurred
public static Int32 Update(string[] argv)
{
return rrd_update(argv.GetUpperBound(0) + 1, argv);
}
///
/// The update function feeds new data values into an RRD. The data is time aligned (interpolated)
/// according to the properties of the RRD to which the data is written.
///
/// String array of command line arguments
/// An rrd_info_t pointer with information about the update
public static IntPtr Update2(string[] argv)
{
return rrd_update_v(argv.GetUpperBound(0) + 1, argv);
}
///
/// The update function feeds new data values into an RRD. The data is time aligned (interpolated)
/// according to the properties of the RRD to which the data is written.
///
/// Full path to the rrd to update
/// List of data sources to update and in which order
/// String array of command line arguments
/// 0 if successful, -1 if an error occurred
public static Int32 Update(string filename, string template, string[] argv)
{
return rrd_update_r(filename, template, argv.GetUpperBound(0)+1, argv);
}
///
/// Generate a graph from an RRD file. Specify all the graph options in the string array as you
/// normally would with the command line version.
///
/// String array of command line arguments
/// 0 if successful, -1 if an error occurred
public static Int32 Graph(string[] argv)
{
return rrd_graph_v(argv.GetUpperBound(0) + 1, argv);
}
///
/// Returns an array of values for the period specified from a given rrd.
/// Specify your parameters in the argv array and check the referenced parameters for
/// values returned from the rrd
///
/// String array of command line arguments (must include the filename)
/// Starting timestamp found in the rrd
/// Ending timestamp found in the rrd
/// The rrd's step value
/// Number of data sources found
/// Names of data sources found
/// Values found (in double type)
/// 0 if successful, -1 if an error occurred
public static Int32 Fetch(string[] argv, ref Int32 start, ref Int32 end, ref UInt32 step,
ref UInt32 ds_cnt, ref string[] ds_namv, ref IntPtr data)
{
IntPtr ptr = new IntPtr();
Int32 rv = rrd_fetch(argv.GetUpperBound(0) + 1, argv, ref start, ref end, ref step, out ds_cnt,
out ptr, out data);
ds_namv = GetStringArray(ptr, ds_cnt);
return rv;
}
///
/// Returns the timestamp of the first value in the rrd given the rra index
///
/// Full path to the rrd file
/// 0 based index of the rra to get a value for
/// Unix timestamp if successful, -1 if an error occurred
public static Int32 First(string filename, int rraindex)
{
return rrd_first_r(filename, rraindex);
}
///
/// Returns the timestamp of the first value in the rrd
///
/// String array of command line arguments
/// Unix timestamp if successful, -1 if an error occurred
public static Int32 First(string[] argv)
{
return rrd_first(argv.GetUpperBound(0) + 1, argv);
}
///
/// Returns the timestamp of the last value in the rrd given the rra index
///
///
/// Full path to the rrd file
/// 0 based index of the rra to get a value for
/// Unix timestamp if successful, -1 if an error occurred
public static Int32 Last(string filename, int rraindex)
{
return rrd_last_r(filename, rraindex);
}
///
/// Returns the timestamp of the last value in the rrd
///
/// String array of command line arguments
/// Unix timestamp if successful, -1 if an error occurred
public static Int32 Last(string[] argv)
{
return rrd_last(argv.GetUpperBound(0) + 1, argv);
}
///
/// Finds the timestamp of the last updated value in the rrd
///
/// Full path to the rrd file
/// Unix timestamp of the last update
/// Number of data sources found
/// Names of the data sources found
/// Name of the last data source found
/// 0 if successful, -1 if an error occurred
public static Int32 Last_Update(string filename, ref Int32 ret_last_update, ref UInt32 ret_ds_count,
ref string[] ret_ds_names, ref string[] ret_last_ds)
{
IntPtr ds_names = new IntPtr();
IntPtr last_ds = new IntPtr();
Int32 rt = rrd_lastupdate_r(filename, ref ret_last_update, ref ret_ds_count, out ds_names,out last_ds);
ret_ds_names = GetStringArray(ds_names, ret_ds_count);
ret_last_ds = GetStringArray(last_ds, 1);
return rt;
}
///
/// Writes the contents of an rrd file to an XML file
///
/// Full path to the rrd file
/// Full path to write the XML output
/// 0 if successful, -1 if an error occurred
public static Int32 Dump(string filename, string outname)
{
return rrd_dump_r(filename, outname);
}
///
/// Writes the contents of an rrd file to an XML file
///
/// String array of command line arguments
/// 0 if successful, -1 if an error occurred
public static Int32 Dump(string[] argv)
{
return rrd_dump(argv.GetUpperBound(0) + 1, argv);
}
///
/// Grabs the values from an rrd. Similar to fetch but enables merging of multiple
/// rrds and calculations
///
/// String array of command line arguments
/// Starting timestamp found in the rrd
/// Ending timestamp found in the rrd
/// Step size found in the rrd
/// Number of data sources found in the rrd
/// Add a legend
/// Values from the rrd as double type
/// 0 if successful, -1 if an error occurred
public static Int32 Xport(string[] argv, ref Int32 start, ref Int32 end, ref UInt32 step,
ref UInt32 col_cnt, ref string[] legend_v, ref IntPtr data)
{
IntPtr legend = new IntPtr();
Int32 rt = rrd_xport(argv.GetUpperBound(0) + 1, argv, 0, ref start, ref end, ref step, ref col_cnt,
out legend, out data);
legend_v = GetStringArray(legend, col_cnt);
return rt;
}
///
/// Creates an rrd from an XML data dump
///
/// String array of command line arguments
/// 0 if successful, -1 if an error occurred
public static Int32 Restore(string[] argv)
{
return rrd_restore(argv.GetUpperBound(0) + 1, argv);
}
///
/// Alters the size of an RRA and creates a new rrd in the dll's directory
/// NOTE: The new rrd may return unexpected results if you are not very careful
/// NOTE: This may crash in version 1.4.3
///
/// String array of command line arguments
/// 0 if successful, -1 if an error occurred
public static Int32 Resize(string[] argv)
{
return rrd_resize(argv.GetUpperBound(0) + 1, argv);
}
///
/// Modify the characteristics of an rrd
///
/// String array of command line arguments
/// 0 if successful, -1 if an error occurred
public static Int32 Tune(string[] argv)
{
return rrd_tune(argv.GetUpperBound(0) + 1, argv);
}
// UTILITIES
///
/// Returns a string with the numeric version of the rrdlib build version
///
/// A string with version information
public static string Version()
{
return rrd_strversion();
}
///
/// Generates a random number for testing rrdlib
///
/// A random integer
public static int Random()
{
return rrd_random();
}
///
/// Returns the latest error from rrdlib
///
/// A string with the error message, or an emtpy string if no error occurred
public static string Get_Error()
{
IntPtr ptr = rrd_get_error();
if (ptr == IntPtr.Zero)
return "";
return Marshal.PtrToStringAnsi(ptr);
}
///
/// Formats and prints information in the object to the standard output
///
/// rrd_info_t object with data to print
public static void Info_Print(rrd_info_t info)
{
IntPtr newptr = Marshal.AllocHGlobal(Marshal.SizeOf(info));
Marshal.StructureToPtr(info, newptr, true);
rrd_info_print(newptr);
}
///
/// Converts a Char ** array of characters from the RRDLib returned as an IntPtr and converts
/// it to a String array given the number of items in the ptr array.
/// Re: http://stackoverflow.com/questions/1498931/marshalling-array-of-strings-to-char-in-c-must-be-quite-easy-if-you-know-ho
///
/// Pointer to a character array returned from the RRDLib
/// Number of items in the character array (not the number of characters)
/// A string array
private static string[] GetStringArray(IntPtr ptr, UInt32 size)
{
var list = new List();
for (int i = 0; i < size; i++)
{
var strPtr = (IntPtr)Marshal.PtrToStructure(ptr, typeof(IntPtr));
list.Add(Marshal.PtrToStringAnsi(strPtr));
ptr = new IntPtr(ptr.ToInt64() + IntPtr.Size);
}
return list.ToArray();
}
}
}