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