python: Extend Notification class
[collectd.git] / src / python.c
1 /**
2  * collectd - src/python.c
3  * Copyright (C) 2009  Sven Trenkel
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *   Sven Trenkel <collectd at semidefinite.de>
25  **/
26
27 #include <Python.h>
28 #include <structmember.h>
29
30 #include <signal.h>
31
32 #include "collectd.h"
33
34 #include "common.h"
35
36 #include "cpython.h"
37
38 typedef struct cpy_callback_s {
39   char *name;
40   PyObject *callback;
41   PyObject *data;
42   struct cpy_callback_s *next;
43 } cpy_callback_t;
44
45 static char log_doc[] = "This function sends a string to all logging plugins.";
46
47 static char get_ds_doc[] =
48     "get_dataset(name) -> definition\n"
49     "\n"
50     "Returns the definition of a dataset specified by name.\n"
51     "\n"
52     "'name' is a string specifying the dataset to query.\n"
53     "'definition' is a list of 4-tuples. Every tuple represents a \n"
54     "    data source within the data set and its 4 values are the \n"
55     "    name, type, min and max value.\n"
56     "    'name' is a string.\n"
57     "    'type' is a string that is equal to either DS_TYPE_COUNTER,\n"
58     "        DS_TYPE_GAUGE, DS_TYPE_DERIVE or DS_TYPE_ABSOLUTE.\n"
59     "    'min' and 'max' are either a float or None.";
60
61 static char flush_doc[] = "flush([plugin][, timeout][, identifier]) -> None\n"
62                           "\n"
63                           "Flushes the cache of another plugin.";
64
65 static char unregister_doc[] =
66     "Unregisters a callback. This function needs exactly one parameter either\n"
67     "the function to unregister or the callback identifier to unregister.";
68
69 static char reg_log_doc[] =
70     "register_log(callback[, data][, name]) -> identifier\n"
71     "\n"
72     "Register a callback function for log messages.\n"
73     "\n"
74     "'callback' is a callable object that will be called every time something\n"
75     "    is logged.\n"
76     "'data' is an optional object that will be passed back to the callback\n"
77     "    function every time it is called.\n"
78     "'name' is an optional identifier for this callback. The default name\n"
79     "    is 'python.<module>'.\n"
80     "    Every callback needs a unique identifier, so if you want to\n"
81     "    register this callback multiple time from the same module you need\n"
82     "    to specify a name here.\n"
83     "'identifier' is the full identifier assigned to this callback.\n"
84     "\n"
85     "The callback function will be called with two or three parameters:\n"
86     "severity: An integer that should be compared to the LOG_ constants.\n"
87     "message: The text to be logged.\n"
88     "data: The optional data parameter passed to the register function.\n"
89     "    If the parameter was omitted it will be omitted here, too.";
90
91 static char reg_init_doc[] =
92     "register_init(callback[, data][, name]) -> identifier\n"
93     "\n"
94     "Register a callback function that will be executed once after the "
95     "config.\n"
96     "file has been read, all plugins heve been loaded and the collectd has\n"
97     "forked into the background.\n"
98     "\n"
99     "'callback' is a callable object that will be executed.\n"
100     "'data' is an optional object that will be passed back to the callback\n"
101     "    function when it is called.\n"
102     "'name' is an optional identifier for this callback. The default name\n"
103     "    is 'python.<module>'.\n"
104     "    Every callback needs a unique identifier, so if you want to\n"
105     "    register this callback multiple time from the same module you need\n"
106     "    to specify a name here.\n"
107     "'identifier' is the full identifier assigned to this callback.\n"
108     "\n"
109     "The callback function will be called without parameters, except for\n"
110     "data if it was supplied.";
111
112 static char reg_config_doc[] =
113     "register_config(callback[, data][, name]) -> identifier\n"
114     "\n"
115     "Register a callback function for config file entries.\n"
116     "'callback' is a callable object that will be called for every config "
117     "block.\n"
118     "'data' is an optional object that will be passed back to the callback\n"
119     "    function every time it is called.\n"
120     "'name' is an optional identifier for this callback. The default name\n"
121     "    is 'python.<module>'.\n"
122     "    Every callback needs a unique identifier, so if you want to\n"
123     "    register this callback multiple time from the same module you need\n"
124     "    to specify a name here.\n"
125     "'identifier' is the full identifier assigned to this callback.\n"
126     "\n"
127     "The callback function will be called with one or two parameters:\n"
128     "config: A Config object.\n"
129     "data: The optional data parameter passed to the register function.\n"
130     "    If the parameter was omitted it will be omitted here, too.";
131
132 static char reg_read_doc[] =
133     "register_read(callback[, interval][, data][, name]) -> identifier\n"
134     "\n"
135     "Register a callback function for reading data. It will just be called\n"
136     "in a fixed interval to signal that it's time to dispatch new values.\n"
137     "'callback' is a callable object that will be called every time something\n"
138     "    is logged.\n"
139     "'interval' is the number of seconds between between calls to the "
140     "callback\n"
141     "    function. Full float precision is supported here.\n"
142     "'data' is an optional object that will be passed back to the callback\n"
143     "    function every time it is called.\n"
144     "'name' is an optional identifier for this callback. The default name\n"
145     "    is 'python.<module>'.\n"
146     "    Every callback needs a unique identifier, so if you want to\n"
147     "    register this callback multiple time from the same module you need\n"
148     "    to specify a name here.\n"
149     "'identifier' is the full identifier assigned to this callback.\n"
150     "\n"
151     "The callback function will be called without parameters, except for\n"
152     "data if it was supplied.";
153
154 static char reg_write_doc[] =
155     "register_write(callback[, data][, name]) -> identifier\n"
156     "\n"
157     "Register a callback function to receive values dispatched by other "
158     "plugins.\n"
159     "'callback' is a callable object that will be called every time a value\n"
160     "    is dispatched.\n"
161     "'data' is an optional object that will be passed back to the callback\n"
162     "    function every time it is called.\n"
163     "'name' is an optional identifier for this callback. The default name\n"
164     "    is 'python.<module>'.\n"
165     "    Every callback needs a unique identifier, so if you want to\n"
166     "    register this callback multiple time from the same module you need\n"
167     "    to specify a name here.\n"
168     "'identifier' is the full identifier assigned to this callback.\n"
169     "\n"
170     "The callback function will be called with one or two parameters:\n"
171     "values: A Values object which is a copy of the dispatched values.\n"
172     "data: The optional data parameter passed to the register function.\n"
173     "    If the parameter was omitted it will be omitted here, too.";
174
175 static char reg_notification_doc[] =
176     "register_notification(callback[, data][, name]) -> identifier\n"
177     "\n"
178     "Register a callback function for notifications.\n"
179     "'callback' is a callable object that will be called every time a "
180     "notification\n"
181     "    is dispatched.\n"
182     "'data' is an optional object that will be passed back to the callback\n"
183     "    function every time it is called.\n"
184     "'name' is an optional identifier for this callback. The default name\n"
185     "    is 'python.<module>'.\n"
186     "    Every callback needs a unique identifier, so if you want to\n"
187     "    register this callback multiple time from the same module you need\n"
188     "    to specify a name here.\n"
189     "'identifier' is the full identifier assigned to this callback.\n"
190     "\n"
191     "The callback function will be called with one or two parameters:\n"
192     "notification: A copy of the notification that was dispatched.\n"
193     "data: The optional data parameter passed to the register function.\n"
194     "    If the parameter was omitted it will be omitted here, too.";
195
196 static char reg_flush_doc[] =
197     "register_flush(callback[, data][, name]) -> identifier\n"
198     "\n"
199     "Register a callback function for flush messages.\n"
200     "'callback' is a callable object that will be called every time a plugin\n"
201     "    requests a flush for either this or all plugins.\n"
202     "'data' is an optional object that will be passed back to the callback\n"
203     "    function every time it is called.\n"
204     "'name' is an optional identifier for this callback. The default name\n"
205     "    is 'python.<module>'.\n"
206     "    Every callback needs a unique identifier, so if you want to\n"
207     "    register this callback multiple time from the same module you need\n"
208     "    to specify a name here.\n"
209     "'identifier' is the full identifier assigned to this callback.\n"
210     "\n"
211     "The callback function will be called with two or three parameters:\n"
212     "timeout: Indicates that only data older than 'timeout' seconds is to\n"
213     "    be flushed.\n"
214     "id: Specifies which values are to be flushed. Might be None.\n"
215     "data: The optional data parameter passed to the register function.\n"
216     "    If the parameter was omitted it will be omitted here, too.";
217
218 static char reg_shutdown_doc[] =
219     "register_shutdown(callback[, data][, name]) -> identifier\n"
220     "\n"
221     "Register a callback function for collectd shutdown.\n"
222     "'callback' is a callable object that will be called once collectd is\n"
223     "    shutting down.\n"
224     "'data' is an optional object that will be passed back to the callback\n"
225     "    function if it is called.\n"
226     "'name' is an optional identifier for this callback. The default name\n"
227     "    is 'python.<module>'.\n"
228     "    Every callback needs a unique identifier, so if you want to\n"
229     "    register this callback multiple time from the same module you need\n"
230     "    to specify a name here.\n"
231     "'identifier' is the full identifier assigned to this callback.\n"
232     "\n"
233     "The callback function will be called with no parameters except for\n"
234     "    data if it was supplied.";
235
236 static pthread_t main_thread;
237 static PyOS_sighandler_t python_sigint_handler;
238 static _Bool do_interactive = 0;
239
240 /* This is our global thread state. Python saves some stuff in thread-local
241  * storage. So if we allow the interpreter to run in the background
242  * (the scriptwriters might have created some threads from python), we have
243  * to save the state so we can resume it later after shutdown. */
244
245 static PyThreadState *state;
246
247 static PyObject *sys_path, *cpy_format_exception;
248
249 static cpy_callback_t *cpy_config_callbacks;
250 static cpy_callback_t *cpy_init_callbacks;
251 static cpy_callback_t *cpy_shutdown_callbacks;
252
253 /* Make sure to hold the GIL while modifying these. */
254 static int cpy_shutdown_triggered = 0;
255 static int cpy_num_callbacks = 0;
256
257 static void cpy_destroy_user_data(void *data) {
258   cpy_callback_t *c = data;
259   free(c->name);
260   CPY_LOCK_THREADS
261   Py_DECREF(c->callback);
262   Py_XDECREF(c->data);
263   free(c);
264   --cpy_num_callbacks;
265   if (!cpy_num_callbacks && cpy_shutdown_triggered) {
266     Py_Finalize();
267     return;
268   }
269   CPY_RELEASE_THREADS
270 }
271
272 /* You must hold the GIL to call this function!
273  * But if you managed to extract the callback parameter then you probably
274  * already do. */
275
276 static void cpy_build_name(char *buf, size_t size, PyObject *callback,
277                            const char *name) {
278   const char *module = NULL;
279   PyObject *mod = NULL;
280
281   if (name != NULL) {
282     snprintf(buf, size, "python.%s", name);
283     return;
284   }
285
286   mod = PyObject_GetAttrString(callback, "__module__"); /* New reference. */
287   if (mod != NULL)
288     module = cpy_unicode_or_bytes_to_string(&mod);
289
290   if (module != NULL) {
291     snprintf(buf, size, "python.%s", module);
292     Py_XDECREF(mod);
293     PyErr_Clear();
294     return;
295   }
296   Py_XDECREF(mod);
297
298   snprintf(buf, size, "python.%p", callback);
299   PyErr_Clear();
300 }
301
302 void cpy_log_exception(const char *context) {
303   int l = 0;
304   const char *typename = NULL, *message = NULL;
305   PyObject *type, *value, *traceback, *tn, *m, *list;
306
307   PyErr_Fetch(&type, &value, &traceback);
308   PyErr_NormalizeException(&type, &value, &traceback);
309   if (type == NULL)
310     return;
311   tn = PyObject_GetAttrString(type, "__name__"); /* New reference. */
312   m = PyObject_Str(value);                       /* New reference. */
313   if (tn != NULL)
314     typename = cpy_unicode_or_bytes_to_string(&tn);
315   if (m != NULL)
316     message = cpy_unicode_or_bytes_to_string(&m);
317   if (typename == NULL)
318     typename = "NamelessException";
319   if (message == NULL)
320     message = "N/A";
321   Py_BEGIN_ALLOW_THREADS ERROR("Unhandled python exception in %s: %s: %s",
322                                context, typename, message);
323   Py_END_ALLOW_THREADS Py_XDECREF(tn);
324   Py_XDECREF(m);
325   if (!cpy_format_exception || !traceback) {
326     PyErr_Clear();
327     Py_DECREF(type);
328     Py_XDECREF(value);
329     Py_XDECREF(traceback);
330     return;
331   }
332   list = PyObject_CallFunction(cpy_format_exception, "NNN", type, value,
333                                traceback); /* New reference. Steals references
334                                               from "type", "value" and
335                                               "traceback". */
336   if (list)
337     l = PyObject_Length(list);
338
339   for (int i = 0; i < l; ++i) {
340     PyObject *line;
341     char const *msg;
342     char *cpy;
343
344     line = PyList_GET_ITEM(list, i); /* Borrowed reference. */
345     Py_INCREF(line);
346
347     msg = cpy_unicode_or_bytes_to_string(&line);
348     Py_DECREF(line);
349     if (msg == NULL)
350       continue;
351
352     cpy = strdup(msg);
353     if (cpy == NULL)
354       continue;
355
356     if (cpy[strlen(cpy) - 1] == '\n')
357       cpy[strlen(cpy) - 1] = 0;
358
359     Py_BEGIN_ALLOW_THREADS ERROR("%s", cpy);
360     Py_END_ALLOW_THREADS
361
362         free(cpy);
363   }
364
365   Py_XDECREF(list);
366   PyErr_Clear();
367 }
368
369 static int cpy_read_callback(user_data_t *data) {
370   cpy_callback_t *c = data->data;
371   PyObject *ret;
372
373   CPY_LOCK_THREADS
374   ret = PyObject_CallFunctionObjArgs(c->callback, c->data,
375                                      (void *)0); /* New reference. */
376   if (ret == NULL) {
377     cpy_log_exception("read callback");
378   } else {
379     Py_DECREF(ret);
380   }
381   CPY_RELEASE_THREADS
382   if (ret == NULL)
383     return 1;
384   return 0;
385 }
386
387 static int cpy_write_callback(const data_set_t *ds,
388                               const value_list_t *value_list,
389                               user_data_t *data) {
390   cpy_callback_t *c = data->data;
391   PyObject *ret, *list, *temp, *dict = NULL;
392   Values *v;
393
394   CPY_LOCK_THREADS
395   list = PyList_New(value_list->values_len); /* New reference. */
396   if (list == NULL) {
397     cpy_log_exception("write callback");
398     CPY_RETURN_FROM_THREADS 0;
399   }
400   for (size_t i = 0; i < value_list->values_len; ++i) {
401     if (ds->ds[i].type == DS_TYPE_COUNTER) {
402       PyList_SetItem(
403           list, i, PyLong_FromUnsignedLongLong(value_list->values[i].counter));
404     } else if (ds->ds[i].type == DS_TYPE_GAUGE) {
405       PyList_SetItem(list, i, PyFloat_FromDouble(value_list->values[i].gauge));
406     } else if (ds->ds[i].type == DS_TYPE_DERIVE) {
407       PyList_SetItem(list, i,
408                      PyLong_FromLongLong(value_list->values[i].derive));
409     } else if (ds->ds[i].type == DS_TYPE_ABSOLUTE) {
410       PyList_SetItem(
411           list, i, PyLong_FromUnsignedLongLong(value_list->values[i].absolute));
412     } else {
413       Py_BEGIN_ALLOW_THREADS ERROR("cpy_write_callback: Unknown value type %d.",
414                                    ds->ds[i].type);
415       Py_END_ALLOW_THREADS Py_DECREF(list);
416       CPY_RETURN_FROM_THREADS 0;
417     }
418     if (PyErr_Occurred() != NULL) {
419       cpy_log_exception("value building for write callback");
420       Py_DECREF(list);
421       CPY_RETURN_FROM_THREADS 0;
422     }
423   }
424   dict = PyDict_New(); /* New reference. */
425   if (value_list->meta) {
426     char **table;
427     meta_data_t *meta = value_list->meta;
428
429     int num = meta_data_toc(meta, &table);
430     for (int i = 0; i < num; ++i) {
431       int type;
432       char *string;
433       int64_t si;
434       uint64_t ui;
435       double d;
436       _Bool b;
437
438       type = meta_data_type(meta, table[i]);
439       if (type == MD_TYPE_STRING) {
440         if (meta_data_get_string(meta, table[i], &string))
441           continue;
442         temp = cpy_string_to_unicode_or_bytes(string); /* New reference. */
443         free(string);
444         PyDict_SetItemString(dict, table[i], temp);
445         Py_XDECREF(temp);
446       } else if (type == MD_TYPE_SIGNED_INT) {
447         if (meta_data_get_signed_int(meta, table[i], &si))
448           continue;
449         temp = PyObject_CallFunctionObjArgs((void *)&SignedType,
450                                             PyLong_FromLongLong(si),
451                                             (void *)0); /* New reference. */
452         PyDict_SetItemString(dict, table[i], temp);
453         Py_XDECREF(temp);
454       } else if (type == MD_TYPE_UNSIGNED_INT) {
455         if (meta_data_get_unsigned_int(meta, table[i], &ui))
456           continue;
457         temp = PyObject_CallFunctionObjArgs((void *)&UnsignedType,
458                                             PyLong_FromUnsignedLongLong(ui),
459                                             (void *)0); /* New reference. */
460         PyDict_SetItemString(dict, table[i], temp);
461         Py_XDECREF(temp);
462       } else if (type == MD_TYPE_DOUBLE) {
463         if (meta_data_get_double(meta, table[i], &d))
464           continue;
465         temp = PyFloat_FromDouble(d); /* New reference. */
466         PyDict_SetItemString(dict, table[i], temp);
467         Py_XDECREF(temp);
468       } else if (type == MD_TYPE_BOOLEAN) {
469         if (meta_data_get_boolean(meta, table[i], &b))
470           continue;
471         if (b)
472           PyDict_SetItemString(dict, table[i], Py_True);
473         else
474           PyDict_SetItemString(dict, table[i], Py_False);
475       }
476       free(table[i]);
477     }
478     free(table);
479   }
480   v = (Values *)Values_New(); /* New reference. */
481   sstrncpy(v->data.host, value_list->host, sizeof(v->data.host));
482   sstrncpy(v->data.type, value_list->type, sizeof(v->data.type));
483   sstrncpy(v->data.type_instance, value_list->type_instance,
484            sizeof(v->data.type_instance));
485   sstrncpy(v->data.plugin, value_list->plugin, sizeof(v->data.plugin));
486   sstrncpy(v->data.plugin_instance, value_list->plugin_instance,
487            sizeof(v->data.plugin_instance));
488   v->data.time = CDTIME_T_TO_DOUBLE(value_list->time);
489   v->interval = CDTIME_T_TO_DOUBLE(value_list->interval);
490   Py_CLEAR(v->values);
491   v->values = list;
492   Py_CLEAR(v->meta);
493   v->meta = dict; /* Steals a reference. */
494   ret = PyObject_CallFunctionObjArgs(c->callback, v, c->data,
495                                      (void *)0); /* New reference. */
496   Py_XDECREF(v);
497   if (ret == NULL) {
498     cpy_log_exception("write callback");
499   } else {
500     Py_DECREF(ret);
501   }
502   CPY_RELEASE_THREADS
503   return 0;
504 }
505
506 static int cpy_notification_callback(const notification_t *notification,
507                                      user_data_t *data) {
508   cpy_callback_t *c = data->data;
509   PyObject *ret, *notify;
510   Notification *n;
511
512   CPY_LOCK_THREADS
513   PyObject *dict = PyDict_New(); /* New reference. */
514   for (notification_meta_t *meta = notification->meta;
515        meta != NULL; meta = meta->next) {
516     PyObject *temp = NULL;
517     if (meta->type == NM_TYPE_STRING) {
518       temp = cpy_string_to_unicode_or_bytes(meta->nm_value.nm_string); /* New reference. */
519       PyDict_SetItemString(dict, meta->name, temp);
520       Py_XDECREF(temp);
521     } else if (meta->type == NM_TYPE_SIGNED_INT) {
522       PyObject *sival = PyLong_FromLongLong(meta->nm_value.nm_signed_int);
523       temp = PyObject_CallFunctionObjArgs((void *)&SignedType, sival,
524                                           (void *)0); /* New reference. */
525       PyDict_SetItemString(dict, meta->name, temp);
526       Py_XDECREF(temp);
527     } else if (meta->type == NM_TYPE_UNSIGNED_INT) {
528       PyObject *uval = PyLong_FromUnsignedLongLong(meta->nm_value.nm_unsigned_int);
529       temp = PyObject_CallFunctionObjArgs((void *)&UnsignedType, uval,
530                                           (void *)0); /* New reference. */
531       PyDict_SetItemString(dict, meta->name, temp);
532       Py_XDECREF(temp);
533     } else if (meta->type == NM_TYPE_DOUBLE) {
534       temp = PyFloat_FromDouble(meta->nm_value.nm_double); /* New reference. */
535       PyDict_SetItemString(dict, meta->name, temp);
536       Py_XDECREF(temp);
537     } else if (meta->type == NM_TYPE_BOOLEAN) {
538       PyDict_SetItemString(dict, meta->name,
539                             meta->nm_value.nm_boolean ? Py_True : Py_False);
540     }
541   }
542   notify = Notification_New(); /* New reference. */
543   n = (Notification *)notify;
544   sstrncpy(n->data.host, notification->host, sizeof(n->data.host));
545   sstrncpy(n->data.type, notification->type, sizeof(n->data.type));
546   sstrncpy(n->data.type_instance, notification->type_instance,
547            sizeof(n->data.type_instance));
548   sstrncpy(n->data.plugin, notification->plugin, sizeof(n->data.plugin));
549   sstrncpy(n->data.plugin_instance, notification->plugin_instance,
550            sizeof(n->data.plugin_instance));
551   n->data.time = CDTIME_T_TO_DOUBLE(notification->time);
552   sstrncpy(n->message, notification->message, sizeof(n->message));
553   n->severity = notification->severity;
554   Py_CLEAR(n->meta);
555   n->meta = dict; /* Steals a reference. */
556   ret = PyObject_CallFunctionObjArgs(c->callback, n, c->data,
557                                      (void *)0); /* New reference. */
558   Py_XDECREF(notify);
559   if (ret == NULL) {
560     cpy_log_exception("notification callback");
561   } else {
562     Py_DECREF(ret);
563   }
564   CPY_RELEASE_THREADS
565   return 0;
566 }
567
568 static void cpy_log_callback(int severity, const char *message,
569                              user_data_t *data) {
570   cpy_callback_t *c = data->data;
571   PyObject *ret, *text;
572
573   CPY_LOCK_THREADS
574   text = cpy_string_to_unicode_or_bytes(message); /* New reference. */
575   if (c->data == NULL)
576     ret = PyObject_CallFunction(
577         c->callback, "iN", severity,
578         text); /* New reference. Steals a reference from "text". */
579   else
580     ret = PyObject_CallFunction(
581         c->callback, "iNO", severity, text,
582         c->data); /* New reference. Steals a reference from "text". */
583
584   if (ret == NULL) {
585     /* FIXME */
586     /* Do we really want to trigger a log callback because a log callback
587      * failed?
588      * Probably not. */
589     PyErr_Print();
590     /* In case someone wanted to be clever, replaced stderr and failed at that.
591      */
592     PyErr_Clear();
593   } else {
594     Py_DECREF(ret);
595   }
596   CPY_RELEASE_THREADS
597 }
598
599 static void cpy_flush_callback(int timeout, const char *id, user_data_t *data) {
600   cpy_callback_t *c = data->data;
601   PyObject *ret, *text;
602
603   CPY_LOCK_THREADS
604   if (id) {
605     text = cpy_string_to_unicode_or_bytes(id);
606   } else {
607     text = Py_None;
608     Py_INCREF(text);
609   }
610   if (c->data == NULL)
611     ret = PyObject_CallFunction(c->callback, "iN", timeout,
612                                 text); /* New reference. */
613   else
614     ret = PyObject_CallFunction(c->callback, "iNO", timeout, text,
615                                 c->data); /* New reference. */
616
617   if (ret == NULL) {
618     cpy_log_exception("flush callback");
619   } else {
620     Py_DECREF(ret);
621   }
622   CPY_RELEASE_THREADS
623 }
624
625 static PyObject *cpy_register_generic(cpy_callback_t **list_head,
626                                       PyObject *args, PyObject *kwds) {
627   char buf[512];
628   cpy_callback_t *c;
629   char *name = NULL;
630   PyObject *callback = NULL, *data = NULL, *mod = NULL;
631   static char *kwlist[] = {"callback", "data", "name", NULL};
632
633   if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oet", kwlist, &callback, &data,
634                                   NULL, &name) == 0)
635     return NULL;
636   if (PyCallable_Check(callback) == 0) {
637     PyMem_Free(name);
638     PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
639     return NULL;
640   }
641   cpy_build_name(buf, sizeof(buf), callback, name);
642
643   Py_INCREF(callback);
644   Py_XINCREF(data);
645
646   c = calloc(1, sizeof(*c));
647   if (c == NULL)
648     return NULL;
649
650   c->name = strdup(buf);
651   c->callback = callback;
652   c->data = data;
653   c->next = *list_head;
654   ++cpy_num_callbacks;
655   *list_head = c;
656   Py_XDECREF(mod);
657   PyMem_Free(name);
658   return cpy_string_to_unicode_or_bytes(buf);
659 }
660
661 static PyObject *float_or_none(float number) {
662   if (isnan(number)) {
663     Py_RETURN_NONE;
664   }
665   return PyFloat_FromDouble(number);
666 }
667
668 static PyObject *cpy_get_dataset(PyObject *self, PyObject *args) {
669   char *name;
670   const data_set_t *ds;
671   PyObject *list, *tuple;
672
673   if (PyArg_ParseTuple(args, "et", NULL, &name) == 0)
674     return NULL;
675   ds = plugin_get_ds(name);
676   PyMem_Free(name);
677   if (ds == NULL) {
678     PyErr_Format(PyExc_TypeError, "Dataset %s not found", name);
679     return NULL;
680   }
681   list = PyList_New(ds->ds_num); /* New reference. */
682   for (size_t i = 0; i < ds->ds_num; ++i) {
683     tuple = PyTuple_New(4);
684     PyTuple_SET_ITEM(tuple, 0, cpy_string_to_unicode_or_bytes(ds->ds[i].name));
685     PyTuple_SET_ITEM(tuple, 1, cpy_string_to_unicode_or_bytes(
686                                    DS_TYPE_TO_STRING(ds->ds[i].type)));
687     PyTuple_SET_ITEM(tuple, 2, float_or_none(ds->ds[i].min));
688     PyTuple_SET_ITEM(tuple, 3, float_or_none(ds->ds[i].max));
689     PyList_SET_ITEM(list, i, tuple);
690   }
691   return list;
692 }
693
694 static PyObject *cpy_flush(PyObject *self, PyObject *args, PyObject *kwds) {
695   int timeout = -1;
696   char *plugin = NULL, *identifier = NULL;
697   static char *kwlist[] = {"plugin", "timeout", "identifier", NULL};
698
699   if (PyArg_ParseTupleAndKeywords(args, kwds, "|etiet", kwlist, NULL, &plugin,
700                                   &timeout, NULL, &identifier) == 0)
701     return NULL;
702   Py_BEGIN_ALLOW_THREADS plugin_flush(plugin, timeout, identifier);
703   Py_END_ALLOW_THREADS PyMem_Free(plugin);
704   PyMem_Free(identifier);
705   Py_RETURN_NONE;
706 }
707
708 static PyObject *cpy_register_config(PyObject *self, PyObject *args,
709                                      PyObject *kwds) {
710   return cpy_register_generic(&cpy_config_callbacks, args, kwds);
711 }
712
713 static PyObject *cpy_register_init(PyObject *self, PyObject *args,
714                                    PyObject *kwds) {
715   return cpy_register_generic(&cpy_init_callbacks, args, kwds);
716 }
717
718 typedef int reg_function_t(const char *name, void *callback, void *data);
719
720 static PyObject *cpy_register_generic_userdata(void *reg, void *handler,
721                                                PyObject *args, PyObject *kwds) {
722   char buf[512];
723   reg_function_t *register_function = (reg_function_t *)reg;
724   cpy_callback_t *c = NULL;
725   char *name = NULL;
726   PyObject *callback = NULL, *data = NULL;
727   static char *kwlist[] = {"callback", "data", "name", NULL};
728
729   if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oet", kwlist, &callback, &data,
730                                   NULL, &name) == 0)
731     return NULL;
732   if (PyCallable_Check(callback) == 0) {
733     PyMem_Free(name);
734     PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
735     return NULL;
736   }
737   cpy_build_name(buf, sizeof(buf), callback, name);
738   PyMem_Free(name);
739
740   Py_INCREF(callback);
741   Py_XINCREF(data);
742
743   c = calloc(1, sizeof(*c));
744   if (c == NULL)
745     return NULL;
746
747   c->name = strdup(buf);
748   c->callback = callback;
749   c->data = data;
750   c->next = NULL;
751
752   register_function(buf, handler,
753                     &(user_data_t){
754                         .data = c, .free_func = cpy_destroy_user_data,
755                     });
756
757   ++cpy_num_callbacks;
758   return cpy_string_to_unicode_or_bytes(buf);
759 }
760
761 static PyObject *cpy_register_read(PyObject *self, PyObject *args,
762                                    PyObject *kwds) {
763   char buf[512];
764   cpy_callback_t *c = NULL;
765   double interval = 0;
766   char *name = NULL;
767   PyObject *callback = NULL, *data = NULL;
768   static char *kwlist[] = {"callback", "interval", "data", "name", NULL};
769
770   if (PyArg_ParseTupleAndKeywords(args, kwds, "O|dOet", kwlist, &callback,
771                                   &interval, &data, NULL, &name) == 0)
772     return NULL;
773   if (PyCallable_Check(callback) == 0) {
774     PyMem_Free(name);
775     PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
776     return NULL;
777   }
778   cpy_build_name(buf, sizeof(buf), callback, name);
779   PyMem_Free(name);
780
781   Py_INCREF(callback);
782   Py_XINCREF(data);
783
784   c = calloc(1, sizeof(*c));
785   if (c == NULL)
786     return NULL;
787
788   c->name = strdup(buf);
789   c->callback = callback;
790   c->data = data;
791   c->next = NULL;
792
793   plugin_register_complex_read(
794       /* group = */ "python", buf, cpy_read_callback,
795       DOUBLE_TO_CDTIME_T(interval),
796       &(user_data_t){
797           .data = c, .free_func = cpy_destroy_user_data,
798       });
799   ++cpy_num_callbacks;
800   return cpy_string_to_unicode_or_bytes(buf);
801 }
802
803 static PyObject *cpy_register_log(PyObject *self, PyObject *args,
804                                   PyObject *kwds) {
805   return cpy_register_generic_userdata((void *)plugin_register_log,
806                                        (void *)cpy_log_callback, args, kwds);
807 }
808
809 static PyObject *cpy_register_write(PyObject *self, PyObject *args,
810                                     PyObject *kwds) {
811   return cpy_register_generic_userdata((void *)plugin_register_write,
812                                        (void *)cpy_write_callback, args, kwds);
813 }
814
815 static PyObject *cpy_register_notification(PyObject *self, PyObject *args,
816                                            PyObject *kwds) {
817   return cpy_register_generic_userdata((void *)plugin_register_notification,
818                                        (void *)cpy_notification_callback, args,
819                                        kwds);
820 }
821
822 static PyObject *cpy_register_flush(PyObject *self, PyObject *args,
823                                     PyObject *kwds) {
824   return cpy_register_generic_userdata((void *)plugin_register_flush,
825                                        (void *)cpy_flush_callback, args, kwds);
826 }
827
828 static PyObject *cpy_register_shutdown(PyObject *self, PyObject *args,
829                                        PyObject *kwds) {
830   return cpy_register_generic(&cpy_shutdown_callbacks, args, kwds);
831 }
832
833 static PyObject *cpy_error(PyObject *self, PyObject *args) {
834   char *text;
835   if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
836     return NULL;
837   Py_BEGIN_ALLOW_THREADS plugin_log(LOG_ERR, "%s", text);
838   Py_END_ALLOW_THREADS PyMem_Free(text);
839   Py_RETURN_NONE;
840 }
841
842 static PyObject *cpy_warning(PyObject *self, PyObject *args) {
843   char *text;
844   if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
845     return NULL;
846   Py_BEGIN_ALLOW_THREADS plugin_log(LOG_WARNING, "%s", text);
847   Py_END_ALLOW_THREADS PyMem_Free(text);
848   Py_RETURN_NONE;
849 }
850
851 static PyObject *cpy_notice(PyObject *self, PyObject *args) {
852   char *text;
853   if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
854     return NULL;
855   Py_BEGIN_ALLOW_THREADS plugin_log(LOG_NOTICE, "%s", text);
856   Py_END_ALLOW_THREADS PyMem_Free(text);
857   Py_RETURN_NONE;
858 }
859
860 static PyObject *cpy_info(PyObject *self, PyObject *args) {
861   char *text;
862   if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
863     return NULL;
864   Py_BEGIN_ALLOW_THREADS plugin_log(LOG_INFO, "%s", text);
865   Py_END_ALLOW_THREADS PyMem_Free(text);
866   Py_RETURN_NONE;
867 }
868
869 static PyObject *cpy_debug(PyObject *self, PyObject *args) {
870 #ifdef COLLECT_DEBUG
871   char *text;
872   if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
873     return NULL;
874   Py_BEGIN_ALLOW_THREADS plugin_log(LOG_DEBUG, "%s", text);
875   Py_END_ALLOW_THREADS PyMem_Free(text);
876 #endif
877   Py_RETURN_NONE;
878 }
879
880 static PyObject *cpy_unregister_generic(cpy_callback_t **list_head,
881                                         PyObject *arg, const char *desc) {
882   char buf[512];
883   const char *name;
884   cpy_callback_t *prev = NULL, *tmp;
885
886   Py_INCREF(arg);
887   name = cpy_unicode_or_bytes_to_string(&arg);
888   if (name == NULL) {
889     PyErr_Clear();
890     if (!PyCallable_Check(arg)) {
891       PyErr_SetString(PyExc_TypeError, "This function needs a string or a "
892                                        "callable object as its only "
893                                        "parameter.");
894       Py_DECREF(arg);
895       return NULL;
896     }
897     cpy_build_name(buf, sizeof(buf), arg, NULL);
898     name = buf;
899   }
900   for (tmp = *list_head; tmp; prev = tmp, tmp = tmp->next)
901     if (strcmp(name, tmp->name) == 0)
902       break;
903
904   Py_DECREF(arg);
905   if (tmp == NULL) {
906     PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.",
907                  desc, name);
908     return NULL;
909   }
910   /* Yes, this is actually safe. To call this function the caller has to
911    * hold the GIL. Well, safe as long as there is only one GIL anyway ... */
912   if (prev == NULL)
913     *list_head = tmp->next;
914   else
915     prev->next = tmp->next;
916   cpy_destroy_user_data(tmp);
917   Py_RETURN_NONE;
918 }
919
920 static void cpy_unregister_list(cpy_callback_t **list_head) {
921   cpy_callback_t *cur, *next;
922   for (cur = *list_head; cur; cur = next) {
923     next = cur->next;
924     cpy_destroy_user_data(cur);
925   }
926   *list_head = NULL;
927 }
928
929 typedef int cpy_unregister_function_t(const char *name);
930
931 static PyObject *
932 cpy_unregister_generic_userdata(cpy_unregister_function_t *unreg, PyObject *arg,
933                                 const char *desc) {
934   char buf[512];
935   const char *name;
936
937   Py_INCREF(arg);
938   name = cpy_unicode_or_bytes_to_string(&arg);
939   if (name == NULL) {
940     PyErr_Clear();
941     if (!PyCallable_Check(arg)) {
942       PyErr_SetString(PyExc_TypeError, "This function needs a string or a "
943                                        "callable object as its only "
944                                        "parameter.");
945       Py_DECREF(arg);
946       return NULL;
947     }
948     cpy_build_name(buf, sizeof(buf), arg, NULL);
949     name = buf;
950   }
951   if (unreg(name) == 0) {
952     Py_DECREF(arg);
953     Py_RETURN_NONE;
954   }
955   PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.",
956                desc, name);
957   Py_DECREF(arg);
958   return NULL;
959 }
960
961 static PyObject *cpy_unregister_log(PyObject *self, PyObject *arg) {
962   return cpy_unregister_generic_userdata(plugin_unregister_log, arg, "log");
963 }
964
965 static PyObject *cpy_unregister_init(PyObject *self, PyObject *arg) {
966   return cpy_unregister_generic(&cpy_init_callbacks, arg, "init");
967 }
968
969 static PyObject *cpy_unregister_config(PyObject *self, PyObject *arg) {
970   return cpy_unregister_generic(&cpy_config_callbacks, arg, "config");
971 }
972
973 static PyObject *cpy_unregister_read(PyObject *self, PyObject *arg) {
974   return cpy_unregister_generic_userdata(plugin_unregister_read, arg, "read");
975 }
976
977 static PyObject *cpy_unregister_write(PyObject *self, PyObject *arg) {
978   return cpy_unregister_generic_userdata(plugin_unregister_write, arg, "write");
979 }
980
981 static PyObject *cpy_unregister_notification(PyObject *self, PyObject *arg) {
982   return cpy_unregister_generic_userdata(plugin_unregister_notification, arg,
983                                          "notification");
984 }
985
986 static PyObject *cpy_unregister_flush(PyObject *self, PyObject *arg) {
987   return cpy_unregister_generic_userdata(plugin_unregister_flush, arg, "flush");
988 }
989
990 static PyObject *cpy_unregister_shutdown(PyObject *self, PyObject *arg) {
991   return cpy_unregister_generic(&cpy_shutdown_callbacks, arg, "shutdown");
992 }
993
994 static PyMethodDef cpy_methods[] = {
995     {"debug", cpy_debug, METH_VARARGS, log_doc},
996     {"info", cpy_info, METH_VARARGS, log_doc},
997     {"notice", cpy_notice, METH_VARARGS, log_doc},
998     {"warning", cpy_warning, METH_VARARGS, log_doc},
999     {"error", cpy_error, METH_VARARGS, log_doc},
1000     {"get_dataset", (PyCFunction)cpy_get_dataset, METH_VARARGS, get_ds_doc},
1001     {"flush", (PyCFunction)cpy_flush, METH_VARARGS | METH_KEYWORDS, flush_doc},
1002     {"register_log", (PyCFunction)cpy_register_log,
1003      METH_VARARGS | METH_KEYWORDS, reg_log_doc},
1004     {"register_init", (PyCFunction)cpy_register_init,
1005      METH_VARARGS | METH_KEYWORDS, reg_init_doc},
1006     {"register_config", (PyCFunction)cpy_register_config,
1007      METH_VARARGS | METH_KEYWORDS, reg_config_doc},
1008     {"register_read", (PyCFunction)cpy_register_read,
1009      METH_VARARGS | METH_KEYWORDS, reg_read_doc},
1010     {"register_write", (PyCFunction)cpy_register_write,
1011      METH_VARARGS | METH_KEYWORDS, reg_write_doc},
1012     {"register_notification", (PyCFunction)cpy_register_notification,
1013      METH_VARARGS | METH_KEYWORDS, reg_notification_doc},
1014     {"register_flush", (PyCFunction)cpy_register_flush,
1015      METH_VARARGS | METH_KEYWORDS, reg_flush_doc},
1016     {"register_shutdown", (PyCFunction)cpy_register_shutdown,
1017      METH_VARARGS | METH_KEYWORDS, reg_shutdown_doc},
1018     {"unregister_log", cpy_unregister_log, METH_O, unregister_doc},
1019     {"unregister_init", cpy_unregister_init, METH_O, unregister_doc},
1020     {"unregister_config", cpy_unregister_config, METH_O, unregister_doc},
1021     {"unregister_read", cpy_unregister_read, METH_O, unregister_doc},
1022     {"unregister_write", cpy_unregister_write, METH_O, unregister_doc},
1023     {"unregister_notification", cpy_unregister_notification, METH_O,
1024      unregister_doc},
1025     {"unregister_flush", cpy_unregister_flush, METH_O, unregister_doc},
1026     {"unregister_shutdown", cpy_unregister_shutdown, METH_O, unregister_doc},
1027     {0, 0, 0, 0}};
1028
1029 static int cpy_shutdown(void) {
1030   PyObject *ret;
1031
1032   if (!state) {
1033     printf(
1034         "================================================================\n");
1035     printf(
1036         "collectd shutdown while running an interactive session. This will\n");
1037     printf("probably leave your terminal in a mess.\n");
1038     printf("Run the command \"reset\" to get it back into a usable state.\n");
1039     printf("You can press Ctrl+D in the interactive session to\n");
1040     printf("close collectd and avoid this problem in the future.\n");
1041     printf(
1042         "================================================================\n");
1043   }
1044
1045   CPY_LOCK_THREADS
1046
1047   for (cpy_callback_t *c = cpy_shutdown_callbacks; c; c = c->next) {
1048     ret = PyObject_CallFunctionObjArgs(c->callback, c->data,
1049                                        (void *)0); /* New reference. */
1050     if (ret == NULL)
1051       cpy_log_exception("shutdown callback");
1052     else
1053       Py_DECREF(ret);
1054   }
1055   PyErr_Print();
1056
1057   Py_BEGIN_ALLOW_THREADS cpy_unregister_list(&cpy_config_callbacks);
1058   cpy_unregister_list(&cpy_init_callbacks);
1059   cpy_unregister_list(&cpy_shutdown_callbacks);
1060   cpy_shutdown_triggered = 1;
1061   Py_END_ALLOW_THREADS
1062
1063       if (!cpy_num_callbacks) {
1064     Py_Finalize();
1065     return 0;
1066   }
1067
1068   CPY_RELEASE_THREADS
1069   return 0;
1070 }
1071
1072 static void *cpy_interactive(void *pipefd) {
1073   PyOS_sighandler_t cur_sig;
1074
1075   /* Signal handler in a plugin? Bad stuff, but the best way to
1076    * handle it I guess. In an interactive session people will
1077    * press Ctrl+C at some time, which will generate a SIGINT.
1078    * This will cause collectd to shutdown, thus killing the
1079    * interactive interpreter, and leaving the terminal in a
1080    * mess. Chances are, this isn't what the user wanted to do.
1081    *
1082    * So this is the plan:
1083    * 1. Restore Python's own signal handler
1084    * 2. Tell Python we just forked so it will accept this thread
1085    *    as the main one. No version of Python will ever handle
1086    *    interrupts anywhere but in the main thread.
1087    * 3. After the interactive loop is done, restore collectd's
1088    *    SIGINT handler.
1089    * 4. Raise SIGINT for a clean shutdown. The signal is sent to
1090    *    the main thread to ensure it wakes up the main interval
1091    *    sleep so that collectd shuts down immediately not in 10
1092    *    seconds.
1093    *
1094    * This will make sure that SIGINT won't kill collectd but
1095    * still interrupt syscalls like sleep and pause. */
1096
1097   if (PyImport_ImportModule("readline") == NULL) {
1098     /* This interactive session will suck. */
1099     cpy_log_exception("interactive session init");
1100   }
1101   cur_sig = PyOS_setsig(SIGINT, python_sigint_handler);
1102   PyOS_AfterFork();
1103   PyEval_InitThreads();
1104   close(*(int *)pipefd);
1105   PyRun_InteractiveLoop(stdin, "<stdin>");
1106   PyOS_setsig(SIGINT, cur_sig);
1107   PyErr_Print();
1108   state = PyEval_SaveThread();
1109   NOTICE("python: Interactive interpreter exited, stopping collectd ...");
1110   pthread_kill(main_thread, SIGINT);
1111   return NULL;
1112 }
1113
1114 static int cpy_init(void) {
1115   PyObject *ret;
1116   int pipefd[2];
1117   char buf;
1118   static pthread_t thread;
1119
1120   if (!Py_IsInitialized()) {
1121     WARNING("python: Plugin loaded but not configured.");
1122     plugin_unregister_shutdown("python");
1123     Py_Finalize();
1124     return 0;
1125   }
1126   main_thread = pthread_self();
1127   if (do_interactive) {
1128     if (pipe(pipefd)) {
1129       ERROR("python: Unable to create pipe.");
1130       return 1;
1131     }
1132     if (plugin_thread_create(&thread, NULL, cpy_interactive, pipefd + 1,
1133                              "python interpreter")) {
1134       ERROR("python: Error creating thread for interactive interpreter.");
1135     }
1136     if (read(pipefd[0], &buf, 1))
1137       ;
1138     (void)close(pipefd[0]);
1139   } else {
1140     PyEval_InitThreads();
1141     state = PyEval_SaveThread();
1142   }
1143   CPY_LOCK_THREADS
1144   for (cpy_callback_t *c = cpy_init_callbacks; c; c = c->next) {
1145     ret = PyObject_CallFunctionObjArgs(c->callback, c->data,
1146                                        (void *)0); /* New reference. */
1147     if (ret == NULL)
1148       cpy_log_exception("init callback");
1149     else
1150       Py_DECREF(ret);
1151   }
1152   CPY_RELEASE_THREADS
1153
1154   return 0;
1155 }
1156
1157 static PyObject *cpy_oconfig_to_pyconfig(oconfig_item_t *ci, PyObject *parent) {
1158   PyObject *item, *values, *children, *tmp;
1159
1160   if (parent == NULL)
1161     parent = Py_None;
1162
1163   values = PyTuple_New(ci->values_num); /* New reference. */
1164   for (int i = 0; i < ci->values_num; ++i) {
1165     if (ci->values[i].type == OCONFIG_TYPE_STRING) {
1166       PyTuple_SET_ITEM(values, i, cpy_string_to_unicode_or_bytes(
1167                                       ci->values[i].value.string));
1168     } else if (ci->values[i].type == OCONFIG_TYPE_NUMBER) {
1169       PyTuple_SET_ITEM(values, i,
1170                        PyFloat_FromDouble(ci->values[i].value.number));
1171     } else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN) {
1172       PyTuple_SET_ITEM(values, i, PyBool_FromLong(ci->values[i].value.boolean));
1173     }
1174   }
1175
1176   tmp = cpy_string_to_unicode_or_bytes(ci->key);
1177   item = PyObject_CallFunction((void *)&ConfigType, "NONO", tmp, parent, values,
1178                                Py_None);
1179   if (item == NULL)
1180     return NULL;
1181   children = PyTuple_New(ci->children_num); /* New reference. */
1182   for (int i = 0; i < ci->children_num; ++i) {
1183     PyTuple_SET_ITEM(children, i,
1184                      cpy_oconfig_to_pyconfig(ci->children + i, item));
1185   }
1186   tmp = ((Config *)item)->children;
1187   ((Config *)item)->children = children;
1188   Py_XDECREF(tmp);
1189   return item;
1190 }
1191
1192 #ifdef IS_PY3K
1193 static struct PyModuleDef collectdmodule = {
1194     PyModuleDef_HEAD_INIT, "collectd",  /* name of module */
1195     "The python interface to collectd", /* module documentation, may be NULL */
1196     -1, cpy_methods};
1197
1198 PyMODINIT_FUNC PyInit_collectd(void) {
1199   return PyModule_Create(&collectdmodule);
1200 }
1201 #endif
1202
1203 static int cpy_init_python(void) {
1204   PyOS_sighandler_t cur_sig;
1205   PyObject *sys;
1206   PyObject *module;
1207
1208 #ifdef IS_PY3K
1209   wchar_t *argv = L"";
1210   /* Add a builtin module, before Py_Initialize */
1211   PyImport_AppendInittab("collectd", PyInit_collectd);
1212 #else
1213   char *argv = "";
1214 #endif
1215
1216   /* Chances are the current signal handler is already SIG_DFL, but let's make
1217    * sure. */
1218   cur_sig = PyOS_setsig(SIGINT, SIG_DFL);
1219   Py_Initialize();
1220   python_sigint_handler = PyOS_setsig(SIGINT, cur_sig);
1221
1222   PyType_Ready(&ConfigType);
1223   PyType_Ready(&PluginDataType);
1224   ValuesType.tp_base = &PluginDataType;
1225   PyType_Ready(&ValuesType);
1226   NotificationType.tp_base = &PluginDataType;
1227   PyType_Ready(&NotificationType);
1228   SignedType.tp_base = &PyLong_Type;
1229   PyType_Ready(&SignedType);
1230   UnsignedType.tp_base = &PyLong_Type;
1231   PyType_Ready(&UnsignedType);
1232   sys = PyImport_ImportModule("sys"); /* New reference. */
1233   if (sys == NULL) {
1234     cpy_log_exception("python initialization");
1235     return 1;
1236   }
1237   sys_path = PyObject_GetAttrString(sys, "path"); /* New reference. */
1238   Py_DECREF(sys);
1239   if (sys_path == NULL) {
1240     cpy_log_exception("python initialization");
1241     return 1;
1242   }
1243   PySys_SetArgv(1, &argv);
1244   PyList_SetSlice(sys_path, 0, 1, NULL);
1245
1246 #ifdef IS_PY3K
1247   module = PyImport_ImportModule("collectd");
1248 #else
1249   module = Py_InitModule("collectd", cpy_methods); /* Borrowed reference. */
1250 #endif
1251   PyModule_AddObject(module, "Config",
1252                      (void *)&ConfigType); /* Steals a reference. */
1253   PyModule_AddObject(module, "Values",
1254                      (void *)&ValuesType); /* Steals a reference. */
1255   PyModule_AddObject(module, "Notification",
1256                      (void *)&NotificationType); /* Steals a reference. */
1257   PyModule_AddObject(module, "Signed",
1258                      (void *)&SignedType); /* Steals a reference. */
1259   PyModule_AddObject(module, "Unsigned",
1260                      (void *)&UnsignedType); /* Steals a reference. */
1261   PyModule_AddIntConstant(module, "LOG_DEBUG", LOG_DEBUG);
1262   PyModule_AddIntConstant(module, "LOG_INFO", LOG_INFO);
1263   PyModule_AddIntConstant(module, "LOG_NOTICE", LOG_NOTICE);
1264   PyModule_AddIntConstant(module, "LOG_WARNING", LOG_WARNING);
1265   PyModule_AddIntConstant(module, "LOG_ERROR", LOG_ERR);
1266   PyModule_AddIntConstant(module, "NOTIF_FAILURE", NOTIF_FAILURE);
1267   PyModule_AddIntConstant(module, "NOTIF_WARNING", NOTIF_WARNING);
1268   PyModule_AddIntConstant(module, "NOTIF_OKAY", NOTIF_OKAY);
1269   PyModule_AddStringConstant(module, "DS_TYPE_COUNTER",
1270                              DS_TYPE_TO_STRING(DS_TYPE_COUNTER));
1271   PyModule_AddStringConstant(module, "DS_TYPE_GAUGE",
1272                              DS_TYPE_TO_STRING(DS_TYPE_GAUGE));
1273   PyModule_AddStringConstant(module, "DS_TYPE_DERIVE",
1274                              DS_TYPE_TO_STRING(DS_TYPE_DERIVE));
1275   PyModule_AddStringConstant(module, "DS_TYPE_ABSOLUTE",
1276                              DS_TYPE_TO_STRING(DS_TYPE_ABSOLUTE));
1277   return 0;
1278 }
1279
1280 static int cpy_config(oconfig_item_t *ci) {
1281   PyObject *tb;
1282   int status = 0;
1283
1284   /* Ok in theory we shouldn't do initialization at this point
1285    * but we have to. In order to give python scripts a chance
1286    * to register a config callback we need to be able to execute
1287    * python code during the config callback so we have to start
1288    * the interpreter here. */
1289   /* Do *not* use the python "thread" module at this point! */
1290
1291   if (!Py_IsInitialized() && cpy_init_python())
1292     return 1;
1293
1294   for (int i = 0; i < ci->children_num; ++i) {
1295     oconfig_item_t *item = ci->children + i;
1296
1297     if (strcasecmp(item->key, "Interactive") == 0) {
1298       if (cf_util_get_boolean(item, &do_interactive) != 0) {
1299         status = 1;
1300         continue;
1301       }
1302     } else if (strcasecmp(item->key, "Encoding") == 0) {
1303       char *encoding = NULL;
1304       if (cf_util_get_string(item, &encoding) != 0) {
1305         status = 1;
1306         continue;
1307       }
1308 #ifdef IS_PY3K
1309       ERROR("python: \"Encoding\" was used in the config file but Python3 was "
1310             "used, which does not support changing encodings");
1311       status = 1;
1312       sfree(encoding);
1313       continue;
1314 #else
1315       /* Why is this even necessary? And undocumented? */
1316       if (PyUnicode_SetDefaultEncoding(encoding)) {
1317         cpy_log_exception("setting default encoding");
1318         status = 1;
1319       }
1320 #endif
1321       sfree(encoding);
1322     } else if (strcasecmp(item->key, "LogTraces") == 0) {
1323       _Bool log_traces;
1324       if (cf_util_get_boolean(item, &log_traces) != 0) {
1325         status = 1;
1326         continue;
1327       }
1328       if (!log_traces) {
1329         Py_XDECREF(cpy_format_exception);
1330         cpy_format_exception = NULL;
1331         continue;
1332       }
1333       if (cpy_format_exception)
1334         continue;
1335       tb = PyImport_ImportModule("traceback"); /* New reference. */
1336       if (tb == NULL) {
1337         cpy_log_exception("python initialization");
1338         status = 1;
1339         continue;
1340       }
1341       cpy_format_exception =
1342           PyObject_GetAttrString(tb, "format_exception"); /* New reference. */
1343       Py_DECREF(tb);
1344       if (cpy_format_exception == NULL) {
1345         cpy_log_exception("python initialization");
1346         status = 1;
1347       }
1348     } else if (strcasecmp(item->key, "ModulePath") == 0) {
1349       char *dir = NULL;
1350       PyObject *dir_object;
1351
1352       if (cf_util_get_string(item, &dir) != 0) {
1353         status = 1;
1354         continue;
1355       }
1356       dir_object = cpy_string_to_unicode_or_bytes(dir); /* New reference. */
1357       if (dir_object == NULL) {
1358         ERROR("python plugin: Unable to convert \"%s\" to "
1359               "a python object.",
1360               dir);
1361         free(dir);
1362         cpy_log_exception("python initialization");
1363         status = 1;
1364         continue;
1365       }
1366       if (PyList_Insert(sys_path, 0, dir_object) != 0) {
1367         ERROR("python plugin: Unable to prepend \"%s\" to "
1368               "python module path.",
1369               dir);
1370         cpy_log_exception("python initialization");
1371         status = 1;
1372       }
1373       Py_DECREF(dir_object);
1374       free(dir);
1375     } else if (strcasecmp(item->key, "Import") == 0) {
1376       char *module_name = NULL;
1377       PyObject *module;
1378
1379       if (cf_util_get_string(item, &module_name) != 0) {
1380         status = 1;
1381         continue;
1382       }
1383       module = PyImport_ImportModule(module_name); /* New reference. */
1384       if (module == NULL) {
1385         ERROR("python plugin: Error importing module \"%s\".", module_name);
1386         cpy_log_exception("importing module");
1387         status = 1;
1388       }
1389       free(module_name);
1390       Py_XDECREF(module);
1391     } else if (strcasecmp(item->key, "Module") == 0) {
1392       char *name = NULL;
1393       cpy_callback_t *c;
1394       PyObject *ret;
1395
1396       if (cf_util_get_string(item, &name) != 0) {
1397         status = 1;
1398         continue;
1399       }
1400       for (c = cpy_config_callbacks; c; c = c->next) {
1401         if (strcasecmp(c->name + 7, name) == 0)
1402           break;
1403       }
1404       if (c == NULL) {
1405         WARNING("python plugin: Found a configuration for the \"%s\" plugin, "
1406                 "but the plugin isn't loaded or didn't register "
1407                 "a configuration callback.",
1408                 name);
1409         free(name);
1410         continue;
1411       }
1412       free(name);
1413       if (c->data == NULL)
1414         ret = PyObject_CallFunction(
1415             c->callback, "N",
1416             cpy_oconfig_to_pyconfig(item, NULL)); /* New reference. */
1417       else
1418         ret = PyObject_CallFunction(c->callback, "NO",
1419                                     cpy_oconfig_to_pyconfig(item, NULL),
1420                                     c->data); /* New reference. */
1421       if (ret == NULL) {
1422         cpy_log_exception("loading module");
1423         status = 1;
1424       } else
1425         Py_DECREF(ret);
1426     } else {
1427       ERROR("python plugin: Unknown config key \"%s\".", item->key);
1428       status = 1;
1429     }
1430   }
1431   return (status);
1432 }
1433
1434 void module_register(void) {
1435   plugin_register_complex_config("python", cpy_config);
1436   plugin_register_init("python", cpy_init);
1437   plugin_register_shutdown("python", cpy_shutdown);
1438 }