Added notification support.
[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 int cpy_notification_callback(const notification_t *notification, user_data_t *data) {
204         cpy_callback_t *c = data->data;
205         PyObject *ret, *n;
206
207         CPY_LOCK_THREADS
208                 n = PyObject_CallFunction((PyObject *) &NotificationType, "ssssssdi", notification->type, notification->message,
209                                 notification->plugin_instance, notification->type_instance, notification->plugin,
210                                 notification->host, (double) notification->time, notification->severity);
211                 ret = PyObject_CallFunctionObjArgs(c->callback, n, c->data, (void *) 0); /* New reference. */
212                 if (ret == NULL) {
213                         cpy_log_exception("notification callback");
214                 } else {
215                         Py_DECREF(ret);
216                 }
217         CPY_RELEASE_THREADS
218         return 0;
219 }
220
221 static void cpy_log_callback(int severity, const char *message, user_data_t *data) {
222         cpy_callback_t * c = data->data;
223         PyObject *ret;
224
225         CPY_LOCK_THREADS
226         if (c->data == NULL)
227                 ret = PyObject_CallFunction(c->callback, "is", severity, message); /* New reference. */
228         else
229                 ret = PyObject_CallFunction(c->callback, "isO", severity, message, c->data); /* New reference. */
230
231         if (ret == NULL) {
232                 /* FIXME */
233                 /* Do we really want to trigger a log callback because a log callback failed?
234                  * Probably not. */
235                 PyErr_Print();
236         } else {
237                 Py_DECREF(ret);
238         }
239         CPY_RELEASE_THREADS
240 }
241
242 static void cpy_flush_callback(int timeout, const char *id, user_data_t *data) {
243         cpy_callback_t * c = data->data;
244         PyObject *ret;
245
246         CPY_LOCK_THREADS
247         if (c->data == NULL)
248                 ret = PyObject_CallFunction(c->callback, "is", timeout, id); /* New reference. */
249         else
250                 ret = PyObject_CallFunction(c->callback, "isO", timeout, id, c->data); /* New reference. */
251
252         if (ret == NULL) {
253                 cpy_log_exception("flush callback");
254         } else {
255                 Py_DECREF(ret);
256         }
257         CPY_RELEASE_THREADS
258 }
259
260 static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args, PyObject *kwds, int short_name) {
261         char buf[512];
262         cpy_callback_t *c;
263         const char *name = NULL;
264         PyObject *callback = NULL, *data = NULL, *mod = NULL;
265         static char *kwlist[] = {"callback", "data", "name", NULL};
266         
267         if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oz", kwlist, &callback, &data, &name) == 0) return NULL;
268         if (PyCallable_Check(callback) == 0) {
269                 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
270                 return NULL;
271         }
272         cpy_build_name(buf, sizeof(buf), callback, name, short_name);
273
274         Py_INCREF(callback);
275         Py_XINCREF(data);
276         c = malloc(sizeof(*c));
277         c->name = strdup(buf);
278         c->callback = callback;
279         c->data = data;
280         c->next = *list_head;
281         *list_head = c;
282         Py_XDECREF(mod);
283         return PyString_FromString(buf);
284 }
285
286 static PyObject *cpy_flush(cpy_callback_t **list_head, PyObject *args, PyObject *kwds) {
287         int timeout = -1;
288         const char *plugin = NULL, *identifier = NULL;
289         static char *kwlist[] = {"plugin", "timeout", "identifier", NULL};
290         
291         if (PyArg_ParseTupleAndKeywords(args, kwds, "|ziz", kwlist, &plugin, &timeout, &identifier) == 0) return NULL;
292         Py_BEGIN_ALLOW_THREADS
293         plugin_flush(plugin, timeout, identifier);
294         Py_END_ALLOW_THREADS
295         Py_RETURN_NONE;
296 }
297
298 static PyObject *cpy_register_config(PyObject *self, PyObject *args, PyObject *kwds) {
299         return cpy_register_generic(&cpy_config_callbacks, args, kwds, 1);
300 }
301
302 static PyObject *cpy_register_init(PyObject *self, PyObject *args, PyObject *kwds) {
303         return cpy_register_generic(&cpy_init_callbacks, args, kwds, 0);
304 }
305
306 typedef int reg_function_t(const char *name, void *callback, void *data);
307
308 static PyObject *cpy_register_generic_userdata(void *reg, void *handler, PyObject *args, PyObject *kwds, int short_name) {
309         char buf[512];
310         reg_function_t *register_function = (reg_function_t *) reg;
311         cpy_callback_t *c = NULL;
312         user_data_t *user_data = NULL;
313         const char *name = NULL;
314         PyObject *callback = NULL, *data = NULL;
315         static char *kwlist[] = {"callback", "data", "name", NULL};
316         
317         if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oz", kwlist, &callback, &data, &name) == 0) return NULL;
318         if (PyCallable_Check(callback) == 0) {
319                 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
320                 return NULL;
321         }
322         cpy_build_name(buf, sizeof(buf), callback, name, short_name);
323         
324         Py_INCREF(callback);
325         Py_XINCREF(data);
326         c = malloc(sizeof(*c));
327         c->name = strdup(buf);
328         c->callback = callback;
329         c->data = data;
330         c->next = NULL;
331         user_data = malloc(sizeof(*user_data));
332         user_data->free_func = cpy_destroy_user_data;
333         user_data->data = c;
334         register_function(buf, handler, user_data);
335         return PyString_FromString(buf);
336 }
337
338 static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwds) {
339         char buf[512];
340         cpy_callback_t *c = NULL;
341         user_data_t *user_data = NULL;
342         double interval = 0;
343         const char *name = NULL;
344         PyObject *callback = NULL, *data = NULL;
345         struct timespec ts;
346         static char *kwlist[] = {"callback", "interval", "data", "name", NULL};
347         
348         if (PyArg_ParseTupleAndKeywords(args, kwds, "O|dOz", kwlist, &callback, &interval, &data, &name) == 0) return NULL;
349         if (PyCallable_Check(callback) == 0) {
350                 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
351                 return NULL;
352         }
353         cpy_build_name(buf, sizeof(buf), callback, name, 0);
354         
355         Py_INCREF(callback);
356         Py_XINCREF(data);
357         c = malloc(sizeof(*c));
358         c->name = strdup(buf);
359         c->callback = callback;
360         c->data = data;
361         c->next = NULL;
362         user_data = malloc(sizeof(*user_data));
363         user_data->free_func = cpy_destroy_user_data;
364         user_data->data = c;
365         ts.tv_sec = interval;
366         ts.tv_nsec = (interval - ts.tv_sec) * 1000000000;
367         plugin_register_complex_read(buf, cpy_read_callback, &ts, user_data);
368         return PyString_FromString(buf);
369 }
370
371 static PyObject *cpy_register_log(PyObject *self, PyObject *args, PyObject *kwds) {
372         return cpy_register_generic_userdata(plugin_register_log, cpy_log_callback, args, kwds, 0);
373 }
374
375 static PyObject *cpy_register_write(PyObject *self, PyObject *args, PyObject *kwds) {
376         return cpy_register_generic_userdata(plugin_register_write, cpy_write_callback, args, kwds, 0);
377 }
378
379 static PyObject *cpy_register_notification(PyObject *self, PyObject *args, PyObject *kwds) {
380         return cpy_register_generic_userdata(plugin_register_notification, cpy_notification_callback, args, kwds, 0);
381 }
382
383 static PyObject *cpy_register_flush(PyObject *self, PyObject *args, PyObject *kwds) {
384         return cpy_register_generic_userdata(plugin_register_flush, cpy_flush_callback, args, kwds, 1);
385 }
386
387 static PyObject *cpy_register_shutdown(PyObject *self, PyObject *args, PyObject *kwds) {
388         return cpy_register_generic(&cpy_shutdown_callbacks, args, kwds, 0);
389 }
390
391 static PyObject *cpy_error(PyObject *self, PyObject *args) {
392         const char *text;
393         if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
394         Py_BEGIN_ALLOW_THREADS
395         plugin_log(LOG_ERR, "%s", text);
396         Py_END_ALLOW_THREADS
397         Py_RETURN_NONE;
398 }
399
400 static PyObject *cpy_warning(PyObject *self, PyObject *args) {
401         const char *text;
402         if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
403         Py_BEGIN_ALLOW_THREADS
404         plugin_log(LOG_WARNING, "%s", text);
405         Py_END_ALLOW_THREADS
406         Py_RETURN_NONE;
407 }
408
409 static PyObject *cpy_notice(PyObject *self, PyObject *args) {
410         const char *text;
411         if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
412         Py_BEGIN_ALLOW_THREADS
413         plugin_log(LOG_NOTICE, "%s", text);
414         Py_END_ALLOW_THREADS
415         Py_RETURN_NONE;
416 }
417
418 static PyObject *cpy_info(PyObject *self, PyObject *args) {
419         const char *text;
420         if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
421         Py_BEGIN_ALLOW_THREADS
422         plugin_log(LOG_INFO, "%s", text);
423         Py_END_ALLOW_THREADS
424         Py_RETURN_NONE;
425 }
426
427 static PyObject *cpy_debug(PyObject *self, PyObject *args) {
428 #ifdef COLLECT_DEBUG
429         const char *text;
430         if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
431         plugin_log(LOG_DEBUG, "%s", text);
432 #endif
433         Py_RETURN_NONE;
434 }
435
436 static PyObject *cpy_unregister_generic(cpy_callback_t **list_head, PyObject *arg, const char *desc, int short_name) {
437         char buf[512];
438         const char *name;
439         cpy_callback_t *prev = NULL, *tmp;
440
441         if (PyString_Check(arg)) {
442                 name = PyString_AsString(arg);
443         } else {
444                 if (!PyCallable_Check(arg)) {
445                         PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
446                         return NULL;
447                 }
448                 cpy_build_name(buf, sizeof(buf), arg, NULL, short_name);
449                 name = buf;
450         }
451         for (tmp = *list_head; tmp; prev = tmp, tmp = tmp->next)
452                 if (strcmp(name, tmp->name) == 0)
453                         break;
454         
455         if (tmp == NULL) {
456                 PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
457                 return NULL;
458         }
459         /* Yes, this is actually save. To call this function the calles has to
460          * hold the GIL. Well, save as long as there is only one GIL anyway ... */
461         if (prev == NULL)
462                 *list_head = tmp->next;
463         else
464                 prev->next = tmp->next;
465         cpy_destroy_user_data(tmp);
466         Py_RETURN_NONE;
467 }
468
469 typedef int cpy_unregister_function_t(const char *name);
470
471 static PyObject *cpy_unregister_generic_userdata(cpy_unregister_function_t *unreg, PyObject *arg, const char *desc, int short_name) {
472         char buf[512];
473         const char *name;
474
475         if (PyString_Check(arg)) {
476                 name = PyString_AsString(arg);
477         } else {
478                 if (!PyCallable_Check(arg)) {
479                         PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
480                         return NULL;
481                 }
482                 cpy_build_name(buf, sizeof(buf), arg, NULL, short_name);
483                 name = buf;
484         }
485         if (unreg(name) == 0)
486                 Py_RETURN_NONE;
487         PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
488         return NULL;
489 }
490
491 static PyObject *cpy_unregister_log(PyObject *self, PyObject *arg) {
492         return cpy_unregister_generic_userdata(plugin_unregister_log, arg, "log", 0);
493 }
494
495 static PyObject *cpy_unregister_init(PyObject *self, PyObject *arg) {
496         return cpy_unregister_generic(&cpy_init_callbacks, arg, "init", 0);
497 }
498
499 static PyObject *cpy_unregister_config(PyObject *self, PyObject *arg) {
500         return cpy_unregister_generic(&cpy_config_callbacks, arg, "config", 1);
501 }
502
503 static PyObject *cpy_unregister_read(PyObject *self, PyObject *arg) {
504         return cpy_unregister_generic_userdata(plugin_unregister_read, arg, "read", 0);
505 }
506
507 static PyObject *cpy_unregister_write(PyObject *self, PyObject *arg) {
508         return cpy_unregister_generic_userdata(plugin_unregister_write, arg, "write", 0);
509 }
510
511 static PyObject *cpy_unregister_notification(PyObject *self, PyObject *arg) {
512         return cpy_unregister_generic_userdata(plugin_unregister_notification, arg, "notification", 0);
513 }
514
515 static PyObject *cpy_unregister_flush(PyObject *self, PyObject *arg) {
516         return cpy_unregister_generic_userdata(plugin_unregister_flush, arg, "flush", 1);
517 }
518
519 static PyObject *cpy_unregister_shutdown(PyObject *self, PyObject *arg) {
520         return cpy_unregister_generic(&cpy_shutdown_callbacks, arg, "shutdown", 0);
521 }
522
523 static PyMethodDef cpy_methods[] = {
524         {"debug", cpy_debug, METH_VARARGS, "This is an unhelpful text."},
525         {"info", cpy_info, METH_VARARGS, "This is an unhelpful text."},
526         {"notice", cpy_notice, METH_VARARGS, "This is an unhelpful text."},
527         {"warning", cpy_warning, METH_VARARGS, "This is an unhelpful text."},
528         {"error", cpy_error, METH_VARARGS, "This is an unhelpful text."},
529         {"flush", (PyCFunction) cpy_flush, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
530         {"register_log", (PyCFunction) cpy_register_log, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
531         {"register_init", (PyCFunction) cpy_register_init, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
532         {"register_config", (PyCFunction) cpy_register_config, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
533         {"register_read", (PyCFunction) cpy_register_read, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
534         {"register_write", (PyCFunction) cpy_register_write, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
535         {"register_notification", (PyCFunction) cpy_register_notification, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
536         {"register_flush", (PyCFunction) cpy_register_flush, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
537         {"register_shutdown", (PyCFunction) cpy_register_shutdown, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
538         {"unregister_log", cpy_unregister_log, METH_O, "This is an unhelpful text."},
539         {"unregister_init", cpy_unregister_init, METH_O, "This is an unhelpful text."},
540         {"unregister_config", cpy_unregister_config, METH_O, "This is an unhelpful text."},
541         {"unregister_read", cpy_unregister_read, METH_O, "This is an unhelpful text."},
542         {"unregister_write", cpy_unregister_write, METH_O, "This is an unhelpful text."},
543         {"unregister_notification", cpy_unregister_notification, METH_O, "This is an unhelpful text."},
544         {"unregister_flush", cpy_unregister_flush, METH_O, "This is an unhelpful text."},
545         {"unregister_shutdown", cpy_unregister_shutdown, METH_O, "This is an unhelpful text."},
546         {0, 0, 0, 0}
547 };
548
549 static int cpy_shutdown(void) {
550         cpy_callback_t *c;
551         PyObject *ret;
552         
553         /* This can happen if the module was loaded but not configured. */
554         if (state != NULL)
555                 PyEval_RestoreThread(state);
556
557         for (c = cpy_shutdown_callbacks; c; c = c->next) {
558                 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
559                 if (ret == NULL)
560                         cpy_log_exception("shutdown callback");
561                 else
562                         Py_DECREF(ret);
563         }
564         Py_Finalize();
565         return 0;
566 }
567
568 static void *cpy_interactive(void *data) {
569         CPY_LOCK_THREADS
570                 if (PyImport_ImportModule("readline") == NULL) {
571                         /* This interactive session will suck. */
572                         cpy_log_exception("interactive session init");
573                 }
574                 PyRun_InteractiveLoop(stdin, "<stdin>");
575         CPY_RELEASE_THREADS
576         NOTICE("python: Interactive interpreter exited, stopping collectd ...");
577         raise(SIGINT);
578         return NULL;
579 }
580
581 static int cpy_init(void) {
582         cpy_callback_t *c;
583         PyObject *ret;
584         static pthread_t thread;
585         
586         PyEval_InitThreads();
587         /* Now it's finally OK to use python threads. */
588         for (c = cpy_init_callbacks; c; c = c->next) {
589                 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
590                 if (ret == NULL)
591                         cpy_log_exception("init callback");
592                 else
593                         Py_DECREF(ret);
594         }
595         state = PyEval_SaveThread();
596         if (do_interactive) {
597                 if (pthread_create(&thread, NULL, cpy_interactive, NULL)) {
598                         ERROR("python: Error creating thread for interactive interpreter.");
599                 }
600         }
601
602         return 0;
603 }
604
605 static PyObject *cpy_oconfig_to_pyconfig(oconfig_item_t *ci, PyObject *parent) {
606         int i;
607         PyObject *item, *values, *children, *tmp;
608         
609         if (parent == NULL)
610                 parent = Py_None;
611         
612         values = PyTuple_New(ci->values_num); /* New reference. */
613         for (i = 0; i < ci->values_num; ++i) {
614                 if (ci->values[i].type == OCONFIG_TYPE_STRING) {
615                         PyTuple_SET_ITEM(values, i, PyString_FromString(ci->values[i].value.string));
616                 } else if (ci->values[i].type == OCONFIG_TYPE_NUMBER) {
617                         PyTuple_SET_ITEM(values, i, PyFloat_FromDouble(ci->values[i].value.number));
618                 } else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN) {
619                         PyTuple_SET_ITEM(values, i, PyBool_FromLong(ci->values[i].value.boolean));
620                 }
621         }
622         
623         item = PyObject_CallFunction((PyObject *) &ConfigType, "sONO", ci->key, parent, values, Py_None);
624         if (item == NULL)
625                 return NULL;
626         children = PyTuple_New(ci->children_num); /* New reference. */
627         for (i = 0; i < ci->children_num; ++i) {
628                 PyTuple_SET_ITEM(children, i, cpy_oconfig_to_pyconfig(ci->children + i, item));
629         }
630         tmp = ((Config *) item)->children;
631         ((Config *) item)->children = children;
632         Py_XDECREF(tmp);
633         return item;
634 }
635
636 static int cpy_config(oconfig_item_t *ci) {
637         int i;
638         PyObject *sys, *tb;
639         PyObject *sys_path;
640         PyObject *module;
641         
642         /* Ok in theory we shouldn't do initialization at this point
643          * but we have to. In order to give python scripts a chance
644          * to register a config callback we need to be able to execute
645          * python code during the config callback so we have to start
646          * the interpreter here. */
647         /* Do *not* use the python "thread" module at this point! */
648         Py_Initialize();
649         
650         PyType_Ready(&ConfigType);
651         PyType_Ready(&PluginDataType);
652         ValuesType.tp_base = &PluginDataType;
653         PyType_Ready(&ValuesType);
654         NotificationType.tp_base = &PluginDataType;
655         PyType_Ready(&NotificationType);
656         sys = PyImport_ImportModule("sys"); /* New reference. */
657         if (sys == NULL) {
658                 cpy_log_exception("python initialization");
659                 return 1;
660         }
661         sys_path = PyObject_GetAttrString(sys, "path"); /* New reference. */
662         Py_DECREF(sys);
663         if (sys_path == NULL) {
664                 cpy_log_exception("python initialization");
665                 return 1;
666         }
667         module = Py_InitModule("collectd", cpy_methods); /* Borrowed reference. */
668         PyModule_AddObject(module, "Config", (PyObject *) &ConfigType); /* Steals a reference. */
669         PyModule_AddObject(module, "Values", (PyObject *) &ValuesType); /* Steals a reference. */
670         PyModule_AddObject(module, "Notification", (PyObject *) &NotificationType); /* Steals a reference. */
671         PyModule_AddIntConstant(module, "LOG_DEBUG", LOG_DEBUG);
672         PyModule_AddIntConstant(module, "LOG_INFO", LOG_INFO);
673         PyModule_AddIntConstant(module, "LOG_NOTICE", LOG_NOTICE);
674         PyModule_AddIntConstant(module, "LOG_WARNING", LOG_WARNING);
675         PyModule_AddIntConstant(module, "LOG_ERROR", LOG_ERR);
676         PyModule_AddIntConstant(module, "NOTIF_FAILURE", NOTIF_FAILURE);
677         PyModule_AddIntConstant(module, "NOTIF_WARNING", NOTIF_WARNING);
678         PyModule_AddIntConstant(module, "NOTIF_OKAY", NOTIF_OKAY);
679         for (i = 0; i < ci->children_num; ++i) {
680                 oconfig_item_t *item = ci->children + i;
681                 
682                 if (strcasecmp(item->key, "Interactive") == 0) {
683                         if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
684                                 continue;
685                         do_interactive = item->values[0].value.boolean;
686                 } else if (strcasecmp(item->key, "LogTraces") == 0) {
687                         if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
688                                 continue;
689                         if (!item->values[0].value.boolean) {
690                                 Py_XDECREF(cpy_format_exception);
691                                 cpy_format_exception = NULL;
692                                 continue;
693                         }
694                         if (cpy_format_exception)
695                                 continue;
696                         tb = PyImport_ImportModule("traceback"); /* New reference. */
697                         if (tb == NULL) {
698                                 cpy_log_exception("python initialization");
699                                 continue;
700                         }
701                         cpy_format_exception = PyObject_GetAttrString(tb, "format_exception"); /* New reference. */
702                         Py_DECREF(tb);
703                         if (cpy_format_exception == NULL)
704                                 cpy_log_exception("python initialization");
705                 } else if (strcasecmp(item->key, "ModulePath") == 0) {
706                         char *dir = NULL;
707                         PyObject *dir_object;
708                         
709                         if (cf_util_get_string(item, &dir) != 0) 
710                                 continue;
711                         dir_object = PyString_FromString(dir); /* New reference. */
712                         if (dir_object == NULL) {
713                                 ERROR("python plugin: Unable to convert \"%s\" to "
714                                       "a python object.", dir);
715                                 free(dir);
716                                 cpy_log_exception("python initialization");
717                                 continue;
718                         }
719                         if (PyList_Append(sys_path, dir_object) != 0) {
720                                 ERROR("python plugin: Unable to append \"%s\" to "
721                                       "python module path.", dir);
722                                 cpy_log_exception("python initialization");
723                         }
724                         Py_DECREF(dir_object);
725                         free(dir);
726                 } else if (strcasecmp(item->key, "Import") == 0) {
727                         char *module_name = NULL;
728                         PyObject *module;
729                         
730                         if (cf_util_get_string(item, &module_name) != 0) 
731                                 continue;
732                         module = PyImport_ImportModule(module_name); /* New reference. */
733                         if (module == NULL) {
734                                 ERROR("python plugin: Error importing module \"%s\".", module_name);
735                                 cpy_log_exception("python initialization");
736                                 PyErr_Print();
737                         }
738                         free(module_name);
739                         Py_XDECREF(module);
740                 } else if (strcasecmp(item->key, "Module") == 0) {
741                         char *name = NULL;
742                         cpy_callback_t *c;
743                         PyObject *ret;
744                         
745                         if (cf_util_get_string(item, &name) != 0)
746                                 continue;
747                         for (c = cpy_config_callbacks; c; c = c->next) {
748                                 if (strcasecmp(c->name + 7, name) == 0)
749                                         break;
750                         }
751                         if (c == NULL) {
752                                 WARNING("python plugin: Found a configuration for the \"%s\" plugin, "
753                                         "but the plugin isn't loaded or didn't register "
754                                         "a configuration callback.", name);
755                                 free(name);
756                                 continue;
757                         }
758                         free(name);
759                         if (c->data == NULL)
760                                 ret = PyObject_CallFunction(c->callback, "N",
761                                         cpy_oconfig_to_pyconfig(item, NULL)); /* New reference. */
762                         else
763                                 ret = PyObject_CallFunction(c->callback, "NO",
764                                         cpy_oconfig_to_pyconfig(item, NULL), c->data); /* New reference. */
765                         if (ret == NULL)
766                                 cpy_log_exception("loading module");
767                         else
768                                 Py_DECREF(ret);
769                 } else {
770                         WARNING("python plugin: Ignoring unknown config key \"%s\".", item->key);
771                 }
772         }
773         Py_DECREF(sys_path);
774         return 0;
775 }
776
777 void module_register(void) {
778         plugin_register_complex_config("python", cpy_config);
779         plugin_register_init("python", cpy_init);
780 //      plugin_register_read("python", cna_read);
781         plugin_register_shutdown("python", cpy_shutdown);
782 }