Code

e2d0bbd5e5142ecce9aeec2b7a592d691eab419e
[rrdtool-all.git] / program / bindings / python / rrdtoolmodule.c
1 /*
2  * rrdtoolmodule.c
3  *
4  * RRDTool Python binding
5  *
6  * Author  : Hye-Shik Chang <perky@fallin.lv>
7  * Date    : $Date: 2003/02/22 07:41:19 $
8  * Created : 23 May 2002
9  *
10  * $Revision: 1.14 $
11  *
12  *  ==========================================================================
13  *  This file is part of py-rrdtool.
14  *
15  *  py-rrdtool is free software; you can redistribute it and/or modify
16  *  it under the terms of the GNU Lesser General Public License as published
17  *  by the Free Software Foundation; either version 2 of the License, or
18  *  (at your option) any later version.
19  *
20  *  py-rrdtool is distributed in the hope that it will be useful,
21  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  *  GNU Lesser General Public License for more details.
24  *
25  *  You should have received a copy of the GNU Lesser General Public License
26  *  along with Foobar; if not, write to the Free Software
27  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28  *
29  */
31 #ifdef UNUSED
32 #elif defined(__GNUC__)
33 # define UNUSED(x) x __attribute__((unused))
34 #elif defined(__LCLINT__)
35 # define UNUSED(x) /*@unused@*/ x
36 #else
37 # define UNUSED(x) x
38 #endif
41 #include "../../rrd_config.h"
42 static const char *__version__ = PACKAGE_VERSION;
44 #include "Python.h"
45 #include "../../src/rrd_tool.h"
46 //#include "rrd.h"
47 //#include "rrd_extra.h"
49 static PyObject *ErrorObject;
50 extern int optind;
51 extern int opterr;
53 /* forward declaration to keep compiler happy */
54 void      initrrdtool(
55     void);
57 static int create_args(
58     char *command,
59     PyObject * args,
60     int *argc,
61     char ***argv)
62 {
63     PyObject *o;
64     int       size, i;
66     size = PyTuple_Size(args);
67     *argv = PyMem_New(char *,
68                       size + 1);
70     if (*argv == NULL)
71         return -1;
73     for (i = 0; i < size; i++) {
74         o = PyTuple_GET_ITEM(args, i);
75         if (PyString_Check(o))
76             (*argv)[i + 1] = PyString_AS_STRING(o);
77         else {
78             PyMem_Del(*argv);
79             PyErr_Format(PyExc_TypeError, "argument %d must be string", i);
80             return -1;
81         }
82     }
83     (*argv)[0] = command;
84     *argc = size + 1;
86     /* reset getopt state */
87     opterr = optind = 0;
89     return 0;
90 }
92 static void destroy_args(
93     char ***argv)
94 {
95     PyMem_Del(*argv);
96     *argv = NULL;
97 }
99 static char PyRRD_create__doc__[] =
100     "create(args..): Set up a new Round Robin Database\n\
101     create filename [--start|-b start time] \
102 [--step|-s step] [DS:ds-name:DST:heartbeat:min:max] \
103 [RRA:CF:xff:steps:rows]";
105 static PyObject *PyRRD_create(
106     PyObject UNUSED(*self),
107     PyObject * args)
109     PyObject *r;
110     char    **argv;
111     int       argc;
113     if (create_args("create", args, &argc, &argv) < 0)
114         return NULL;
116     if (rrd_create(argc, argv) == -1) {
117         PyErr_SetString(ErrorObject, rrd_get_error());
118         rrd_clear_error();
119         r = NULL;
120     } else {
121         Py_INCREF(Py_None);
122         r = Py_None;
123     }
125     destroy_args(&argv);
126     return r;
129 static char PyRRD_update__doc__[] =
130     "update(args..): Store a new set of values into the rrd\n"
131     "    update filename [--template|-t ds-name[:ds-name]...] "
132     "N|timestamp:value[:value...] [timestamp:value[:value...] ...]";
134 static PyObject *PyRRD_update(
135     PyObject UNUSED(*self),
136     PyObject * args)
138     PyObject *r;
139     char    **argv;
140     int       argc;
142     if (create_args("update", args, &argc, &argv) < 0)
143         return NULL;
145     if (rrd_update(argc, argv) == -1) {
146         PyErr_SetString(ErrorObject, rrd_get_error());
147         rrd_clear_error();
148         r = NULL;
149     } else {
150         Py_INCREF(Py_None);
151         r = Py_None;
152     }
154     destroy_args(&argv);
155     return r;
158 static char PyRRD_fetch__doc__[] =
159     "fetch(args..): fetch data from an rrd.\n"
160     "    fetch filename CF [--resolution|-r resolution] "
161     "[--start|-s start] [--end|-e end]";
163 static PyObject *PyRRD_fetch(
164     PyObject UNUSED(*self),
165     PyObject * args)
167     PyObject *r;
168     rrd_value_t *data, *datai;
169     unsigned long step, ds_cnt;
170     time_t    start, end;
171     int       argc;
172     char    **argv, **ds_namv;
174     if (create_args("fetch", args, &argc, &argv) < 0)
175         return NULL;
177     if (rrd_fetch(argc, argv, &start, &end, &step,
178                   &ds_cnt, &ds_namv, &data) == -1) {
179         PyErr_SetString(ErrorObject, rrd_get_error());
180         rrd_clear_error();
181         r = NULL;
182     } else {
183         /* Return :
184            ((start, end, step), (name1, name2, ...), [(data1, data2, ..), ...]) */
185         PyObject *range_tup, *dsnam_tup, *data_list, *t;
186         unsigned long i, j, row;
187         rrd_value_t dv;
189         row = (end - start) / step;
191         r = PyTuple_New(3);
192         range_tup = PyTuple_New(3);
193         dsnam_tup = PyTuple_New(ds_cnt);
194         data_list = PyList_New(row);
195         PyTuple_SET_ITEM(r, 0, range_tup);
196         PyTuple_SET_ITEM(r, 1, dsnam_tup);
197         PyTuple_SET_ITEM(r, 2, data_list);
199         datai = data;
201         PyTuple_SET_ITEM(range_tup, 0, PyInt_FromLong((long) start));
202         PyTuple_SET_ITEM(range_tup, 1, PyInt_FromLong((long) end));
203         PyTuple_SET_ITEM(range_tup, 2, PyInt_FromLong((long) step));
205         for (i = 0; i < ds_cnt; i++)
206             PyTuple_SET_ITEM(dsnam_tup, i, PyString_FromString(ds_namv[i]));
208         for (i = 0; i < row; i++) {
209             t = PyTuple_New(ds_cnt);
210             PyList_SET_ITEM(data_list, i, t);
212             for (j = 0; j < ds_cnt; j++) {
213                 dv = *(datai++);
214                 if (isnan(dv)) {
215                     PyTuple_SET_ITEM(t, j, Py_None);
216                     Py_INCREF(Py_None);
217                 } else {
218                     PyTuple_SET_ITEM(t, j, PyFloat_FromDouble((double) dv));
219                 }
220             }
221         }
223         for (i = 0; i < ds_cnt; i++)
224             rrd_freemem(ds_namv[i]);
225         rrd_freemem(ds_namv);   /* rrdtool don't use PyMem_Malloc :) */
226         rrd_freemem(data);
227     }
229     destroy_args(&argv);
230     return r;
233 static char PyRRD_graph__doc__[] =
234     "graph(args..): Create a graph based on data from one or several RRD\n"
235     "    graph filename [-s|--start seconds] "
236     "[-e|--end seconds] [-x|--x-grid x-axis grid and label] "
237     "[-y|--y-grid y-axis grid and label] [--alt-y-grid] [--alt-y-mrtg] "
238     "[--alt-autoscale] [--alt-autoscale-max] [--units-exponent] value "
239     "[-v|--vertical-label text] [-w|--width pixels] [-h|--height pixels] "
240     "[-i|--interlaced] "
241     "[-f|--imginfo formatstring] [-a|--imgformat GIF|PNG|GD] "
242     "[-B|--background value] [-O|--overlay value] "
243     "[-U|--unit value] [-z|--lazy] [-o|--logarithmic] "
244     "[-u|--upper-limit value] [-l|--lower-limit value] "
245     "[-g|--no-legend] [-r|--rigid] [--step value] "
246     "[-b|--base value] [-c|--color COLORTAG#rrggbb] "
247     "[-t|--title title] [DEF:vname=rrd:ds-name:CF] "
248     "[CDEF:vname=rpn-expression] [PRINT:vname:CF:format] "
249     "[GPRINT:vname:CF:format] [COMMENT:text] "
250     "[HRULE:value#rrggbb[:legend]] [VRULE:time#rrggbb[:legend]] "
251     "[LINE{1|2|3}:vname[#rrggbb[:legend]]] "
252     "[AREA:vname[#rrggbb[:legend]]] " "[STACK:vname[#rrggbb[:legend]]]";
254 static PyObject *PyRRD_graph(
255     PyObject UNUSED(*self),
256     PyObject * args)
258     PyObject *r;
259     char    **argv, **calcpr;
260     int       argc, xsize, ysize, i;
261     double    ymin, ymax;
263     if (create_args("graph", args, &argc, &argv) < 0)
264         return NULL;
266     if (rrd_graph(argc, argv, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) ==
267         -1) {
268         PyErr_SetString(ErrorObject, rrd_get_error());
269         rrd_clear_error();
270         r = NULL;
271     } else {
272         r = PyTuple_New(3);
274         PyTuple_SET_ITEM(r, 0, PyInt_FromLong((long) xsize));
275         PyTuple_SET_ITEM(r, 1, PyInt_FromLong((long) ysize));
277         if (calcpr) {
278             PyObject *e, *t;
280             e = PyList_New(0);
281             PyTuple_SET_ITEM(r, 2, e);
283             for (i = 0; calcpr[i]; i++) {
284                 t = PyString_FromString(calcpr[i]);
285                 PyList_Append(e, t);
286                 Py_DECREF(t);
287                 rrd_freemem(calcpr[i]);
288             }
289             rrd_freemem(calcpr);
290         } else {
291             Py_INCREF(Py_None);
292             PyTuple_SET_ITEM(r, 2, Py_None);
293         }
294     }
296     destroy_args(&argv);
297     return r;
300 static char PyRRD_tune__doc__[] =
301     "tune(args...): Modify some basic properties of a Round Robin Database\n"
302     "    tune filename [--heartbeat|-h ds-name:heartbeat] "
303     "[--minimum|-i ds-name:min] [--maximum|-a ds-name:max] "
304     "[--data-source-type|-d ds-name:DST] [--data-source-rename|-r old-name:new-name]";
306 static PyObject *PyRRD_tune(
307     PyObject UNUSED(*self),
308     PyObject * args)
310     PyObject *r;
311     char    **argv;
312     int       argc;
314     if (create_args("tune", args, &argc, &argv) < 0)
315         return NULL;
317     if (rrd_tune(argc, argv) == -1) {
318         PyErr_SetString(ErrorObject, rrd_get_error());
319         rrd_clear_error();
320         r = NULL;
321     } else {
322         Py_INCREF(Py_None);
323         r = Py_None;
324     }
326     destroy_args(&argv);
327     return r;
330 static char PyRRD_first__doc__[] =
331     "first(filename): Return the timestamp of the first data sample in an RRD";
333 static PyObject *PyRRD_first(
334     PyObject UNUSED(*self),
335     PyObject * args)
337     PyObject *r;
338     int       argc, ts;
339     char    **argv;
341     if (create_args("first", args, &argc, &argv) < 0)
342         return NULL;
344     if ((ts = rrd_first(argc, argv)) == -1) {
345         PyErr_SetString(ErrorObject, rrd_get_error());
346         rrd_clear_error();
347         r = NULL;
348     } else
349         r = PyInt_FromLong((long) ts);
351     destroy_args(&argv);
352     return r;
355 static char PyRRD_last__doc__[] =
356     "last(filename): Return the timestamp of the last data sample in an RRD";
358 static PyObject *PyRRD_last(
359     PyObject UNUSED(*self),
360     PyObject * args)
362     PyObject *r;
363     int       argc, ts;
364     char    **argv;
366     if (create_args("last", args, &argc, &argv) < 0)
367         return NULL;
369     if ((ts = rrd_last(argc, argv)) == -1) {
370         PyErr_SetString(ErrorObject, rrd_get_error());
371         rrd_clear_error();
372         r = NULL;
373     } else
374         r = PyInt_FromLong((long) ts);
376     destroy_args(&argv);
377     return r;
380 static char PyRRD_resize__doc__[] =
381     "resize(args...): alters the size of an RRA.\n"
382     "    resize filename rra-num GROW|SHRINK rows";
384 static PyObject *PyRRD_resize(
385     PyObject UNUSED(*self),
386     PyObject * args)
388     PyObject *r;
389     char    **argv;
390     int       argc, ts;
392     if (create_args("resize", args, &argc, &argv) < 0)
393         return NULL;
395     if ((ts = rrd_resize(argc, argv)) == -1) {
396         PyErr_SetString(ErrorObject, rrd_get_error());
397         rrd_clear_error();
398         r = NULL;
399     } else {
400         Py_INCREF(Py_None);
401         r = Py_None;
402     }
404     destroy_args(&argv);
405     return r;
408 static PyObject *PyDict_FromInfo(
409     rrd_info_t * data)
411     PyObject *r;
413     r = PyDict_New();
414     while (data) {
415         PyObject *val = NULL;
417         switch (data->type) {
418         case RD_I_VAL:
419             val = isnan(data->value.u_val)
420                 ? (Py_INCREF(Py_None), Py_None)
421                 : PyFloat_FromDouble(data->value.u_val);
422             break;
423         case RD_I_CNT:
424             val = PyLong_FromUnsignedLong(data->value.u_cnt);
425             break;
426         case RD_I_INT:
427             val = PyLong_FromLong(data->value.u_int);
428             break;
429         case RD_I_STR:
430             val = PyString_FromString(data->value.u_str);
431             break;
432         case RD_I_BLO:
433             val =
434                 PyString_FromStringAndSize((char *) data->value.u_blo.ptr,
435                                            data->value.u_blo.size);
436             break;
437         }
438         if (val) {
439             PyDict_SetItemString(r, data->key, val);
440             Py_DECREF(val);
441         }
442         data = data->next;
443     }
444     return r;
447 static char PyRRD_info__doc__[] =
448     "info(filename): extract header information from an rrd";
450 static PyObject *PyRRD_info(
451     PyObject UNUSED(*self),
452     PyObject * args)
454     PyObject *r;
455     int       argc;
456     char    **argv;
457     rrd_info_t *data;
459     if (create_args("info", args, &argc, &argv) < 0)
460         return NULL;
462     if ((data = rrd_info(argc, argv)) == NULL) {
463         PyErr_SetString(ErrorObject, rrd_get_error());
464         rrd_clear_error();
465         r = NULL;
466     } else {
467         r = PyDict_FromInfo(data);
468         rrd_info_free(data);
469     }
471     destroy_args(&argv);
472     return r;
475 static char PyRRD_graphv__doc__[] =
476     "graphv is called in the same manner as graph";
478 static PyObject *PyRRD_graphv(
479     PyObject UNUSED(*self),
480     PyObject * args)
482     PyObject *r;
483     int       argc;
484     char    **argv;
485     rrd_info_t *data;
487     if (create_args("graphv", args, &argc, &argv) < 0)
488         return NULL;
490     if ((data = rrd_graph_v(argc, argv)) == NULL) {
491         PyErr_SetString(ErrorObject, rrd_get_error());
492         rrd_clear_error();
493         r = NULL;
494     } else {
495         r = PyDict_FromInfo(data);
496         rrd_info_free(data);
497     }
499     destroy_args(&argv);
500     return r;
503 static char PyRRD_updatev__doc__[] =
504     "updatev is called in the same manner as update";
506 static PyObject *PyRRD_updatev(
507     PyObject UNUSED(*self),
508     PyObject * args)
510     PyObject *r;
511     int       argc;
512     char    **argv;
513     rrd_info_t *data;
515     if (create_args("updatev", args, &argc, &argv) < 0)
516         return NULL;
518     if ((data = rrd_update_v(argc, argv)) == NULL) {
519         PyErr_SetString(ErrorObject, rrd_get_error());
520         rrd_clear_error();
521         r = NULL;
522     } else {
523         r = PyDict_FromInfo(data);
524         rrd_info_free(data);
525     }
527     destroy_args(&argv);
528     return r;
531 /* List of methods defined in the module */
532 #define meth(name, func, doc) {name, (PyCFunction)func, METH_VARARGS, doc}
534 static PyMethodDef _rrdtool_methods[] = {
535     meth("create", PyRRD_create, PyRRD_create__doc__),
536     meth("update", PyRRD_update, PyRRD_update__doc__),
537     meth("fetch", PyRRD_fetch, PyRRD_fetch__doc__),
538     meth("graph", PyRRD_graph, PyRRD_graph__doc__),
539     meth("tune", PyRRD_tune, PyRRD_tune__doc__),
540     meth("first", PyRRD_first, PyRRD_first__doc__),
541     meth("last", PyRRD_last, PyRRD_last__doc__),
542     meth("resize", PyRRD_resize, PyRRD_resize__doc__),
543     meth("info", PyRRD_info, PyRRD_info__doc__),
544     meth("graphv", PyRRD_graphv, PyRRD_graphv__doc__),
545     meth("updatev", PyRRD_updatev, PyRRD_updatev__doc__),
546     {NULL, NULL, 0, NULL}
547 };
549 #define SET_INTCONSTANT(dict, value) \
550             t = PyInt_FromLong((long)value); \
551             PyDict_SetItemString(dict, #value, t); \
552             Py_DECREF(t);
553 #define SET_STRCONSTANT(dict, value) \
554             t = PyString_FromString(value); \
555             PyDict_SetItemString(dict, #value, t); \
556             Py_DECREF(t);
558 /* Initialization function for the module */
559 void initrrdtool(
560     void)
562     PyObject *m, *d, *t;
564     /* Create the module and add the functions */
565     m = Py_InitModule("rrdtool", _rrdtool_methods);
567     /* Add some symbolic constants to the module */
568     d = PyModule_GetDict(m);
570     SET_STRCONSTANT(d, __version__);
571     ErrorObject = PyErr_NewException("rrdtool.error", NULL, NULL);
572     PyDict_SetItemString(d, "error", ErrorObject);
574     /* Check for errors */
575     if (PyErr_Occurred())
576         Py_FatalError("can't initialize the rrdtool module");
579 /*
580  * $Id: _rrdtoolmodule.c,v 1.14 2003/02/22 07:41:19 perky Exp $
581  * ex: ts=8 sts=4 et
582  */