109d66f3194d7b0c5c45a57d96559631dcdf31f4
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
40 static const char *__version__ = "$Revision: 1.14 $";
42 #include "Python.h"
43 #include "../../src/rrd_tool.h"
44 //#include "rrd.h"
45 //#include "rrd_extra.h"
47 static PyObject *ErrorObject;
48 extern int optind;
49 extern int opterr;
51 /* forward declaration to keep compiler happy */
52 void initrrdtool(
53 void);
55 static int create_args(
56 char *command,
57 PyObject * args,
58 int *argc,
59 char ***argv)
60 {
61 PyObject *o;
62 int size, i;
64 size = PyTuple_Size(args);
65 *argv = PyMem_New(char *,
66 size + 1);
68 if (*argv == NULL)
69 return -1;
71 for (i = 0; i < size; i++) {
72 o = PyTuple_GET_ITEM(args, i);
73 if (PyString_Check(o))
74 (*argv)[i + 1] = PyString_AS_STRING(o);
75 else {
76 PyMem_Del(*argv);
77 PyErr_Format(PyExc_TypeError, "argument %d must be string", i);
78 return -1;
79 }
80 }
81 (*argv)[0] = command;
82 *argc = size + 1;
84 /* reset getopt state */
85 opterr = optind = 0;
87 return 0;
88 }
90 static void destroy_args(
91 char ***argv)
92 {
93 PyMem_Del(*argv);
94 *argv = NULL;
95 }
97 static char PyRRD_create__doc__[] =
98 "create(args..): Set up a new Round Robin Database\n\
99 create filename [--start|-b start time] \
100 [--step|-s step] [DS:ds-name:DST:heartbeat:min:max] \
101 [RRA:CF:xff:steps:rows]";
103 static PyObject *PyRRD_create(
104 PyObject UNUSED(*self),
105 PyObject * args)
106 {
107 PyObject *r;
108 char **argv;
109 int argc;
111 if (create_args("create", args, &argc, &argv) < 0)
112 return NULL;
114 if (rrd_create(argc, argv) == -1) {
115 PyErr_SetString(ErrorObject, rrd_get_error());
116 rrd_clear_error();
117 r = NULL;
118 } else {
119 Py_INCREF(Py_None);
120 r = Py_None;
121 }
123 destroy_args(&argv);
124 return r;
125 }
127 static char PyRRD_update__doc__[] =
128 "update(args..): Store a new set of values into the rrd\n"
129 " update filename [--template|-t ds-name[:ds-name]...] "
130 "N|timestamp:value[:value...] [timestamp:value[:value...] ...]";
132 static PyObject *PyRRD_update(
133 PyObject UNUSED(*self),
134 PyObject * args)
135 {
136 PyObject *r;
137 char **argv;
138 int argc;
140 if (create_args("update", args, &argc, &argv) < 0)
141 return NULL;
143 if (rrd_update(argc, argv) == -1) {
144 PyErr_SetString(ErrorObject, rrd_get_error());
145 rrd_clear_error();
146 r = NULL;
147 } else {
148 Py_INCREF(Py_None);
149 r = Py_None;
150 }
152 destroy_args(&argv);
153 return r;
154 }
156 static char PyRRD_fetch__doc__[] =
157 "fetch(args..): fetch data from an rrd.\n"
158 " fetch filename CF [--resolution|-r resolution] "
159 "[--start|-s start] [--end|-e end]";
161 static PyObject *PyRRD_fetch(
162 PyObject UNUSED(*self),
163 PyObject * args)
164 {
165 PyObject *r;
166 rrd_value_t *data, *datai;
167 unsigned long step, ds_cnt;
168 time_t start, end;
169 int argc;
170 char **argv, **ds_namv;
172 if (create_args("fetch", args, &argc, &argv) < 0)
173 return NULL;
175 if (rrd_fetch(argc, argv, &start, &end, &step,
176 &ds_cnt, &ds_namv, &data) == -1) {
177 PyErr_SetString(ErrorObject, rrd_get_error());
178 rrd_clear_error();
179 r = NULL;
180 } else {
181 /* Return :
182 ((start, end, step), (name1, name2, ...), [(data1, data2, ..), ...]) */
183 PyObject *range_tup, *dsnam_tup, *data_list, *t;
184 unsigned long i, j, row;
185 rrd_value_t dv;
187 row = ((end - start) / step + 1);
189 r = PyTuple_New(3);
190 range_tup = PyTuple_New(3);
191 dsnam_tup = PyTuple_New(ds_cnt);
192 data_list = PyList_New(row);
193 PyTuple_SET_ITEM(r, 0, range_tup);
194 PyTuple_SET_ITEM(r, 1, dsnam_tup);
195 PyTuple_SET_ITEM(r, 2, data_list);
197 datai = data;
199 PyTuple_SET_ITEM(range_tup, 0, PyInt_FromLong((long) start));
200 PyTuple_SET_ITEM(range_tup, 1, PyInt_FromLong((long) end));
201 PyTuple_SET_ITEM(range_tup, 2, PyInt_FromLong((long) step));
203 for (i = 0; i < ds_cnt; i++)
204 PyTuple_SET_ITEM(dsnam_tup, i, PyString_FromString(ds_namv[i]));
206 for (i = 0; i < row; i++) {
207 t = PyTuple_New(ds_cnt);
208 PyList_SET_ITEM(data_list, i, t);
210 for (j = 0; j < ds_cnt; j++) {
211 dv = *(datai++);
212 if (isnan(dv)) {
213 PyTuple_SET_ITEM(t, j, Py_None);
214 Py_INCREF(Py_None);
215 } else {
216 PyTuple_SET_ITEM(t, j, PyFloat_FromDouble((double) dv));
217 }
218 }
219 }
221 for (i = 0; i < ds_cnt; i++)
222 rrd_freemem(ds_namv[i]);
223 rrd_freemem(ds_namv); /* rrdtool don't use PyMem_Malloc :) */
224 rrd_freemem(data);
225 }
227 destroy_args(&argv);
228 return r;
229 }
231 static char PyRRD_graph__doc__[] =
232 "graph(args..): Create a graph based on data from one or several RRD\n"
233 " graph filename [-s|--start seconds] "
234 "[-e|--end seconds] [-x|--x-grid x-axis grid and label] "
235 "[-y|--y-grid y-axis grid and label] [--alt-y-grid] [--alt-y-mrtg] "
236 "[--alt-autoscale] [--alt-autoscale-max] [--units-exponent] value "
237 "[-v|--vertical-label text] [-w|--width pixels] [-h|--height pixels] "
238 "[-i|--interlaced] "
239 "[-f|--imginfo formatstring] [-a|--imgformat GIF|PNG|GD] "
240 "[-B|--background value] [-O|--overlay value] "
241 "[-U|--unit value] [-z|--lazy] [-o|--logarithmic] "
242 "[-u|--upper-limit value] [-l|--lower-limit value] "
243 "[-g|--no-legend] [-r|--rigid] [--step value] "
244 "[-b|--base value] [-c|--color COLORTAG#rrggbb] "
245 "[-t|--title title] [DEF:vname=rrd:ds-name:CF] "
246 "[CDEF:vname=rpn-expression] [PRINT:vname:CF:format] "
247 "[GPRINT:vname:CF:format] [COMMENT:text] "
248 "[HRULE:value#rrggbb[:legend]] [VRULE:time#rrggbb[:legend]] "
249 "[LINE{1|2|3}:vname[#rrggbb[:legend]]] "
250 "[AREA:vname[#rrggbb[:legend]]] " "[STACK:vname[#rrggbb[:legend]]]";
252 static PyObject *PyRRD_graph(
253 PyObject UNUSED(*self),
254 PyObject * args)
255 {
256 PyObject *r;
257 char **argv, **calcpr;
258 int argc, xsize, ysize, i;
259 double ymin, ymax;
261 if (create_args("graph", args, &argc, &argv) < 0)
262 return NULL;
264 if (rrd_graph(argc, argv, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) ==
265 -1) {
266 PyErr_SetString(ErrorObject, rrd_get_error());
267 rrd_clear_error();
268 r = NULL;
269 } else {
270 r = PyTuple_New(3);
272 PyTuple_SET_ITEM(r, 0, PyInt_FromLong((long) xsize));
273 PyTuple_SET_ITEM(r, 1, PyInt_FromLong((long) ysize));
275 if (calcpr) {
276 PyObject *e, *t;
278 e = PyList_New(0);
279 PyTuple_SET_ITEM(r, 2, e);
281 for (i = 0; calcpr[i]; i++) {
282 t = PyString_FromString(calcpr[i]);
283 PyList_Append(e, t);
284 Py_DECREF(t);
285 rrd_freemem(calcpr[i]);
286 }
287 rrd_freemem(calcpr);
288 } else {
289 Py_INCREF(Py_None);
290 PyTuple_SET_ITEM(r, 2, Py_None);
291 }
292 }
294 destroy_args(&argv);
295 return r;
296 }
298 static char PyRRD_tune__doc__[] =
299 "tune(args...): Modify some basic properties of a Round Robin Database\n"
300 " tune filename [--heartbeat|-h ds-name:heartbeat] "
301 "[--minimum|-i ds-name:min] [--maximum|-a ds-name:max] "
302 "[--data-source-type|-d ds-name:DST] [--data-source-rename|-r old-name:new-name]";
304 static PyObject *PyRRD_tune(
305 PyObject UNUSED(*self),
306 PyObject * args)
307 {
308 PyObject *r;
309 char **argv;
310 int argc;
312 if (create_args("tune", args, &argc, &argv) < 0)
313 return NULL;
315 if (rrd_tune(argc, argv) == -1) {
316 PyErr_SetString(ErrorObject, rrd_get_error());
317 rrd_clear_error();
318 r = NULL;
319 } else {
320 Py_INCREF(Py_None);
321 r = Py_None;
322 }
324 destroy_args(&argv);
325 return r;
326 }
328 static char PyRRD_first__doc__[] =
329 "first(filename): Return the timestamp of the first data sample in an RRD";
331 static PyObject *PyRRD_first(
332 PyObject UNUSED(*self),
333 PyObject * args)
334 {
335 PyObject *r;
336 int argc, ts;
337 char **argv;
339 if (create_args("first", args, &argc, &argv) < 0)
340 return NULL;
342 if ((ts = rrd_first(argc, argv)) == -1) {
343 PyErr_SetString(ErrorObject, rrd_get_error());
344 rrd_clear_error();
345 r = NULL;
346 } else
347 r = PyInt_FromLong((long) ts);
349 destroy_args(&argv);
350 return r;
351 }
353 static char PyRRD_last__doc__[] =
354 "last(filename): Return the timestamp of the last data sample in an RRD";
356 static PyObject *PyRRD_last(
357 PyObject UNUSED(*self),
358 PyObject * args)
359 {
360 PyObject *r;
361 int argc, ts;
362 char **argv;
364 if (create_args("last", args, &argc, &argv) < 0)
365 return NULL;
367 if ((ts = rrd_last(argc, argv)) == -1) {
368 PyErr_SetString(ErrorObject, rrd_get_error());
369 rrd_clear_error();
370 r = NULL;
371 } else
372 r = PyInt_FromLong((long) ts);
374 destroy_args(&argv);
375 return r;
376 }
378 static char PyRRD_resize__doc__[] =
379 "resize(args...): alters the size of an RRA.\n"
380 " resize filename rra-num GROW|SHRINK rows";
382 static PyObject *PyRRD_resize(
383 PyObject UNUSED(*self),
384 PyObject * args)
385 {
386 PyObject *r;
387 char **argv;
388 int argc, ts;
390 if (create_args("resize", args, &argc, &argv) < 0)
391 return NULL;
393 if ((ts = rrd_resize(argc, argv)) == -1) {
394 PyErr_SetString(ErrorObject, rrd_get_error());
395 rrd_clear_error();
396 r = NULL;
397 } else {
398 Py_INCREF(Py_None);
399 r = Py_None;
400 }
402 destroy_args(&argv);
403 return r;
404 }
406 static PyObject *PyDict_FromInfo(
407 rrd_info_t *data)
408 {
409 PyObject *r;
411 r = PyDict_New();
412 while (data) {
413 PyObject *val = NULL;
415 switch (data->type) {
416 case RD_I_VAL:
417 val = isnan(data->value.u_val)
418 ? (Py_INCREF(Py_None), Py_None)
419 : PyFloat_FromDouble(data->value.u_val);
420 break;
421 case RD_I_CNT:
422 val = PyLong_FromUnsignedLong(data->value.u_cnt);
423 break;
424 case RD_I_INT:
425 val = PyLong_FromLong(data->value.u_int);
426 break;
427 case RD_I_STR:
428 val = PyString_FromString(data->value.u_str);
429 break;
430 case RD_I_BLO:
431 val =
432 PyString_FromStringAndSize((char *) data->value.u_blo.ptr,
433 data->value.u_blo.size);
434 break;
435 }
436 if (val) {
437 PyDict_SetItemString(r, data->key, val);
438 }
439 data = data->next;
440 }
441 return r;
442 }
444 static char PyRRD_info__doc__[] =
445 "info(filename): extract header information from an rrd";
447 static PyObject *PyRRD_info(
448 PyObject UNUSED(*self),
449 PyObject * args)
450 {
451 PyObject *r;
452 int argc;
453 char **argv;
454 rrd_info_t *data;
456 if (create_args("info", args, &argc, &argv) < 0)
457 return NULL;
459 if ((data = rrd_info(argc, argv)) == NULL) {
460 PyErr_SetString(ErrorObject, rrd_get_error());
461 rrd_clear_error();
462 return NULL;
463 }
464 r = PyDict_FromInfo(data);
465 rrd_info_free(data);
466 return r;
467 }
469 static char PyRRD_graphv__doc__[] =
470 "graphv is called in the same manner as graph";
472 static PyObject *PyRRD_graphv(
473 PyObject UNUSED(*self),
474 PyObject * args)
475 {
476 PyObject *r;
477 int argc;
478 char **argv;
479 rrd_info_t *data;
481 if (create_args("graphv", args, &argc, &argv) < 0)
482 return NULL;
484 if ((data = rrd_graph_v(argc, argv)) == NULL) {
485 PyErr_SetString(ErrorObject, rrd_get_error());
486 rrd_clear_error();
487 return NULL;
488 }
489 r = PyDict_FromInfo(data);
490 rrd_info_free(data);
491 return r;
492 }
494 static char PyRRD_updatev__doc__[] =
495 "updatev is called in the same manner as update";
497 static PyObject *PyRRD_updatev(
498 PyObject UNUSED(*self),
499 PyObject * args)
500 {
501 PyObject *r;
502 int argc;
503 char **argv;
504 rrd_info_t *data;
506 if (create_args("updatev", args, &argc, &argv) < 0)
507 return NULL;
509 if ((data = rrd_update_v(argc, argv)) == NULL) {
510 PyErr_SetString(ErrorObject, rrd_get_error());
511 rrd_clear_error();
512 return NULL;
513 }
514 r = PyDict_FromInfo(data);
515 rrd_info_free(data);
516 return r;
517 }
519 /* List of methods defined in the module */
520 #define meth(name, func, doc) {name, (PyCFunction)func, METH_VARARGS, doc}
522 static PyMethodDef _rrdtool_methods[] = {
523 meth("create", PyRRD_create, PyRRD_create__doc__),
524 meth("update", PyRRD_update, PyRRD_update__doc__),
525 meth("fetch", PyRRD_fetch, PyRRD_fetch__doc__),
526 meth("graph", PyRRD_graph, PyRRD_graph__doc__),
527 meth("tune", PyRRD_tune, PyRRD_tune__doc__),
528 meth("first", PyRRD_first, PyRRD_first__doc__),
529 meth("last", PyRRD_last, PyRRD_last__doc__),
530 meth("resize", PyRRD_resize, PyRRD_resize__doc__),
531 meth("info", PyRRD_info, PyRRD_info__doc__),
532 meth("graphv", PyRRD_graphv, PyRRD_graphv__doc__),
533 meth("updatev", PyRRD_updatev, PyRRD_updatev__doc__),
534 {NULL, NULL, 0, NULL}
535 };
537 #define SET_INTCONSTANT(dict, value) \
538 t = PyInt_FromLong((long)value); \
539 PyDict_SetItemString(dict, #value, t); \
540 Py_DECREF(t);
541 #define SET_STRCONSTANT(dict, value) \
542 t = PyString_FromString(value); \
543 PyDict_SetItemString(dict, #value, t); \
544 Py_DECREF(t);
546 /* Initialization function for the module */
547 void initrrdtool(
548 void)
549 {
550 PyObject *m, *d, *t;
552 /* Create the module and add the functions */
553 m = Py_InitModule("rrdtool", _rrdtool_methods);
555 /* Add some symbolic constants to the module */
556 d = PyModule_GetDict(m);
558 SET_STRCONSTANT(d, __version__);
559 ErrorObject = PyErr_NewException("rrdtool.error", NULL, NULL);
560 PyDict_SetItemString(d, "error", ErrorObject);
562 /* Check for errors */
563 if (PyErr_Occurred())
564 Py_FatalError("can't initialize the rrdtool module");
565 }
567 /*
568 * $Id: _rrdtoolmodule.c,v 1.14 2003/02/22 07:41:19 perky Exp $
569 * ex: ts=8 sts=4 et
570 */