ae853c38e8be412d05092fdf49914d397765b66f
1 #include <Python.h>
2 #include <structmember.h>
4 #include <signal.h>
5 #if HAVE_PTHREAD_H
6 # include <pthread.h>
7 #endif
9 #include "collectd.h"
10 #include "common.h"
12 #include "cpython.h"
14 typedef struct cpy_callback_s {
15 char *name;
16 PyObject *callback;
17 PyObject *data;
18 struct cpy_callback_s *next;
19 } cpy_callback_t;
21 static char log_doc[] = "This function sends a string to all logging plugins.";
23 static char flush_doc[] = "flush([plugin][, timeout][, identifier]) -> None\n"
24 "\n"
25 "Flushes the cache of another plugin.";
27 static char unregister_doc[] = "Unregisters a callback. This function needs exactly one parameter either\n"
28 "the function to unregister or the callback identifier to unregister.";
30 static char reg_log_doc[] = "register_log(callback[, data][, name]) -> identifier\n"
31 "\n"
32 "Register a callback function for log messages.\n"
33 "\n"
34 "'callback' is a callable object that will be called every time something\n"
35 " is logged.\n"
36 "'data' is an optional object that will be passed back to the callback\n"
37 " function every time it is called.\n"
38 "'name' is an optional identifier for this callback. The default name\n"
39 " is 'python.<module>'.\n"
40 " Every callback needs a unique identifier, so if you want to\n"
41 " register this callback multiple time from the same module you need\n"
42 " to specify a name here.\n"
43 "'identifier' is the full identifier assigned to this callback.\n"
44 "\n"
45 "The callback function will be called with two or three parameters:\n"
46 "severity: An integer that should be compared to the LOG_ constants.\n"
47 "message: The text to be logged.\n"
48 "data: The optional data parameter passed to the register function.\n"
49 " If the parameter was omitted it will be omitted here, too.";
51 static char reg_init_doc[] = "register_init(callback[, data][, name]) -> identifier\n"
52 "\n"
53 "Register a callback function that will be executed once after the config.\n"
54 "file has been read, all plugins heve been loaded and the collectd has\n"
55 "forked into the background.\n"
56 "\n"
57 "'callback' is a callable object that will be executed.\n"
58 "'data' is an optional object that will be passed back to the callback\n"
59 " function when it is called.\n"
60 "'name' is an optional identifier for this callback. The default name\n"
61 " is 'python.<module>'.\n"
62 " Every callback needs a unique identifier, so if you want to\n"
63 " register this callback multiple time from the same module you need\n"
64 " to specify a name here.\n"
65 "'identifier' is the full identifier assigned to this callback.\n"
66 "\n"
67 "The callback function will be called without parameters, except for\n"
68 "data if it was supplied.";
70 static char reg_config_doc[] = "register_config(callback[, data][, name]) -> identifier\n"
71 "\n"
72 "Register a callback function for config file entries.\n"
73 "'callback' is a callable object that will be called for every config block.\n"
74 "'data' is an optional object that will be passed back to the callback\n"
75 " function every time it is called.\n"
76 "'name' is an optional identifier for this callback. The default name\n"
77 " is 'python.<module>'.\n"
78 " Every callback needs a unique identifier, so if you want to\n"
79 " register this callback multiple time from the same module you need\n"
80 " to specify a name here.\n"
81 "'identifier' is the full identifier assigned to this callback.\n"
82 "\n"
83 "The callback function will be called with one or two parameters:\n"
84 "config: A Config object.\n"
85 "data: The optional data parameter passed to the register function.\n"
86 " If the parameter was omitted it will be omitted here, too.";
88 static char reg_read_doc[] = "register_read(callback[, interval][, data][, name]) -> identifier\n"
89 "\n"
90 "Register a callback function for reading data. It will just be called\n"
91 "in a fixed interval to signal that it's time to dispatch new values.\n"
92 "'callback' is a callable object that will be called every time something\n"
93 " is logged.\n"
94 "'interval' is the number of seconds between between calls to the callback\n"
95 " function. Full float precision is supported here.\n"
96 "'data' is an optional object that will be passed back to the callback\n"
97 " function every time it is called.\n"
98 "'name' is an optional identifier for this callback. The default name\n"
99 " is 'python.<module>'.\n"
100 " Every callback needs a unique identifier, so if you want to\n"
101 " register this callback multiple time from the same module you need\n"
102 " to specify a name here.\n"
103 "'identifier' is the full identifier assigned to this callback.\n"
104 "\n"
105 "The callback function will be called without parameters, except for\n"
106 "data if it was supplied.";
108 static char reg_write_doc[] = "register_write(callback[, data][, name]) -> identifier\n"
109 "\n"
110 "Register a callback function to receive values dispatched by other plugins.\n"
111 "'callback' is a callable object that will be called every time a value\n"
112 " is dispatched.\n"
113 "'data' is an optional object that will be passed back to the callback\n"
114 " function every time it is called.\n"
115 "'name' is an optional identifier for this callback. The default name\n"
116 " is 'python.<module>'.\n"
117 " Every callback needs a unique identifier, so if you want to\n"
118 " register this callback multiple time from the same module you need\n"
119 " to specify a name here.\n"
120 "'identifier' is the full identifier assigned to this callback.\n"
121 "\n"
122 "The callback function will be called with one or two parameters:\n"
123 "values: A Values object which is a copy of the dispatched values.\n"
124 "data: The optional data parameter passed to the register function.\n"
125 " If the parameter was omitted it will be omitted here, too.";
127 static char reg_notification_doc[] = "register_notification(callback[, data][, name]) -> identifier\n"
128 "\n"
129 "Register a callback function for notifications.\n"
130 "'callback' is a callable object that will be called every time a notification\n"
131 " is dispatched.\n"
132 "'data' is an optional object that will be passed back to the callback\n"
133 " function every time it is called.\n"
134 "'name' is an optional identifier for this callback. The default name\n"
135 " is 'python.<module>'.\n"
136 " Every callback needs a unique identifier, so if you want to\n"
137 " register this callback multiple time from the same module you need\n"
138 " to specify a name here.\n"
139 "'identifier' is the full identifier assigned to this callback.\n"
140 "\n"
141 "The callback function will be called with one or two parameters:\n"
142 "notification: A copy of the notification that was dispatched.\n"
143 "data: The optional data parameter passed to the register function.\n"
144 " If the parameter was omitted it will be omitted here, too.";
146 static char reg_flush_doc[] = "register_flush(callback[, data][, name]) -> identifier\n"
147 "\n"
148 "Register a callback function for flush messages.\n"
149 "'callback' is a callable object that will be called every time a plugin\n"
150 " requests a flush for either this or all plugins.\n"
151 "'data' is an optional object that will be passed back to the callback\n"
152 " function every time it is called.\n"
153 "'name' is an optional identifier for this callback. The default name\n"
154 " is 'python.<module>'.\n"
155 " Every callback needs a unique identifier, so if you want to\n"
156 " register this callback multiple time from the same module you need\n"
157 " to specify a name here.\n"
158 "'identifier' is the full identifier assigned to this callback.\n"
159 "\n"
160 "The callback function will be called with two or three parameters:\n"
161 "timeout: Indicates that only data older than 'timeout' seconds is to\n"
162 " be flushed.\n"
163 "id: Specifies which values are to be flushed.\n"
164 "data: The optional data parameter passed to the register function.\n"
165 " If the parameter was omitted it will be omitted here, too.";
167 static char reg_shutdown_doc[] = "register_shutdown(callback[, data][, name]) -> identifier\n"
168 "\n"
169 "Register a callback function for collectd shutdown.\n"
170 "'callback' is a callable object that will be called once collectd is\n"
171 " shutting down.\n"
172 "'data' is an optional object that will be passed back to the callback\n"
173 " function if it is called.\n"
174 "'name' is an optional identifier for this callback. The default name\n"
175 " is 'python.<module>'.\n"
176 " Every callback needs a unique identifier, so if you want to\n"
177 " register this callback multiple time from the same module you need\n"
178 " to specify a name here.\n"
179 "'identifier' is the full identifier assigned to this callback.\n"
180 "\n"
181 "The callback function will be called with no parameters except for\n"
182 " data if it was supplied.";
185 static int do_interactive = 0;
187 /* This is our global thread state. Python saves some stuff in thread-local
188 * storage. So if we allow the interpreter to run in the background
189 * (the scriptwriters might have created some threads from python), we have
190 * to save the state so we can resume it later after shutdown. */
192 static PyThreadState *state;
194 static PyObject *cpy_format_exception;
196 static cpy_callback_t *cpy_config_callbacks;
197 static cpy_callback_t *cpy_init_callbacks;
198 static cpy_callback_t *cpy_shutdown_callbacks;
200 static void cpy_destroy_user_data(void *data) {
201 cpy_callback_t *c = data;
202 free(c->name);
203 Py_DECREF(c->callback);
204 Py_XDECREF(c->data);
205 free(c);
206 }
208 /* You must hold the GIL to call this function!
209 * But if you managed to extract the callback parameter then you probably already do. */
211 static void cpy_build_name(char *buf, size_t size, PyObject *callback, const char *name) {
212 const char *module = NULL;
213 PyObject *mod = NULL;
215 if (name != NULL) {
216 snprintf(buf, size, "python.%s", name);
217 return;
218 }
220 mod = PyObject_GetAttrString(callback, "__module__"); /* New reference. */
221 if (mod != NULL)
222 module = PyString_AsString(mod);
224 if (module != NULL) {
225 snprintf(buf, size, "python.%s", module);
226 Py_XDECREF(mod);
227 PyErr_Clear();
228 return;
229 }
230 Py_XDECREF(mod);
232 snprintf(buf, size, "python.%p", callback);
233 PyErr_Clear();
234 }
236 static void cpy_log_exception(const char *context) {
237 int l = 0, i;
238 const char *typename = NULL, *message = NULL;
239 PyObject *type, *value, *traceback, *tn, *m, *list;
241 PyErr_Fetch(&type, &value, &traceback);
242 PyErr_NormalizeException(&type, &value, &traceback);
243 if (type == NULL) return;
244 tn = PyObject_GetAttrString(type, "__name__"); /* New reference. */
245 m = PyObject_GetAttrString(value, "message"); /* New reference. */
246 if (tn != NULL)
247 typename = PyString_AsString(tn);
248 if (m != NULL)
249 message = PyString_AsString(m);
250 if (typename == NULL)
251 typename = "NamelessException";
252 if (message == NULL)
253 message = "N/A";
254 Py_BEGIN_ALLOW_THREADS
255 ERROR("Unhandled python exception in %s: %s: %s", context, typename, message);
256 Py_END_ALLOW_THREADS
257 Py_XDECREF(tn);
258 Py_XDECREF(m);
259 if (!cpy_format_exception) {
260 PyErr_Clear();
261 Py_XDECREF(type);
262 Py_XDECREF(value);
263 Py_XDECREF(traceback);
264 return;
265 }
266 if (!traceback) {
267 PyErr_Clear();
268 return;
269 }
270 list = PyObject_CallFunction(cpy_format_exception, "NNN", type, value, traceback); /* New reference. */
271 if (list)
272 l = PyObject_Length(list);
273 for (i = 0; i < l; ++i) {
274 char *s;
275 PyObject *line;
277 line = PyList_GET_ITEM(list, i); /* Borrowed reference. */
278 s = strdup(PyString_AsString(line));
279 Py_DECREF(line);
280 if (s[strlen(s) - 1] == '\n')
281 s[strlen(s) - 1] = 0;
282 Py_BEGIN_ALLOW_THREADS
283 ERROR("%s", s);
284 Py_END_ALLOW_THREADS
285 free(s);
286 }
287 Py_XDECREF(list);
288 PyErr_Clear();
289 }
291 static int cpy_read_callback(user_data_t *data) {
292 cpy_callback_t *c = data->data;
293 PyObject *ret;
295 CPY_LOCK_THREADS
296 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
297 if (ret == NULL) {
298 cpy_log_exception("read callback");
299 } else {
300 Py_DECREF(ret);
301 }
302 CPY_RELEASE_THREADS
303 if (ret == NULL)
304 return 1;
305 return 0;
306 }
308 static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_list, user_data_t *data) {
309 int i;
310 cpy_callback_t *c = data->data;
311 PyObject *ret, *v, *list;
313 CPY_LOCK_THREADS
314 list = PyList_New(value_list->values_len); /* New reference. */
315 if (list == NULL) {
316 cpy_log_exception("write callback");
317 CPY_RETURN_FROM_THREADS 0;
318 }
319 for (i = 0; i < value_list->values_len; ++i) {
320 if (ds->ds->type == DS_TYPE_COUNTER) {
321 if ((long) value_list->values[i].counter == value_list->values[i].counter)
322 PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].counter));
323 else
324 PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].counter));
325 } else if (ds->ds->type == DS_TYPE_GAUGE) {
326 PyList_SetItem(list, i, PyFloat_FromDouble(value_list->values[i].gauge));
327 } else if (ds->ds->type == DS_TYPE_DERIVE) {
328 if ((long) value_list->values[i].derive == value_list->values[i].derive)
329 PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].derive));
330 else
331 PyList_SetItem(list, i, PyLong_FromLongLong(value_list->values[i].derive));
332 } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
333 if ((long) value_list->values[i].absolute == value_list->values[i].absolute)
334 PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].absolute));
335 else
336 PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].absolute));
337 } else {
338 Py_BEGIN_ALLOW_THREADS
339 ERROR("cpy_write_callback: Unknown value type %d.", ds->ds->type);
340 Py_END_ALLOW_THREADS
341 Py_DECREF(list);
342 CPY_RETURN_FROM_THREADS 0;
343 }
344 if (PyErr_Occurred() != NULL) {
345 cpy_log_exception("value building for write callback");
346 CPY_RETURN_FROM_THREADS 0;
347 }
348 }
349 v = PyObject_CallFunction((PyObject *) &ValuesType, "sOssssdi", value_list->type, list,
350 value_list->plugin_instance, value_list->type_instance, value_list->plugin,
351 value_list->host, (double) value_list->time, value_list->interval);
352 Py_DECREF(list);
353 ret = PyObject_CallFunctionObjArgs(c->callback, v, c->data, (void *) 0); /* New reference. */
354 if (ret == NULL) {
355 cpy_log_exception("write callback");
356 } else {
357 Py_DECREF(ret);
358 }
359 CPY_RELEASE_THREADS
360 return 0;
361 }
363 static int cpy_notification_callback(const notification_t *notification, user_data_t *data) {
364 cpy_callback_t *c = data->data;
365 PyObject *ret, *n;
367 CPY_LOCK_THREADS
368 n = PyObject_CallFunction((PyObject *) &NotificationType, "ssssssdi", notification->type, notification->message,
369 notification->plugin_instance, notification->type_instance, notification->plugin,
370 notification->host, (double) notification->time, notification->severity);
371 ret = PyObject_CallFunctionObjArgs(c->callback, n, c->data, (void *) 0); /* New reference. */
372 if (ret == NULL) {
373 cpy_log_exception("notification callback");
374 } else {
375 Py_DECREF(ret);
376 }
377 CPY_RELEASE_THREADS
378 return 0;
379 }
381 static void cpy_log_callback(int severity, const char *message, user_data_t *data) {
382 cpy_callback_t * c = data->data;
383 PyObject *ret;
385 CPY_LOCK_THREADS
386 if (c->data == NULL)
387 ret = PyObject_CallFunction(c->callback, "is", severity, message); /* New reference. */
388 else
389 ret = PyObject_CallFunction(c->callback, "isO", severity, message, c->data); /* New reference. */
391 if (ret == NULL) {
392 /* FIXME */
393 /* Do we really want to trigger a log callback because a log callback failed?
394 * Probably not. */
395 PyErr_Print();
396 /* In case someone wanted to be clever, replaced stderr and failed at that. */
397 PyErr_Clear();
398 } else {
399 Py_DECREF(ret);
400 }
401 CPY_RELEASE_THREADS
402 }
404 static void cpy_flush_callback(int timeout, const char *id, user_data_t *data) {
405 cpy_callback_t * c = data->data;
406 PyObject *ret;
408 CPY_LOCK_THREADS
409 if (c->data == NULL)
410 ret = PyObject_CallFunction(c->callback, "is", timeout, id); /* New reference. */
411 else
412 ret = PyObject_CallFunction(c->callback, "isO", timeout, id, c->data); /* New reference. */
414 if (ret == NULL) {
415 cpy_log_exception("flush callback");
416 } else {
417 Py_DECREF(ret);
418 }
419 CPY_RELEASE_THREADS
420 }
422 static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args, PyObject *kwds) {
423 char buf[512];
424 cpy_callback_t *c;
425 const char *name = NULL;
426 PyObject *callback = NULL, *data = NULL, *mod = NULL;
427 static char *kwlist[] = {"callback", "data", "name", NULL};
429 if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oz", kwlist, &callback, &data, &name) == 0) return NULL;
430 if (PyCallable_Check(callback) == 0) {
431 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
432 return NULL;
433 }
434 cpy_build_name(buf, sizeof(buf), callback, name);
436 Py_INCREF(callback);
437 Py_XINCREF(data);
438 c = malloc(sizeof(*c));
439 c->name = strdup(buf);
440 c->callback = callback;
441 c->data = data;
442 c->next = *list_head;
443 *list_head = c;
444 Py_XDECREF(mod);
445 return PyString_FromString(buf);
446 }
448 static PyObject *cpy_flush(cpy_callback_t **list_head, PyObject *args, PyObject *kwds) {
449 int timeout = -1;
450 const char *plugin = NULL, *identifier = NULL;
451 static char *kwlist[] = {"plugin", "timeout", "identifier", NULL};
453 if (PyArg_ParseTupleAndKeywords(args, kwds, "|ziz", kwlist, &plugin, &timeout, &identifier) == 0) return NULL;
454 Py_BEGIN_ALLOW_THREADS
455 plugin_flush(plugin, timeout, identifier);
456 Py_END_ALLOW_THREADS
457 Py_RETURN_NONE;
458 }
460 static PyObject *cpy_register_config(PyObject *self, PyObject *args, PyObject *kwds) {
461 return cpy_register_generic(&cpy_config_callbacks, args, kwds);
462 }
464 static PyObject *cpy_register_init(PyObject *self, PyObject *args, PyObject *kwds) {
465 return cpy_register_generic(&cpy_init_callbacks, args, kwds);
466 }
468 typedef int reg_function_t(const char *name, void *callback, void *data);
470 static PyObject *cpy_register_generic_userdata(void *reg, void *handler, PyObject *args, PyObject *kwds) {
471 char buf[512];
472 reg_function_t *register_function = (reg_function_t *) reg;
473 cpy_callback_t *c = NULL;
474 user_data_t *user_data = NULL;
475 const char *name = NULL;
476 PyObject *callback = NULL, *data = NULL;
477 static char *kwlist[] = {"callback", "data", "name", NULL};
479 if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oz", kwlist, &callback, &data, &name) == 0) return NULL;
480 if (PyCallable_Check(callback) == 0) {
481 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
482 return NULL;
483 }
484 cpy_build_name(buf, sizeof(buf), callback, name);
486 Py_INCREF(callback);
487 Py_XINCREF(data);
488 c = malloc(sizeof(*c));
489 c->name = strdup(buf);
490 c->callback = callback;
491 c->data = data;
492 c->next = NULL;
493 user_data = malloc(sizeof(*user_data));
494 user_data->free_func = cpy_destroy_user_data;
495 user_data->data = c;
496 register_function(buf, handler, user_data);
497 return PyString_FromString(buf);
498 }
500 static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwds) {
501 char buf[512];
502 cpy_callback_t *c = NULL;
503 user_data_t *user_data = NULL;
504 double interval = 0;
505 const char *name = NULL;
506 PyObject *callback = NULL, *data = NULL;
507 struct timespec ts;
508 static char *kwlist[] = {"callback", "interval", "data", "name", NULL};
510 if (PyArg_ParseTupleAndKeywords(args, kwds, "O|dOz", kwlist, &callback, &interval, &data, &name) == 0) return NULL;
511 if (PyCallable_Check(callback) == 0) {
512 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
513 return NULL;
514 }
515 cpy_build_name(buf, sizeof(buf), callback, name);
517 Py_INCREF(callback);
518 Py_XINCREF(data);
519 c = malloc(sizeof(*c));
520 c->name = strdup(buf);
521 c->callback = callback;
522 c->data = data;
523 c->next = NULL;
524 user_data = malloc(sizeof(*user_data));
525 user_data->free_func = cpy_destroy_user_data;
526 user_data->data = c;
527 ts.tv_sec = interval;
528 ts.tv_nsec = (interval - ts.tv_sec) * 1000000000;
529 plugin_register_complex_read(buf, cpy_read_callback, &ts, user_data);
530 return PyString_FromString(buf);
531 }
533 static PyObject *cpy_register_log(PyObject *self, PyObject *args, PyObject *kwds) {
534 return cpy_register_generic_userdata(plugin_register_log, cpy_log_callback, args, kwds);
535 }
537 static PyObject *cpy_register_write(PyObject *self, PyObject *args, PyObject *kwds) {
538 return cpy_register_generic_userdata(plugin_register_write, cpy_write_callback, args, kwds);
539 }
541 static PyObject *cpy_register_notification(PyObject *self, PyObject *args, PyObject *kwds) {
542 return cpy_register_generic_userdata(plugin_register_notification, cpy_notification_callback, args, kwds);
543 }
545 static PyObject *cpy_register_flush(PyObject *self, PyObject *args, PyObject *kwds) {
546 return cpy_register_generic_userdata(plugin_register_flush, cpy_flush_callback, args, kwds);
547 }
549 static PyObject *cpy_register_shutdown(PyObject *self, PyObject *args, PyObject *kwds) {
550 return cpy_register_generic(&cpy_shutdown_callbacks, args, kwds);
551 }
553 static PyObject *cpy_error(PyObject *self, PyObject *args) {
554 const char *text;
555 if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
556 Py_BEGIN_ALLOW_THREADS
557 plugin_log(LOG_ERR, "%s", text);
558 Py_END_ALLOW_THREADS
559 Py_RETURN_NONE;
560 }
562 static PyObject *cpy_warning(PyObject *self, PyObject *args) {
563 const char *text;
564 if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
565 Py_BEGIN_ALLOW_THREADS
566 plugin_log(LOG_WARNING, "%s", text);
567 Py_END_ALLOW_THREADS
568 Py_RETURN_NONE;
569 }
571 static PyObject *cpy_notice(PyObject *self, PyObject *args) {
572 const char *text;
573 if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
574 Py_BEGIN_ALLOW_THREADS
575 plugin_log(LOG_NOTICE, "%s", text);
576 Py_END_ALLOW_THREADS
577 Py_RETURN_NONE;
578 }
580 static PyObject *cpy_info(PyObject *self, PyObject *args) {
581 const char *text;
582 if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
583 Py_BEGIN_ALLOW_THREADS
584 plugin_log(LOG_INFO, "%s", text);
585 Py_END_ALLOW_THREADS
586 Py_RETURN_NONE;
587 }
589 static PyObject *cpy_debug(PyObject *self, PyObject *args) {
590 #ifdef COLLECT_DEBUG
591 const char *text;
592 if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
593 Py_BEGIN_ALLOW_THREADS
594 plugin_log(LOG_DEBUG, "%s", text);
595 Py_END_ALLOW_THREADS
596 #endif
597 Py_RETURN_NONE;
598 }
600 static PyObject *cpy_unregister_generic(cpy_callback_t **list_head, PyObject *arg, const char *desc) {
601 char buf[512];
602 const char *name;
603 cpy_callback_t *prev = NULL, *tmp;
605 if (PyUnicode_Check(arg)) {
606 arg = PyUnicode_AsEncodedString(arg, NULL, NULL);
607 if (arg == NULL)
608 return NULL;
609 name = PyString_AsString(arg);
610 Py_DECREF(arg);
611 } else if (PyString_Check(arg)) {
612 name = PyString_AsString(arg);
613 } else {
614 if (!PyCallable_Check(arg)) {
615 PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
616 return NULL;
617 }
618 cpy_build_name(buf, sizeof(buf), arg, NULL);
619 name = buf;
620 }
621 for (tmp = *list_head; tmp; prev = tmp, tmp = tmp->next)
622 if (strcmp(name, tmp->name) == 0)
623 break;
625 if (tmp == NULL) {
626 PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
627 return NULL;
628 }
629 /* Yes, this is actually save. To call this function the caller has to
630 * hold the GIL. Well, save as long as there is only one GIL anyway ... */
631 if (prev == NULL)
632 *list_head = tmp->next;
633 else
634 prev->next = tmp->next;
635 cpy_destroy_user_data(tmp);
636 Py_RETURN_NONE;
637 }
639 typedef int cpy_unregister_function_t(const char *name);
641 static PyObject *cpy_unregister_generic_userdata(cpy_unregister_function_t *unreg, PyObject *arg, const char *desc) {
642 char buf[512];
643 const char *name;
645 if (PyUnicode_Check(arg)) {
646 arg = PyUnicode_AsEncodedString(arg, NULL, NULL);
647 if (arg == NULL)
648 return NULL;
649 name = PyString_AsString(arg);
650 Py_DECREF(arg);
651 } else if (PyString_Check(arg)) {
652 name = PyString_AsString(arg);
653 } else {
654 if (!PyCallable_Check(arg)) {
655 PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
656 return NULL;
657 }
658 cpy_build_name(buf, sizeof(buf), arg, NULL);
659 name = buf;
660 }
661 if (unreg(name) == 0)
662 Py_RETURN_NONE;
663 PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
664 return NULL;
665 }
667 static PyObject *cpy_unregister_log(PyObject *self, PyObject *arg) {
668 return cpy_unregister_generic_userdata(plugin_unregister_log, arg, "log");
669 }
671 static PyObject *cpy_unregister_init(PyObject *self, PyObject *arg) {
672 return cpy_unregister_generic(&cpy_init_callbacks, arg, "init");
673 }
675 static PyObject *cpy_unregister_config(PyObject *self, PyObject *arg) {
676 return cpy_unregister_generic(&cpy_config_callbacks, arg, "config");
677 }
679 static PyObject *cpy_unregister_read(PyObject *self, PyObject *arg) {
680 return cpy_unregister_generic_userdata(plugin_unregister_read, arg, "read");
681 }
683 static PyObject *cpy_unregister_write(PyObject *self, PyObject *arg) {
684 return cpy_unregister_generic_userdata(plugin_unregister_write, arg, "write");
685 }
687 static PyObject *cpy_unregister_notification(PyObject *self, PyObject *arg) {
688 return cpy_unregister_generic_userdata(plugin_unregister_notification, arg, "notification");
689 }
691 static PyObject *cpy_unregister_flush(PyObject *self, PyObject *arg) {
692 return cpy_unregister_generic_userdata(plugin_unregister_flush, arg, "flush");
693 }
695 static PyObject *cpy_unregister_shutdown(PyObject *self, PyObject *arg) {
696 return cpy_unregister_generic(&cpy_shutdown_callbacks, arg, "shutdown");
697 }
699 static PyMethodDef cpy_methods[] = {
700 {"debug", cpy_debug, METH_VARARGS, log_doc},
701 {"info", cpy_info, METH_VARARGS, log_doc},
702 {"notice", cpy_notice, METH_VARARGS, log_doc},
703 {"warning", cpy_warning, METH_VARARGS, log_doc},
704 {"error", cpy_error, METH_VARARGS, log_doc},
705 {"flush", (PyCFunction) cpy_flush, METH_VARARGS | METH_KEYWORDS, flush_doc},
706 {"register_log", (PyCFunction) cpy_register_log, METH_VARARGS | METH_KEYWORDS, reg_log_doc},
707 {"register_init", (PyCFunction) cpy_register_init, METH_VARARGS | METH_KEYWORDS, reg_init_doc},
708 {"register_config", (PyCFunction) cpy_register_config, METH_VARARGS | METH_KEYWORDS, reg_config_doc},
709 {"register_read", (PyCFunction) cpy_register_read, METH_VARARGS | METH_KEYWORDS, reg_read_doc},
710 {"register_write", (PyCFunction) cpy_register_write, METH_VARARGS | METH_KEYWORDS, reg_write_doc},
711 {"register_notification", (PyCFunction) cpy_register_notification, METH_VARARGS | METH_KEYWORDS, reg_notification_doc},
712 {"register_flush", (PyCFunction) cpy_register_flush, METH_VARARGS | METH_KEYWORDS, reg_flush_doc},
713 {"register_shutdown", (PyCFunction) cpy_register_shutdown, METH_VARARGS | METH_KEYWORDS, reg_shutdown_doc},
714 {"unregister_log", cpy_unregister_log, METH_O, unregister_doc},
715 {"unregister_init", cpy_unregister_init, METH_O, unregister_doc},
716 {"unregister_config", cpy_unregister_config, METH_O, unregister_doc},
717 {"unregister_read", cpy_unregister_read, METH_O, unregister_doc},
718 {"unregister_write", cpy_unregister_write, METH_O, unregister_doc},
719 {"unregister_notification", cpy_unregister_notification, METH_O, unregister_doc},
720 {"unregister_flush", cpy_unregister_flush, METH_O, unregister_doc},
721 {"unregister_shutdown", cpy_unregister_shutdown, METH_O, unregister_doc},
722 {0, 0, 0, 0}
723 };
725 static int cpy_shutdown(void) {
726 cpy_callback_t *c;
727 PyObject *ret;
729 /* This can happen if the module was loaded but not configured. */
730 if (state != NULL)
731 PyEval_RestoreThread(state);
733 for (c = cpy_shutdown_callbacks; c; c = c->next) {
734 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
735 if (ret == NULL)
736 cpy_log_exception("shutdown callback");
737 else
738 Py_DECREF(ret);
739 }
740 PyErr_Print();
741 Py_Finalize();
742 return 0;
743 }
745 static void cpy_int_handler(int sig) {
746 return;
747 }
749 static void *cpy_interactive(void *data) {
750 sigset_t sigset;
751 struct sigaction sig_int_action, old;
753 /* Signal handler in a plugin? Bad stuff, but the best way to
754 * handle it I guess. In an interactive session people will
755 * press Ctrl+C at some time, which will generate a SIGINT.
756 * This will cause collectd to shutdown, thus killing the
757 * interactive interpreter, and leaving the terminal in a
758 * mess. Chances are, this isn't what the user wanted to do.
759 *
760 * So this is the plan:
761 * 1. Block SIGINT in the main thread.
762 * 2. Install our own signal handler that does nothing.
763 * 3. Unblock SIGINT in the interactive thread.
764 *
765 * This will make sure that SIGINT won't kill collectd but
766 * still interrupt syscalls like sleep and pause.
767 * It does not raise a KeyboardInterrupt exception because so
768 * far nobody managed to figure out how to do that. */
769 memset (&sig_int_action, '\0', sizeof (sig_int_action));
770 sig_int_action.sa_handler = cpy_int_handler;
771 sigaction (SIGINT, &sig_int_action, &old);
773 sigemptyset(&sigset);
774 sigaddset(&sigset, SIGINT);
775 pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
776 PyEval_AcquireThread(state);
777 if (PyImport_ImportModule("readline") == NULL) {
778 /* This interactive session will suck. */
779 cpy_log_exception("interactive session init");
780 }
781 PyRun_InteractiveLoop(stdin, "<stdin>");
782 PyErr_Print();
783 PyEval_ReleaseThread(state);
784 NOTICE("python: Interactive interpreter exited, stopping collectd ...");
785 /* Restore the original collectd SIGINT handler and raise SIGINT.
786 * The main thread still has SIGINT blocked and there's nothing we
787 * can do about that so this thread will handle it. But that's not
788 * important, except that it won't interrupt the main loop and so
789 * it might take a few seconds before collectd really shuts down. */
790 sigaction (SIGINT, &old, NULL);
791 raise(SIGINT);
792 pause();
793 return NULL;
794 }
796 static int cpy_init(void) {
797 cpy_callback_t *c;
798 PyObject *ret;
799 static pthread_t thread;
800 sigset_t sigset;
802 PyEval_InitThreads();
803 /* Now it's finally OK to use python threads. */
804 for (c = cpy_init_callbacks; c; c = c->next) {
805 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
806 if (ret == NULL)
807 cpy_log_exception("init callback");
808 else
809 Py_DECREF(ret);
810 }
811 sigemptyset(&sigset);
812 sigaddset(&sigset, SIGINT);
813 pthread_sigmask(SIG_BLOCK, &sigset, NULL);
814 state = PyEval_SaveThread();
815 if (do_interactive) {
816 if (pthread_create(&thread, NULL, cpy_interactive, NULL)) {
817 ERROR("python: Error creating thread for interactive interpreter.");
818 }
819 }
821 return 0;
822 }
824 static PyObject *cpy_oconfig_to_pyconfig(oconfig_item_t *ci, PyObject *parent) {
825 int i;
826 PyObject *item, *values, *children, *tmp;
828 if (parent == NULL)
829 parent = Py_None;
831 values = PyTuple_New(ci->values_num); /* New reference. */
832 for (i = 0; i < ci->values_num; ++i) {
833 if (ci->values[i].type == OCONFIG_TYPE_STRING) {
834 PyTuple_SET_ITEM(values, i, PyString_FromString(ci->values[i].value.string));
835 } else if (ci->values[i].type == OCONFIG_TYPE_NUMBER) {
836 PyTuple_SET_ITEM(values, i, PyFloat_FromDouble(ci->values[i].value.number));
837 } else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN) {
838 PyTuple_SET_ITEM(values, i, PyBool_FromLong(ci->values[i].value.boolean));
839 }
840 }
842 item = PyObject_CallFunction((PyObject *) &ConfigType, "sONO", ci->key, parent, values, Py_None);
843 if (item == NULL)
844 return NULL;
845 children = PyTuple_New(ci->children_num); /* New reference. */
846 for (i = 0; i < ci->children_num; ++i) {
847 PyTuple_SET_ITEM(children, i, cpy_oconfig_to_pyconfig(ci->children + i, item));
848 }
849 tmp = ((Config *) item)->children;
850 ((Config *) item)->children = children;
851 Py_XDECREF(tmp);
852 return item;
853 }
855 static int cpy_config(oconfig_item_t *ci) {
856 int i;
857 PyObject *sys, *tb;
858 PyObject *sys_path;
859 PyObject *module;
861 /* Ok in theory we shouldn't do initialization at this point
862 * but we have to. In order to give python scripts a chance
863 * to register a config callback we need to be able to execute
864 * python code during the config callback so we have to start
865 * the interpreter here. */
866 /* Do *not* use the python "thread" module at this point! */
867 Py_Initialize();
869 PyType_Ready(&ConfigType);
870 PyType_Ready(&PluginDataType);
871 ValuesType.tp_base = &PluginDataType;
872 PyType_Ready(&ValuesType);
873 NotificationType.tp_base = &PluginDataType;
874 PyType_Ready(&NotificationType);
875 sys = PyImport_ImportModule("sys"); /* New reference. */
876 if (sys == NULL) {
877 cpy_log_exception("python initialization");
878 return 1;
879 }
880 sys_path = PyObject_GetAttrString(sys, "path"); /* New reference. */
881 Py_DECREF(sys);
882 if (sys_path == NULL) {
883 cpy_log_exception("python initialization");
884 return 1;
885 }
886 module = Py_InitModule("collectd", cpy_methods); /* Borrowed reference. */
887 PyModule_AddObject(module, "Config", (PyObject *) &ConfigType); /* Steals a reference. */
888 PyModule_AddObject(module, "Values", (PyObject *) &ValuesType); /* Steals a reference. */
889 PyModule_AddObject(module, "Notification", (PyObject *) &NotificationType); /* Steals a reference. */
890 PyModule_AddIntConstant(module, "LOG_DEBUG", LOG_DEBUG);
891 PyModule_AddIntConstant(module, "LOG_INFO", LOG_INFO);
892 PyModule_AddIntConstant(module, "LOG_NOTICE", LOG_NOTICE);
893 PyModule_AddIntConstant(module, "LOG_WARNING", LOG_WARNING);
894 PyModule_AddIntConstant(module, "LOG_ERROR", LOG_ERR);
895 PyModule_AddIntConstant(module, "NOTIF_FAILURE", NOTIF_FAILURE);
896 PyModule_AddIntConstant(module, "NOTIF_WARNING", NOTIF_WARNING);
897 PyModule_AddIntConstant(module, "NOTIF_OKAY", NOTIF_OKAY);
898 for (i = 0; i < ci->children_num; ++i) {
899 oconfig_item_t *item = ci->children + i;
901 if (strcasecmp(item->key, "Interactive") == 0) {
902 if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
903 continue;
904 do_interactive = item->values[0].value.boolean;
905 } else if (strcasecmp(item->key, "Encoding") == 0) {
906 if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_STRING)
907 continue;
908 /* Why is this even necessary? And undocumented? */
909 if (PyUnicode_SetDefaultEncoding(item->values[0].value.string))
910 cpy_log_exception("setting default encoding");
911 } else if (strcasecmp(item->key, "LogTraces") == 0) {
912 if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
913 continue;
914 if (!item->values[0].value.boolean) {
915 Py_XDECREF(cpy_format_exception);
916 cpy_format_exception = NULL;
917 continue;
918 }
919 if (cpy_format_exception)
920 continue;
921 tb = PyImport_ImportModule("traceback"); /* New reference. */
922 if (tb == NULL) {
923 cpy_log_exception("python initialization");
924 continue;
925 }
926 cpy_format_exception = PyObject_GetAttrString(tb, "format_exception"); /* New reference. */
927 Py_DECREF(tb);
928 if (cpy_format_exception == NULL)
929 cpy_log_exception("python initialization");
930 } else if (strcasecmp(item->key, "ModulePath") == 0) {
931 char *dir = NULL;
932 PyObject *dir_object;
934 if (cf_util_get_string(item, &dir) != 0)
935 continue;
936 dir_object = PyString_FromString(dir); /* New reference. */
937 if (dir_object == NULL) {
938 ERROR("python plugin: Unable to convert \"%s\" to "
939 "a python object.", dir);
940 free(dir);
941 cpy_log_exception("python initialization");
942 continue;
943 }
944 if (PyList_Append(sys_path, dir_object) != 0) {
945 ERROR("python plugin: Unable to append \"%s\" to "
946 "python module path.", dir);
947 cpy_log_exception("python initialization");
948 }
949 Py_DECREF(dir_object);
950 free(dir);
951 } else if (strcasecmp(item->key, "Import") == 0) {
952 char *module_name = NULL;
953 PyObject *module;
955 if (cf_util_get_string(item, &module_name) != 0)
956 continue;
957 module = PyImport_ImportModule(module_name); /* New reference. */
958 if (module == NULL) {
959 ERROR("python plugin: Error importing module \"%s\".", module_name);
960 cpy_log_exception("importing module");
961 PyErr_Print();
962 }
963 free(module_name);
964 Py_XDECREF(module);
965 } else if (strcasecmp(item->key, "Module") == 0) {
966 char *name = NULL;
967 cpy_callback_t *c;
968 PyObject *ret;
970 if (cf_util_get_string(item, &name) != 0)
971 continue;
972 for (c = cpy_config_callbacks; c; c = c->next) {
973 if (strcasecmp(c->name + 7, name) == 0)
974 break;
975 }
976 if (c == NULL) {
977 WARNING("python plugin: Found a configuration for the \"%s\" plugin, "
978 "but the plugin isn't loaded or didn't register "
979 "a configuration callback.", name);
980 free(name);
981 continue;
982 }
983 free(name);
984 if (c->data == NULL)
985 ret = PyObject_CallFunction(c->callback, "N",
986 cpy_oconfig_to_pyconfig(item, NULL)); /* New reference. */
987 else
988 ret = PyObject_CallFunction(c->callback, "NO",
989 cpy_oconfig_to_pyconfig(item, NULL), c->data); /* New reference. */
990 if (ret == NULL)
991 cpy_log_exception("loading module");
992 else
993 Py_DECREF(ret);
994 } else {
995 WARNING("python plugin: Ignoring unknown config key \"%s\".", item->key);
996 }
997 }
998 Py_DECREF(sys_path);
999 return 0;
1000 }
1002 void module_register(void) {
1003 plugin_register_complex_config("python", cpy_config);
1004 plugin_register_init("python", cpy_init);
1005 plugin_register_shutdown("python", cpy_shutdown);
1006 }