Split the Values class into PluginData and Values to use PluginData as a baseclass...
[collectd.git] / src / python.c
1 #include <Python.h>
2 #include <structmember.h>
3
4 #if HAVE_PTHREAD_H
5 # include <pthread.h>
6 #endif
7
8 #include "collectd.h"
9 #include "common.h"
10
11 #include "cpython.h"
12
13 typedef struct cpy_callback_s {
14         char *name;
15         PyObject *callback;
16         PyObject *data;
17         struct cpy_callback_s *next;
18 } cpy_callback_t;
19
20 static int do_interactive = 0;
21
22 /* This is our global thread state. Python saves some stuff in thread-local
23  * storage. So if we allow the interpreter to run in the background
24  * (the scriptwriters might have created some threads from python), we have
25  * to save the state so we can resume it later after shutdown. */
26
27 static PyThreadState *state;
28
29 static PyObject *cpy_format_exception;
30
31 static cpy_callback_t *cpy_config_callbacks;
32 static cpy_callback_t *cpy_init_callbacks;
33 static cpy_callback_t *cpy_shutdown_callbacks;
34
35 static void cpy_destroy_user_data(void *data) {
36         cpy_callback_t *c = data;
37         free(c->name);
38         Py_DECREF(c->callback);
39         Py_XDECREF(c->data);
40         free(c);
41 }
42
43 /* You must hold the GIL to call this function!
44  * But if you managed to extract the callback parameter then you probably already do. */
45
46 static void cpy_build_name(char *buf, size_t size, PyObject *callback, const char *name, int short_name) {
47         const char *module;
48         PyObject *mod = NULL, *n = NULL;
49         
50         if (name != NULL && (strchr(name, '.') != NULL || short_name)) {
51                 snprintf(buf, size, "python.%s", name);
52                 return;
53         }
54         
55         mod = PyObject_GetAttrString(callback, "__module__"); /* New reference. */
56         if (mod != NULL)
57                 module = PyString_AsString(mod);
58         else
59                 module = "collectd";
60         
61         if (short_name) {
62                 snprintf(buf, size, "python.%s", module);
63                 Py_XDECREF(mod);
64                 return;
65         }
66         
67         if (name != NULL) {
68                 snprintf(buf, size, "python.%s.%s", module, name);
69                 Py_XDECREF(mod);
70                 return;
71         }
72         
73         n = PyObject_GetAttrString(callback, "__name__"); /* New reference. */
74         if (n != NULL)
75                 name = PyString_AsString(n);
76         
77         if (name != NULL)
78                 snprintf(buf, size, "python.%s.%s", module, name);
79         else
80                 snprintf(buf, size, "python.%s.%p", module, callback);
81         Py_XDECREF(mod);
82         Py_XDECREF(n);
83 }
84
85 static void cpy_log_exception(const char *context) {
86         int l = 0, i;
87         const char *typename = NULL, *message = NULL;
88         PyObject *type, *value, *traceback, *tn, *m, *list;
89         
90         PyErr_Fetch(&type, &value, &traceback);
91         PyErr_NormalizeException(&type, &value, &traceback);
92         if (type == NULL) return;
93         tn = PyObject_GetAttrString(type, "__name__"); /* New reference. */
94         m = PyObject_GetAttrString(value, "message"); /* New reference. */
95         if (tn != NULL)
96                 typename = PyString_AsString(tn);
97         if (m != NULL)
98                 message = PyString_AsString(m);
99         if (typename == NULL)
100                 typename = "NamelessException";
101         if (message == NULL)
102                 message = "N/A";
103         ERROR("Unhandled python exception in %s: %s: %s", context, typename, message);
104         Py_XDECREF(tn);
105         Py_XDECREF(m);
106         if (!cpy_format_exception) {
107                 PyErr_Clear();
108                 Py_XDECREF(type);
109                 Py_XDECREF(value);
110                 Py_XDECREF(traceback);
111                 return;
112         }
113         if (!traceback) {
114                 PyErr_Clear();
115                 return;
116         }
117         list = PyObject_CallFunction(cpy_format_exception, "NNN", type, value, traceback);
118         if (list)
119                 l = PyObject_Length(list);
120         for (i = 0; i < l; ++i) {
121                 char *s;
122                 PyObject *line;
123                 
124                 line = PyList_GET_ITEM(list, i);
125                 s = strdup(PyString_AsString(line));
126                 Py_DECREF(line);
127                 if (s[strlen(s) - 1] == '\n')
128                         s[strlen(s) - 1] = 0;
129                 ERROR("%s", s);
130                 free(s);
131         }
132         PyErr_Clear();
133 }
134
135 static int cpy_read_callback(user_data_t *data) {
136         cpy_callback_t *c = data->data;
137         PyObject *ret;
138
139         CPY_LOCK_THREADS
140                 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
141                 if (ret == NULL) {
142                         cpy_log_exception("read callback");
143                 } else {
144                         Py_DECREF(ret);
145                 }
146         CPY_RELEASE_THREADS
147         return 0;
148 }
149
150 static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_list, user_data_t *data) {
151         int i;
152         cpy_callback_t *c = data->data;
153         PyObject *ret, *v, *list;
154
155         CPY_LOCK_THREADS
156                 list = PyList_New(value_list->values_len); /* New reference. */
157                 if (list == NULL) {
158                         cpy_log_exception("write callback");
159                         CPY_RETURN_FROM_THREADS 0;
160                 }
161                 for (i = 0; i < value_list->values_len; ++i) {
162                         if (ds->ds->type == DS_TYPE_COUNTER) {
163                                 if ((long) value_list->values[i].counter == value_list->values[i].counter)
164                                         PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].counter));
165                                 else
166                                         PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].counter));
167                         } else if (ds->ds->type == DS_TYPE_GAUGE) {
168                                 PyList_SetItem(list, i, PyFloat_FromDouble(value_list->values[i].gauge));
169                         } else if (ds->ds->type == DS_TYPE_DERIVE) {
170                                 if ((long) value_list->values[i].derive == value_list->values[i].derive)
171                                         PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].derive));
172                                 else
173                                         PyList_SetItem(list, i, PyLong_FromLongLong(value_list->values[i].derive));
174                         } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
175                                 if ((long) value_list->values[i].absolute == value_list->values[i].absolute)
176                                         PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].absolute));
177                                 else
178                                         PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].absolute));
179                         } else {
180                                 ERROR("cpy_write_callback: Unknown value type %d.", ds->ds->type);
181                                 Py_DECREF(list);
182                                 CPY_RETURN_FROM_THREADS 0;
183                         }
184                         if (PyErr_Occurred() != NULL) {
185                                 cpy_log_exception("value building for write callback");
186                                 CPY_RETURN_FROM_THREADS 0;
187                         }
188                 }
189                 v = PyObject_CallFunction((PyObject *) &ValuesType, "sOssssdi", value_list->type, list,
190                                 value_list->plugin_instance, value_list->type_instance, value_list->plugin,
191                                 value_list->host, (double) value_list->time, value_list->interval);
192                 Py_DECREF(list);
193                 ret = PyObject_CallFunctionObjArgs(c->callback, v, c->data, (void *) 0); /* New reference. */
194                 if (ret == NULL) {
195                         cpy_log_exception("write callback");
196                 } else {
197                         Py_DECREF(ret);
198                 }
199         CPY_RELEASE_THREADS
200         return 0;
201 }
202
203 static void cpy_log_callback(int severity, const char *message, user_data_t *data) {
204         cpy_callback_t * c = data->data;
205         PyObject *ret;
206
207         CPY_LOCK_THREADS
208         if (c->data == NULL)
209                 ret = PyObject_CallFunction(c->callback, "is", severity, message); /* New reference. */
210         else
211                 ret = PyObject_CallFunction(c->callback, "isO", severity, message, c->data); /* New reference. */
212
213         if (ret == NULL) {
214                 /* FIXME */
215                 /* Do we really want to trigger a log callback because a log callback failed?
216                  * Probably not. */
217                 PyErr_Print();
218         } else {
219                 Py_DECREF(ret);
220         }
221         CPY_RELEASE_THREADS
222 }
223
224 static void cpy_flush_callback(int timeout, const char *id, user_data_t *data) {
225         cpy_callback_t * c = data->data;
226         PyObject *ret;
227
228         CPY_LOCK_THREADS
229         if (c->data == NULL)
230                 ret = PyObject_CallFunction(c->callback, "is", timeout, id); /* New reference. */
231         else
232                 ret = PyObject_CallFunction(c->callback, "isO", timeout, id, c->data); /* New reference. */
233
234         if (ret == NULL) {
235                 cpy_log_exception("flush callback");
236         } else {
237                 Py_DECREF(ret);
238         }
239         CPY_RELEASE_THREADS
240 }
241
242 static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args, PyObject *kwds, int short_name) {
243         char buf[512];
244         cpy_callback_t *c;
245         const char *name = NULL;
246         PyObject *callback = NULL, *data = NULL, *mod = NULL;
247         static char *kwlist[] = {"callback", "data", "name", NULL};
248         
249         if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oz", kwlist, &callback, &data, &name) == 0) return NULL;
250         if (PyCallable_Check(callback) == 0) {
251                 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
252                 return NULL;
253         }
254         cpy_build_name(buf, sizeof(buf), callback, name, short_name);
255
256         Py_INCREF(callback);
257         Py_XINCREF(data);
258         c = malloc(sizeof(*c));
259         c->name = strdup(buf);
260         c->callback = callback;
261         c->data = data;
262         c->next = *list_head;
263         *list_head = c;
264         Py_XDECREF(mod);
265         return PyString_FromString(buf);
266 }
267
268 static PyObject *cpy_flush(cpy_callback_t **list_head, PyObject *args, PyObject *kwds) {
269         int timeout = -1;
270         const char *plugin = NULL, *identifier = NULL;
271         static char *kwlist[] = {"plugin", "timeout", "identifier", NULL};
272         
273         if (PyArg_ParseTupleAndKeywords(args, kwds, "|ziz", kwlist, &plugin, &timeout, &identifier) == 0) return NULL;
274         Py_BEGIN_ALLOW_THREADS
275         plugin_flush(plugin, timeout, identifier);
276         Py_END_ALLOW_THREADS
277         Py_RETURN_NONE;
278 }
279
280 static PyObject *cpy_register_config(PyObject *self, PyObject *args, PyObject *kwds) {
281         return cpy_register_generic(&cpy_config_callbacks, args, kwds, 1);
282 }
283
284 static PyObject *cpy_register_init(PyObject *self, PyObject *args, PyObject *kwds) {
285         return cpy_register_generic(&cpy_init_callbacks, args, kwds, 0);
286 }
287
288 typedef int reg_function_t(const char *name, void *callback, void *data);
289
290 static PyObject *cpy_register_generic_userdata(void *reg, void *handler, PyObject *args, PyObject *kwds, int short_name) {
291         char buf[512];
292         reg_function_t *register_function = (reg_function_t *) reg;
293         cpy_callback_t *c = NULL;
294         user_data_t *user_data = NULL;
295         const char *name = NULL;
296         PyObject *callback = NULL, *data = NULL;
297         static char *kwlist[] = {"callback", "data", "name", NULL};
298         
299         if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oz", kwlist, &callback, &data, &name) == 0) return NULL;
300         if (PyCallable_Check(callback) == 0) {
301                 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
302                 return NULL;
303         }
304         cpy_build_name(buf, sizeof(buf), callback, name, short_name);
305         
306         Py_INCREF(callback);
307         Py_XINCREF(data);
308         c = malloc(sizeof(*c));
309         c->name = strdup(buf);
310         c->callback = callback;
311         c->data = data;
312         c->next = NULL;
313         user_data = malloc(sizeof(*user_data));
314         user_data->free_func = cpy_destroy_user_data;
315         user_data->data = c;
316         register_function(buf, handler, user_data);
317         return PyString_FromString(buf);
318 }
319
320 static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwds) {
321         char buf[512];
322         cpy_callback_t *c = NULL;
323         user_data_t *user_data = NULL;
324         double interval = 0;
325         const char *name = NULL;
326         PyObject *callback = NULL, *data = NULL;
327         struct timespec ts;
328         static char *kwlist[] = {"callback", "interval", "data", "name", NULL};
329         
330         if (PyArg_ParseTupleAndKeywords(args, kwds, "O|dOz", kwlist, &callback, &interval, &data, &name) == 0) return NULL;
331         if (PyCallable_Check(callback) == 0) {
332                 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
333                 return NULL;
334         }
335         cpy_build_name(buf, sizeof(buf), callback, name, 0);
336         
337         Py_INCREF(callback);
338         Py_XINCREF(data);
339         c = malloc(sizeof(*c));
340         c->name = strdup(buf);
341         c->callback = callback;
342         c->data = data;
343         c->next = NULL;
344         user_data = malloc(sizeof(*user_data));
345         user_data->free_func = cpy_destroy_user_data;
346         user_data->data = c;
347         ts.tv_sec = interval;
348         ts.tv_nsec = (interval - ts.tv_sec) * 1000000000;
349         plugin_register_complex_read(buf, cpy_read_callback, &ts, user_data);
350         return PyString_FromString(buf);
351 }
352
353 static PyObject *cpy_register_log(PyObject *self, PyObject *args, PyObject *kwds) {
354         return cpy_register_generic_userdata(plugin_register_log, cpy_log_callback, args, kwds, 0);
355 }
356
357 static PyObject *cpy_register_write(PyObject *self, PyObject *args, PyObject *kwds) {
358         return cpy_register_generic_userdata(plugin_register_write, cpy_write_callback, args, kwds, 0);
359 }
360
361 static PyObject *cpy_register_flush(PyObject *self, PyObject *args, PyObject *kwds) {
362         return cpy_register_generic_userdata(plugin_register_flush, cpy_flush_callback, args, kwds, 1);
363 }
364
365 static PyObject *cpy_register_shutdown(PyObject *self, PyObject *args, PyObject *kwds) {
366         return cpy_register_generic(&cpy_shutdown_callbacks, args, kwds, 0);
367 }
368
369 static PyObject *cpy_error(PyObject *self, PyObject *args) {
370         const char *text;
371         if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
372         Py_BEGIN_ALLOW_THREADS
373         plugin_log(LOG_ERR, "%s", text);
374         Py_END_ALLOW_THREADS
375         Py_RETURN_NONE;
376 }
377
378 static PyObject *cpy_warning(PyObject *self, PyObject *args) {
379         const char *text;
380         if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
381         Py_BEGIN_ALLOW_THREADS
382         plugin_log(LOG_WARNING, "%s", text);
383         Py_END_ALLOW_THREADS
384         Py_RETURN_NONE;
385 }
386
387 static PyObject *cpy_notice(PyObject *self, PyObject *args) {
388         const char *text;
389         if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
390         Py_BEGIN_ALLOW_THREADS
391         plugin_log(LOG_NOTICE, "%s", text);
392         Py_END_ALLOW_THREADS
393         Py_RETURN_NONE;
394 }
395
396 static PyObject *cpy_info(PyObject *self, PyObject *args) {
397         const char *text;
398         if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
399         Py_BEGIN_ALLOW_THREADS
400         plugin_log(LOG_INFO, "%s", text);
401         Py_END_ALLOW_THREADS
402         Py_RETURN_NONE;
403 }
404
405 static PyObject *cpy_debug(PyObject *self, PyObject *args) {
406 #ifdef COLLECT_DEBUG
407         const char *text;
408         if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
409         plugin_log(LOG_DEBUG, "%s", text);
410 #endif
411         Py_RETURN_NONE;
412 }
413
414 static PyObject *cpy_unregister_generic(cpy_callback_t **list_head, PyObject *arg, const char *desc, int short_name) {
415         char buf[512];
416         const char *name;
417         cpy_callback_t *prev = NULL, *tmp;
418
419         if (PyString_Check(arg)) {
420                 name = PyString_AsString(arg);
421         } else {
422                 if (!PyCallable_Check(arg)) {
423                         PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
424                         return NULL;
425                 }
426                 cpy_build_name(buf, sizeof(buf), arg, NULL, short_name);
427                 name = buf;
428         }
429         for (tmp = *list_head; tmp; prev = tmp, tmp = tmp->next)
430                 if (strcmp(name, tmp->name) == 0)
431                         break;
432         
433         if (tmp == NULL) {
434                 PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
435                 return NULL;
436         }
437         /* Yes, this is actually save. To call this function the calles has to
438          * hold the GIL. Well, save as long as there is only one GIL anyway ... */
439         if (prev == NULL)
440                 *list_head = tmp->next;
441         else
442                 prev->next = tmp->next;
443         cpy_destroy_user_data(tmp);
444         Py_RETURN_NONE;
445 }
446
447 typedef int cpy_unregister_function_t(const char *name);
448
449 static PyObject *cpy_unregister_generic_userdata(cpy_unregister_function_t *unreg, PyObject *arg, const char *desc, int short_name) {
450         char buf[512];
451         const char *name;
452
453         if (PyString_Check(arg)) {
454                 name = PyString_AsString(arg);
455         } else {
456                 if (!PyCallable_Check(arg)) {
457                         PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
458                         return NULL;
459                 }
460                 cpy_build_name(buf, sizeof(buf), arg, NULL, short_name);
461                 name = buf;
462         }
463         if (unreg(name) == 0)
464                 Py_RETURN_NONE;
465         PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
466         return NULL;
467 }
468
469 static PyObject *cpy_unregister_log(PyObject *self, PyObject *arg) {
470         return cpy_unregister_generic_userdata(plugin_unregister_log, arg, "log", 0);
471 }
472
473 static PyObject *cpy_unregister_init(PyObject *self, PyObject *arg) {
474         return cpy_unregister_generic(&cpy_init_callbacks, arg, "init", 0);
475 }
476
477 static PyObject *cpy_unregister_config(PyObject *self, PyObject *arg) {
478         return cpy_unregister_generic(&cpy_config_callbacks, arg, "config", 1);
479 }
480
481 static PyObject *cpy_unregister_read(PyObject *self, PyObject *arg) {
482         return cpy_unregister_generic_userdata(plugin_unregister_read, arg, "read", 0);
483 }
484
485 static PyObject *cpy_unregister_write(PyObject *self, PyObject *arg) {
486         return cpy_unregister_generic_userdata(plugin_unregister_write, arg, "write", 0);
487 }
488
489 static PyObject *cpy_unregister_flush(PyObject *self, PyObject *arg) {
490         return cpy_unregister_generic_userdata(plugin_unregister_flush, arg, "flush", 1);
491 }
492
493 static PyObject *cpy_unregister_shutdown(PyObject *self, PyObject *arg) {
494         return cpy_unregister_generic(&cpy_shutdown_callbacks, arg, "shutdown", 0);
495 }
496
497 static PyMethodDef cpy_methods[] = {
498         {"debug", cpy_debug, METH_VARARGS, "This is an unhelpful text."},
499         {"info", cpy_info, METH_VARARGS, "This is an unhelpful text."},
500         {"notice", cpy_notice, METH_VARARGS, "This is an unhelpful text."},
501         {"warning", cpy_warning, METH_VARARGS, "This is an unhelpful text."},
502         {"error", cpy_error, METH_VARARGS, "This is an unhelpful text."},
503         {"flush", (PyCFunction) cpy_flush, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
504         {"register_log", (PyCFunction) cpy_register_log, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
505         {"register_init", (PyCFunction) cpy_register_init, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
506         {"register_config", (PyCFunction) cpy_register_config, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
507         {"register_read", (PyCFunction) cpy_register_read, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
508         {"register_write", (PyCFunction) cpy_register_write, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
509         {"register_flush", (PyCFunction) cpy_register_flush, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
510         {"register_shutdown", (PyCFunction) cpy_register_shutdown, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
511         {"unregister_log", cpy_unregister_log, METH_O, "This is an unhelpful text."},
512         {"unregister_init", cpy_unregister_init, METH_O, "This is an unhelpful text."},
513         {"unregister_config", cpy_unregister_config, METH_O, "This is an unhelpful text."},
514         {"unregister_read", cpy_unregister_read, METH_O, "This is an unhelpful text."},
515         {"unregister_write", cpy_unregister_write, METH_O, "This is an unhelpful text."},
516         {"unregister_flush", cpy_unregister_flush, METH_O, "This is an unhelpful text."},
517         {"unregister_shutdown", cpy_unregister_shutdown, METH_O, "This is an unhelpful text."},
518         {0, 0, 0, 0}
519 };
520
521 static int cpy_shutdown(void) {
522         cpy_callback_t *c;
523         PyObject *ret;
524         
525         /* This can happen if the module was loaded but not configured. */
526         if (state != NULL)
527                 PyEval_RestoreThread(state);
528
529         for (c = cpy_shutdown_callbacks; c; c = c->next) {
530                 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
531                 if (ret == NULL)
532                         cpy_log_exception("shutdown callback");
533                 else
534                         Py_DECREF(ret);
535         }
536         Py_Finalize();
537         return 0;
538 }
539
540 static void *cpy_interactive(void *data) {
541         CPY_LOCK_THREADS
542                 if (PyImport_ImportModule("readline") == NULL) {
543                         /* This interactive session will suck. */
544                         cpy_log_exception("interactive session init");
545                 }
546                 PyRun_InteractiveLoop(stdin, "<stdin>");
547         CPY_RELEASE_THREADS
548         NOTICE("python: Interactive interpreter exited, stopping collectd ...");
549         raise(SIGINT);
550         return NULL;
551 }
552
553 static int cpy_init(void) {
554         cpy_callback_t *c;
555         PyObject *ret;
556         static pthread_t thread;
557         
558         PyEval_InitThreads();
559         /* Now it's finally OK to use python threads. */
560         for (c = cpy_init_callbacks; c; c = c->next) {
561                 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
562                 if (ret == NULL)
563                         cpy_log_exception("init callback");
564                 else
565                         Py_DECREF(ret);
566         }
567         state = PyEval_SaveThread();
568         if (do_interactive) {
569                 if (pthread_create(&thread, NULL, cpy_interactive, NULL)) {
570                         ERROR("python: Error creating thread for interactive interpreter.");
571                 }
572         }
573
574         return 0;
575 }
576
577 static PyObject *cpy_oconfig_to_pyconfig(oconfig_item_t *ci, PyObject *parent) {
578         int i;
579         PyObject *item, *values, *children, *tmp;
580         
581         if (parent == NULL)
582                 parent = Py_None;
583         
584         values = PyTuple_New(ci->values_num); /* New reference. */
585         for (i = 0; i < ci->values_num; ++i) {
586                 if (ci->values[i].type == OCONFIG_TYPE_STRING) {
587                         PyTuple_SET_ITEM(values, i, PyString_FromString(ci->values[i].value.string));
588                 } else if (ci->values[i].type == OCONFIG_TYPE_NUMBER) {
589                         PyTuple_SET_ITEM(values, i, PyFloat_FromDouble(ci->values[i].value.number));
590                 } else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN) {
591                         PyTuple_SET_ITEM(values, i, PyBool_FromLong(ci->values[i].value.boolean));
592                 }
593         }
594         
595         item = PyObject_CallFunction((PyObject *) &ConfigType, "sONO", ci->key, parent, values, Py_None);
596         if (item == NULL)
597                 return NULL;
598         children = PyTuple_New(ci->children_num); /* New reference. */
599         for (i = 0; i < ci->children_num; ++i) {
600                 PyTuple_SET_ITEM(children, i, cpy_oconfig_to_pyconfig(ci->children + i, item));
601         }
602         tmp = ((Config *) item)->children;
603         ((Config *) item)->children = children;
604         Py_XDECREF(tmp);
605         return item;
606 }
607
608 static int cpy_config(oconfig_item_t *ci) {
609         int i;
610         PyObject *sys, *tb;
611         PyObject *sys_path;
612         PyObject *module;
613         
614         /* Ok in theory we shouldn't do initialization at this point
615          * but we have to. In order to give python scripts a chance
616          * to register a config callback we need to be able to execute
617          * python code during the config callback so we have to start
618          * the interpreter here. */
619         /* Do *not* use the python "thread" module at this point! */
620         Py_Initialize();
621         
622         PyType_Ready(&ConfigType);
623         PyType_Ready(&PluginDataType);
624         ValuesType.tp_base = &PluginDataType;
625         PyType_Ready(&ValuesType);
626         sys = PyImport_ImportModule("sys"); /* New reference. */
627         if (sys == NULL) {
628                 cpy_log_exception("python initialization");
629                 return 1;
630         }
631         sys_path = PyObject_GetAttrString(sys, "path"); /* New reference. */
632         Py_DECREF(sys);
633         if (sys_path == NULL) {
634                 cpy_log_exception("python initialization");
635                 return 1;
636         }
637         module = Py_InitModule("collectd", cpy_methods); /* Borrowed reference. */
638         PyModule_AddObject(module, "Config", (PyObject *) &ConfigType); /* Steals a reference. */
639         PyModule_AddObject(module, "Values", (PyObject *) &ValuesType); /* Steals a reference. */
640         PyModule_AddIntConstant(module, "LOG_DEBUG", LOG_DEBUG);
641         PyModule_AddIntConstant(module, "LOG_INFO", LOG_INFO);
642         PyModule_AddIntConstant(module, "LOG_NOTICE", LOG_NOTICE);
643         PyModule_AddIntConstant(module, "LOG_WARNING", LOG_WARNING);
644         PyModule_AddIntConstant(module, "LOG_ERROR", LOG_ERR);
645         for (i = 0; i < ci->children_num; ++i) {
646                 oconfig_item_t *item = ci->children + i;
647                 
648                 if (strcasecmp(item->key, "Interactive") == 0) {
649                         if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
650                                 continue;
651                         do_interactive = item->values[0].value.boolean;
652                 } else if (strcasecmp(item->key, "LogTraces") == 0) {
653                         if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
654                                 continue;
655                         if (!item->values[0].value.boolean) {
656                                 Py_XDECREF(cpy_format_exception);
657                                 cpy_format_exception = NULL;
658                                 continue;
659                         }
660                         if (cpy_format_exception)
661                                 continue;
662                         tb = PyImport_ImportModule("traceback"); /* New reference. */
663                         if (tb == NULL) {
664                                 cpy_log_exception("python initialization");
665                                 continue;
666                         }
667                         cpy_format_exception = PyObject_GetAttrString(tb, "format_exception"); /* New reference. */
668                         Py_DECREF(tb);
669                         if (cpy_format_exception == NULL)
670                                 cpy_log_exception("python initialization");
671                 } else if (strcasecmp(item->key, "ModulePath") == 0) {
672                         char *dir = NULL;
673                         PyObject *dir_object;
674                         
675                         if (cf_util_get_string(item, &dir) != 0) 
676                                 continue;
677                         dir_object = PyString_FromString(dir); /* New reference. */
678                         if (dir_object == NULL) {
679                                 ERROR("python plugin: Unable to convert \"%s\" to "
680                                       "a python object.", dir);
681                                 free(dir);
682                                 cpy_log_exception("python initialization");
683                                 continue;
684                         }
685                         if (PyList_Append(sys_path, dir_object) != 0) {
686                                 ERROR("python plugin: Unable to append \"%s\" to "
687                                       "python module path.", dir);
688                                 cpy_log_exception("python initialization");
689                         }
690                         Py_DECREF(dir_object);
691                         free(dir);
692                 } else if (strcasecmp(item->key, "Import") == 0) {
693                         char *module_name = NULL;
694                         PyObject *module;
695                         
696                         if (cf_util_get_string(item, &module_name) != 0) 
697                                 continue;
698                         module = PyImport_ImportModule(module_name); /* New reference. */
699                         if (module == NULL) {
700                                 ERROR("python plugin: Error importing module \"%s\".", module_name);
701                                 cpy_log_exception("python initialization");
702                                 PyErr_Print();
703                         }
704                         free(module_name);
705                         Py_XDECREF(module);
706                 } else if (strcasecmp(item->key, "Module") == 0) {
707                         char *name = NULL;
708                         cpy_callback_t *c;
709                         PyObject *ret;
710                         
711                         if (cf_util_get_string(item, &name) != 0)
712                                 continue;
713                         for (c = cpy_config_callbacks; c; c = c->next) {
714                                 if (strcasecmp(c->name + 7, name) == 0)
715                                         break;
716                         }
717                         if (c == NULL) {
718                                 WARNING("python plugin: Found a configuration for the \"%s\" plugin, "
719                                         "but the plugin isn't loaded or didn't register "
720                                         "a configuration callback.", name);
721                                 free(name);
722                                 continue;
723                         }
724                         free(name);
725                         if (c->data == NULL)
726                                 ret = PyObject_CallFunction(c->callback, "N",
727                                         cpy_oconfig_to_pyconfig(item, NULL)); /* New reference. */
728                         else
729                                 ret = PyObject_CallFunction(c->callback, "NO",
730                                         cpy_oconfig_to_pyconfig(item, NULL), c->data); /* New reference. */
731                         if (ret == NULL)
732                                 cpy_log_exception("loading module");
733                         else
734                                 Py_DECREF(ret);
735                 } else {
736                         WARNING("python plugin: Ignoring unknown config key \"%s\".", item->key);
737                 }
738         }
739         Py_DECREF(sys_path);
740         return 0;
741 }
742
743 void module_register(void) {
744         plugin_register_complex_config("python", cpy_config);
745         plugin_register_init("python", cpy_init);
746 //      plugin_register_read("python", cna_read);
747         plugin_register_shutdown("python", cpy_shutdown);
748 }