08abfd1d2168e74b998640c5f3b9ee84c7b298dc
[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 (PyString_Check(arg)) {
604                 name = PyString_AsString(arg);
605         } else {
606                 if (!PyCallable_Check(arg)) {
607                         PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
608                         return NULL;
609                 }
610                 cpy_build_name(buf, sizeof(buf), arg, NULL);
611                 name = buf;
612         }
613         for (tmp = *list_head; tmp; prev = tmp, tmp = tmp->next)
614                 if (strcmp(name, tmp->name) == 0)
615                         break;
616         
617         if (tmp == NULL) {
618                 PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
619                 return NULL;
620         }
621         /* Yes, this is actually save. To call this function the calles has to
622          * hold the GIL. Well, save as long as there is only one GIL anyway ... */
623         if (prev == NULL)
624                 *list_head = tmp->next;
625         else
626                 prev->next = tmp->next;
627         cpy_destroy_user_data(tmp);
628         Py_RETURN_NONE;
629 }
630
631 typedef int cpy_unregister_function_t(const char *name);
632
633 static PyObject *cpy_unregister_generic_userdata(cpy_unregister_function_t *unreg, PyObject *arg, const char *desc) {
634         char buf[512];
635         const char *name;
636
637         if (PyUnicode_Check(arg)) {
638                 arg = PyUnicode_AsEncodedString(arg, NULL, NULL);
639                 if (arg == NULL)
640                         return NULL;
641                 name = PyString_AsString(arg);
642                 Py_DECREF(arg);
643         } else if (PyString_Check(arg)) {
644                 name = PyString_AsString(arg);
645         } else {
646                 if (!PyCallable_Check(arg)) {
647                         PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
648                         return NULL;
649                 }
650                 cpy_build_name(buf, sizeof(buf), arg, NULL);
651                 name = buf;
652         }
653         if (unreg(name) == 0)
654                 Py_RETURN_NONE;
655         PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
656         return NULL;
657 }
658
659 static PyObject *cpy_unregister_log(PyObject *self, PyObject *arg) {
660         return cpy_unregister_generic_userdata(plugin_unregister_log, arg, "log");
661 }
662
663 static PyObject *cpy_unregister_init(PyObject *self, PyObject *arg) {
664         return cpy_unregister_generic(&cpy_init_callbacks, arg, "init");
665 }
666
667 static PyObject *cpy_unregister_config(PyObject *self, PyObject *arg) {
668         return cpy_unregister_generic(&cpy_config_callbacks, arg, "config");
669 }
670
671 static PyObject *cpy_unregister_read(PyObject *self, PyObject *arg) {
672         return cpy_unregister_generic_userdata(plugin_unregister_read, arg, "read");
673 }
674
675 static PyObject *cpy_unregister_write(PyObject *self, PyObject *arg) {
676         return cpy_unregister_generic_userdata(plugin_unregister_write, arg, "write");
677 }
678
679 static PyObject *cpy_unregister_notification(PyObject *self, PyObject *arg) {
680         return cpy_unregister_generic_userdata(plugin_unregister_notification, arg, "notification");
681 }
682
683 static PyObject *cpy_unregister_flush(PyObject *self, PyObject *arg) {
684         return cpy_unregister_generic_userdata(plugin_unregister_flush, arg, "flush");
685 }
686
687 static PyObject *cpy_unregister_shutdown(PyObject *self, PyObject *arg) {
688         return cpy_unregister_generic(&cpy_shutdown_callbacks, arg, "shutdown");
689 }
690
691 static PyMethodDef cpy_methods[] = {
692         {"debug", cpy_debug, METH_VARARGS, log_doc},
693         {"info", cpy_info, METH_VARARGS, log_doc},
694         {"notice", cpy_notice, METH_VARARGS, log_doc},
695         {"warning", cpy_warning, METH_VARARGS, log_doc},
696         {"error", cpy_error, METH_VARARGS, log_doc},
697         {"flush", (PyCFunction) cpy_flush, METH_VARARGS | METH_KEYWORDS, flush_doc},
698         {"register_log", (PyCFunction) cpy_register_log, METH_VARARGS | METH_KEYWORDS, reg_log_doc},
699         {"register_init", (PyCFunction) cpy_register_init, METH_VARARGS | METH_KEYWORDS, reg_init_doc},
700         {"register_config", (PyCFunction) cpy_register_config, METH_VARARGS | METH_KEYWORDS, reg_config_doc},
701         {"register_read", (PyCFunction) cpy_register_read, METH_VARARGS | METH_KEYWORDS, reg_read_doc},
702         {"register_write", (PyCFunction) cpy_register_write, METH_VARARGS | METH_KEYWORDS, reg_write_doc},
703         {"register_notification", (PyCFunction) cpy_register_notification, METH_VARARGS | METH_KEYWORDS, reg_notification_doc},
704         {"register_flush", (PyCFunction) cpy_register_flush, METH_VARARGS | METH_KEYWORDS, reg_flush_doc},
705         {"register_shutdown", (PyCFunction) cpy_register_shutdown, METH_VARARGS | METH_KEYWORDS, reg_shutdown_doc},
706         {"unregister_log", cpy_unregister_log, METH_O, unregister_doc},
707         {"unregister_init", cpy_unregister_init, METH_O, unregister_doc},
708         {"unregister_config", cpy_unregister_config, METH_O, unregister_doc},
709         {"unregister_read", cpy_unregister_read, METH_O, unregister_doc},
710         {"unregister_write", cpy_unregister_write, METH_O, unregister_doc},
711         {"unregister_notification", cpy_unregister_notification, METH_O, unregister_doc},
712         {"unregister_flush", cpy_unregister_flush, METH_O, unregister_doc},
713         {"unregister_shutdown", cpy_unregister_shutdown, METH_O, unregister_doc},
714         {0, 0, 0, 0}
715 };
716
717 static int cpy_shutdown(void) {
718         cpy_callback_t *c;
719         PyObject *ret;
720         
721         /* This can happen if the module was loaded but not configured. */
722         if (state != NULL)
723                 PyEval_RestoreThread(state);
724
725         for (c = cpy_shutdown_callbacks; c; c = c->next) {
726                 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
727                 if (ret == NULL)
728                         cpy_log_exception("shutdown callback");
729                 else
730                         Py_DECREF(ret);
731         }
732         PyErr_Print();
733         Py_Finalize();
734         return 0;
735 }
736
737 static void cpy_int_handler(int sig) {
738         return;
739 }
740
741 static void *cpy_interactive(void *data) {
742         sigset_t sigset;
743         struct sigaction sig_int_action, old;
744         
745         /* Signal handler in a plugin? Bad stuff, but the best way to
746          * handle it I guess. In an interactive session people will
747          * press Ctrl+C at some time, which will generate a SIGINT.
748          * This will cause collectd to shutdown, thus killing the
749          * interactive interpreter, and leaving the terminal in a
750          * mess. Chances are, this isn't what the user wanted to do.
751          * 
752          * So this is the plan:
753          * 1. Block SIGINT in the main thread.
754          * 2. Install our own signal handler that does nothing.
755          * 3. Unblock SIGINT in the interactive thread.
756          *
757          * This will make sure that SIGINT won't kill collectd but
758          * still interrupt syscalls like sleep and pause.
759          * It does not raise a KeyboardInterrupt exception because so
760          * far nobody managed to figure out how to do that. */
761         memset (&sig_int_action, '\0', sizeof (sig_int_action));
762         sig_int_action.sa_handler = cpy_int_handler;
763         sigaction (SIGINT, &sig_int_action, &old);
764         
765         sigemptyset(&sigset);
766         sigaddset(&sigset, SIGINT);
767         pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
768         PyEval_AcquireThread(state);
769         if (PyImport_ImportModule("readline") == NULL) {
770                 /* This interactive session will suck. */
771                 cpy_log_exception("interactive session init");
772         }
773         PyRun_InteractiveLoop(stdin, "<stdin>");
774         PyErr_Print();
775         PyEval_ReleaseThread(state);
776         NOTICE("python: Interactive interpreter exited, stopping collectd ...");
777         /* Restore the original collectd SIGINT handler and raise SIGINT.
778          * The main thread still has SIGINT blocked and there's nothing we
779          * can do about that so this thread will handle it. But that's not
780          * important, except that it won't interrupt the main loop and so
781          * it might take a few seconds before collectd really shuts down. */
782         sigaction (SIGINT, &old, NULL);
783         raise(SIGINT);
784         pause();
785         return NULL;
786 }
787
788 static int cpy_init(void) {
789         cpy_callback_t *c;
790         PyObject *ret;
791         static pthread_t thread;
792         sigset_t sigset;
793         
794         PyEval_InitThreads();
795         /* Now it's finally OK to use python threads. */
796         for (c = cpy_init_callbacks; c; c = c->next) {
797                 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
798                 if (ret == NULL)
799                         cpy_log_exception("init callback");
800                 else
801                         Py_DECREF(ret);
802         }
803         sigemptyset(&sigset);
804         sigaddset(&sigset, SIGINT);
805         pthread_sigmask(SIG_BLOCK, &sigset, NULL);
806         state = PyEval_SaveThread();
807         if (do_interactive) {
808                 if (pthread_create(&thread, NULL, cpy_interactive, NULL)) {
809                         ERROR("python: Error creating thread for interactive interpreter.");
810                 }
811         }
812
813         return 0;
814 }
815
816 static PyObject *cpy_oconfig_to_pyconfig(oconfig_item_t *ci, PyObject *parent) {
817         int i;
818         PyObject *item, *values, *children, *tmp;
819         
820         if (parent == NULL)
821                 parent = Py_None;
822         
823         values = PyTuple_New(ci->values_num); /* New reference. */
824         for (i = 0; i < ci->values_num; ++i) {
825                 if (ci->values[i].type == OCONFIG_TYPE_STRING) {
826                         PyTuple_SET_ITEM(values, i, PyString_FromString(ci->values[i].value.string));
827                 } else if (ci->values[i].type == OCONFIG_TYPE_NUMBER) {
828                         PyTuple_SET_ITEM(values, i, PyFloat_FromDouble(ci->values[i].value.number));
829                 } else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN) {
830                         PyTuple_SET_ITEM(values, i, PyBool_FromLong(ci->values[i].value.boolean));
831                 }
832         }
833         
834         item = PyObject_CallFunction((PyObject *) &ConfigType, "sONO", ci->key, parent, values, Py_None);
835         if (item == NULL)
836                 return NULL;
837         children = PyTuple_New(ci->children_num); /* New reference. */
838         for (i = 0; i < ci->children_num; ++i) {
839                 PyTuple_SET_ITEM(children, i, cpy_oconfig_to_pyconfig(ci->children + i, item));
840         }
841         tmp = ((Config *) item)->children;
842         ((Config *) item)->children = children;
843         Py_XDECREF(tmp);
844         return item;
845 }
846
847 static int cpy_config(oconfig_item_t *ci) {
848         int i;
849         PyObject *sys, *tb;
850         PyObject *sys_path;
851         PyObject *module;
852         
853         /* Ok in theory we shouldn't do initialization at this point
854          * but we have to. In order to give python scripts a chance
855          * to register a config callback we need to be able to execute
856          * python code during the config callback so we have to start
857          * the interpreter here. */
858         /* Do *not* use the python "thread" module at this point! */
859         Py_Initialize();
860         
861         PyType_Ready(&ConfigType);
862         PyType_Ready(&PluginDataType);
863         ValuesType.tp_base = &PluginDataType;
864         PyType_Ready(&ValuesType);
865         NotificationType.tp_base = &PluginDataType;
866         PyType_Ready(&NotificationType);
867         sys = PyImport_ImportModule("sys"); /* New reference. */
868         if (sys == NULL) {
869                 cpy_log_exception("python initialization");
870                 return 1;
871         }
872         sys_path = PyObject_GetAttrString(sys, "path"); /* New reference. */
873         Py_DECREF(sys);
874         if (sys_path == NULL) {
875                 cpy_log_exception("python initialization");
876                 return 1;
877         }
878         module = Py_InitModule("collectd", cpy_methods); /* Borrowed reference. */
879         PyModule_AddObject(module, "Config", (PyObject *) &ConfigType); /* Steals a reference. */
880         PyModule_AddObject(module, "Values", (PyObject *) &ValuesType); /* Steals a reference. */
881         PyModule_AddObject(module, "Notification", (PyObject *) &NotificationType); /* Steals a reference. */
882         PyModule_AddIntConstant(module, "LOG_DEBUG", LOG_DEBUG);
883         PyModule_AddIntConstant(module, "LOG_INFO", LOG_INFO);
884         PyModule_AddIntConstant(module, "LOG_NOTICE", LOG_NOTICE);
885         PyModule_AddIntConstant(module, "LOG_WARNING", LOG_WARNING);
886         PyModule_AddIntConstant(module, "LOG_ERROR", LOG_ERR);
887         PyModule_AddIntConstant(module, "NOTIF_FAILURE", NOTIF_FAILURE);
888         PyModule_AddIntConstant(module, "NOTIF_WARNING", NOTIF_WARNING);
889         PyModule_AddIntConstant(module, "NOTIF_OKAY", NOTIF_OKAY);
890         for (i = 0; i < ci->children_num; ++i) {
891                 oconfig_item_t *item = ci->children + i;
892                 
893                 if (strcasecmp(item->key, "Interactive") == 0) {
894                         if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
895                                 continue;
896                         do_interactive = item->values[0].value.boolean;
897                 } else if (strcasecmp(item->key, "Encoding") == 0) {
898                         if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_STRING)
899                                 continue;
900                         /* Why is this even necessary? And undocumented? */
901                         if (PyUnicode_SetDefaultEncoding(item->values[0].value.string))
902                                 cpy_log_exception("setting default encoding");
903                 } else if (strcasecmp(item->key, "LogTraces") == 0) {
904                         if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
905                                 continue;
906                         if (!item->values[0].value.boolean) {
907                                 Py_XDECREF(cpy_format_exception);
908                                 cpy_format_exception = NULL;
909                                 continue;
910                         }
911                         if (cpy_format_exception)
912                                 continue;
913                         tb = PyImport_ImportModule("traceback"); /* New reference. */
914                         if (tb == NULL) {
915                                 cpy_log_exception("python initialization");
916                                 continue;
917                         }
918                         cpy_format_exception = PyObject_GetAttrString(tb, "format_exception"); /* New reference. */
919                         Py_DECREF(tb);
920                         if (cpy_format_exception == NULL)
921                                 cpy_log_exception("python initialization");
922                 } else if (strcasecmp(item->key, "ModulePath") == 0) {
923                         char *dir = NULL;
924                         PyObject *dir_object;
925                         
926                         if (cf_util_get_string(item, &dir) != 0) 
927                                 continue;
928                         dir_object = PyString_FromString(dir); /* New reference. */
929                         if (dir_object == NULL) {
930                                 ERROR("python plugin: Unable to convert \"%s\" to "
931                                       "a python object.", dir);
932                                 free(dir);
933                                 cpy_log_exception("python initialization");
934                                 continue;
935                         }
936                         if (PyList_Append(sys_path, dir_object) != 0) {
937                                 ERROR("python plugin: Unable to append \"%s\" to "
938                                       "python module path.", dir);
939                                 cpy_log_exception("python initialization");
940                         }
941                         Py_DECREF(dir_object);
942                         free(dir);
943                 } else if (strcasecmp(item->key, "Import") == 0) {
944                         char *module_name = NULL;
945                         PyObject *module;
946                         
947                         if (cf_util_get_string(item, &module_name) != 0) 
948                                 continue;
949                         module = PyImport_ImportModule(module_name); /* New reference. */
950                         if (module == NULL) {
951                                 ERROR("python plugin: Error importing module \"%s\".", module_name);
952                                 cpy_log_exception("importing module");
953                                 PyErr_Print();
954                         }
955                         free(module_name);
956                         Py_XDECREF(module);
957                 } else if (strcasecmp(item->key, "Module") == 0) {
958                         char *name = NULL;
959                         cpy_callback_t *c;
960                         PyObject *ret;
961                         
962                         if (cf_util_get_string(item, &name) != 0)
963                                 continue;
964                         for (c = cpy_config_callbacks; c; c = c->next) {
965                                 if (strcasecmp(c->name + 7, name) == 0)
966                                         break;
967                         }
968                         if (c == NULL) {
969                                 WARNING("python plugin: Found a configuration for the \"%s\" plugin, "
970                                         "but the plugin isn't loaded or didn't register "
971                                         "a configuration callback.", name);
972                                 free(name);
973                                 continue;
974                         }
975                         free(name);
976                         if (c->data == NULL)
977                                 ret = PyObject_CallFunction(c->callback, "N",
978                                         cpy_oconfig_to_pyconfig(item, NULL)); /* New reference. */
979                         else
980                                 ret = PyObject_CallFunction(c->callback, "NO",
981                                         cpy_oconfig_to_pyconfig(item, NULL), c->data); /* New reference. */
982                         if (ret == NULL)
983                                 cpy_log_exception("loading module");
984                         else
985                                 Py_DECREF(ret);
986                 } else {
987                         WARNING("python plugin: Ignoring unknown config key \"%s\".", item->key);
988                 }
989         }
990         Py_DECREF(sys_path);
991         return 0;
992 }
993
994 void module_register(void) {
995         plugin_register_complex_config("python", cpy_config);
996         plugin_register_init("python", cpy_init);
997         plugin_register_shutdown("python", cpy_shutdown);
998 }