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>
31 #if HAVE_PTHREAD_H
32 # include <pthread.h>
33 #endif
35 #include "collectd.h"
36 #include "common.h"
38 #include "cpython.h"
40 typedef struct cpy_callback_s {
41 char *name;
42 PyObject *callback;
43 PyObject *data;
44 struct cpy_callback_s *next;
45 } cpy_callback_t;
47 static char log_doc[] = "This function sends a string to all logging plugins.";
49 static char get_ds_doc[] = "get_dataset(name) -> definition\n"
50 "\n"
51 "Returns the definition of a dataset specified by name.\n"
52 "\n"
53 "'name' is a string specifying the dataset to query.\n"
54 "'definition' is a list of 4-tuples. Every tuple represents a \n"
55 " data source within the data set and its 4 values are the \n"
56 " name, type, min and max value.\n"
57 " 'name' is a string.\n"
58 " 'type' is a string that is equal to either DS_TYPE_COUNTER,\n"
59 " DS_TYPE_GAUGE, DS_TYPE_DERIVE or DS_TYPE_ABSOLUTE.\n"
60 " 'min' and 'max' are either a float or None.";
62 static char flush_doc[] = "flush([plugin][, timeout][, identifier]) -> None\n"
63 "\n"
64 "Flushes the cache of another plugin.";
66 static char unregister_doc[] = "Unregisters a callback. This function needs exactly one parameter either\n"
67 "the function to unregister or the callback identifier to unregister.";
69 static char reg_log_doc[] = "register_log(callback[, data][, name]) -> identifier\n"
70 "\n"
71 "Register a callback function for log messages.\n"
72 "\n"
73 "'callback' is a callable object that will be called every time something\n"
74 " is logged.\n"
75 "'data' is an optional object that will be passed back to the callback\n"
76 " function every time it is called.\n"
77 "'name' is an optional identifier for this callback. The default name\n"
78 " is 'python.<module>'.\n"
79 " Every callback needs a unique identifier, so if you want to\n"
80 " register this callback multiple time from the same module you need\n"
81 " to specify a name here.\n"
82 "'identifier' is the full identifier assigned to this callback.\n"
83 "\n"
84 "The callback function will be called with two or three parameters:\n"
85 "severity: An integer that should be compared to the LOG_ constants.\n"
86 "message: The text to be logged.\n"
87 "data: The optional data parameter passed to the register function.\n"
88 " If the parameter was omitted it will be omitted here, too.";
90 static char reg_init_doc[] = "register_init(callback[, data][, name]) -> identifier\n"
91 "\n"
92 "Register a callback function that will be executed once after the config.\n"
93 "file has been read, all plugins heve been loaded and the collectd has\n"
94 "forked into the background.\n"
95 "\n"
96 "'callback' is a callable object that will be executed.\n"
97 "'data' is an optional object that will be passed back to the callback\n"
98 " function when it is called.\n"
99 "'name' is an optional identifier for this callback. The default name\n"
100 " is 'python.<module>'.\n"
101 " Every callback needs a unique identifier, so if you want to\n"
102 " register this callback multiple time from the same module you need\n"
103 " to specify a name here.\n"
104 "'identifier' is the full identifier assigned to this callback.\n"
105 "\n"
106 "The callback function will be called without parameters, except for\n"
107 "data if it was supplied.";
109 static char reg_config_doc[] = "register_config(callback[, data][, name]) -> identifier\n"
110 "\n"
111 "Register a callback function for config file entries.\n"
112 "'callback' is a callable object that will be called for every config block.\n"
113 "'data' is an optional object that will be passed back to the callback\n"
114 " function every time it is called.\n"
115 "'name' is an optional identifier for this callback. The default name\n"
116 " is 'python.<module>'.\n"
117 " Every callback needs a unique identifier, so if you want to\n"
118 " register this callback multiple time from the same module you need\n"
119 " to specify a name here.\n"
120 "'identifier' is the full identifier assigned to this callback.\n"
121 "\n"
122 "The callback function will be called with one or two parameters:\n"
123 "config: A Config object.\n"
124 "data: The optional data parameter passed to the register function.\n"
125 " If the parameter was omitted it will be omitted here, too.";
127 static char reg_read_doc[] = "register_read(callback[, interval][, data][, name]) -> identifier\n"
128 "\n"
129 "Register a callback function for reading data. It will just be called\n"
130 "in a fixed interval to signal that it's time to dispatch new values.\n"
131 "'callback' is a callable object that will be called every time something\n"
132 " is logged.\n"
133 "'interval' is the number of seconds between between calls to the callback\n"
134 " function. Full float precision is supported here.\n"
135 "'data' is an optional object that will be passed back to the callback\n"
136 " function every time it is called.\n"
137 "'name' is an optional identifier for this callback. The default name\n"
138 " is 'python.<module>'.\n"
139 " Every callback needs a unique identifier, so if you want to\n"
140 " register this callback multiple time from the same module you need\n"
141 " to specify a name here.\n"
142 "'identifier' is the full identifier assigned to this callback.\n"
143 "\n"
144 "The callback function will be called without parameters, except for\n"
145 "data if it was supplied.";
147 static char reg_write_doc[] = "register_write(callback[, data][, name]) -> identifier\n"
148 "\n"
149 "Register a callback function to receive values dispatched by other plugins.\n"
150 "'callback' is a callable object that will be called every time a value\n"
151 " is dispatched.\n"
152 "'data' is an optional object that will be passed back to the callback\n"
153 " function every time it is called.\n"
154 "'name' is an optional identifier for this callback. The default name\n"
155 " is 'python.<module>'.\n"
156 " Every callback needs a unique identifier, so if you want to\n"
157 " register this callback multiple time from the same module you need\n"
158 " to specify a name here.\n"
159 "'identifier' is the full identifier assigned to this callback.\n"
160 "\n"
161 "The callback function will be called with one or two parameters:\n"
162 "values: A Values object which is a copy of the dispatched values.\n"
163 "data: The optional data parameter passed to the register function.\n"
164 " If the parameter was omitted it will be omitted here, too.";
166 static char reg_notification_doc[] = "register_notification(callback[, data][, name]) -> identifier\n"
167 "\n"
168 "Register a callback function for notifications.\n"
169 "'callback' is a callable object that will be called every time a notification\n"
170 " is dispatched.\n"
171 "'data' is an optional object that will be passed back to the callback\n"
172 " function every time it is called.\n"
173 "'name' is an optional identifier for this callback. The default name\n"
174 " is 'python.<module>'.\n"
175 " Every callback needs a unique identifier, so if you want to\n"
176 " register this callback multiple time from the same module you need\n"
177 " to specify a name here.\n"
178 "'identifier' is the full identifier assigned to this callback.\n"
179 "\n"
180 "The callback function will be called with one or two parameters:\n"
181 "notification: A copy of the notification that was dispatched.\n"
182 "data: The optional data parameter passed to the register function.\n"
183 " If the parameter was omitted it will be omitted here, too.";
185 static char reg_flush_doc[] = "register_flush(callback[, data][, name]) -> identifier\n"
186 "\n"
187 "Register a callback function for flush messages.\n"
188 "'callback' is a callable object that will be called every time a plugin\n"
189 " requests a flush for either this or all plugins.\n"
190 "'data' is an optional object that will be passed back to the callback\n"
191 " function every time it is called.\n"
192 "'name' is an optional identifier for this callback. The default name\n"
193 " is 'python.<module>'.\n"
194 " Every callback needs a unique identifier, so if you want to\n"
195 " register this callback multiple time from the same module you need\n"
196 " to specify a name here.\n"
197 "'identifier' is the full identifier assigned to this callback.\n"
198 "\n"
199 "The callback function will be called with two or three parameters:\n"
200 "timeout: Indicates that only data older than 'timeout' seconds is to\n"
201 " be flushed.\n"
202 "id: Specifies which values are to be flushed.\n"
203 "data: The optional data parameter passed to the register function.\n"
204 " If the parameter was omitted it will be omitted here, too.";
206 static char reg_shutdown_doc[] = "register_shutdown(callback[, data][, name]) -> identifier\n"
207 "\n"
208 "Register a callback function for collectd shutdown.\n"
209 "'callback' is a callable object that will be called once collectd is\n"
210 " shutting down.\n"
211 "'data' is an optional object that will be passed back to the callback\n"
212 " function if it is called.\n"
213 "'name' is an optional identifier for this callback. The default name\n"
214 " is 'python.<module>'.\n"
215 " Every callback needs a unique identifier, so if you want to\n"
216 " register this callback multiple time from the same module you need\n"
217 " to specify a name here.\n"
218 "'identifier' is the full identifier assigned to this callback.\n"
219 "\n"
220 "The callback function will be called with no parameters except for\n"
221 " data if it was supplied.";
224 static int 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 static void cpy_destroy_user_data(void *data) {
240 cpy_callback_t *c = data;
241 free(c->name);
242 Py_DECREF(c->callback);
243 Py_XDECREF(c->data);
244 free(c);
245 }
247 /* You must hold the GIL to call this function!
248 * But if you managed to extract the callback parameter then you probably already do. */
250 static void cpy_build_name(char *buf, size_t size, PyObject *callback, const char *name) {
251 const char *module = NULL;
252 PyObject *mod = NULL;
254 if (name != NULL) {
255 snprintf(buf, size, "python.%s", name);
256 return;
257 }
259 mod = PyObject_GetAttrString(callback, "__module__"); /* New reference. */
260 if (mod != NULL)
261 module = cpy_unicode_or_bytes_to_string(&mod);
263 if (module != NULL) {
264 snprintf(buf, size, "python.%s", module);
265 Py_XDECREF(mod);
266 PyErr_Clear();
267 return;
268 }
269 Py_XDECREF(mod);
271 snprintf(buf, size, "python.%p", callback);
272 PyErr_Clear();
273 }
275 void cpy_log_exception(const char *context) {
276 int l = 0, i;
277 const char *typename = NULL, *message = NULL;
278 PyObject *type, *value, *traceback, *tn, *m, *list;
280 PyErr_Fetch(&type, &value, &traceback);
281 PyErr_NormalizeException(&type, &value, &traceback);
282 if (type == NULL) return;
283 tn = PyObject_GetAttrString(type, "__name__"); /* New reference. */
284 m = PyObject_Str(value); /* New reference. */
285 if (tn != NULL)
286 typename = cpy_unicode_or_bytes_to_string(&tn);
287 if (m != NULL)
288 message = cpy_unicode_or_bytes_to_string(&m);
289 if (typename == NULL)
290 typename = "NamelessException";
291 if (message == NULL)
292 message = "N/A";
293 Py_BEGIN_ALLOW_THREADS
294 ERROR("Unhandled python exception in %s: %s: %s", context, typename, message);
295 Py_END_ALLOW_THREADS
296 Py_XDECREF(tn);
297 Py_XDECREF(m);
298 if (!cpy_format_exception || !traceback) {
299 PyErr_Clear();
300 Py_DECREF(type);
301 Py_XDECREF(value);
302 Py_XDECREF(traceback);
303 return;
304 }
305 list = PyObject_CallFunction(cpy_format_exception, "NNN", type, value, traceback); /* New reference. */
306 if (list)
307 l = PyObject_Length(list);
308 for (i = 0; i < l; ++i) {
309 char *s;
310 PyObject *line;
312 line = PyList_GET_ITEM(list, i); /* Borrowed reference. */
313 Py_INCREF(line);
314 s = strdup(cpy_unicode_or_bytes_to_string(&line));
315 Py_DECREF(line);
316 if (s[strlen(s) - 1] == '\n')
317 s[strlen(s) - 1] = 0;
318 Py_BEGIN_ALLOW_THREADS
319 ERROR("%s", s);
320 Py_END_ALLOW_THREADS
321 free(s);
322 }
323 Py_XDECREF(list);
324 PyErr_Clear();
325 Py_DECREF(type);
326 Py_XDECREF(value);
327 Py_XDECREF(traceback);
328 }
330 static int cpy_read_callback(user_data_t *data) {
331 cpy_callback_t *c = data->data;
332 PyObject *ret;
334 CPY_LOCK_THREADS
335 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
336 if (ret == NULL) {
337 cpy_log_exception("read callback");
338 } else {
339 Py_DECREF(ret);
340 }
341 CPY_RELEASE_THREADS
342 if (ret == NULL)
343 return 1;
344 return 0;
345 }
347 static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_list, user_data_t *data) {
348 size_t i;
349 cpy_callback_t *c = data->data;
350 PyObject *ret, *list, *temp, *dict = NULL;
351 Values *v;
353 CPY_LOCK_THREADS
354 list = PyList_New(value_list->values_len); /* New reference. */
355 if (list == NULL) {
356 cpy_log_exception("write callback");
357 CPY_RETURN_FROM_THREADS 0;
358 }
359 for (i = 0; i < value_list->values_len; ++i) {
360 if (ds->ds[i].type == DS_TYPE_COUNTER) {
361 PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].counter));
362 } else if (ds->ds[i].type == DS_TYPE_GAUGE) {
363 PyList_SetItem(list, i, PyFloat_FromDouble(value_list->values[i].gauge));
364 } else if (ds->ds[i].type == DS_TYPE_DERIVE) {
365 PyList_SetItem(list, i, PyLong_FromLongLong(value_list->values[i].derive));
366 } else if (ds->ds[i].type == DS_TYPE_ABSOLUTE) {
367 PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].absolute));
368 } else {
369 Py_BEGIN_ALLOW_THREADS
370 ERROR("cpy_write_callback: Unknown value type %d.", ds->ds[i].type);
371 Py_END_ALLOW_THREADS
372 Py_DECREF(list);
373 CPY_RETURN_FROM_THREADS 0;
374 }
375 if (PyErr_Occurred() != NULL) {
376 cpy_log_exception("value building for write callback");
377 Py_DECREF(list);
378 CPY_RETURN_FROM_THREADS 0;
379 }
380 }
381 dict = PyDict_New(); /* New reference. */
382 if (value_list->meta) {
383 int i, num;
384 char **table;
385 meta_data_t *meta = value_list->meta;
387 num = meta_data_toc(meta, &table);
388 for (i = 0; i < num; ++i) {
389 int type;
390 char *string;
391 int64_t si;
392 uint64_t ui;
393 double d;
394 _Bool b;
396 type = meta_data_type(meta, table[i]);
397 if (type == MD_TYPE_STRING) {
398 if (meta_data_get_string(meta, table[i], &string))
399 continue;
400 temp = cpy_string_to_unicode_or_bytes(string); /* New reference. */
401 free(string);
402 PyDict_SetItemString(dict, table[i], temp);
403 Py_XDECREF(temp);
404 } else if (type == MD_TYPE_SIGNED_INT) {
405 if (meta_data_get_signed_int(meta, table[i], &si))
406 continue;
407 temp = PyObject_CallFunctionObjArgs((void *) &SignedType, PyLong_FromLongLong(si), (void *) 0); /* New reference. */
408 PyDict_SetItemString(dict, table[i], temp);
409 Py_XDECREF(temp);
410 } else if (type == MD_TYPE_UNSIGNED_INT) {
411 if (meta_data_get_unsigned_int(meta, table[i], &ui))
412 continue;
413 temp = PyObject_CallFunctionObjArgs((void *) &UnsignedType, PyLong_FromUnsignedLongLong(ui), (void *) 0); /* New reference. */
414 PyDict_SetItemString(dict, table[i], temp);
415 Py_XDECREF(temp);
416 } else if (type == MD_TYPE_DOUBLE) {
417 if (meta_data_get_double(meta, table[i], &d))
418 continue;
419 temp = PyFloat_FromDouble(d); /* New reference. */
420 PyDict_SetItemString(dict, table[i], temp);
421 Py_XDECREF(temp);
422 } else if (type == MD_TYPE_BOOLEAN) {
423 if (meta_data_get_boolean(meta, table[i], &b))
424 continue;
425 if (b)
426 PyDict_SetItemString(dict, table[i], Py_True);
427 else
428 PyDict_SetItemString(dict, table[i], Py_False);
429 }
430 free(table[i]);
431 }
432 free(table);
433 }
434 v = (Values *) Values_New(); /* New reference. */
435 sstrncpy(v->data.host, value_list->host, sizeof(v->data.host));
436 sstrncpy(v->data.type, value_list->type, sizeof(v->data.type));
437 sstrncpy(v->data.type_instance, value_list->type_instance, sizeof(v->data.type_instance));
438 sstrncpy(v->data.plugin, value_list->plugin, sizeof(v->data.plugin));
439 sstrncpy(v->data.plugin_instance, value_list->plugin_instance, sizeof(v->data.plugin_instance));
440 v->data.time = CDTIME_T_TO_DOUBLE(value_list->time);
441 v->interval = CDTIME_T_TO_DOUBLE(value_list->interval);
442 Py_CLEAR(v->values);
443 v->values = list;
444 Py_CLEAR(v->meta);
445 v->meta = dict; /* Steals a reference. */
446 ret = PyObject_CallFunctionObjArgs(c->callback, v, c->data, (void *) 0); /* New reference. */
447 Py_XDECREF(v);
448 if (ret == NULL) {
449 cpy_log_exception("write callback");
450 } else {
451 Py_DECREF(ret);
452 }
453 CPY_RELEASE_THREADS
454 return 0;
455 }
457 static int cpy_notification_callback(const notification_t *notification, user_data_t *data) {
458 cpy_callback_t *c = data->data;
459 PyObject *ret, *notify;
460 Notification *n;
462 CPY_LOCK_THREADS
463 notify = Notification_New(); /* New reference. */
464 n = (Notification *) notify;
465 sstrncpy(n->data.host, notification->host, sizeof(n->data.host));
466 sstrncpy(n->data.type, notification->type, sizeof(n->data.type));
467 sstrncpy(n->data.type_instance, notification->type_instance, sizeof(n->data.type_instance));
468 sstrncpy(n->data.plugin, notification->plugin, sizeof(n->data.plugin));
469 sstrncpy(n->data.plugin_instance, notification->plugin_instance, sizeof(n->data.plugin_instance));
470 n->data.time = CDTIME_T_TO_DOUBLE(notification->time);
471 sstrncpy(n->message, notification->message, sizeof(n->message));
472 n->severity = notification->severity;
473 ret = PyObject_CallFunctionObjArgs(c->callback, n, c->data, (void *) 0); /* New reference. */
474 Py_XDECREF(notify);
475 if (ret == NULL) {
476 cpy_log_exception("notification callback");
477 } else {
478 Py_DECREF(ret);
479 }
480 CPY_RELEASE_THREADS
481 return 0;
482 }
484 static void cpy_log_callback(int severity, const char *message, user_data_t *data) {
485 cpy_callback_t * c = data->data;
486 PyObject *ret, *text;
488 CPY_LOCK_THREADS
489 text = cpy_string_to_unicode_or_bytes(message); /* New reference. */
490 if (c->data == NULL)
491 ret = PyObject_CallFunction(c->callback, "iN", severity, text); /* New reference. Steals a reference from "text". */
492 else
493 ret = PyObject_CallFunction(c->callback, "iNO", severity, text, c->data); /* New reference. Steals a reference from "text". */
495 if (ret == NULL) {
496 /* FIXME */
497 /* Do we really want to trigger a log callback because a log callback failed?
498 * Probably not. */
499 PyErr_Print();
500 /* In case someone wanted to be clever, replaced stderr and failed at that. */
501 PyErr_Clear();
502 } else {
503 Py_DECREF(ret);
504 }
505 CPY_RELEASE_THREADS
506 }
508 static void cpy_flush_callback(int timeout, const char *id, user_data_t *data) {
509 cpy_callback_t * c = data->data;
510 PyObject *ret, *text;
512 CPY_LOCK_THREADS
513 text = cpy_string_to_unicode_or_bytes(id);
514 if (c->data == NULL)
515 ret = PyObject_CallFunction(c->callback, "iN", timeout, text); /* New reference. */
516 else
517 ret = PyObject_CallFunction(c->callback, "iNO", timeout, text, c->data); /* New reference. */
519 if (ret == NULL) {
520 cpy_log_exception("flush callback");
521 } else {
522 Py_DECREF(ret);
523 }
524 CPY_RELEASE_THREADS
525 }
527 static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args, PyObject *kwds) {
528 char buf[512];
529 cpy_callback_t *c;
530 char *name = NULL;
531 PyObject *callback = NULL, *data = NULL, *mod = NULL;
532 static char *kwlist[] = {"callback", "data", "name", NULL};
534 if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oet", kwlist, &callback, &data, NULL, &name) == 0) return NULL;
535 if (PyCallable_Check(callback) == 0) {
536 PyMem_Free(name);
537 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
538 return NULL;
539 }
540 cpy_build_name(buf, sizeof(buf), callback, name);
542 Py_INCREF(callback);
543 Py_XINCREF(data);
544 c = malloc(sizeof(*c));
545 c->name = strdup(buf);
546 c->callback = callback;
547 c->data = data;
548 c->next = *list_head;
549 *list_head = c;
550 Py_XDECREF(mod);
551 PyMem_Free(name);
552 return cpy_string_to_unicode_or_bytes(buf);
553 }
555 static PyObject *float_or_none(float number) {
556 if (isnan(number)) {
557 Py_RETURN_NONE;
558 }
559 return PyFloat_FromDouble(number);
560 }
562 static PyObject *cpy_get_dataset(PyObject *self, PyObject *args) {
563 size_t i;
564 char *name;
565 const data_set_t *ds;
566 PyObject *list, *tuple;
568 if (PyArg_ParseTuple(args, "et", NULL, &name) == 0) return NULL;
569 ds = plugin_get_ds(name);
570 PyMem_Free(name);
571 if (ds == NULL) {
572 PyErr_Format(PyExc_TypeError, "Dataset %s not found", name);
573 return NULL;
574 }
575 list = PyList_New(ds->ds_num); /* New reference. */
576 for (i = 0; i < ds->ds_num; ++i) {
577 tuple = PyTuple_New(4);
578 PyTuple_SET_ITEM(tuple, 0, cpy_string_to_unicode_or_bytes(ds->ds[i].name));
579 PyTuple_SET_ITEM(tuple, 1, cpy_string_to_unicode_or_bytes(DS_TYPE_TO_STRING(ds->ds[i].type)));
580 PyTuple_SET_ITEM(tuple, 2, float_or_none(ds->ds[i].min));
581 PyTuple_SET_ITEM(tuple, 3, float_or_none(ds->ds[i].max));
582 PyList_SET_ITEM(list, i, tuple);
583 }
584 return list;
585 }
587 static PyObject *cpy_flush(PyObject *self, PyObject *args, PyObject *kwds) {
588 int timeout = -1;
589 char *plugin = NULL, *identifier = NULL;
590 static char *kwlist[] = {"plugin", "timeout", "identifier", NULL};
592 if (PyArg_ParseTupleAndKeywords(args, kwds, "|etiet", kwlist, NULL, &plugin, &timeout, NULL, &identifier) == 0) return NULL;
593 Py_BEGIN_ALLOW_THREADS
594 plugin_flush(plugin, timeout, identifier);
595 Py_END_ALLOW_THREADS
596 PyMem_Free(plugin);
597 PyMem_Free(identifier);
598 Py_RETURN_NONE;
599 }
601 static PyObject *cpy_register_config(PyObject *self, PyObject *args, PyObject *kwds) {
602 return cpy_register_generic(&cpy_config_callbacks, args, kwds);
603 }
605 static PyObject *cpy_register_init(PyObject *self, PyObject *args, PyObject *kwds) {
606 return cpy_register_generic(&cpy_init_callbacks, args, kwds);
607 }
609 typedef int reg_function_t(const char *name, void *callback, void *data);
611 static PyObject *cpy_register_generic_userdata(void *reg, void *handler, PyObject *args, PyObject *kwds) {
612 char buf[512];
613 reg_function_t *register_function = (reg_function_t *) reg;
614 cpy_callback_t *c = NULL;
615 user_data_t *user_data = NULL;
616 char *name = NULL;
617 PyObject *callback = NULL, *data = NULL;
618 static char *kwlist[] = {"callback", "data", "name", NULL};
620 if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oet", kwlist, &callback, &data, NULL, &name) == 0) return NULL;
621 if (PyCallable_Check(callback) == 0) {
622 PyMem_Free(name);
623 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
624 return NULL;
625 }
626 cpy_build_name(buf, sizeof(buf), callback, name);
627 PyMem_Free(name);
629 Py_INCREF(callback);
630 Py_XINCREF(data);
631 c = malloc(sizeof(*c));
632 c->name = strdup(buf);
633 c->callback = callback;
634 c->data = data;
635 c->next = NULL;
636 user_data = malloc(sizeof(*user_data));
637 user_data->free_func = cpy_destroy_user_data;
638 user_data->data = c;
639 register_function(buf, handler, user_data);
640 return cpy_string_to_unicode_or_bytes(buf);
641 }
643 static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwds) {
644 char buf[512];
645 cpy_callback_t *c = NULL;
646 user_data_t *user_data = NULL;
647 double interval = 0;
648 char *name = NULL;
649 PyObject *callback = NULL, *data = NULL;
650 static char *kwlist[] = {"callback", "interval", "data", "name", NULL};
652 if (PyArg_ParseTupleAndKeywords(args, kwds, "O|dOet", kwlist, &callback, &interval, &data, NULL, &name) == 0) return NULL;
653 if (PyCallable_Check(callback) == 0) {
654 PyMem_Free(name);
655 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
656 return NULL;
657 }
658 cpy_build_name(buf, sizeof(buf), callback, name);
659 PyMem_Free(name);
661 Py_INCREF(callback);
662 Py_XINCREF(data);
663 c = malloc(sizeof(*c));
664 c->name = strdup(buf);
665 c->callback = callback;
666 c->data = data;
667 c->next = NULL;
668 user_data = malloc(sizeof(*user_data));
669 user_data->free_func = cpy_destroy_user_data;
670 user_data->data = c;
671 plugin_register_complex_read(/* group = */ NULL, buf,
672 cpy_read_callback, DOUBLE_TO_CDTIME_T (interval), user_data);
673 return cpy_string_to_unicode_or_bytes(buf);
674 }
676 static PyObject *cpy_register_log(PyObject *self, PyObject *args, PyObject *kwds) {
677 return cpy_register_generic_userdata((void *) plugin_register_log,
678 (void *) cpy_log_callback, args, kwds);
679 }
681 static PyObject *cpy_register_write(PyObject *self, PyObject *args, PyObject *kwds) {
682 return cpy_register_generic_userdata((void *) plugin_register_write,
683 (void *) cpy_write_callback, args, kwds);
684 }
686 static PyObject *cpy_register_notification(PyObject *self, PyObject *args, PyObject *kwds) {
687 return cpy_register_generic_userdata((void *) plugin_register_notification,
688 (void *) cpy_notification_callback, args, kwds);
689 }
691 static PyObject *cpy_register_flush(PyObject *self, PyObject *args, PyObject *kwds) {
692 return cpy_register_generic_userdata((void *) plugin_register_flush,
693 (void *) cpy_flush_callback, args, kwds);
694 }
696 static PyObject *cpy_register_shutdown(PyObject *self, PyObject *args, PyObject *kwds) {
697 return cpy_register_generic(&cpy_shutdown_callbacks, args, kwds);
698 }
700 static PyObject *cpy_error(PyObject *self, PyObject *args) {
701 char *text;
702 if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL;
703 Py_BEGIN_ALLOW_THREADS
704 plugin_log(LOG_ERR, "%s", text);
705 Py_END_ALLOW_THREADS
706 PyMem_Free(text);
707 Py_RETURN_NONE;
708 }
710 static PyObject *cpy_warning(PyObject *self, PyObject *args) {
711 char *text;
712 if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL;
713 Py_BEGIN_ALLOW_THREADS
714 plugin_log(LOG_WARNING, "%s", text);
715 Py_END_ALLOW_THREADS
716 PyMem_Free(text);
717 Py_RETURN_NONE;
718 }
720 static PyObject *cpy_notice(PyObject *self, PyObject *args) {
721 char *text;
722 if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL;
723 Py_BEGIN_ALLOW_THREADS
724 plugin_log(LOG_NOTICE, "%s", text);
725 Py_END_ALLOW_THREADS
726 PyMem_Free(text);
727 Py_RETURN_NONE;
728 }
730 static PyObject *cpy_info(PyObject *self, PyObject *args) {
731 char *text;
732 if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL;
733 Py_BEGIN_ALLOW_THREADS
734 plugin_log(LOG_INFO, "%s", text);
735 Py_END_ALLOW_THREADS
736 PyMem_Free(text);
737 Py_RETURN_NONE;
738 }
740 static PyObject *cpy_debug(PyObject *self, PyObject *args) {
741 #ifdef COLLECT_DEBUG
742 char *text;
743 if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL;
744 Py_BEGIN_ALLOW_THREADS
745 plugin_log(LOG_DEBUG, "%s", text);
746 Py_END_ALLOW_THREADS
747 PyMem_Free(text);
748 #endif
749 Py_RETURN_NONE;
750 }
752 static PyObject *cpy_unregister_generic(cpy_callback_t **list_head, PyObject *arg, const char *desc) {
753 char buf[512];
754 const char *name;
755 cpy_callback_t *prev = NULL, *tmp;
757 Py_INCREF(arg);
758 name = cpy_unicode_or_bytes_to_string(&arg);
759 if (name == NULL) {
760 PyErr_Clear();
761 if (!PyCallable_Check(arg)) {
762 PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
763 Py_DECREF(arg);
764 return NULL;
765 }
766 cpy_build_name(buf, sizeof(buf), arg, NULL);
767 name = buf;
768 }
769 for (tmp = *list_head; tmp; prev = tmp, tmp = tmp->next)
770 if (strcmp(name, tmp->name) == 0)
771 break;
773 Py_DECREF(arg);
774 if (tmp == NULL) {
775 PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
776 return NULL;
777 }
778 /* Yes, this is actually save. To call this function the caller has to
779 * hold the GIL. Well, save as long as there is only one GIL anyway ... */
780 if (prev == NULL)
781 *list_head = tmp->next;
782 else
783 prev->next = tmp->next;
784 cpy_destroy_user_data(tmp);
785 Py_RETURN_NONE;
786 }
788 typedef int cpy_unregister_function_t(const char *name);
790 static PyObject *cpy_unregister_generic_userdata(cpy_unregister_function_t *unreg, PyObject *arg, const char *desc) {
791 char buf[512];
792 const char *name;
794 Py_INCREF(arg);
795 name = cpy_unicode_or_bytes_to_string(&arg);
796 if (name == NULL) {
797 PyErr_Clear();
798 if (!PyCallable_Check(arg)) {
799 PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
800 Py_DECREF(arg);
801 return NULL;
802 }
803 cpy_build_name(buf, sizeof(buf), arg, NULL);
804 name = buf;
805 }
806 if (unreg(name) == 0) {
807 Py_DECREF(arg);
808 Py_RETURN_NONE;
809 }
810 PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
811 Py_DECREF(arg);
812 return NULL;
813 }
815 static PyObject *cpy_unregister_log(PyObject *self, PyObject *arg) {
816 return cpy_unregister_generic_userdata(plugin_unregister_log, arg, "log");
817 }
819 static PyObject *cpy_unregister_init(PyObject *self, PyObject *arg) {
820 return cpy_unregister_generic(&cpy_init_callbacks, arg, "init");
821 }
823 static PyObject *cpy_unregister_config(PyObject *self, PyObject *arg) {
824 return cpy_unregister_generic(&cpy_config_callbacks, arg, "config");
825 }
827 static PyObject *cpy_unregister_read(PyObject *self, PyObject *arg) {
828 return cpy_unregister_generic_userdata(plugin_unregister_read, arg, "read");
829 }
831 static PyObject *cpy_unregister_write(PyObject *self, PyObject *arg) {
832 return cpy_unregister_generic_userdata(plugin_unregister_write, arg, "write");
833 }
835 static PyObject *cpy_unregister_notification(PyObject *self, PyObject *arg) {
836 return cpy_unregister_generic_userdata(plugin_unregister_notification, arg, "notification");
837 }
839 static PyObject *cpy_unregister_flush(PyObject *self, PyObject *arg) {
840 return cpy_unregister_generic_userdata(plugin_unregister_flush, arg, "flush");
841 }
843 static PyObject *cpy_unregister_shutdown(PyObject *self, PyObject *arg) {
844 return cpy_unregister_generic(&cpy_shutdown_callbacks, arg, "shutdown");
845 }
847 static PyMethodDef cpy_methods[] = {
848 {"debug", cpy_debug, METH_VARARGS, log_doc},
849 {"info", cpy_info, METH_VARARGS, log_doc},
850 {"notice", cpy_notice, METH_VARARGS, log_doc},
851 {"warning", cpy_warning, METH_VARARGS, log_doc},
852 {"error", cpy_error, METH_VARARGS, log_doc},
853 {"get_dataset", (PyCFunction) cpy_get_dataset, METH_VARARGS, get_ds_doc},
854 {"flush", (PyCFunction) cpy_flush, METH_VARARGS | METH_KEYWORDS, flush_doc},
855 {"register_log", (PyCFunction) cpy_register_log, METH_VARARGS | METH_KEYWORDS, reg_log_doc},
856 {"register_init", (PyCFunction) cpy_register_init, METH_VARARGS | METH_KEYWORDS, reg_init_doc},
857 {"register_config", (PyCFunction) cpy_register_config, METH_VARARGS | METH_KEYWORDS, reg_config_doc},
858 {"register_read", (PyCFunction) cpy_register_read, METH_VARARGS | METH_KEYWORDS, reg_read_doc},
859 {"register_write", (PyCFunction) cpy_register_write, METH_VARARGS | METH_KEYWORDS, reg_write_doc},
860 {"register_notification", (PyCFunction) cpy_register_notification, METH_VARARGS | METH_KEYWORDS, reg_notification_doc},
861 {"register_flush", (PyCFunction) cpy_register_flush, METH_VARARGS | METH_KEYWORDS, reg_flush_doc},
862 {"register_shutdown", (PyCFunction) cpy_register_shutdown, METH_VARARGS | METH_KEYWORDS, reg_shutdown_doc},
863 {"unregister_log", cpy_unregister_log, METH_O, unregister_doc},
864 {"unregister_init", cpy_unregister_init, METH_O, unregister_doc},
865 {"unregister_config", cpy_unregister_config, METH_O, unregister_doc},
866 {"unregister_read", cpy_unregister_read, METH_O, unregister_doc},
867 {"unregister_write", cpy_unregister_write, METH_O, unregister_doc},
868 {"unregister_notification", cpy_unregister_notification, METH_O, unregister_doc},
869 {"unregister_flush", cpy_unregister_flush, METH_O, unregister_doc},
870 {"unregister_shutdown", cpy_unregister_shutdown, METH_O, unregister_doc},
871 {0, 0, 0, 0}
872 };
874 static int cpy_shutdown(void) {
875 cpy_callback_t *c;
876 PyObject *ret;
878 /* This can happen if the module was loaded but not configured. */
879 if (state != NULL)
880 PyEval_RestoreThread(state);
882 for (c = cpy_shutdown_callbacks; c; c = c->next) {
883 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
884 if (ret == NULL)
885 cpy_log_exception("shutdown callback");
886 else
887 Py_DECREF(ret);
888 }
889 PyErr_Print();
890 Py_Finalize();
891 return 0;
892 }
894 static void cpy_int_handler(int sig) {
895 return;
896 }
898 static void *cpy_interactive(void *data) {
899 sigset_t sigset;
900 struct sigaction sig_int_action, old;
902 /* Signal handler in a plugin? Bad stuff, but the best way to
903 * handle it I guess. In an interactive session people will
904 * press Ctrl+C at some time, which will generate a SIGINT.
905 * This will cause collectd to shutdown, thus killing the
906 * interactive interpreter, and leaving the terminal in a
907 * mess. Chances are, this isn't what the user wanted to do.
908 *
909 * So this is the plan:
910 * 1. Block SIGINT in the main thread.
911 * 2. Install our own signal handler that does nothing.
912 * 3. Unblock SIGINT in the interactive thread.
913 *
914 * This will make sure that SIGINT won't kill collectd but
915 * still interrupt syscalls like sleep and pause.
916 * It does not raise a KeyboardInterrupt exception because so
917 * far nobody managed to figure out how to do that. */
918 memset (&sig_int_action, '\0', sizeof (sig_int_action));
919 sig_int_action.sa_handler = cpy_int_handler;
920 sigaction (SIGINT, &sig_int_action, &old);
922 sigemptyset(&sigset);
923 sigaddset(&sigset, SIGINT);
924 pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
925 PyEval_AcquireThread(state);
926 if (PyImport_ImportModule("readline") == NULL) {
927 /* This interactive session will suck. */
928 cpy_log_exception("interactive session init");
929 }
930 PyRun_InteractiveLoop(stdin, "<stdin>");
931 PyErr_Print();
932 PyEval_ReleaseThread(state);
933 NOTICE("python: Interactive interpreter exited, stopping collectd ...");
934 /* Restore the original collectd SIGINT handler and raise SIGINT.
935 * The main thread still has SIGINT blocked and there's nothing we
936 * can do about that so this thread will handle it. But that's not
937 * important, except that it won't interrupt the main loop and so
938 * it might take a few seconds before collectd really shuts down. */
939 sigaction (SIGINT, &old, NULL);
940 raise(SIGINT);
941 pause();
942 return NULL;
943 }
945 static int cpy_init(void) {
946 cpy_callback_t *c;
947 PyObject *ret;
948 static pthread_t thread;
949 sigset_t sigset;
951 if (!Py_IsInitialized()) {
952 WARNING("python: Plugin loaded but not configured.");
953 plugin_unregister_shutdown("python");
954 return 0;
955 }
956 PyEval_InitThreads();
957 /* Now it's finally OK to use python threads. */
958 for (c = cpy_init_callbacks; c; c = c->next) {
959 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
960 if (ret == NULL)
961 cpy_log_exception("init callback");
962 else
963 Py_DECREF(ret);
964 }
965 sigemptyset(&sigset);
966 sigaddset(&sigset, SIGINT);
967 pthread_sigmask(SIG_BLOCK, &sigset, NULL);
968 state = PyEval_SaveThread();
969 if (do_interactive) {
970 if (plugin_thread_create(&thread, NULL, cpy_interactive, NULL)) {
971 ERROR("python: Error creating thread for interactive interpreter.");
972 }
973 }
975 return 0;
976 }
978 static PyObject *cpy_oconfig_to_pyconfig(oconfig_item_t *ci, PyObject *parent) {
979 int i;
980 PyObject *item, *values, *children, *tmp;
982 if (parent == NULL)
983 parent = Py_None;
985 values = PyTuple_New(ci->values_num); /* New reference. */
986 for (i = 0; i < ci->values_num; ++i) {
987 if (ci->values[i].type == OCONFIG_TYPE_STRING) {
988 PyTuple_SET_ITEM(values, i, cpy_string_to_unicode_or_bytes(ci->values[i].value.string));
989 } else if (ci->values[i].type == OCONFIG_TYPE_NUMBER) {
990 PyTuple_SET_ITEM(values, i, PyFloat_FromDouble(ci->values[i].value.number));
991 } else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN) {
992 PyTuple_SET_ITEM(values, i, PyBool_FromLong(ci->values[i].value.boolean));
993 }
994 }
996 tmp = cpy_string_to_unicode_or_bytes(ci->key);
997 item = PyObject_CallFunction((void *) &ConfigType, "NONO", tmp, parent, values, Py_None);
998 if (item == NULL)
999 return NULL;
1000 children = PyTuple_New(ci->children_num); /* New reference. */
1001 for (i = 0; i < ci->children_num; ++i) {
1002 PyTuple_SET_ITEM(children, i, cpy_oconfig_to_pyconfig(ci->children + i, item));
1003 }
1004 tmp = ((Config *) item)->children;
1005 ((Config *) item)->children = children;
1006 Py_XDECREF(tmp);
1007 return item;
1008 }
1010 #ifdef IS_PY3K
1011 static struct PyModuleDef collectdmodule = {
1012 PyModuleDef_HEAD_INIT,
1013 "collectd", /* name of module */
1014 "The python interface to collectd", /* module documentation, may be NULL */
1015 -1,
1016 cpy_methods
1017 };
1019 PyMODINIT_FUNC PyInit_collectd(void) {
1020 return PyModule_Create(&collectdmodule);
1021 }
1022 #endif
1024 static int cpy_init_python() {
1025 PyObject *sys;
1026 PyObject *module;
1028 #ifdef IS_PY3K
1029 wchar_t *argv = L"";
1030 /* Add a builtin module, before Py_Initialize */
1031 PyImport_AppendInittab("collectd", PyInit_collectd);
1032 #else
1033 char *argv = "";
1034 #endif
1036 Py_Initialize();
1038 PyType_Ready(&ConfigType);
1039 PyType_Ready(&PluginDataType);
1040 ValuesType.tp_base = &PluginDataType;
1041 PyType_Ready(&ValuesType);
1042 NotificationType.tp_base = &PluginDataType;
1043 PyType_Ready(&NotificationType);
1044 SignedType.tp_base = &PyLong_Type;
1045 PyType_Ready(&SignedType);
1046 UnsignedType.tp_base = &PyLong_Type;
1047 PyType_Ready(&UnsignedType);
1048 sys = PyImport_ImportModule("sys"); /* New reference. */
1049 if (sys == NULL) {
1050 cpy_log_exception("python initialization");
1051 return 1;
1052 }
1053 sys_path = PyObject_GetAttrString(sys, "path"); /* New reference. */
1054 Py_DECREF(sys);
1055 if (sys_path == NULL) {
1056 cpy_log_exception("python initialization");
1057 return 1;
1058 }
1059 PySys_SetArgv(1, &argv);
1060 PyList_SetSlice(sys_path, 0, 1, NULL);
1062 #ifdef IS_PY3K
1063 module = PyImport_ImportModule("collectd");
1064 #else
1065 module = Py_InitModule("collectd", cpy_methods); /* Borrowed reference. */
1066 #endif
1067 PyModule_AddObject(module, "Config", (void *) &ConfigType); /* Steals a reference. */
1068 PyModule_AddObject(module, "Values", (void *) &ValuesType); /* Steals a reference. */
1069 PyModule_AddObject(module, "Notification", (void *) &NotificationType); /* Steals a reference. */
1070 PyModule_AddObject(module, "Signed", (void *) &SignedType); /* Steals a reference. */
1071 PyModule_AddObject(module, "Unsigned", (void *) &UnsignedType); /* Steals a reference. */
1072 PyModule_AddIntConstant(module, "LOG_DEBUG", LOG_DEBUG);
1073 PyModule_AddIntConstant(module, "LOG_INFO", LOG_INFO);
1074 PyModule_AddIntConstant(module, "LOG_NOTICE", LOG_NOTICE);
1075 PyModule_AddIntConstant(module, "LOG_WARNING", LOG_WARNING);
1076 PyModule_AddIntConstant(module, "LOG_ERROR", LOG_ERR);
1077 PyModule_AddIntConstant(module, "NOTIF_FAILURE", NOTIF_FAILURE);
1078 PyModule_AddIntConstant(module, "NOTIF_WARNING", NOTIF_WARNING);
1079 PyModule_AddIntConstant(module, "NOTIF_OKAY", NOTIF_OKAY);
1080 PyModule_AddStringConstant(module, "DS_TYPE_COUNTER", DS_TYPE_TO_STRING(DS_TYPE_COUNTER));
1081 PyModule_AddStringConstant(module, "DS_TYPE_GAUGE", DS_TYPE_TO_STRING(DS_TYPE_GAUGE));
1082 PyModule_AddStringConstant(module, "DS_TYPE_DERIVE", DS_TYPE_TO_STRING(DS_TYPE_DERIVE));
1083 PyModule_AddStringConstant(module, "DS_TYPE_ABSOLUTE", DS_TYPE_TO_STRING(DS_TYPE_ABSOLUTE));
1084 return 0;
1085 }
1087 static int cpy_config(oconfig_item_t *ci) {
1088 int i;
1089 PyObject *tb;
1091 /* Ok in theory we shouldn't do initialization at this point
1092 * but we have to. In order to give python scripts a chance
1093 * to register a config callback we need to be able to execute
1094 * python code during the config callback so we have to start
1095 * the interpreter here. */
1096 /* Do *not* use the python "thread" module at this point! */
1098 if (!Py_IsInitialized() && cpy_init_python()) return 1;
1100 for (i = 0; i < ci->children_num; ++i) {
1101 oconfig_item_t *item = ci->children + i;
1103 if (strcasecmp(item->key, "Interactive") == 0) {
1104 if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
1105 continue;
1106 do_interactive = item->values[0].value.boolean;
1107 } else if (strcasecmp(item->key, "Encoding") == 0) {
1108 if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_STRING)
1109 continue;
1110 #ifdef IS_PY3K
1111 NOTICE("python: \"Encoding\" was used in the config file but Python3 was used, which does not support changing encodings. Ignoring this.");
1112 #else
1113 /* Why is this even necessary? And undocumented? */
1114 if (PyUnicode_SetDefaultEncoding(item->values[0].value.string))
1115 cpy_log_exception("setting default encoding");
1116 #endif
1117 } else if (strcasecmp(item->key, "LogTraces") == 0) {
1118 if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
1119 continue;
1120 if (!item->values[0].value.boolean) {
1121 Py_XDECREF(cpy_format_exception);
1122 cpy_format_exception = NULL;
1123 continue;
1124 }
1125 if (cpy_format_exception)
1126 continue;
1127 tb = PyImport_ImportModule("traceback"); /* New reference. */
1128 if (tb == NULL) {
1129 cpy_log_exception("python initialization");
1130 continue;
1131 }
1132 cpy_format_exception = PyObject_GetAttrString(tb, "format_exception"); /* New reference. */
1133 Py_DECREF(tb);
1134 if (cpy_format_exception == NULL)
1135 cpy_log_exception("python initialization");
1136 } else if (strcasecmp(item->key, "ModulePath") == 0) {
1137 char *dir = NULL;
1138 PyObject *dir_object;
1140 if (cf_util_get_string(item, &dir) != 0)
1141 continue;
1142 dir_object = cpy_string_to_unicode_or_bytes(dir); /* New reference. */
1143 if (dir_object == NULL) {
1144 ERROR("python plugin: Unable to convert \"%s\" to "
1145 "a python object.", dir);
1146 free(dir);
1147 cpy_log_exception("python initialization");
1148 continue;
1149 }
1150 if (PyList_Insert(sys_path, 0, dir_object) != 0) {
1151 ERROR("python plugin: Unable to prepend \"%s\" to "
1152 "python module path.", dir);
1153 cpy_log_exception("python initialization");
1154 }
1155 Py_DECREF(dir_object);
1156 free(dir);
1157 } else if (strcasecmp(item->key, "Import") == 0) {
1158 char *module_name = NULL;
1159 PyObject *module;
1161 if (cf_util_get_string(item, &module_name) != 0)
1162 continue;
1163 module = PyImport_ImportModule(module_name); /* New reference. */
1164 if (module == NULL) {
1165 ERROR("python plugin: Error importing module \"%s\".", module_name);
1166 cpy_log_exception("importing module");
1167 }
1168 free(module_name);
1169 Py_XDECREF(module);
1170 } else if (strcasecmp(item->key, "Module") == 0) {
1171 char *name = NULL;
1172 cpy_callback_t *c;
1173 PyObject *ret;
1175 if (cf_util_get_string(item, &name) != 0)
1176 continue;
1177 for (c = cpy_config_callbacks; c; c = c->next) {
1178 if (strcasecmp(c->name + 7, name) == 0)
1179 break;
1180 }
1181 if (c == NULL) {
1182 WARNING("python plugin: Found a configuration for the \"%s\" plugin, "
1183 "but the plugin isn't loaded or didn't register "
1184 "a configuration callback.", name);
1185 free(name);
1186 continue;
1187 }
1188 free(name);
1189 if (c->data == NULL)
1190 ret = PyObject_CallFunction(c->callback, "N",
1191 cpy_oconfig_to_pyconfig(item, NULL)); /* New reference. */
1192 else
1193 ret = PyObject_CallFunction(c->callback, "NO",
1194 cpy_oconfig_to_pyconfig(item, NULL), c->data); /* New reference. */
1195 if (ret == NULL)
1196 cpy_log_exception("loading module");
1197 else
1198 Py_DECREF(ret);
1199 } else {
1200 WARNING("python plugin: Ignoring unknown config key \"%s\".", item->key);
1201 }
1202 }
1203 return 0;
1204 }
1206 void module_register(void) {
1207 plugin_register_complex_config("python", cpy_config);
1208 plugin_register_init("python", cpy_init);
1209 plugin_register_shutdown("python", cpy_shutdown);
1210 }