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