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 "rrd.h"
44 #include "rrd_extra.h"
46 static PyObject *ErrorObject;
47 extern int optind;
48 extern int opterr;
50 /* forward declaration to keep compiler happy */
51 void initrrdtool(
52 void);
54 static int create_args(
55 char *command,
56 PyObject * args,
57 int *argc,
58 char ***argv)
59 {
60 PyObject *o;
61 int size, i;
63 size = PyTuple_Size(args);
64 *argv = PyMem_New(char *,
65 size + 1);
67 if (*argv == NULL)
68 return -1;
70 for (i = 0; i < size; i++) {
71 o = PyTuple_GET_ITEM(args, i);
72 if (PyString_Check(o))
73 (*argv)[i + 1] = PyString_AS_STRING(o);
74 else {
75 PyMem_Del(*argv);
76 PyErr_Format(PyExc_TypeError, "argument %d must be string", i);
77 return -1;
78 }
79 }
80 (*argv)[0] = command;
81 *argc = size + 1;
83 /* reset getopt state */
84 opterr = optind = 0;
86 return 0;
87 }
89 static void destroy_args(
90 char ***argv)
91 {
92 PyMem_Del(*argv);
93 *argv = NULL;
94 }
96 static char PyRRD_create__doc__[] =
97 "create(args..): Set up a new Round Robin Database\n\
98 create filename [--start|-b start time] \
99 [--step|-s step] [DS:ds-name:DST:heartbeat:min:max] \
100 [RRA:CF:xff:steps:rows]";
102 static PyObject *PyRRD_create(
103 PyObject UNUSED(*self),
104 PyObject * args)
105 {
106 PyObject *r;
107 char **argv;
108 int argc;
110 if (create_args("create", args, &argc, &argv) < 0)
111 return NULL;
113 if (rrd_create(argc, argv) == -1) {
114 PyErr_SetString(ErrorObject, rrd_get_error());
115 rrd_clear_error();
116 r = NULL;
117 } else {
118 Py_INCREF(Py_None);
119 r = Py_None;
120 }
122 destroy_args(&argv);
123 return r;
124 }
126 static char PyRRD_update__doc__[] =
127 "update(args..): Store a new set of values into the rrd\n"
128 " update filename [--template|-t ds-name[:ds-name]...] "
129 "N|timestamp:value[:value...] [timestamp:value[:value...] ...]";
131 static PyObject *PyRRD_update(
132 PyObject UNUSED(*self),
133 PyObject * args)
134 {
135 PyObject *r;
136 char **argv;
137 int argc;
139 if (create_args("update", args, &argc, &argv) < 0)
140 return NULL;
142 if (rrd_update(argc, argv) == -1) {
143 PyErr_SetString(ErrorObject, rrd_get_error());
144 rrd_clear_error();
145 r = NULL;
146 } else {
147 Py_INCREF(Py_None);
148 r = Py_None;
149 }
151 destroy_args(&argv);
152 return r;
153 }
155 static char PyRRD_fetch__doc__[] =
156 "fetch(args..): fetch data from an rrd.\n"
157 " fetch filename CF [--resolution|-r resolution] "
158 "[--start|-s start] [--end|-e end]";
160 static PyObject *PyRRD_fetch(
161 PyObject UNUSED(*self),
162 PyObject * args)
163 {
164 PyObject *r;
165 rrd_value_t *data, *datai;
166 unsigned long step, ds_cnt;
167 time_t start, end;
168 int argc;
169 char **argv, **ds_namv;
171 if (create_args("fetch", args, &argc, &argv) < 0)
172 return NULL;
174 if (rrd_fetch(argc, argv, &start, &end, &step,
175 &ds_cnt, &ds_namv, &data) == -1) {
176 PyErr_SetString(ErrorObject, rrd_get_error());
177 rrd_clear_error();
178 r = NULL;
179 } else {
180 /* Return :
181 ((start, end, step), (name1, name2, ...), [(data1, data2, ..), ...]) */
182 PyObject *range_tup, *dsnam_tup, *data_list, *t;
183 unsigned long i, j, row;
184 rrd_value_t dv;
186 row = ((end - start) / step + 1);
188 r = PyTuple_New(3);
189 range_tup = PyTuple_New(3);
190 dsnam_tup = PyTuple_New(ds_cnt);
191 data_list = PyList_New(row);
192 PyTuple_SET_ITEM(r, 0, range_tup);
193 PyTuple_SET_ITEM(r, 1, dsnam_tup);
194 PyTuple_SET_ITEM(r, 2, data_list);
196 datai = data;
198 PyTuple_SET_ITEM(range_tup, 0, PyInt_FromLong((long) start));
199 PyTuple_SET_ITEM(range_tup, 1, PyInt_FromLong((long) end));
200 PyTuple_SET_ITEM(range_tup, 2, PyInt_FromLong((long) step));
202 for (i = 0; i < ds_cnt; i++)
203 PyTuple_SET_ITEM(dsnam_tup, i, PyString_FromString(ds_namv[i]));
205 for (i = 0; i < row; i++) {
206 t = PyTuple_New(ds_cnt);
207 PyList_SET_ITEM(data_list, i, t);
209 for (j = 0; j < ds_cnt; j++) {
210 dv = *(datai++);
211 if (isnan(dv)) {
212 PyTuple_SET_ITEM(t, j, Py_None);
213 Py_INCREF(Py_None);
214 } else {
215 PyTuple_SET_ITEM(t, j, PyFloat_FromDouble((double) dv));
216 }
217 }
218 }
220 for (i = 0; i < ds_cnt; i++)
221 free(ds_namv[i]);
222 free(ds_namv); /* rrdtool don't use PyMem_Malloc :) */
223 free(data);
224 }
226 destroy_args(&argv);
227 return r;
228 }
230 static char PyRRD_graph__doc__[] =
231 "graph(args..): Create a graph based on data from one or several RRD\n"
232 " graph filename [-s|--start seconds] "
233 "[-e|--end seconds] [-x|--x-grid x-axis grid and label] "
234 "[-y|--y-grid y-axis grid and label] [--alt-y-grid] [--alt-y-mrtg] "
235 "[--alt-autoscale] [--alt-autoscale-max] [--units-exponent] value "
236 "[-v|--vertical-label text] [-w|--width pixels] [-h|--height pixels] "
237 "[-i|--interlaced] "
238 "[-f|--imginfo formatstring] [-a|--imgformat GIF|PNG|GD] "
239 "[-B|--background value] [-O|--overlay value] "
240 "[-U|--unit value] [-z|--lazy] [-o|--logarithmic] "
241 "[-u|--upper-limit value] [-l|--lower-limit value] "
242 "[-g|--no-legend] [-r|--rigid] [--step value] "
243 "[-b|--base value] [-c|--color COLORTAG#rrggbb] "
244 "[-t|--title title] [DEF:vname=rrd:ds-name:CF] "
245 "[CDEF:vname=rpn-expression] [PRINT:vname:CF:format] "
246 "[GPRINT:vname:CF:format] [COMMENT:text] "
247 "[HRULE:value#rrggbb[:legend]] [VRULE:time#rrggbb[:legend]] "
248 "[LINE{1|2|3}:vname[#rrggbb[:legend]]] "
249 "[AREA:vname[#rrggbb[:legend]]] " "[STACK:vname[#rrggbb[:legend]]]";
251 static PyObject *PyRRD_graph(
252 PyObject UNUSED(*self),
253 PyObject * args)
254 {
255 PyObject *r;
256 char **argv, **calcpr;
257 int argc, xsize, ysize, i;
258 double ymin, ymax;
260 if (create_args("graph", args, &argc, &argv) < 0)
261 return NULL;
263 if (rrd_graph(argc, argv, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) ==
264 -1) {
265 PyErr_SetString(ErrorObject, rrd_get_error());
266 rrd_clear_error();
267 r = NULL;
268 } else {
269 r = PyTuple_New(3);
271 PyTuple_SET_ITEM(r, 0, PyInt_FromLong((long) xsize));
272 PyTuple_SET_ITEM(r, 1, PyInt_FromLong((long) ysize));
274 if (calcpr) {
275 PyObject *e, *t;
277 e = PyList_New(0);
278 PyTuple_SET_ITEM(r, 2, e);
280 for (i = 0; calcpr[i]; i++) {
281 t = PyString_FromString(calcpr[i]);
282 PyList_Append(e, t);
283 Py_DECREF(t);
284 free(calcpr[i]);
285 }
286 free(calcpr);
287 } else {
288 Py_INCREF(Py_None);
289 PyTuple_SET_ITEM(r, 2, Py_None);
290 }
291 }
293 destroy_args(&argv);
294 return r;
295 }
297 static char PyRRD_tune__doc__[] =
298 "tune(args...): Modify some basic properties of a Round Robin Database\n"
299 " tune filename [--heartbeat|-h ds-name:heartbeat] "
300 "[--minimum|-i ds-name:min] [--maximum|-a ds-name:max] "
301 "[--data-source-type|-d ds-name:DST] [--data-source-rename|-r old-name:new-name]";
303 static PyObject *PyRRD_tune(
304 PyObject UNUSED(*self),
305 PyObject * args)
306 {
307 PyObject *r;
308 char **argv;
309 int argc;
311 if (create_args("tune", args, &argc, &argv) < 0)
312 return NULL;
314 if (rrd_tune(argc, argv) == -1) {
315 PyErr_SetString(ErrorObject, rrd_get_error());
316 rrd_clear_error();
317 r = NULL;
318 } else {
319 Py_INCREF(Py_None);
320 r = Py_None;
321 }
323 destroy_args(&argv);
324 return r;
325 }
327 static char PyRRD_first__doc__[] =
328 "first(filename): Return the timestamp of the first data sample in an RRD";
330 static PyObject *PyRRD_first(
331 PyObject UNUSED(*self),
332 PyObject * args)
333 {
334 PyObject *r;
335 int argc, ts;
336 char **argv;
338 if (create_args("first", args, &argc, &argv) < 0)
339 return NULL;
341 if ((ts = rrd_first(argc, argv)) == -1) {
342 PyErr_SetString(ErrorObject, rrd_get_error());
343 rrd_clear_error();
344 r = NULL;
345 } else
346 r = PyInt_FromLong((long) ts);
348 destroy_args(&argv);
349 return r;
350 }
352 static char PyRRD_last__doc__[] =
353 "last(filename): Return the timestamp of the last data sample in an RRD";
355 static PyObject *PyRRD_last(
356 PyObject UNUSED(*self),
357 PyObject * args)
358 {
359 PyObject *r;
360 int argc, ts;
361 char **argv;
363 if (create_args("last", args, &argc, &argv) < 0)
364 return NULL;
366 if ((ts = rrd_last(argc, argv)) == -1) {
367 PyErr_SetString(ErrorObject, rrd_get_error());
368 rrd_clear_error();
369 r = NULL;
370 } else
371 r = PyInt_FromLong((long) ts);
373 destroy_args(&argv);
374 return r;
375 }
377 static char PyRRD_resize__doc__[] =
378 "resize(args...): alters the size of an RRA.\n"
379 " resize filename rra-num GROW|SHRINK rows";
381 static PyObject *PyRRD_resize(
382 PyObject UNUSED(*self),
383 PyObject * args)
384 {
385 PyObject *r;
386 char **argv;
387 int argc, ts;
389 if (create_args("resize", args, &argc, &argv) < 0)
390 return NULL;
392 if ((ts = rrd_resize(argc, argv)) == -1) {
393 PyErr_SetString(ErrorObject, rrd_get_error());
394 rrd_clear_error();
395 r = NULL;
396 } else {
397 Py_INCREF(Py_None);
398 r = Py_None;
399 }
401 destroy_args(&argv);
402 return r;
403 }
405 static char PyRRD_info__doc__[] =
406 "info(filename): extract header information from an rrd";
408 static PyObject *PyRRD_info(
409 PyObject UNUSED(*self),
410 PyObject * args)
411 {
412 PyObject *r, *t, *ds;
413 rrd_t rrd;
414 char *filename;
415 unsigned long i, j;
417 if (!PyArg_ParseTuple(args, "s:info", &filename))
418 return NULL;
420 if (!rrd_open(filename, &rrd, RRD_READONLY) == -1) {
421 PyErr_SetString(ErrorObject, rrd_get_error());
422 rrd_clear_error();
423 return NULL;
424 }
426 #define DICTSET_STR(dict, name, value) \
427 t = PyString_FromString(value); \
428 PyDict_SetItemString(dict, name, t); \
429 Py_DECREF(t);
431 #define DICTSET_CNT(dict, name, value) \
432 t = PyInt_FromLong((long)value); \
433 PyDict_SetItemString(dict, name, t); \
434 Py_DECREF(t);
436 #define DICTSET_VAL(dict, name, value) \
437 t = isnan(value) ? (Py_INCREF(Py_None), Py_None) : \
438 PyFloat_FromDouble((double)value); \
439 PyDict_SetItemString(dict, name, t); \
440 Py_DECREF(t);
442 r = PyDict_New();
444 DICTSET_STR(r, "filename", filename);
445 DICTSET_STR(r, "rrd_version", rrd.stat_head->version);
446 DICTSET_CNT(r, "step", rrd.stat_head->pdp_step);
447 DICTSET_CNT(r, "last_update", rrd.live_head->last_up);
449 ds = PyDict_New();
450 PyDict_SetItemString(r, "ds", ds);
451 Py_DECREF(ds);
453 for (i = 0; i < rrd.stat_head->ds_cnt; i++) {
454 PyObject *d;
456 d = PyDict_New();
457 PyDict_SetItemString(ds, rrd.ds_def[i].ds_nam, d);
458 Py_DECREF(d);
460 DICTSET_STR(d, "ds_name", rrd.ds_def[i].ds_nam);
461 DICTSET_STR(d, "type", rrd.ds_def[i].dst);
462 DICTSET_CNT(d, "minimal_heartbeat",
463 rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt);
464 DICTSET_VAL(d, "min", rrd.ds_def[i].par[DS_min_val].u_val);
465 DICTSET_VAL(d, "max", rrd.ds_def[i].par[DS_max_val].u_val);
466 DICTSET_STR(d, "last_ds", rrd.pdp_prep[i].last_ds);
467 DICTSET_VAL(d, "value", rrd.pdp_prep[i].scratch[PDP_val].u_val);
468 DICTSET_CNT(d, "unknown_sec",
469 rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt);
470 }
472 ds = PyList_New(rrd.stat_head->rra_cnt);
473 PyDict_SetItemString(r, "rra", ds);
474 Py_DECREF(ds);
476 for (i = 0; i < rrd.stat_head->rra_cnt; i++) {
477 PyObject *d, *cdp;
479 d = PyDict_New();
480 PyList_SET_ITEM(ds, i, d);
482 DICTSET_STR(d, "cf", rrd.rra_def[i].cf_nam);
483 DICTSET_CNT(d, "rows", rrd.rra_def[i].row_cnt);
484 DICTSET_CNT(d, "pdp_per_row", rrd.rra_def[i].pdp_cnt);
485 DICTSET_VAL(d, "xff", rrd.rra_def[i].par[RRA_cdp_xff_val].u_val);
487 cdp = PyList_New(rrd.stat_head->ds_cnt);
488 PyDict_SetItemString(d, "cdp_prep", cdp);
489 Py_DECREF(cdp);
491 for (j = 0; j < rrd.stat_head->ds_cnt; j++) {
492 PyObject *cdd;
494 cdd = PyDict_New();
495 PyList_SET_ITEM(cdp, j, cdd);
497 DICTSET_VAL(cdd, "value",
498 rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
499 j].scratch[CDP_val].u_val);
500 DICTSET_CNT(cdd, "unknown_datapoints",
501 rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
502 j].scratch[CDP_unkn_pdp_cnt].u_cnt);
503 }
504 }
506 rrd_free(&rrd);
508 return r;
509 }
511 /* List of methods defined in the module */
512 #define meth(name, func, doc) {name, (PyCFunction)func, METH_VARARGS, doc}
514 static PyMethodDef _rrdtool_methods[] = {
515 meth("create", PyRRD_create, PyRRD_create__doc__),
516 meth("update", PyRRD_update, PyRRD_update__doc__),
517 meth("fetch", PyRRD_fetch, PyRRD_fetch__doc__),
518 meth("graph", PyRRD_graph, PyRRD_graph__doc__),
519 meth("tune", PyRRD_tune, PyRRD_tune__doc__),
520 meth("first", PyRRD_first, PyRRD_first__doc__),
521 meth("last", PyRRD_last, PyRRD_last__doc__),
522 meth("resize", PyRRD_resize, PyRRD_resize__doc__),
523 meth("info", PyRRD_info, PyRRD_info__doc__),
524 {NULL, NULL, 0, NULL}
525 };
527 #define SET_INTCONSTANT(dict, value) \
528 t = PyInt_FromLong((long)value); \
529 PyDict_SetItemString(dict, #value, t); \
530 Py_DECREF(t);
531 #define SET_STRCONSTANT(dict, value) \
532 t = PyString_FromString(value); \
533 PyDict_SetItemString(dict, #value, t); \
534 Py_DECREF(t);
536 /* Initialization function for the module */
537 void initrrdtool(
538 void)
539 {
540 PyObject *m, *d, *t;
542 /* Create the module and add the functions */
543 m = Py_InitModule("rrdtool", _rrdtool_methods);
545 /* Add some symbolic constants to the module */
546 d = PyModule_GetDict(m);
548 SET_STRCONSTANT(d, __version__);
549 ErrorObject = PyErr_NewException("rrdtool.error", NULL, NULL);
550 PyDict_SetItemString(d, "error", ErrorObject);
552 /* Check for errors */
553 if (PyErr_Occurred())
554 Py_FatalError("can't initialize the rrdtool module");
555 }
557 /*
558 * $Id: _rrdtoolmodule.c,v 1.14 2003/02/22 07:41:19 perky Exp $
559 * ex: ts=8 sts=4 et
560 */