Code

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