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)
108 {
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;
127 }
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)
137 {
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;
156 }
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)
166 {
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;
231 }
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)
257 {
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;
298 }
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)
309 {
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;
328 }
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)
336 {
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;
353 }
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)
361 {
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;
378 }
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)
387 {
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;
406 }
408 static PyObject *PyDict_FromInfo(
409 rrd_info_t * data)
410 {
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;
445 }
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)
453 {
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;
473 }
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)
481 {
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;
501 }
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)
509 {
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;
529 }
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)
561 {
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");
577 }
579 /*
580 * $Id: _rrdtoolmodule.c,v 1.14 2003/02/22 07:41:19 perky Exp $
581 * ex: ts=8 sts=4 et
582 */