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