This should have been in the last commit.
[collectd.git] / src / python.c
1 #include <Python.h>
2 #include <structmember.h>
3
4 #include <signal.h>
5 #if HAVE_PTHREAD_H
6 # include <pthread.h>
7 #endif
8
9 #include "collectd.h"
10 #include "common.h"
11
12 #include "cpython.h"
13
14 typedef struct cpy_callback_s {
15         char *name;
16         PyObject *callback;
17         PyObject *data;
18         struct cpy_callback_s *next;
19 } cpy_callback_t;
20
21 static char log_doc[] = "This function sends a string to all logging plugins.";
22
23 static char flush_doc[] = "flush([plugin][, timeout][, identifier]) -> None\n"
24                 "\n"
25                 "Flushes the cache of another plugin.";
26
27 static char unregister_doc[] = "Unregisters a callback. This function needs exactly one parameter either\n"
28                 "the function to unregister or the callback identifier to unregister.";
29
30 static char reg_log_doc[] = "register_log(callback[, data][, name]) -> identifier\n"
31                 "\n"
32                 "Register a callback function for log messages.\n"
33                 "\n"
34                 "'callback' is a callable object that will be called every time something\n"
35                 "    is logged.\n"
36                 "'data' is an optional object that will be passed back to the callback\n"
37                 "    function every time it is called.\n"
38                 "'name' is an optional identifier for this callback. The default name\n"
39                 "    is 'python.<module>'.\n"
40                 "    Every callback needs a unique identifier, so if you want to\n"
41                 "    register this callback multiple time from the same module you need\n"
42                 "    to specify a name here.\n"
43                 "'identifier' is the full identifier assigned to this callback.\n"
44                 "\n"
45                 "The callback function will be called with two or three parameters:\n"
46                 "severity: An integer that should be compared to the LOG_ constants.\n"
47                 "message: The text to be logged.\n"
48                 "data: The optional data parameter passed to the register function.\n"
49                 "    If the parameter was obmitted it will be obmitted here, too.";
50
51 static char reg_init_doc[] = "register_init(callback[, data][, name]) -> identifier\n"
52                 "\n"
53                 "Register a callback function that will be executed once after the config.\n"
54                 "file has been read, all plugins heve been loaded and the collectd has\n"
55                 "forked into the backgroud.\n"
56                 "\n"
57                 "'callback' is a callable object that will be executed.\n"
58                 "'data' is an optional object that will be passed back to the callback\n"
59                 "    function when it is called.\n"
60                 "'name' is an optional identifier for this callback. The default name\n"
61                 "    is 'python.<module>'.\n"
62                 "    Every callback needs a unique identifier, so if you want to\n"
63                 "    register this callback multiple time from the same module you need\n"
64                 "    to specify a name here.\n"
65                 "'identifier' is the full identifier assigned to this callback.\n"
66                 "\n"
67                 "The callback function will be called without parameters, except for\n"
68                 "data if it was supplied.";
69
70 static char reg_config_doc[] = "register_config(callback[, data][, name]) -> identifier\n"
71                 "\n"
72                 "Register a callback function for config file entries.\n"
73                 "'callback' is a callable object that will be called for every config block.\n"
74                 "'data' is an optional object that will be passed back to the callback\n"
75                 "    function every time it is called.\n"
76                 "'name' is an optional identifier for this callback. The default name\n"
77                 "    is 'python.<module>'.\n"
78                 "    Every callback needs a unique identifier, so if you want to\n"
79                 "    register this callback multiple time from the same module you need\n"
80                 "    to specify a name here.\n"
81                 "'identifier' is the full identifier assigned to this callback.\n"
82                 "\n"
83                 "The callback function will be called with one or two parameters:\n"
84                 "config: A Config object.\n"
85                 "data: The optional data parameter passed to the register function.\n"
86                 "    If the parameter was obmitted it will be obmitted here, too.";
87
88 static char reg_read_doc[] = "register_read(callback[, interval][, data][, name]) -> identifier\n"
89                 "\n"
90                 "Register a callback function for reading data. It will just be called\n"
91                 "in a fixed interval to signal that it's time to dispatch new values.\n"
92                 "'callback' is a callable object that will be called every time something\n"
93                 "    is logged.\n"
94                 "'interval' is the number of seconds between between calls to the callback\n"
95                 "    function. Full float precision is supported here.\n"
96                 "'data' is an optional object that will be passed back to the callback\n"
97                 "    function every time it is called.\n"
98                 "'name' is an optional identifier for this callback. The default name\n"
99                 "    is 'python.<module>'.\n"
100                 "    Every callback needs a unique identifier, so if you want to\n"
101                 "    register this callback multiple time from the same module you need\n"
102                 "    to specify a name here.\n"
103                 "'identifier' is the full identifier assigned to this callback.\n"
104                 "\n"
105                 "The callback function will be called without parameters, except for\n"
106                 "data if it was supplied.";
107
108 static char reg_write_doc[] = "register_write(callback[, data][, name]) -> identifier\n"
109                 "\n"
110                 "Register a callback function to receive values dispatched by other plugins.\n"
111                 "'callback' is a callable object that will be called every time a value\n"
112                 "    is dispatched.\n"
113                 "'data' is an optional object that will be passed back to the callback\n"
114                 "    function every time it is called.\n"
115                 "'name' is an optional identifier for this callback. The default name\n"
116                 "    is 'python.<module>'.\n"
117                 "    Every callback needs a unique identifier, so if you want to\n"
118                 "    register this callback multiple time from the same module you need\n"
119                 "    to specify a name here.\n"
120                 "'identifier' is the full identifier assigned to this callback.\n"
121                 "\n"
122                 "The callback function will be called with one or two parameters:\n"
123                 "values: A Values object which is a copy of the dispatched values.\n"
124                 "data: The optional data parameter passed to the register function.\n"
125                 "    If the parameter was obmitted it will be obmitted here, too.";
126
127 static char reg_notification_doc[] = "register_notification(callback[, data][, name]) -> identifier\n"
128                 "\n"
129                 "Register a callback function for notifications.\n"
130                 "'callback' is a callable object that will be called every time a notification\n"
131                 "    is dispatched.\n"
132                 "'data' is an optional object that will be passed back to the callback\n"
133                 "    function every time it is called.\n"
134                 "'name' is an optional identifier for this callback. The default name\n"
135                 "    is 'python.<module>'.\n"
136                 "    Every callback needs a unique identifier, so if you want to\n"
137                 "    register this callback multiple time from the same module you need\n"
138                 "    to specify a name here.\n"
139                 "'identifier' is the full identifier assigned to this callback.\n"
140                 "\n"
141                 "The callback function will be called with one or two parameters:\n"
142                 "notification: A copy of the notification that was dispatched.\n"
143                 "data: The optional data parameter passed to the register function.\n"
144                 "    If the parameter was obmitted it will be obmitted here, too.";
145
146 static char reg_flush_doc[] = "register_flush(callback[, data][, name]) -> identifier\n"
147                 "\n"
148                 "Register a callback function for flush messages.\n"
149                 "'callback' is a callable object that will be called every time a plugin\n"
150                 "    requests a flush for either this or all plugins.\n"
151                 "'data' is an optional object that will be passed back to the callback\n"
152                 "    function every time it is called.\n"
153                 "'name' is an optional identifier for this callback. The default name\n"
154                 "    is 'python.<module>'.\n"
155                 "    Every callback needs a unique identifier, so if you want to\n"
156                 "    register this callback multiple time from the same module you need\n"
157                 "    to specify a name here.\n"
158                 "'identifier' is the full identifier assigned to this callback.\n"
159                 "\n"
160                 "The callback function will be called with two or three parameters:\n"
161                 "timeout: Indicates that only data older than 'timeout' seconds is to\n"
162                 "    be flushed.\n"
163                 "id: Specifies which values are to be flushed.\n"
164                 "data: The optional data parameter passed to the register function.\n"
165                 "    If the parameter was obmitted it will be obmitted here, too.";
166
167 static char reg_shutdown_doc[] = "register_shutdown(callback[, data][, name]) -> identifier\n"
168                 "\n"
169                 "Register a callback function for collectd shutdown.\n"
170                 "'callback' is a callable object that will be called once collectd is\n"
171                 "    shutting down.\n"
172                 "'data' is an optional object that will be passed back to the callback\n"
173                 "    function if it is called.\n"
174                 "'name' is an optional identifier for this callback. The default name\n"
175                 "    is 'python.<module>'.\n"
176                 "    Every callback needs a unique identifier, so if you want to\n"
177                 "    register this callback multiple time from the same module you need\n"
178                 "    to specify a name here.\n"
179                 "'identifier' is the full identifier assigned to this callback.\n"
180                 "\n"
181                 "The callback function will be called with no parameters except for\n"
182                 "    data if it was supplied.";
183
184
185 static int do_interactive = 0;
186
187 /* This is our global thread state. Python saves some stuff in thread-local
188  * storage. So if we allow the interpreter to run in the background
189  * (the scriptwriters might have created some threads from python), we have
190  * to save the state so we can resume it later after shutdown. */
191
192 static PyThreadState *state;
193
194 static PyObject *cpy_format_exception;
195
196 static cpy_callback_t *cpy_config_callbacks;
197 static cpy_callback_t *cpy_init_callbacks;
198 static cpy_callback_t *cpy_shutdown_callbacks;
199
200 static void cpy_destroy_user_data(void *data) {
201         cpy_callback_t *c = data;
202         free(c->name);
203         Py_DECREF(c->callback);
204         Py_XDECREF(c->data);
205         free(c);
206 }
207
208 /* You must hold the GIL to call this function!
209  * But if you managed to extract the callback parameter then you probably already do. */
210
211 static void cpy_build_name(char *buf, size_t size, PyObject *callback, const char *name) {
212         const char *module = NULL;
213         PyObject *mod = NULL;
214         
215         if (name != NULL) {
216                 snprintf(buf, size, "python.%s", name);
217                 return;
218         }
219         
220         mod = PyObject_GetAttrString(callback, "__module__"); /* New reference. */
221         if (mod != NULL)
222                 module = PyString_AsString(mod);
223         
224         if (module != NULL) {
225                 snprintf(buf, size, "python.%s", module);
226                 Py_XDECREF(mod);
227                 return;
228         }
229         Py_XDECREF(mod);
230         
231         snprintf(buf, size, "python.%p", callback);
232 }
233
234 static void cpy_log_exception(const char *context) {
235         int l = 0, i;
236         const char *typename = NULL, *message = NULL;
237         PyObject *type, *value, *traceback, *tn, *m, *list;
238         
239         PyErr_Fetch(&type, &value, &traceback);
240         PyErr_NormalizeException(&type, &value, &traceback);
241         if (type == NULL) return;
242         tn = PyObject_GetAttrString(type, "__name__"); /* New reference. */
243         m = PyObject_GetAttrString(value, "message"); /* New reference. */
244         if (tn != NULL)
245                 typename = PyString_AsString(tn);
246         if (m != NULL)
247                 message = PyString_AsString(m);
248         if (typename == NULL)
249                 typename = "NamelessException";
250         if (message == NULL)
251                 message = "N/A";
252         Py_BEGIN_ALLOW_THREADS
253         ERROR("Unhandled python exception in %s: %s: %s", context, typename, message);
254         Py_END_ALLOW_THREADS
255         Py_XDECREF(tn);
256         Py_XDECREF(m);
257         if (!cpy_format_exception) {
258                 PyErr_Clear();
259                 Py_XDECREF(type);
260                 Py_XDECREF(value);
261                 Py_XDECREF(traceback);
262                 return;
263         }
264         if (!traceback) {
265                 PyErr_Clear();
266                 return;
267         }
268         list = PyObject_CallFunction(cpy_format_exception, "NNN", type, value, traceback); /* New reference. */
269         if (list)
270                 l = PyObject_Length(list);
271         for (i = 0; i < l; ++i) {
272                 char *s;
273                 PyObject *line;
274                 
275                 line = PyList_GET_ITEM(list, i); /* Borrowed reference. */
276                 s = strdup(PyString_AsString(line));
277                 Py_DECREF(line);
278                 if (s[strlen(s) - 1] == '\n')
279                         s[strlen(s) - 1] = 0;
280                 Py_BEGIN_ALLOW_THREADS
281                 ERROR("%s", s);
282                 Py_END_ALLOW_THREADS
283                 free(s);
284         }
285         Py_XDECREF(list);
286         PyErr_Clear();
287 }
288
289 static int cpy_read_callback(user_data_t *data) {
290         cpy_callback_t *c = data->data;
291         PyObject *ret;
292
293         CPY_LOCK_THREADS
294                 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
295                 if (ret == NULL) {
296                         cpy_log_exception("read callback");
297                 } else {
298                         Py_DECREF(ret);
299                 }
300         CPY_RELEASE_THREADS
301         if (ret == NULL)
302                 return 1;
303         return 0;
304 }
305
306 static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_list, user_data_t *data) {
307         int i;
308         cpy_callback_t *c = data->data;
309         PyObject *ret, *v, *list;
310
311         CPY_LOCK_THREADS
312                 list = PyList_New(value_list->values_len); /* New reference. */
313                 if (list == NULL) {
314                         cpy_log_exception("write callback");
315                         CPY_RETURN_FROM_THREADS 0;
316                 }
317                 for (i = 0; i < value_list->values_len; ++i) {
318                         if (ds->ds->type == DS_TYPE_COUNTER) {
319                                 if ((long) value_list->values[i].counter == value_list->values[i].counter)
320                                         PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].counter));
321                                 else
322                                         PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].counter));
323                         } else if (ds->ds->type == DS_TYPE_GAUGE) {
324                                 PyList_SetItem(list, i, PyFloat_FromDouble(value_list->values[i].gauge));
325                         } else if (ds->ds->type == DS_TYPE_DERIVE) {
326                                 if ((long) value_list->values[i].derive == value_list->values[i].derive)
327                                         PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].derive));
328                                 else
329                                         PyList_SetItem(list, i, PyLong_FromLongLong(value_list->values[i].derive));
330                         } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
331                                 if ((long) value_list->values[i].absolute == value_list->values[i].absolute)
332                                         PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].absolute));
333                                 else
334                                         PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].absolute));
335                         } else {
336                                 Py_BEGIN_ALLOW_THREADS
337                                 ERROR("cpy_write_callback: Unknown value type %d.", ds->ds->type);
338                                 Py_END_ALLOW_THREADS
339                                 Py_DECREF(list);
340                                 CPY_RETURN_FROM_THREADS 0;
341                         }
342                         if (PyErr_Occurred() != NULL) {
343                                 cpy_log_exception("value building for write callback");
344                                 CPY_RETURN_FROM_THREADS 0;
345                         }
346                 }
347                 v = PyObject_CallFunction((PyObject *) &ValuesType, "sOssssdi", value_list->type, list,
348                                 value_list->plugin_instance, value_list->type_instance, value_list->plugin,
349                                 value_list->host, (double) value_list->time, value_list->interval);
350                 Py_DECREF(list);
351                 ret = PyObject_CallFunctionObjArgs(c->callback, v, c->data, (void *) 0); /* New reference. */
352                 if (ret == NULL) {
353                         cpy_log_exception("write callback");
354                 } else {
355                         Py_DECREF(ret);
356                 }
357         CPY_RELEASE_THREADS
358         return 0;
359 }
360
361 static int cpy_notification_callback(const notification_t *notification, user_data_t *data) {
362         cpy_callback_t *c = data->data;
363         PyObject *ret, *n;
364
365         CPY_LOCK_THREADS
366                 n = PyObject_CallFunction((PyObject *) &NotificationType, "ssssssdi", notification->type, notification->message,
367                                 notification->plugin_instance, notification->type_instance, notification->plugin,
368                                 notification->host, (double) notification->time, notification->severity);
369                 ret = PyObject_CallFunctionObjArgs(c->callback, n, c->data, (void *) 0); /* New reference. */
370                 if (ret == NULL) {
371                         cpy_log_exception("notification callback");
372                 } else {
373                         Py_DECREF(ret);
374                 }
375         CPY_RELEASE_THREADS
376         return 0;
377 }
378
379 static void cpy_log_callback(int severity, const char *message, user_data_t *data) {
380         cpy_callback_t * c = data->data;
381         PyObject *ret;
382
383         CPY_LOCK_THREADS
384         if (c->data == NULL)
385                 ret = PyObject_CallFunction(c->callback, "is", severity, message); /* New reference. */
386         else
387                 ret = PyObject_CallFunction(c->callback, "isO", severity, message, c->data); /* New reference. */
388
389         if (ret == NULL) {
390                 /* FIXME */
391                 /* Do we really want to trigger a log callback because a log callback failed?
392                  * Probably not. */
393                 PyErr_Print();
394                 /* In case someone wanted to be clever, replaced stderr and failed at that. */
395                 PyErr_Clear();
396         } else {
397                 Py_DECREF(ret);
398         }
399         CPY_RELEASE_THREADS
400 }
401
402 static void cpy_flush_callback(int timeout, const char *id, user_data_t *data) {
403         cpy_callback_t * c = data->data;
404         PyObject *ret;
405
406         CPY_LOCK_THREADS
407         if (c->data == NULL)
408                 ret = PyObject_CallFunction(c->callback, "is", timeout, id); /* New reference. */
409         else
410                 ret = PyObject_CallFunction(c->callback, "isO", timeout, id, c->data); /* New reference. */
411
412         if (ret == NULL) {
413                 cpy_log_exception("flush callback");
414         } else {
415                 Py_DECREF(ret);
416         }
417         CPY_RELEASE_THREADS
418 }
419
420 static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args, PyObject *kwds) {
421         char buf[512];
422         cpy_callback_t *c;
423         const char *name = NULL;
424         PyObject *callback = NULL, *data = NULL, *mod = NULL;
425         static char *kwlist[] = {"callback", "data", "name", NULL};
426         
427         if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oz", kwlist, &callback, &data, &name) == 0) return NULL;
428         if (PyCallable_Check(callback) == 0) {
429                 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
430                 return NULL;
431         }
432         cpy_build_name(buf, sizeof(buf), callback, name);
433
434         Py_INCREF(callback);
435         Py_XINCREF(data);
436         c = malloc(sizeof(*c));
437         c->name = strdup(buf);
438         c->callback = callback;
439         c->data = data;
440         c->next = *list_head;
441         *list_head = c;
442         Py_XDECREF(mod);
443         return PyString_FromString(buf);
444 }
445
446 static PyObject *cpy_flush(cpy_callback_t **list_head, PyObject *args, PyObject *kwds) {
447         int timeout = -1;
448         const char *plugin = NULL, *identifier = NULL;
449         static char *kwlist[] = {"plugin", "timeout", "identifier", NULL};
450         
451         if (PyArg_ParseTupleAndKeywords(args, kwds, "|ziz", kwlist, &plugin, &timeout, &identifier) == 0) return NULL;
452         Py_BEGIN_ALLOW_THREADS
453         plugin_flush(plugin, timeout, identifier);
454         Py_END_ALLOW_THREADS
455         Py_RETURN_NONE;
456 }
457
458 static PyObject *cpy_register_config(PyObject *self, PyObject *args, PyObject *kwds) {
459         return cpy_register_generic(&cpy_config_callbacks, args, kwds);
460 }
461
462 static PyObject *cpy_register_init(PyObject *self, PyObject *args, PyObject *kwds) {
463         return cpy_register_generic(&cpy_init_callbacks, args, kwds);
464 }
465
466 typedef int reg_function_t(const char *name, void *callback, void *data);
467
468 static PyObject *cpy_register_generic_userdata(void *reg, void *handler, PyObject *args, PyObject *kwds) {
469         char buf[512];
470         reg_function_t *register_function = (reg_function_t *) reg;
471         cpy_callback_t *c = NULL;
472         user_data_t *user_data = NULL;
473         const char *name = NULL;
474         PyObject *callback = NULL, *data = NULL;
475         static char *kwlist[] = {"callback", "data", "name", NULL};
476         
477         if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oz", kwlist, &callback, &data, &name) == 0) return NULL;
478         if (PyCallable_Check(callback) == 0) {
479                 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
480                 return NULL;
481         }
482         cpy_build_name(buf, sizeof(buf), callback, name);
483         
484         Py_INCREF(callback);
485         Py_XINCREF(data);
486         c = malloc(sizeof(*c));
487         c->name = strdup(buf);
488         c->callback = callback;
489         c->data = data;
490         c->next = NULL;
491         user_data = malloc(sizeof(*user_data));
492         user_data->free_func = cpy_destroy_user_data;
493         user_data->data = c;
494         register_function(buf, handler, user_data);
495         return PyString_FromString(buf);
496 }
497
498 static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwds) {
499         char buf[512];
500         cpy_callback_t *c = NULL;
501         user_data_t *user_data = NULL;
502         double interval = 0;
503         const char *name = NULL;
504         PyObject *callback = NULL, *data = NULL;
505         struct timespec ts;
506         static char *kwlist[] = {"callback", "interval", "data", "name", NULL};
507         
508         if (PyArg_ParseTupleAndKeywords(args, kwds, "O|dOz", kwlist, &callback, &interval, &data, &name) == 0) return NULL;
509         if (PyCallable_Check(callback) == 0) {
510                 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
511                 return NULL;
512         }
513         cpy_build_name(buf, sizeof(buf), callback, name);
514         
515         Py_INCREF(callback);
516         Py_XINCREF(data);
517         c = malloc(sizeof(*c));
518         c->name = strdup(buf);
519         c->callback = callback;
520         c->data = data;
521         c->next = NULL;
522         user_data = malloc(sizeof(*user_data));
523         user_data->free_func = cpy_destroy_user_data;
524         user_data->data = c;
525         ts.tv_sec = interval;
526         ts.tv_nsec = (interval - ts.tv_sec) * 1000000000;
527         plugin_register_complex_read(buf, cpy_read_callback, &ts, user_data);
528         return PyString_FromString(buf);
529 }
530
531 static PyObject *cpy_register_log(PyObject *self, PyObject *args, PyObject *kwds) {
532         return cpy_register_generic_userdata(plugin_register_log, cpy_log_callback, args, kwds);
533 }
534
535 static PyObject *cpy_register_write(PyObject *self, PyObject *args, PyObject *kwds) {
536         return cpy_register_generic_userdata(plugin_register_write, cpy_write_callback, args, kwds);
537 }
538
539 static PyObject *cpy_register_notification(PyObject *self, PyObject *args, PyObject *kwds) {
540         return cpy_register_generic_userdata(plugin_register_notification, cpy_notification_callback, args, kwds);
541 }
542
543 static PyObject *cpy_register_flush(PyObject *self, PyObject *args, PyObject *kwds) {
544         return cpy_register_generic_userdata(plugin_register_flush, cpy_flush_callback, args, kwds);
545 }
546
547 static PyObject *cpy_register_shutdown(PyObject *self, PyObject *args, PyObject *kwds) {
548         return cpy_register_generic(&cpy_shutdown_callbacks, args, kwds);
549 }
550
551 static PyObject *cpy_error(PyObject *self, PyObject *args) {
552         const char *text;
553         if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
554         Py_BEGIN_ALLOW_THREADS
555         plugin_log(LOG_ERR, "%s", text);
556         Py_END_ALLOW_THREADS
557         Py_RETURN_NONE;
558 }
559
560 static PyObject *cpy_warning(PyObject *self, PyObject *args) {
561         const char *text;
562         if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
563         Py_BEGIN_ALLOW_THREADS
564         plugin_log(LOG_WARNING, "%s", text);
565         Py_END_ALLOW_THREADS
566         Py_RETURN_NONE;
567 }
568
569 static PyObject *cpy_notice(PyObject *self, PyObject *args) {
570         const char *text;
571         if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
572         Py_BEGIN_ALLOW_THREADS
573         plugin_log(LOG_NOTICE, "%s", text);
574         Py_END_ALLOW_THREADS
575         Py_RETURN_NONE;
576 }
577
578 static PyObject *cpy_info(PyObject *self, PyObject *args) {
579         const char *text;
580         if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
581         Py_BEGIN_ALLOW_THREADS
582         plugin_log(LOG_INFO, "%s", text);
583         Py_END_ALLOW_THREADS
584         Py_RETURN_NONE;
585 }
586
587 static PyObject *cpy_debug(PyObject *self, PyObject *args) {
588 #ifdef COLLECT_DEBUG
589         const char *text;
590         if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
591         Py_BEGIN_ALLOW_THREADS
592         plugin_log(LOG_DEBUG, "%s", text);
593         Py_END_ALLOW_THREADS
594 #endif
595         Py_RETURN_NONE;
596 }
597
598 static PyObject *cpy_unregister_generic(cpy_callback_t **list_head, PyObject *arg, const char *desc) {
599         char buf[512];
600         const char *name;
601         cpy_callback_t *prev = NULL, *tmp;
602
603         if (PyUnicode_Check(arg)) {
604                 arg = PyUnicode_AsEncodedString(arg, NULL, NULL);
605                 if (arg == NULL)
606                         return NULL;
607                 name = PyString_AsString(arg);
608                 Py_DECREF(arg);
609         } else if (PyString_Check(arg)) {
610                 name = PyString_AsString(arg);
611         } else {
612                 if (!PyCallable_Check(arg)) {
613                         PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
614                         return NULL;
615                 }
616                 cpy_build_name(buf, sizeof(buf), arg, NULL);
617                 name = buf;
618         }
619         for (tmp = *list_head; tmp; prev = tmp, tmp = tmp->next)
620                 if (strcmp(name, tmp->name) == 0)
621                         break;
622         
623         if (tmp == NULL) {
624                 PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
625                 return NULL;
626         }
627         /* Yes, this is actually save. To call this function the calles has to
628          * hold the GIL. Well, save as long as there is only one GIL anyway ... */
629         if (prev == NULL)
630                 *list_head = tmp->next;
631         else
632                 prev->next = tmp->next;
633         cpy_destroy_user_data(tmp);
634         Py_RETURN_NONE;
635 }
636
637 typedef int cpy_unregister_function_t(const char *name);
638
639 static PyObject *cpy_unregister_generic_userdata(cpy_unregister_function_t *unreg, PyObject *arg, const char *desc) {
640         char buf[512];
641         const char *name;
642
643         if (PyUnicode_Check(arg)) {
644                 arg = PyUnicode_AsEncodedString(arg, NULL, NULL);
645                 if (arg == NULL)
646                         return NULL;
647                 name = PyString_AsString(arg);
648                 Py_DECREF(arg);
649         } else if (PyString_Check(arg)) {
650                 name = PyString_AsString(arg);
651         } else {
652                 if (!PyCallable_Check(arg)) {
653                         PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
654                         return NULL;
655                 }
656                 cpy_build_name(buf, sizeof(buf), arg, NULL);
657                 name = buf;
658         }
659         if (unreg(name) == 0)
660                 Py_RETURN_NONE;
661         PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
662         return NULL;
663 }
664
665 static PyObject *cpy_unregister_log(PyObject *self, PyObject *arg) {
666         return cpy_unregister_generic_userdata(plugin_unregister_log, arg, "log");
667 }
668
669 static PyObject *cpy_unregister_init(PyObject *self, PyObject *arg) {
670         return cpy_unregister_generic(&cpy_init_callbacks, arg, "init");
671 }
672
673 static PyObject *cpy_unregister_config(PyObject *self, PyObject *arg) {
674         return cpy_unregister_generic(&cpy_config_callbacks, arg, "config");
675 }
676
677 static PyObject *cpy_unregister_read(PyObject *self, PyObject *arg) {
678         return cpy_unregister_generic_userdata(plugin_unregister_read, arg, "read");
679 }
680
681 static PyObject *cpy_unregister_write(PyObject *self, PyObject *arg) {
682         return cpy_unregister_generic_userdata(plugin_unregister_write, arg, "write");
683 }
684
685 static PyObject *cpy_unregister_notification(PyObject *self, PyObject *arg) {
686         return cpy_unregister_generic_userdata(plugin_unregister_notification, arg, "notification");
687 }
688
689 static PyObject *cpy_unregister_flush(PyObject *self, PyObject *arg) {
690         return cpy_unregister_generic_userdata(plugin_unregister_flush, arg, "flush");
691 }
692
693 static PyObject *cpy_unregister_shutdown(PyObject *self, PyObject *arg) {
694         return cpy_unregister_generic(&cpy_shutdown_callbacks, arg, "shutdown");
695 }
696
697 static PyMethodDef cpy_methods[] = {
698         {"debug", cpy_debug, METH_VARARGS, log_doc},
699         {"info", cpy_info, METH_VARARGS, log_doc},
700         {"notice", cpy_notice, METH_VARARGS, log_doc},
701         {"warning", cpy_warning, METH_VARARGS, log_doc},
702         {"error", cpy_error, METH_VARARGS, log_doc},
703         {"flush", (PyCFunction) cpy_flush, METH_VARARGS | METH_KEYWORDS, flush_doc},
704         {"register_log", (PyCFunction) cpy_register_log, METH_VARARGS | METH_KEYWORDS, reg_log_doc},
705         {"register_init", (PyCFunction) cpy_register_init, METH_VARARGS | METH_KEYWORDS, reg_init_doc},
706         {"register_config", (PyCFunction) cpy_register_config, METH_VARARGS | METH_KEYWORDS, reg_config_doc},
707         {"register_read", (PyCFunction) cpy_register_read, METH_VARARGS | METH_KEYWORDS, reg_read_doc},
708         {"register_write", (PyCFunction) cpy_register_write, METH_VARARGS | METH_KEYWORDS, reg_write_doc},
709         {"register_notification", (PyCFunction) cpy_register_notification, METH_VARARGS | METH_KEYWORDS, reg_notification_doc},
710         {"register_flush", (PyCFunction) cpy_register_flush, METH_VARARGS | METH_KEYWORDS, reg_flush_doc},
711         {"register_shutdown", (PyCFunction) cpy_register_shutdown, METH_VARARGS | METH_KEYWORDS, reg_shutdown_doc},
712         {"unregister_log", cpy_unregister_log, METH_O, unregister_doc},
713         {"unregister_init", cpy_unregister_init, METH_O, unregister_doc},
714         {"unregister_config", cpy_unregister_config, METH_O, unregister_doc},
715         {"unregister_read", cpy_unregister_read, METH_O, unregister_doc},
716         {"unregister_write", cpy_unregister_write, METH_O, unregister_doc},
717         {"unregister_notification", cpy_unregister_notification, METH_O, unregister_doc},
718         {"unregister_flush", cpy_unregister_flush, METH_O, unregister_doc},
719         {"unregister_shutdown", cpy_unregister_shutdown, METH_O, unregister_doc},
720         {0, 0, 0, 0}
721 };
722
723 static int cpy_shutdown(void) {
724         cpy_callback_t *c;
725         PyObject *ret;
726         
727         /* This can happen if the module was loaded but not configured. */
728         if (state != NULL)
729                 PyEval_RestoreThread(state);
730
731         for (c = cpy_shutdown_callbacks; c; c = c->next) {
732                 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
733                 if (ret == NULL)
734                         cpy_log_exception("shutdown callback");
735                 else
736                         Py_DECREF(ret);
737         }
738         PyErr_Print();
739         Py_Finalize();
740         return 0;
741 }
742
743 static void cpy_int_handler(int sig) {
744         return;
745 }
746
747 static void *cpy_interactive(void *data) {
748         sigset_t sigset;
749         struct sigaction sig_int_action, old;
750         
751         /* Signal handler in a plugin? Bad stuff, but the best way to
752          * handle it I guess. In an interactive session people will
753          * press Ctrl+C at some time, which will generate a SIGINT.
754          * This will cause collectd to shutdown, thus killing the
755          * interactive interpreter, and leaving the terminal in a
756          * mess. Chances are, this isn't what the user wanted to do.
757          * 
758          * So this is the plan:
759          * 1. Block SIGINT in the main thread.
760          * 2. Install our own signal handler that does nothing.
761          * 3. Unblock SIGINT in the interactive thread.
762          *
763          * This will make sure that SIGINT won't kill collectd but
764          * still interrupt syscalls like sleep and pause.
765          * It does not raise a KeyboardInterrupt exception because so
766          * far nobody managed to figure out how to do that. */
767         memset (&sig_int_action, '\0', sizeof (sig_int_action));
768         sig_int_action.sa_handler = cpy_int_handler;
769         sigaction (SIGINT, &sig_int_action, &old);
770         
771         sigemptyset(&sigset);
772         sigaddset(&sigset, SIGINT);
773         pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
774         PyEval_AcquireThread(state);
775         if (PyImport_ImportModule("readline") == NULL) {
776                 /* This interactive session will suck. */
777                 cpy_log_exception("interactive session init");
778         }
779         PyRun_InteractiveLoop(stdin, "<stdin>");
780         PyErr_Print();
781         PyEval_ReleaseThread(state);
782         NOTICE("python: Interactive interpreter exited, stopping collectd ...");
783         /* Restore the original collectd SIGINT handler and raise SIGINT.
784          * The main thread still has SIGINT blocked and there's nothing we
785          * can do about that so this thread will handle it. But that's not
786          * important, except that it won't interrupt the main loop and so
787          * it might take a few seconds before collectd really shuts down. */
788         sigaction (SIGINT, &old, NULL);
789         raise(SIGINT);
790         pause();
791         return NULL;
792 }
793
794 static int cpy_init(void) {
795         cpy_callback_t *c;
796         PyObject *ret;
797         static pthread_t thread;
798         sigset_t sigset;
799         
800         PyEval_InitThreads();
801         /* Now it's finally OK to use python threads. */
802         for (c = cpy_init_callbacks; c; c = c->next) {
803                 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
804                 if (ret == NULL)
805                         cpy_log_exception("init callback");
806                 else
807                         Py_DECREF(ret);
808         }
809         sigemptyset(&sigset);
810         sigaddset(&sigset, SIGINT);
811         pthread_sigmask(SIG_BLOCK, &sigset, NULL);
812         state = PyEval_SaveThread();
813         if (do_interactive) {
814                 if (pthread_create(&thread, NULL, cpy_interactive, NULL)) {
815                         ERROR("python: Error creating thread for interactive interpreter.");
816                 }
817         }
818
819         return 0;
820 }
821
822 static PyObject *cpy_oconfig_to_pyconfig(oconfig_item_t *ci, PyObject *parent) {
823         int i;
824         PyObject *item, *values, *children, *tmp;
825         
826         if (parent == NULL)
827                 parent = Py_None;
828         
829         values = PyTuple_New(ci->values_num); /* New reference. */
830         for (i = 0; i < ci->values_num; ++i) {
831                 if (ci->values[i].type == OCONFIG_TYPE_STRING) {
832                         PyTuple_SET_ITEM(values, i, PyString_FromString(ci->values[i].value.string));
833                 } else if (ci->values[i].type == OCONFIG_TYPE_NUMBER) {
834                         PyTuple_SET_ITEM(values, i, PyFloat_FromDouble(ci->values[i].value.number));
835                 } else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN) {
836                         PyTuple_SET_ITEM(values, i, PyBool_FromLong(ci->values[i].value.boolean));
837                 }
838         }
839         
840         item = PyObject_CallFunction((PyObject *) &ConfigType, "sONO", ci->key, parent, values, Py_None);
841         if (item == NULL)
842                 return NULL;
843         children = PyTuple_New(ci->children_num); /* New reference. */
844         for (i = 0; i < ci->children_num; ++i) {
845                 PyTuple_SET_ITEM(children, i, cpy_oconfig_to_pyconfig(ci->children + i, item));
846         }
847         tmp = ((Config *) item)->children;
848         ((Config *) item)->children = children;
849         Py_XDECREF(tmp);
850         return item;
851 }
852
853 static int cpy_config(oconfig_item_t *ci) {
854         int i;
855         PyObject *sys, *tb;
856         PyObject *sys_path;
857         PyObject *module;
858         
859         /* Ok in theory we shouldn't do initialization at this point
860          * but we have to. In order to give python scripts a chance
861          * to register a config callback we need to be able to execute
862          * python code during the config callback so we have to start
863          * the interpreter here. */
864         /* Do *not* use the python "thread" module at this point! */
865         Py_Initialize();
866         
867         PyType_Ready(&ConfigType);
868         PyType_Ready(&PluginDataType);
869         ValuesType.tp_base = &PluginDataType;
870         PyType_Ready(&ValuesType);
871         NotificationType.tp_base = &PluginDataType;
872         PyType_Ready(&NotificationType);
873         sys = PyImport_ImportModule("sys"); /* New reference. */
874         if (sys == NULL) {
875                 cpy_log_exception("python initialization");
876                 return 1;
877         }
878         sys_path = PyObject_GetAttrString(sys, "path"); /* New reference. */
879         Py_DECREF(sys);
880         if (sys_path == NULL) {
881                 cpy_log_exception("python initialization");
882                 return 1;
883         }
884         module = Py_InitModule("collectd", cpy_methods); /* Borrowed reference. */
885         PyModule_AddObject(module, "Config", (PyObject *) &ConfigType); /* Steals a reference. */
886         PyModule_AddObject(module, "Values", (PyObject *) &ValuesType); /* Steals a reference. */
887         PyModule_AddObject(module, "Notification", (PyObject *) &NotificationType); /* Steals a reference. */
888         PyModule_AddIntConstant(module, "LOG_DEBUG", LOG_DEBUG);
889         PyModule_AddIntConstant(module, "LOG_INFO", LOG_INFO);
890         PyModule_AddIntConstant(module, "LOG_NOTICE", LOG_NOTICE);
891         PyModule_AddIntConstant(module, "LOG_WARNING", LOG_WARNING);
892         PyModule_AddIntConstant(module, "LOG_ERROR", LOG_ERR);
893         PyModule_AddIntConstant(module, "NOTIF_FAILURE", NOTIF_FAILURE);
894         PyModule_AddIntConstant(module, "NOTIF_WARNING", NOTIF_WARNING);
895         PyModule_AddIntConstant(module, "NOTIF_OKAY", NOTIF_OKAY);
896         for (i = 0; i < ci->children_num; ++i) {
897                 oconfig_item_t *item = ci->children + i;
898                 
899                 if (strcasecmp(item->key, "Interactive") == 0) {
900                         if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
901                                 continue;
902                         do_interactive = item->values[0].value.boolean;
903                 } else if (strcasecmp(item->key, "Encoding") == 0) {
904                         if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_STRING)
905                                 continue;
906                         /* Why is this even necessary? And undocumented? */
907                         if (PyUnicode_SetDefaultEncoding(item->values[0].value.string))
908                                 cpy_log_exception("setting default encoding");
909                 } else if (strcasecmp(item->key, "LogTraces") == 0) {
910                         if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
911                                 continue;
912                         if (!item->values[0].value.boolean) {
913                                 Py_XDECREF(cpy_format_exception);
914                                 cpy_format_exception = NULL;
915                                 continue;
916                         }
917                         if (cpy_format_exception)
918                                 continue;
919                         tb = PyImport_ImportModule("traceback"); /* New reference. */
920                         if (tb == NULL) {
921                                 cpy_log_exception("python initialization");
922                                 continue;
923                         }
924                         cpy_format_exception = PyObject_GetAttrString(tb, "format_exception"); /* New reference. */
925                         Py_DECREF(tb);
926                         if (cpy_format_exception == NULL)
927                                 cpy_log_exception("python initialization");
928                 } else if (strcasecmp(item->key, "ModulePath") == 0) {
929                         char *dir = NULL;
930                         PyObject *dir_object;
931                         
932                         if (cf_util_get_string(item, &dir) != 0) 
933                                 continue;
934                         dir_object = PyString_FromString(dir); /* New reference. */
935                         if (dir_object == NULL) {
936                                 ERROR("python plugin: Unable to convert \"%s\" to "
937                                       "a python object.", dir);
938                                 free(dir);
939                                 cpy_log_exception("python initialization");
940                                 continue;
941                         }
942                         if (PyList_Append(sys_path, dir_object) != 0) {
943                                 ERROR("python plugin: Unable to append \"%s\" to "
944                                       "python module path.", dir);
945                                 cpy_log_exception("python initialization");
946                         }
947                         Py_DECREF(dir_object);
948                         free(dir);
949                 } else if (strcasecmp(item->key, "Import") == 0) {
950                         char *module_name = NULL;
951                         PyObject *module;
952                         
953                         if (cf_util_get_string(item, &module_name) != 0) 
954                                 continue;
955                         module = PyImport_ImportModule(module_name); /* New reference. */
956                         if (module == NULL) {
957                                 ERROR("python plugin: Error importing module \"%s\".", module_name);
958                                 cpy_log_exception("importing module");
959                                 PyErr_Print();
960                         }
961                         free(module_name);
962                         Py_XDECREF(module);
963                 } else if (strcasecmp(item->key, "Module") == 0) {
964                         char *name = NULL;
965                         cpy_callback_t *c;
966                         PyObject *ret;
967                         
968                         if (cf_util_get_string(item, &name) != 0)
969                                 continue;
970                         for (c = cpy_config_callbacks; c; c = c->next) {
971                                 if (strcasecmp(c->name + 7, name) == 0)
972                                         break;
973                         }
974                         if (c == NULL) {
975                                 WARNING("python plugin: Found a configuration for the \"%s\" plugin, "
976                                         "but the plugin isn't loaded or didn't register "
977                                         "a configuration callback.", name);
978                                 free(name);
979                                 continue;
980                         }
981                         free(name);
982                         if (c->data == NULL)
983                                 ret = PyObject_CallFunction(c->callback, "N",
984                                         cpy_oconfig_to_pyconfig(item, NULL)); /* New reference. */
985                         else
986                                 ret = PyObject_CallFunction(c->callback, "NO",
987                                         cpy_oconfig_to_pyconfig(item, NULL), c->data); /* New reference. */
988                         if (ret == NULL)
989                                 cpy_log_exception("loading module");
990                         else
991                                 Py_DECREF(ret);
992                 } else {
993                         WARNING("python plugin: Ignoring unknown config key \"%s\".", item->key);
994                 }
995         }
996         Py_DECREF(sys_path);
997         return 0;
998 }
999
1000 void module_register(void) {
1001         plugin_register_complex_config("python", cpy_config);
1002         plugin_register_init("python", cpy_init);
1003         plugin_register_shutdown("python", cpy_shutdown);
1004 }