]>
Commit | Line | Data |
---|---|---|
ce6564c2 | 1 | /* |
618986c4 CJ |
2 | * rrdtool-py3k, rrdtool bindings for Python 3. |
3 | * Based on the rrdtool Python bindings for Python 2 from | |
4 | * Hye-Shik Chang <perky@fallin.lv>. | |
ce6564c2 CJ |
5 | * |
6 | * Copyright 2012 Christian Jurk <commx@commx.ws> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
275aa95d CJ |
9 | * it under the terms of the GNU Lesser General Public License as |
10 | * published by the Free Software Foundation; either version 3 of the | |
11 | * License, or (at your option) any later version. | |
ce6564c2 CJ |
12 | * |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
275aa95d | 18 | * You should have received a copy of the GNU Lesser General Public License |
ce6564c2 CJ |
19 | * along with this program; if not, write to the Free Software |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | |
21 | * MA 02110-1301, USA. | |
22 | * | |
ce6564c2 CJ |
23 | */ |
24 | ||
25 | #include <Python.h> | |
26 | #include <rrd.h> | |
27 | ||
06fe4e5b CJ |
28 | static const char *_version = "0.1.0"; |
29 | ||
ce6564c2 CJ |
30 | /* Exception types */ |
31 | static PyObject *rrdtool_OperationalError; | |
32 | static PyObject *rrdtool_ProgrammingError; | |
33 | ||
618986c4 CJ |
34 | static char **rrdtool_argv = NULL; |
35 | static int rrdtool_argc = 0; | |
36 | ||
37 | static void | |
38 | destroy_args(void) | |
39 | { | |
40 | PyMem_Del(rrdtool_argv); | |
41 | rrdtool_argv = NULL; | |
42 | } | |
43 | ||
44 | /* Helper function to convert Python objects into a representation that the | |
45 | * rrdtool functions can work with. | |
46 | */ | |
47 | static int | |
48 | convert_args(char *command, PyObject *args) | |
49 | { | |
50 | PyObject *o, *lo; | |
51 | int i, j, args_count, argv_count, element_count; | |
52 | ||
53 | args_count = PyTuple_Size(args); | |
54 | element_count = 0; | |
55 | for (i = 0; i < args_count; i++) | |
56 | { | |
57 | o = PyTuple_GET_ITEM(args, i); | |
58 | if (PyUnicode_Check(o) || PyBytes_Check(o)) | |
59 | element_count++; | |
60 | else if (PyList_CheckExact(o)) | |
61 | element_count += PyList_Size(o); | |
62 | else { | |
63 | PyErr_Format(rrdtool_ProgrammingError, | |
64 | "Argument %d must be string, bytes or list of " \ | |
65 | "string/bytes", i); | |
66 | return -1; | |
67 | } | |
68 | } | |
69 | ||
70 | rrdtool_argv = PyMem_New(char *, element_count + 1); | |
71 | ||
72 | if (rrdtool_argv == NULL) | |
73 | return -1; | |
74 | ||
75 | argv_count = 0; | |
76 | for (i = 0; i < args_count; i++) { | |
77 | o = PyTuple_GET_ITEM(args, i); | |
78 | ||
79 | if (PyUnicode_Check(o)) | |
80 | rrdtool_argv[++argv_count] = PyBytes_AsString( | |
81 | PyUnicode_AsUTF8String(o)); | |
82 | else if (PyBytes_Check(o)) | |
83 | rrdtool_argv[++argv_count] = PyBytes_AS_STRING(o); | |
84 | else if (PyList_CheckExact(o)) { | |
85 | for (j = 0; j < PyList_Size(o); j++) { | |
86 | lo = PyList_GetItem(o, j); | |
87 | if (PyUnicode_Check(lo)) | |
88 | rrdtool_argv[++argv_count] = PyBytes_AS_STRING( | |
89 | PyUnicode_AsUTF8String(lo)); | |
90 | else if (PyBytes_Check(lo)) | |
91 | rrdtool_argv[++argv_count] = PyBytes_AS_STRING(lo); | |
92 | else { | |
93 | PyMem_Del(rrdtool_argv); | |
94 | PyErr_Format(rrdtool_ProgrammingError, | |
95 | "Element %d in argument %d must be string", j, i); | |
96 | return -1; | |
97 | } | |
98 | } | |
99 | } else { | |
100 | PyMem_Del(rrdtool_argv); | |
101 | PyErr_Format(rrdtool_ProgrammingError, | |
102 | "Argument %d must be string or list of strings", i); | |
103 | return -1; | |
104 | } | |
105 | } | |
106 | ||
107 | rrdtool_argv[0] = command; | |
108 | rrdtool_argc = element_count + 1; | |
109 | ||
110 | return 0; | |
111 | } | |
112 | ||
06fe4e5b CJ |
113 | static PyObject * |
114 | _rrdtool_util_info2dict(const rrd_info_t *data) | |
115 | { | |
b4570f2a | 116 | PyObject *dict, *val; |
06fe4e5b CJ |
117 | |
118 | dict = PyDict_New(); | |
119 | ||
120 | while (data) { | |
b4570f2a CJ |
121 | val = NULL; |
122 | ||
06fe4e5b CJ |
123 | switch (data->type) { |
124 | case RD_I_VAL: | |
125 | if (isnan(data->value.u_val)) { | |
126 | Py_INCREF(Py_None); | |
127 | val = Py_None; | |
128 | } else | |
129 | PyFloat_FromDouble(data->value.u_val); | |
130 | break; | |
131 | ||
132 | case RD_I_CNT: | |
133 | val = PyLong_FromUnsignedLong(data->value.u_cnt); | |
134 | break; | |
135 | ||
136 | case RD_I_INT: | |
137 | val = PyLong_FromLong(data->value.u_int); | |
138 | break; | |
139 | ||
140 | case RD_I_STR: | |
141 | val = PyUnicode_FromString(data->value.u_str); | |
142 | break; | |
143 | ||
144 | case RD_I_BLO: | |
145 | val = PyUnicode_FromStringAndSize( | |
146 | (char *)data->value.u_blo.ptr, data->value.u_blo.size); | |
147 | break; | |
148 | default: | |
06fe4e5b CJ |
149 | break; |
150 | } | |
151 | ||
b4570f2a | 152 | if (val != NULL) { |
06fe4e5b CJ |
153 | PyDict_SetItemString(dict, data->key, val); |
154 | Py_DECREF(val); | |
155 | } | |
156 | ||
157 | data = data->next; | |
158 | } | |
159 | ||
160 | return dict; | |
161 | } | |
162 | ||
618986c4 CJ |
163 | static char _rrdtool_create__doc__[] = "Create a new Round Robin Database.\n\n\ |
164 | Usage: create(args...)\n\ | |
165 | Arguments:\n\n\ | |
166 | filename\n\ | |
167 | [--start|-b start time]\n\ | |
168 | [--step|-s step]\n\ | |
169 | [DS:ds-name:DST:heartbeat:min:max]\n\ | |
170 | [RRA:CF:xff:steps:rows]\n\n\ | |
171 | Full documentation can be found at:\n\ | |
172 | http://oss.oetiker.ch/rrdtool/doc/rrdcreate.en.html"; | |
173 | ||
ce6564c2 CJ |
174 | static PyObject * |
175 | _rrdtool_create(PyObject *self, PyObject *args) | |
176 | { | |
618986c4 | 177 | PyObject *ret; |
ce6564c2 | 178 | |
618986c4 CJ |
179 | if (convert_args("create", args) == -1) |
180 | return NULL; | |
ce6564c2 | 181 | |
618986c4 | 182 | if (rrd_create(rrdtool_argc, rrdtool_argv) == -1) { |
ce6564c2 CJ |
183 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); |
184 | rrd_clear_error(); | |
618986c4 CJ |
185 | ret = NULL; |
186 | } else { | |
187 | Py_INCREF(Py_None); | |
188 | ret = Py_None; | |
189 | } | |
190 | ||
191 | destroy_args(); | |
192 | return ret; | |
193 | } | |
194 | ||
195 | static char _rrdtool_update__doc__[] = "Store a new set of values into\ | |
196 | the RRD.\n\n\ | |
197 | Usage: update(args..)\n\ | |
198 | Arguments:\n\n\ | |
199 | filename\n\ | |
200 | [--template|-t ds-name[:ds-name]...]\n\ | |
201 | N|timestamp:value[:value...]\n\ | |
202 | [timestamp:value[:value...] ...]\n\n\ | |
203 | Full documentation can be found at:\n\ | |
204 | http://oss.oetiker.ch/rrdtool/doc/rrdupdate.en.html"; | |
205 | ||
206 | static PyObject * | |
207 | _rrdtool_update(PyObject *self, PyObject *args) | |
208 | { | |
209 | PyObject *ret; | |
210 | ||
211 | if (convert_args("update", args) == -1) | |
212 | return NULL; | |
213 | ||
214 | if (rrd_update(rrdtool_argc, rrdtool_argv) == -1) { | |
215 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |
216 | rrd_clear_error(); | |
217 | ret = NULL; | |
218 | } else { | |
219 | Py_INCREF(Py_None); | |
220 | ret = Py_None; | |
221 | } | |
222 | ||
223 | destroy_args(); | |
224 | return ret; | |
225 | } | |
226 | ||
06fe4e5b CJ |
227 | static char _rrdtool_updatev__doc__[] = "Store a new set of values into "\ |
228 | "the Round Robin Database and return an info dictionary.\n\n\ | |
229 | This function works in the same manner as 'update', but will return an\n\ | |
230 | info dictionary instead of None."; | |
231 | ||
232 | static PyObject * | |
233 | _rrdtool_updatev(PyObject *self, PyObject *args) | |
234 | { | |
235 | PyObject *ret; | |
236 | rrd_info_t *data; | |
237 | ||
238 | if (convert_args("updatev", args) == -1) | |
239 | return NULL; | |
240 | ||
241 | if ((data = rrd_update_v(rrdtool_argc, rrdtool_argv)) == NULL) { | |
242 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |
243 | rrd_clear_error(); | |
244 | ret = NULL; | |
245 | } else { | |
246 | ret = _rrdtool_util_info2dict(data); | |
247 | rrd_info_free(data); | |
248 | } | |
249 | ||
250 | destroy_args(); | |
251 | return ret; | |
252 | } | |
253 | ||
618986c4 CJ |
254 | static char _rrdtool_fetch__doc__[] = "Fetch data from an RRD.\n\n\ |
255 | Usage: fetch(args..)\n\ | |
256 | Arguments:\n\n\ | |
257 | filename\n\ | |
258 | CF\n\ | |
259 | [--resolution|-r resolution]\n\ | |
260 | [--start|-s start]\n\ | |
261 | [--end|-e end]\n\n\ | |
262 | Full documentation can be found at:\n\ | |
263 | http://oss.oetiker.ch/rrdtool/doc/rrdfetch.en.html"; | |
264 | ||
265 | static PyObject * | |
266 | _rrdtool_fetch(PyObject *self, PyObject *args) | |
267 | { | |
268 | PyObject *ret, *range_tup, *dsnam_tup, *data_list, *t; | |
269 | rrd_value_t *data, *datai, dv; | |
270 | unsigned long step, ds_cnt, i, j, row; | |
271 | time_t start, end; | |
272 | char **ds_namv; | |
273 | ||
274 | if (convert_args("fetch", args) == -1) | |
275 | return NULL; | |
276 | ||
277 | if (rrd_fetch(rrdtool_argc, rrdtool_argv, &start, &end, &step, &ds_cnt, | |
278 | &ds_namv, &data) == -1) { | |
279 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |
280 | rrd_clear_error(); | |
281 | ret = NULL; | |
282 | } else { | |
283 | row = (end - start) / step; | |
284 | ret = PyTuple_New(3); | |
285 | range_tup = PyTuple_New(3); | |
286 | dsnam_tup = PyTuple_New(ds_cnt); | |
287 | data_list = PyList_New(row); | |
288 | ||
289 | PyTuple_SET_ITEM(ret, 0, range_tup); | |
290 | PyTuple_SET_ITEM(ret, 1, dsnam_tup); | |
291 | PyTuple_SET_ITEM(ret, 2, data_list); | |
292 | ||
293 | datai = data; | |
294 | ||
295 | PyTuple_SET_ITEM(range_tup, 0, PyLong_FromLong((long)start)); | |
296 | PyTuple_SET_ITEM(range_tup, 1, PyLong_FromLong((long)end)); | |
297 | PyTuple_SET_ITEM(range_tup, 2, PyLong_FromLong((long)step)); | |
298 | ||
299 | for (i = 0; i < ds_cnt; i++) | |
300 | PyTuple_SET_ITEM(dsnam_tup, i, PyUnicode_FromString(ds_namv[i])); | |
301 | ||
302 | for (i = 0; i < row; i++) { | |
303 | t = PyTuple_New(ds_cnt); | |
304 | PyList_SET_ITEM(data_list, i, t); | |
305 | ||
306 | for (j = 0; j < ds_cnt; j++) { | |
307 | dv = *(datai++); | |
308 | if (isnan(dv)) { | |
309 | PyTuple_SET_ITEM(t, j, Py_None); | |
310 | Py_INCREF(Py_None); | |
311 | } else | |
312 | PyTuple_SET_ITEM(t, j, PyFloat_FromDouble((double)dv)); | |
313 | } | |
314 | } | |
315 | ||
316 | for (i = 0; i < ds_cnt; i++) | |
317 | rrd_freemem(ds_namv[i]); | |
318 | ||
319 | rrd_freemem(ds_namv); | |
320 | rrd_freemem(data); | |
321 | } | |
322 | ||
323 | destroy_args(); | |
324 | return ret; | |
325 | } | |
326 | ||
06fe4e5b CJ |
327 | static char _rrdtool_flushcached__doc__[] = "Flush RRD files from memory.\n\n\ |
328 | Usage: flushcached(args..)\n\ | |
329 | Arguments:\n\n\ | |
330 | [--daemon address]\n\ | |
331 | filename\n\ | |
332 | [filename ...]\n\n\ | |
333 | Full documentation can be found at:\n\ | |
334 | http://oss.oetiker.ch/rrdtool/doc/rrdflushcached.en.html"; | |
335 | ||
336 | static PyObject * | |
337 | _rrdtool_flushcached(PyObject *self, PyObject *args) | |
338 | { | |
339 | PyObject *ret; | |
340 | ||
341 | if (convert_args("flushcached", args) == -1) | |
342 | return NULL; | |
343 | ||
344 | if (rrd_flushcached(rrdtool_argc, rrdtool_argv) != 0) { | |
345 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |
346 | rrd_clear_error(); | |
347 | ret = NULL; | |
348 | } else { | |
349 | Py_INCREF(Py_None); | |
350 | ret = Py_None; | |
351 | } | |
352 | ||
353 | destroy_args(); | |
354 | return ret; | |
355 | } | |
356 | ||
618986c4 CJ |
357 | static char _rrdtool_graph__doc__[] = "Create a graph based on one or more " \ |
358 | "RRDs.\n\n\ | |
359 | Usage: graph(args..)\n\ | |
360 | Arguments:\n\n\ | |
361 | filename | -\n\ | |
362 | [-s|--start start]\n\ | |
363 | [-e|--end end]\n\ | |
364 | [-S|--step step]\n\ | |
365 | [-t|--title string]\n\ | |
366 | [-v|--vertical-label string]\n\ | |
367 | [-w|--width pixels]\n\ | |
368 | [-h|--height pixels]\n\ | |
369 | [-j|--only-graph]\n\ | |
370 | [-D|--full-size-mode]\n\ | |
371 | [-u|--upper-limit value]\n\ | |
372 | [-l|--lower-limit value]\n\ | |
373 | [-r|--rigid]\n\ | |
374 | [-A|--alt-autoscale]\n\ | |
375 | [-J|--alt-autoscale-min]\n\ | |
376 | [-M|--alt-autoscale-max]\n\ | |
377 | [-N|--no-gridfit]\n\ | |
378 | [-x|--x-grid (GTM:GST:MTM:MST:LTM:LST:LPR:LFM|none)]\n\ | |
379 | [-y|--y-grid (grid step:label factor|none)]\n\ | |
380 | [-Y|--alt-y-grid]\n\ | |
381 | [-o|--logarithmic]\n\ | |
382 | [-X|--units-exponent value]\n\ | |
383 | [-L|--units-length value]\n\ | |
384 | [--units=si]\n\ | |
385 | [--right-axis scale:shift]\n\ | |
386 | [--right-axis-label label]\n\ | |
387 | [--right-axis-format format-string]\n\ | |
388 | [-g|--no-legend]\n\ | |
389 | [-F|--force-rules-legend]\n\ | |
390 | [--legend-position=(north|south|west|east)]\n\ | |
391 | [--legend-direction=(topdown|bottomup)]\n\ | |
392 | [-z|--lazy]\n\ | |
393 | [--daemon address]\n\ | |
394 | [-f|--imginfo printfstr]\n\ | |
395 | [-c|--color COLORTAG#rrggbb[aa]]\n\ | |
396 | [--grid-dash on:off]\n\ | |
397 | [--border width]\n\ | |
398 | [--dynamic-labels]\n\ | |
399 | [-m|--zoom factor]\n\ | |
400 | [-n|--font FONTTAG:size:[font]]\n\ | |
401 | [-R|--font-render-mode {normal,light,mono}]\n\ | |
402 | [-B|--font-smoothing-threshold size]\n\ | |
403 | [-P|--pango-markup]\n\ | |
404 | [-G|--graph-render-mode {normal,mono}]\n\ | |
405 | [-E|--slope-mode]\n\ | |
406 | [-a|--imgformat {PNG,SVG,EPS,PDF}]\n\ | |
407 | [-T|--tabwidth value]\n\ | |
408 | [-b|--base value]\n\ | |
409 | [-W|--watermark string]\n\ | |
410 | DEF:vname=rrdfile:ds-name:CF[:step=step][:start=time][:end=time]\n\ | |
411 | CDEF:vname=RPN expression\n\ | |
412 | VDEF=vname:RPN expression\n\n\ | |
413 | Full documentation can be found at:\n\ | |
414 | http://oss.oetiker.ch/rrdtool/doc/rrdgraph.en.html"; | |
415 | ||
416 | static PyObject * | |
417 | _rrdtool_graph(PyObject *self, PyObject *args, PyObject *kwargs) | |
418 | { | |
419 | PyObject *ret; | |
06fe4e5b | 420 | int xsize, ysize, i; |
618986c4 CJ |
421 | int keep_in_mem = 0; |
422 | double ymin, ymax; | |
06fe4e5b CJ |
423 | char **calcpr, *bp; |
424 | #ifdef _POSIX_C_SOURCE | |
425 | FILE *orig_stdout = stdout; | |
426 | size_t bsize; | |
427 | #endif | |
618986c4 CJ |
428 | |
429 | if (convert_args("graph", args) == -1) | |
430 | return NULL; | |
431 | ||
06fe4e5b CJ |
432 | if (rrdtool_argc >= 2 && strcmp(rrdtool_argv[1], "-") == 0) { |
433 | #ifdef _POSIX_C_SOURCE | |
618986c4 | 434 | keep_in_mem = 1; |
06fe4e5b CJ |
435 | #else |
436 | PyErr_SetString(rrdtool_ProgrammingError, | |
437 | "Output filename cannot be '-', because this platform does not "\ | |
438 | "support output buffering"); | |
439 | destroy_args(); | |
440 | return NULL; | |
441 | #endif | |
618986c4 CJ |
442 | } |
443 | ||
06fe4e5b CJ |
444 | #ifdef _POSIX_C_SOURCE |
445 | if (keep_in_mem) | |
446 | stdout = open_memstream(&bp, &bsize); | |
447 | #endif | |
448 | ||
618986c4 CJ |
449 | if (rrd_graph(rrdtool_argc, rrdtool_argv, &calcpr, &xsize, &ysize, NULL, |
450 | &ymin, &ymax) == -1) { | |
451 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |
452 | rrd_clear_error(); | |
453 | ret = NULL; | |
454 | } else { | |
455 | ret = PyTuple_New(keep_in_mem ? 4 : 3); | |
456 | ||
457 | PyTuple_SET_ITEM(ret, 0, PyLong_FromLong((long)xsize)); | |
458 | PyTuple_SET_ITEM(ret, 1, PyLong_FromLong((long)ysize)); | |
459 | ||
460 | if (calcpr) { | |
461 | PyObject *e, *t; | |
462 | ||
463 | e = PyList_New(0); | |
464 | PyTuple_SET_ITEM(ret, 2, e); | |
465 | ||
466 | for (i = 0; calcpr[i]; i++) { | |
467 | t = PyUnicode_FromString(calcpr[i]); | |
468 | PyList_Append(e, t); | |
469 | Py_DECREF(t); | |
470 | rrd_freemem(calcpr[i]); | |
471 | } | |
472 | } else { | |
473 | Py_INCREF(Py_None); | |
474 | PyTuple_SET_ITEM(ret, 2, Py_None); | |
475 | } | |
476 | ||
477 | /* feed buffered contents into a PyBytes object */ | |
478 | if (keep_in_mem) { | |
479 | PyObject *pb; | |
06fe4e5b CJ |
480 | |
481 | fflush(stdout); | |
482 | pb = PyBytes_FromStringAndSize(bp, bsize); | |
618986c4 CJ |
483 | |
484 | PyTuple_SET_ITEM(ret, 3, pb); | |
485 | } | |
486 | } | |
487 | ||
06fe4e5b CJ |
488 | if (keep_in_mem) { |
489 | fclose(stdout); | |
490 | stdout = orig_stdout; | |
491 | } | |
492 | ||
493 | destroy_args(); | |
494 | return ret; | |
495 | } | |
496 | ||
497 | static char _rrdtool_graphv__doc__[] = "Create a graph based on one or more "\ | |
498 | "RRDs and return header information.\n\n\ | |
499 | This function works in the same manner as 'graph', but will return a info\n\ | |
500 | dictionary instead of None."; | |
501 | ||
502 | static PyObject * | |
503 | _rrdtool_graphv(PyObject *self, PyObject *args) | |
504 | { | |
505 | PyObject *ret; | |
506 | rrd_info_t *data; | |
507 | ||
508 | if (convert_args("graphv", args) == -1) | |
509 | return NULL; | |
510 | ||
511 | if ((data = rrd_graph_v(rrdtool_argc, rrdtool_argv)) == NULL) { | |
512 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |
513 | rrd_clear_error(); | |
514 | ret = NULL; | |
515 | } else { | |
516 | ret = _rrdtool_util_info2dict(data); | |
517 | rrd_info_free(data); | |
518 | } | |
519 | ||
520 | destroy_args(); | |
521 | return ret; | |
522 | } | |
523 | ||
524 | static char _rrdtool_tune__doc__[] = "Modify some basic properties of a " \ | |
525 | "Round Robin Database.\n\n\ | |
526 | Usage: tune(args..)\n\ | |
527 | Arguments:\n\n\ | |
528 | filename\n\ | |
529 | [-h|--heartbeat ds-name:heartbeat]\n\ | |
530 | [-i|--minimum ds-name:min]\n\ | |
531 | [-a|--maximum ds-name:max]\n\ | |
532 | [-d|--data-source-type ds-name:DST]\n\ | |
533 | [-r|--data-source-rename old-name:new-name]\n\n\ | |
534 | Full documentation can be found at:\n\ | |
535 | http://oss.oetiker.ch/rrdtool/doc/rrdtune.en.html"; | |
536 | ||
537 | static PyObject * | |
538 | _rrdtool_tune(PyObject *self, PyObject *args) | |
539 | { | |
540 | PyObject *ret; | |
541 | ||
542 | if (convert_args("tune", args) == -1) | |
543 | return NULL; | |
544 | ||
545 | if (rrd_tune(rrdtool_argc, rrdtool_argv) == -1) { | |
546 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |
547 | rrd_clear_error(); | |
548 | ret = NULL; | |
549 | } else { | |
550 | Py_INCREF(Py_None); | |
551 | ret = Py_None; | |
552 | } | |
553 | ||
554 | destroy_args(); | |
555 | return ret; | |
556 | } | |
557 | ||
558 | static char _rrdtool_first__doc__[] = "Get the first UNIX timestamp of the "\ | |
559 | "first data sample in an Round Robin Database.\n\n\ | |
560 | Usage: first(args..)\n\ | |
561 | Arguments:\n\n\ | |
562 | filename\n\ | |
563 | [--rraindex number]\n\n\ | |
564 | Full documentation can be found at:\n\ | |
565 | http://oss.oetiker.ch/rrdtool/doc/rrdfirst.en.html"; | |
566 | ||
567 | static PyObject * | |
568 | _rrdtool_first(PyObject *self, PyObject *args) | |
569 | { | |
570 | PyObject *ret; | |
571 | int ts; | |
572 | ||
573 | if (convert_args("first", args) == -1) | |
574 | return NULL; | |
575 | ||
576 | if ((ts = rrd_first(rrdtool_argc, rrdtool_argv)) == -1) { | |
577 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |
578 | rrd_clear_error(); | |
579 | ret = NULL; | |
580 | } else | |
581 | ret = PyLong_FromLong((long)ts); | |
582 | ||
583 | destroy_args(); | |
584 | return ret; | |
585 | } | |
586 | ||
587 | static char _rrdtool_last__doc__[] = "Get the UNIX timestamp of the most "\ | |
588 | "recent data sample in an Round Robin Database.\n\n\ | |
589 | Usage: last(args..)\n\ | |
590 | Arguments:\n\n\ | |
591 | filename\n\ | |
592 | [--daemon address]\n\n\ | |
593 | Full documentation can be found at:\n\ | |
594 | http://oss.oetiker.ch/rrdtool/doc/rrdlast.en.html"; | |
595 | ||
596 | static PyObject * | |
597 | _rrdtool_last(PyObject *self, PyObject *args) | |
598 | { | |
599 | PyObject *ret; | |
600 | int ts; | |
601 | ||
602 | if (convert_args("last", args) == -1) | |
603 | return NULL; | |
604 | ||
605 | if ((ts = rrd_last(rrdtool_argc, rrdtool_argv)) == -1) { | |
606 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |
607 | rrd_clear_error(); | |
608 | ret = NULL; | |
609 | } else | |
610 | ret = PyLong_FromLong((long)ts); | |
611 | ||
612 | destroy_args(); | |
613 | return ret; | |
614 | } | |
615 | ||
616 | static char _rrdtool_resize__doc__[] = "Modify the number of rows in a "\ | |
617 | "Round Robin Database.\n\n\ | |
618 | Usage: resize(args..)\n\ | |
619 | Arguments:\n\n\ | |
620 | filename\n\ | |
621 | rra-num\n\ | |
622 | GROW|SHRINK\n\ | |
623 | rows\n\n\ | |
624 | Full documentation can be found at:\n\ | |
625 | http://oss.oetiker.ch/rrdtool/doc/rrdlast.en.html"; | |
626 | ||
627 | static PyObject * | |
628 | _rrdtool_resize(PyObject *self, PyObject *args) | |
629 | { | |
630 | PyObject *ret; | |
631 | int ts; | |
632 | ||
633 | if (convert_args("resize", args) == -1) | |
634 | return NULL; | |
635 | ||
636 | if ((ts = rrd_resize(rrdtool_argc, rrdtool_argv)) == -1) { | |
637 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |
638 | rrd_clear_error(); | |
639 | ret = NULL; | |
640 | } else { | |
641 | Py_INCREF(Py_None); | |
642 | ret = Py_None; | |
643 | } | |
644 | ||
645 | destroy_args(); | |
646 | return ret; | |
647 | } | |
648 | ||
649 | static char _rrdtool_info__doc__[] = "Extract header information from an "\ | |
650 | "Round Robin Database.\n\n\ | |
651 | Usage: info(filename)\n\ | |
652 | Arguments:\n\n\ | |
653 | filename\n\n\ | |
654 | Full documentation can be found at:\n\ | |
655 | http://oss.oetiker.ch/rrdtool/doc/rrdinfo.en.html"; | |
656 | ||
657 | static PyObject * | |
658 | _rrdtool_info(PyObject *self, PyObject *args) | |
659 | { | |
660 | PyObject *ret; | |
661 | rrd_info_t *data; | |
662 | ||
663 | if (convert_args("info", args) == -1) | |
664 | return NULL; | |
665 | ||
666 | if ((data = rrd_info(rrdtool_argc, rrdtool_argv)) == NULL) { | |
667 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |
668 | rrd_clear_error(); | |
669 | ret = NULL; | |
670 | } else { | |
671 | ret = _rrdtool_util_info2dict(data); | |
672 | rrd_info_free(data); | |
673 | } | |
ce6564c2 | 674 | |
618986c4 CJ |
675 | destroy_args(); |
676 | return ret; | |
ce6564c2 CJ |
677 | } |
678 | ||
b4570f2a CJ |
679 | static char _rrdtool_lib_version__doc__[] = "Get the version this binding "\ |
680 | "was compiled against."; | |
681 | ||
682 | static PyObject * | |
683 | _rrdtool_lib_version(PyObject *self, PyObject *args) | |
684 | { | |
685 | return PyUnicode_FromString(rrd_strversion()); | |
686 | } | |
687 | ||
ce6564c2 | 688 | static PyMethodDef rrdtool_methods[] = { |
618986c4 CJ |
689 | {"create", (PyCFunction)_rrdtool_create, |
690 | METH_VARARGS, _rrdtool_create__doc__}, | |
691 | {"update", (PyCFunction)_rrdtool_update, | |
692 | METH_VARARGS, _rrdtool_update__doc__}, | |
06fe4e5b CJ |
693 | {"updatev", (PyCFunction)_rrdtool_updatev, |
694 | METH_VARARGS, _rrdtool_updatev__doc__}, | |
618986c4 CJ |
695 | {"fetch", (PyCFunction)_rrdtool_fetch, |
696 | METH_VARARGS, _rrdtool_fetch__doc__}, | |
06fe4e5b CJ |
697 | {"flushcached", (PyCFunction)_rrdtool_flushcached, |
698 | METH_VARARGS, _rrdtool_flushcached__doc__}, | |
618986c4 | 699 | {"graph", (PyCFunction)_rrdtool_graph, |
06fe4e5b CJ |
700 | METH_VARARGS, _rrdtool_graph__doc__}, |
701 | {"graphv", (PyCFunction)_rrdtool_graphv, | |
702 | METH_VARARGS, _rrdtool_graphv__doc__}, | |
703 | {"tune", (PyCFunction)_rrdtool_tune, | |
704 | METH_VARARGS, _rrdtool_tune__doc__}, | |
705 | {"first", (PyCFunction)_rrdtool_first, | |
706 | METH_VARARGS, _rrdtool_first__doc__}, | |
707 | {"last", (PyCFunction)_rrdtool_last, | |
708 | METH_VARARGS, _rrdtool_last__doc__}, | |
709 | {"resize", (PyCFunction)_rrdtool_resize, | |
710 | METH_VARARGS, _rrdtool_resize__doc__}, | |
711 | {"info", (PyCFunction)_rrdtool_info, | |
712 | METH_VARARGS, _rrdtool_info__doc__}, | |
b4570f2a CJ |
713 | {"lib_version", (PyCFunction)_rrdtool_lib_version, |
714 | METH_VARARGS, _rrdtool_lib_version__doc__}, | |
ce6564c2 CJ |
715 | {NULL, NULL, 0, NULL} |
716 | }; | |
717 | ||
718 | static struct PyModuleDef rrdtoolmodule = { | |
719 | PyModuleDef_HEAD_INIT, | |
720 | "rrdtool", | |
721 | "rrdtool bindings for Python 3", | |
722 | -1, | |
723 | rrdtool_methods | |
724 | }; | |
725 | ||
726 | PyMODINIT_FUNC | |
727 | PyInit_rrdtool(void) | |
728 | { | |
729 | PyObject *m; | |
730 | ||
731 | m = PyModule_Create(&rrdtoolmodule); | |
732 | if (m == NULL) | |
733 | return NULL; | |
734 | ||
735 | rrdtool_ProgrammingError = PyErr_NewException("rrdtool.ProgrammingError", | |
736 | NULL, NULL); | |
737 | Py_INCREF(rrdtool_ProgrammingError); | |
738 | PyModule_AddObject(m, "ProgrammingError", rrdtool_ProgrammingError); | |
739 | ||
740 | rrdtool_OperationalError = PyErr_NewException("rrdtool.OperationalError", | |
741 | NULL, NULL); | |
742 | Py_INCREF(rrdtool_OperationalError); | |
743 | PyModule_AddObject(m, "OperationalError", rrdtool_OperationalError); | |
06fe4e5b | 744 | PyModule_AddObject(m, "__version__", PyUnicode_FromString(_version)); |
ce6564c2 CJ |
745 | |
746 | return m; | |
747 | } |