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