08abfd1d2168e74b998640c5f3b9ee84c7b298dc
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 obmitted it will be obmitted 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 backgroud.\n"
56 "\n"
57 "'callback' is a callable object that will be executed.\n"
58 "'data' is an optional object that will be passed back to the callback\n"
59 " function when it is called.\n"
60 "'name' is an optional identifier for this callback. The default name\n"
61 " is 'python.<module>'.\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 obmitted it will be obmitted 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 obmitted it will be obmitted 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 obmitted it will be obmitted 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 obmitted it will be obmitted 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 return;
228 }
229 Py_XDECREF(mod);
231 snprintf(buf, size, "python.%p", callback);
232 }
234 static void cpy_log_exception(const char *context) {
235 int l = 0, i;
236 const char *typename = NULL, *message = NULL;
237 PyObject *type, *value, *traceback, *tn, *m, *list;
239 PyErr_Fetch(&type, &value, &traceback);
240 PyErr_NormalizeException(&type, &value, &traceback);
241 if (type == NULL) return;
242 tn = PyObject_GetAttrString(type, "__name__"); /* New reference. */
243 m = PyObject_GetAttrString(value, "message"); /* New reference. */
244 if (tn != NULL)
245 typename = PyString_AsString(tn);
246 if (m != NULL)
247 message = PyString_AsString(m);
248 if (typename == NULL)
249 typename = "NamelessException";
250 if (message == NULL)
251 message = "N/A";
252 Py_BEGIN_ALLOW_THREADS
253 ERROR("Unhandled python exception in %s: %s: %s", context, typename, message);
254 Py_END_ALLOW_THREADS
255 Py_XDECREF(tn);
256 Py_XDECREF(m);
257 if (!cpy_format_exception) {
258 PyErr_Clear();
259 Py_XDECREF(type);
260 Py_XDECREF(value);
261 Py_XDECREF(traceback);
262 return;
263 }
264 if (!traceback) {
265 PyErr_Clear();
266 return;
267 }
268 list = PyObject_CallFunction(cpy_format_exception, "NNN", type, value, traceback); /* New reference. */
269 if (list)
270 l = PyObject_Length(list);
271 for (i = 0; i < l; ++i) {
272 char *s;
273 PyObject *line;
275 line = PyList_GET_ITEM(list, i); /* Borrowed reference. */
276 s = strdup(PyString_AsString(line));
277 Py_DECREF(line);
278 if (s[strlen(s) - 1] == '\n')
279 s[strlen(s) - 1] = 0;
280 Py_BEGIN_ALLOW_THREADS
281 ERROR("%s", s);
282 Py_END_ALLOW_THREADS
283 free(s);
284 }
285 Py_XDECREF(list);
286 PyErr_Clear();
287 }
289 static int cpy_read_callback(user_data_t *data) {
290 cpy_callback_t *c = data->data;
291 PyObject *ret;
293 CPY_LOCK_THREADS
294 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
295 if (ret == NULL) {
296 cpy_log_exception("read callback");
297 } else {
298 Py_DECREF(ret);
299 }
300 CPY_RELEASE_THREADS
301 if (ret == NULL)
302 return 1;
303 return 0;
304 }
306 static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_list, user_data_t *data) {
307 int i;
308 cpy_callback_t *c = data->data;
309 PyObject *ret, *v, *list;
311 CPY_LOCK_THREADS
312 list = PyList_New(value_list->values_len); /* New reference. */
313 if (list == NULL) {
314 cpy_log_exception("write callback");
315 CPY_RETURN_FROM_THREADS 0;
316 }
317 for (i = 0; i < value_list->values_len; ++i) {
318 if (ds->ds->type == DS_TYPE_COUNTER) {
319 if ((long) value_list->values[i].counter == value_list->values[i].counter)
320 PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].counter));
321 else
322 PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].counter));
323 } else if (ds->ds->type == DS_TYPE_GAUGE) {
324 PyList_SetItem(list, i, PyFloat_FromDouble(value_list->values[i].gauge));
325 } else if (ds->ds->type == DS_TYPE_DERIVE) {
326 if ((long) value_list->values[i].derive == value_list->values[i].derive)
327 PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].derive));
328 else
329 PyList_SetItem(list, i, PyLong_FromLongLong(value_list->values[i].derive));
330 } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
331 if ((long) value_list->values[i].absolute == value_list->values[i].absolute)
332 PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].absolute));
333 else
334 PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].absolute));
335 } else {
336 Py_BEGIN_ALLOW_THREADS
337 ERROR("cpy_write_callback: Unknown value type %d.", ds->ds->type);
338 Py_END_ALLOW_THREADS
339 Py_DECREF(list);
340 CPY_RETURN_FROM_THREADS 0;
341 }
342 if (PyErr_Occurred() != NULL) {
343 cpy_log_exception("value building for write callback");
344 CPY_RETURN_FROM_THREADS 0;
345 }
346 }
347 v = PyObject_CallFunction((PyObject *) &ValuesType, "sOssssdi", value_list->type, list,
348 value_list->plugin_instance, value_list->type_instance, value_list->plugin,
349 value_list->host, (double) value_list->time, value_list->interval);
350 Py_DECREF(list);
351 ret = PyObject_CallFunctionObjArgs(c->callback, v, c->data, (void *) 0); /* New reference. */
352 if (ret == NULL) {
353 cpy_log_exception("write callback");
354 } else {
355 Py_DECREF(ret);
356 }
357 CPY_RELEASE_THREADS
358 return 0;
359 }
361 static int cpy_notification_callback(const notification_t *notification, user_data_t *data) {
362 cpy_callback_t *c = data->data;
363 PyObject *ret, *n;
365 CPY_LOCK_THREADS
366 n = PyObject_CallFunction((PyObject *) &NotificationType, "ssssssdi", notification->type, notification->message,
367 notification->plugin_instance, notification->type_instance, notification->plugin,
368 notification->host, (double) notification->time, notification->severity);
369 ret = PyObject_CallFunctionObjArgs(c->callback, n, c->data, (void *) 0); /* New reference. */
370 if (ret == NULL) {
371 cpy_log_exception("notification callback");
372 } else {
373 Py_DECREF(ret);
374 }
375 CPY_RELEASE_THREADS
376 return 0;
377 }
379 static void cpy_log_callback(int severity, const char *message, user_data_t *data) {
380 cpy_callback_t * c = data->data;
381 PyObject *ret;
383 CPY_LOCK_THREADS
384 if (c->data == NULL)
385 ret = PyObject_CallFunction(c->callback, "is", severity, message); /* New reference. */
386 else
387 ret = PyObject_CallFunction(c->callback, "isO", severity, message, c->data); /* New reference. */
389 if (ret == NULL) {
390 /* FIXME */
391 /* Do we really want to trigger a log callback because a log callback failed?
392 * Probably not. */
393 PyErr_Print();
394 /* In case someone wanted to be clever, replaced stderr and failed at that. */
395 PyErr_Clear();
396 } else {
397 Py_DECREF(ret);
398 }
399 CPY_RELEASE_THREADS
400 }
402 static void cpy_flush_callback(int timeout, const char *id, user_data_t *data) {
403 cpy_callback_t * c = data->data;
404 PyObject *ret;
406 CPY_LOCK_THREADS
407 if (c->data == NULL)
408 ret = PyObject_CallFunction(c->callback, "is", timeout, id); /* New reference. */
409 else
410 ret = PyObject_CallFunction(c->callback, "isO", timeout, id, c->data); /* New reference. */
412 if (ret == NULL) {
413 cpy_log_exception("flush callback");
414 } else {
415 Py_DECREF(ret);
416 }
417 CPY_RELEASE_THREADS
418 }
420 static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args, PyObject *kwds) {
421 char buf[512];
422 cpy_callback_t *c;
423 const char *name = NULL;
424 PyObject *callback = NULL, *data = NULL, *mod = NULL;
425 static char *kwlist[] = {"callback", "data", "name", NULL};
427 if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oz", kwlist, &callback, &data, &name) == 0) return NULL;
428 if (PyCallable_Check(callback) == 0) {
429 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
430 return NULL;
431 }
432 cpy_build_name(buf, sizeof(buf), callback, name);
434 Py_INCREF(callback);
435 Py_XINCREF(data);
436 c = malloc(sizeof(*c));
437 c->name = strdup(buf);
438 c->callback = callback;
439 c->data = data;
440 c->next = *list_head;
441 *list_head = c;
442 Py_XDECREF(mod);
443 return PyString_FromString(buf);
444 }
446 static PyObject *cpy_flush(cpy_callback_t **list_head, PyObject *args, PyObject *kwds) {
447 int timeout = -1;
448 const char *plugin = NULL, *identifier = NULL;
449 static char *kwlist[] = {"plugin", "timeout", "identifier", NULL};
451 if (PyArg_ParseTupleAndKeywords(args, kwds, "|ziz", kwlist, &plugin, &timeout, &identifier) == 0) return NULL;
452 Py_BEGIN_ALLOW_THREADS
453 plugin_flush(plugin, timeout, identifier);
454 Py_END_ALLOW_THREADS
455 Py_RETURN_NONE;
456 }
458 static PyObject *cpy_register_config(PyObject *self, PyObject *args, PyObject *kwds) {
459 return cpy_register_generic(&cpy_config_callbacks, args, kwds);
460 }
462 static PyObject *cpy_register_init(PyObject *self, PyObject *args, PyObject *kwds) {
463 return cpy_register_generic(&cpy_init_callbacks, args, kwds);
464 }
466 typedef int reg_function_t(const char *name, void *callback, void *data);
468 static PyObject *cpy_register_generic_userdata(void *reg, void *handler, PyObject *args, PyObject *kwds) {
469 char buf[512];
470 reg_function_t *register_function = (reg_function_t *) reg;
471 cpy_callback_t *c = NULL;
472 user_data_t *user_data = NULL;
473 const char *name = NULL;
474 PyObject *callback = NULL, *data = NULL;
475 static char *kwlist[] = {"callback", "data", "name", NULL};
477 if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oz", kwlist, &callback, &data, &name) == 0) return NULL;
478 if (PyCallable_Check(callback) == 0) {
479 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
480 return NULL;
481 }
482 cpy_build_name(buf, sizeof(buf), callback, name);
484 Py_INCREF(callback);
485 Py_XINCREF(data);
486 c = malloc(sizeof(*c));
487 c->name = strdup(buf);
488 c->callback = callback;
489 c->data = data;
490 c->next = NULL;
491 user_data = malloc(sizeof(*user_data));
492 user_data->free_func = cpy_destroy_user_data;
493 user_data->data = c;
494 register_function(buf, handler, user_data);
495 return PyString_FromString(buf);
496 }
498 static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwds) {
499 char buf[512];
500 cpy_callback_t *c = NULL;
501 user_data_t *user_data = NULL;
502 double interval = 0;
503 const char *name = NULL;
504 PyObject *callback = NULL, *data = NULL;
505 struct timespec ts;
506 static char *kwlist[] = {"callback", "interval", "data", "name", NULL};
508 if (PyArg_ParseTupleAndKeywords(args, kwds, "O|dOz", kwlist, &callback, &interval, &data, &name) == 0) return NULL;
509 if (PyCallable_Check(callback) == 0) {
510 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
511 return NULL;
512 }
513 cpy_build_name(buf, sizeof(buf), callback, name);
515 Py_INCREF(callback);
516 Py_XINCREF(data);
517 c = malloc(sizeof(*c));
518 c->name = strdup(buf);
519 c->callback = callback;
520 c->data = data;
521 c->next = NULL;
522 user_data = malloc(sizeof(*user_data));
523 user_data->free_func = cpy_destroy_user_data;
524 user_data->data = c;
525 ts.tv_sec = interval;
526 ts.tv_nsec = (interval - ts.tv_sec) * 1000000000;
527 plugin_register_complex_read(buf, cpy_read_callback, &ts, user_data);
528 return PyString_FromString(buf);
529 }
531 static PyObject *cpy_register_log(PyObject *self, PyObject *args, PyObject *kwds) {
532 return cpy_register_generic_userdata(plugin_register_log, cpy_log_callback, args, kwds);
533 }
535 static PyObject *cpy_register_write(PyObject *self, PyObject *args, PyObject *kwds) {
536 return cpy_register_generic_userdata(plugin_register_write, cpy_write_callback, args, kwds);
537 }
539 static PyObject *cpy_register_notification(PyObject *self, PyObject *args, PyObject *kwds) {
540 return cpy_register_generic_userdata(plugin_register_notification, cpy_notification_callback, args, kwds);
541 }
543 static PyObject *cpy_register_flush(PyObject *self, PyObject *args, PyObject *kwds) {
544 return cpy_register_generic_userdata(plugin_register_flush, cpy_flush_callback, args, kwds);
545 }
547 static PyObject *cpy_register_shutdown(PyObject *self, PyObject *args, PyObject *kwds) {
548 return cpy_register_generic(&cpy_shutdown_callbacks, args, kwds);
549 }
551 static PyObject *cpy_error(PyObject *self, PyObject *args) {
552 const char *text;
553 if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
554 Py_BEGIN_ALLOW_THREADS
555 plugin_log(LOG_ERR, "%s", text);
556 Py_END_ALLOW_THREADS
557 Py_RETURN_NONE;
558 }
560 static PyObject *cpy_warning(PyObject *self, PyObject *args) {
561 const char *text;
562 if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
563 Py_BEGIN_ALLOW_THREADS
564 plugin_log(LOG_WARNING, "%s", text);
565 Py_END_ALLOW_THREADS
566 Py_RETURN_NONE;
567 }
569 static PyObject *cpy_notice(PyObject *self, PyObject *args) {
570 const char *text;
571 if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
572 Py_BEGIN_ALLOW_THREADS
573 plugin_log(LOG_NOTICE, "%s", text);
574 Py_END_ALLOW_THREADS
575 Py_RETURN_NONE;
576 }
578 static PyObject *cpy_info(PyObject *self, PyObject *args) {
579 const char *text;
580 if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
581 Py_BEGIN_ALLOW_THREADS
582 plugin_log(LOG_INFO, "%s", text);
583 Py_END_ALLOW_THREADS
584 Py_RETURN_NONE;
585 }
587 static PyObject *cpy_debug(PyObject *self, PyObject *args) {
588 #ifdef COLLECT_DEBUG
589 const char *text;
590 if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
591 Py_BEGIN_ALLOW_THREADS
592 plugin_log(LOG_DEBUG, "%s", text);
593 Py_END_ALLOW_THREADS
594 #endif
595 Py_RETURN_NONE;
596 }
598 static PyObject *cpy_unregister_generic(cpy_callback_t **list_head, PyObject *arg, const char *desc) {
599 char buf[512];
600 const char *name;
601 cpy_callback_t *prev = NULL, *tmp;
603 if (PyString_Check(arg)) {
604 name = PyString_AsString(arg);
605 } else {
606 if (!PyCallable_Check(arg)) {
607 PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
608 return NULL;
609 }
610 cpy_build_name(buf, sizeof(buf), arg, NULL);
611 name = buf;
612 }
613 for (tmp = *list_head; tmp; prev = tmp, tmp = tmp->next)
614 if (strcmp(name, tmp->name) == 0)
615 break;
617 if (tmp == NULL) {
618 PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
619 return NULL;
620 }
621 /* Yes, this is actually save. To call this function the calles has to
622 * hold the GIL. Well, save as long as there is only one GIL anyway ... */
623 if (prev == NULL)
624 *list_head = tmp->next;
625 else
626 prev->next = tmp->next;
627 cpy_destroy_user_data(tmp);
628 Py_RETURN_NONE;
629 }
631 typedef int cpy_unregister_function_t(const char *name);
633 static PyObject *cpy_unregister_generic_userdata(cpy_unregister_function_t *unreg, PyObject *arg, const char *desc) {
634 char buf[512];
635 const char *name;
637 if (PyUnicode_Check(arg)) {
638 arg = PyUnicode_AsEncodedString(arg, NULL, NULL);
639 if (arg == NULL)
640 return NULL;
641 name = PyString_AsString(arg);
642 Py_DECREF(arg);
643 } else if (PyString_Check(arg)) {
644 name = PyString_AsString(arg);
645 } else {
646 if (!PyCallable_Check(arg)) {
647 PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
648 return NULL;
649 }
650 cpy_build_name(buf, sizeof(buf), arg, NULL);
651 name = buf;
652 }
653 if (unreg(name) == 0)
654 Py_RETURN_NONE;
655 PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
656 return NULL;
657 }
659 static PyObject *cpy_unregister_log(PyObject *self, PyObject *arg) {
660 return cpy_unregister_generic_userdata(plugin_unregister_log, arg, "log");
661 }
663 static PyObject *cpy_unregister_init(PyObject *self, PyObject *arg) {
664 return cpy_unregister_generic(&cpy_init_callbacks, arg, "init");
665 }
667 static PyObject *cpy_unregister_config(PyObject *self, PyObject *arg) {
668 return cpy_unregister_generic(&cpy_config_callbacks, arg, "config");
669 }
671 static PyObject *cpy_unregister_read(PyObject *self, PyObject *arg) {
672 return cpy_unregister_generic_userdata(plugin_unregister_read, arg, "read");
673 }
675 static PyObject *cpy_unregister_write(PyObject *self, PyObject *arg) {
676 return cpy_unregister_generic_userdata(plugin_unregister_write, arg, "write");
677 }
679 static PyObject *cpy_unregister_notification(PyObject *self, PyObject *arg) {
680 return cpy_unregister_generic_userdata(plugin_unregister_notification, arg, "notification");
681 }
683 static PyObject *cpy_unregister_flush(PyObject *self, PyObject *arg) {
684 return cpy_unregister_generic_userdata(plugin_unregister_flush, arg, "flush");
685 }
687 static PyObject *cpy_unregister_shutdown(PyObject *self, PyObject *arg) {
688 return cpy_unregister_generic(&cpy_shutdown_callbacks, arg, "shutdown");
689 }
691 static PyMethodDef cpy_methods[] = {
692 {"debug", cpy_debug, METH_VARARGS, log_doc},
693 {"info", cpy_info, METH_VARARGS, log_doc},
694 {"notice", cpy_notice, METH_VARARGS, log_doc},
695 {"warning", cpy_warning, METH_VARARGS, log_doc},
696 {"error", cpy_error, METH_VARARGS, log_doc},
697 {"flush", (PyCFunction) cpy_flush, METH_VARARGS | METH_KEYWORDS, flush_doc},
698 {"register_log", (PyCFunction) cpy_register_log, METH_VARARGS | METH_KEYWORDS, reg_log_doc},
699 {"register_init", (PyCFunction) cpy_register_init, METH_VARARGS | METH_KEYWORDS, reg_init_doc},
700 {"register_config", (PyCFunction) cpy_register_config, METH_VARARGS | METH_KEYWORDS, reg_config_doc},
701 {"register_read", (PyCFunction) cpy_register_read, METH_VARARGS | METH_KEYWORDS, reg_read_doc},
702 {"register_write", (PyCFunction) cpy_register_write, METH_VARARGS | METH_KEYWORDS, reg_write_doc},
703 {"register_notification", (PyCFunction) cpy_register_notification, METH_VARARGS | METH_KEYWORDS, reg_notification_doc},
704 {"register_flush", (PyCFunction) cpy_register_flush, METH_VARARGS | METH_KEYWORDS, reg_flush_doc},
705 {"register_shutdown", (PyCFunction) cpy_register_shutdown, METH_VARARGS | METH_KEYWORDS, reg_shutdown_doc},
706 {"unregister_log", cpy_unregister_log, METH_O, unregister_doc},
707 {"unregister_init", cpy_unregister_init, METH_O, unregister_doc},
708 {"unregister_config", cpy_unregister_config, METH_O, unregister_doc},
709 {"unregister_read", cpy_unregister_read, METH_O, unregister_doc},
710 {"unregister_write", cpy_unregister_write, METH_O, unregister_doc},
711 {"unregister_notification", cpy_unregister_notification, METH_O, unregister_doc},
712 {"unregister_flush", cpy_unregister_flush, METH_O, unregister_doc},
713 {"unregister_shutdown", cpy_unregister_shutdown, METH_O, unregister_doc},
714 {0, 0, 0, 0}
715 };
717 static int cpy_shutdown(void) {
718 cpy_callback_t *c;
719 PyObject *ret;
721 /* This can happen if the module was loaded but not configured. */
722 if (state != NULL)
723 PyEval_RestoreThread(state);
725 for (c = cpy_shutdown_callbacks; c; c = c->next) {
726 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
727 if (ret == NULL)
728 cpy_log_exception("shutdown callback");
729 else
730 Py_DECREF(ret);
731 }
732 PyErr_Print();
733 Py_Finalize();
734 return 0;
735 }
737 static void cpy_int_handler(int sig) {
738 return;
739 }
741 static void *cpy_interactive(void *data) {
742 sigset_t sigset;
743 struct sigaction sig_int_action, old;
745 /* Signal handler in a plugin? Bad stuff, but the best way to
746 * handle it I guess. In an interactive session people will
747 * press Ctrl+C at some time, which will generate a SIGINT.
748 * This will cause collectd to shutdown, thus killing the
749 * interactive interpreter, and leaving the terminal in a
750 * mess. Chances are, this isn't what the user wanted to do.
751 *
752 * So this is the plan:
753 * 1. Block SIGINT in the main thread.
754 * 2. Install our own signal handler that does nothing.
755 * 3. Unblock SIGINT in the interactive thread.
756 *
757 * This will make sure that SIGINT won't kill collectd but
758 * still interrupt syscalls like sleep and pause.
759 * It does not raise a KeyboardInterrupt exception because so
760 * far nobody managed to figure out how to do that. */
761 memset (&sig_int_action, '\0', sizeof (sig_int_action));
762 sig_int_action.sa_handler = cpy_int_handler;
763 sigaction (SIGINT, &sig_int_action, &old);
765 sigemptyset(&sigset);
766 sigaddset(&sigset, SIGINT);
767 pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
768 PyEval_AcquireThread(state);
769 if (PyImport_ImportModule("readline") == NULL) {
770 /* This interactive session will suck. */
771 cpy_log_exception("interactive session init");
772 }
773 PyRun_InteractiveLoop(stdin, "<stdin>");
774 PyErr_Print();
775 PyEval_ReleaseThread(state);
776 NOTICE("python: Interactive interpreter exited, stopping collectd ...");
777 /* Restore the original collectd SIGINT handler and raise SIGINT.
778 * The main thread still has SIGINT blocked and there's nothing we
779 * can do about that so this thread will handle it. But that's not
780 * important, except that it won't interrupt the main loop and so
781 * it might take a few seconds before collectd really shuts down. */
782 sigaction (SIGINT, &old, NULL);
783 raise(SIGINT);
784 pause();
785 return NULL;
786 }
788 static int cpy_init(void) {
789 cpy_callback_t *c;
790 PyObject *ret;
791 static pthread_t thread;
792 sigset_t sigset;
794 PyEval_InitThreads();
795 /* Now it's finally OK to use python threads. */
796 for (c = cpy_init_callbacks; c; c = c->next) {
797 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
798 if (ret == NULL)
799 cpy_log_exception("init callback");
800 else
801 Py_DECREF(ret);
802 }
803 sigemptyset(&sigset);
804 sigaddset(&sigset, SIGINT);
805 pthread_sigmask(SIG_BLOCK, &sigset, NULL);
806 state = PyEval_SaveThread();
807 if (do_interactive) {
808 if (pthread_create(&thread, NULL, cpy_interactive, NULL)) {
809 ERROR("python: Error creating thread for interactive interpreter.");
810 }
811 }
813 return 0;
814 }
816 static PyObject *cpy_oconfig_to_pyconfig(oconfig_item_t *ci, PyObject *parent) {
817 int i;
818 PyObject *item, *values, *children, *tmp;
820 if (parent == NULL)
821 parent = Py_None;
823 values = PyTuple_New(ci->values_num); /* New reference. */
824 for (i = 0; i < ci->values_num; ++i) {
825 if (ci->values[i].type == OCONFIG_TYPE_STRING) {
826 PyTuple_SET_ITEM(values, i, PyString_FromString(ci->values[i].value.string));
827 } else if (ci->values[i].type == OCONFIG_TYPE_NUMBER) {
828 PyTuple_SET_ITEM(values, i, PyFloat_FromDouble(ci->values[i].value.number));
829 } else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN) {
830 PyTuple_SET_ITEM(values, i, PyBool_FromLong(ci->values[i].value.boolean));
831 }
832 }
834 item = PyObject_CallFunction((PyObject *) &ConfigType, "sONO", ci->key, parent, values, Py_None);
835 if (item == NULL)
836 return NULL;
837 children = PyTuple_New(ci->children_num); /* New reference. */
838 for (i = 0; i < ci->children_num; ++i) {
839 PyTuple_SET_ITEM(children, i, cpy_oconfig_to_pyconfig(ci->children + i, item));
840 }
841 tmp = ((Config *) item)->children;
842 ((Config *) item)->children = children;
843 Py_XDECREF(tmp);
844 return item;
845 }
847 static int cpy_config(oconfig_item_t *ci) {
848 int i;
849 PyObject *sys, *tb;
850 PyObject *sys_path;
851 PyObject *module;
853 /* Ok in theory we shouldn't do initialization at this point
854 * but we have to. In order to give python scripts a chance
855 * to register a config callback we need to be able to execute
856 * python code during the config callback so we have to start
857 * the interpreter here. */
858 /* Do *not* use the python "thread" module at this point! */
859 Py_Initialize();
861 PyType_Ready(&ConfigType);
862 PyType_Ready(&PluginDataType);
863 ValuesType.tp_base = &PluginDataType;
864 PyType_Ready(&ValuesType);
865 NotificationType.tp_base = &PluginDataType;
866 PyType_Ready(&NotificationType);
867 sys = PyImport_ImportModule("sys"); /* New reference. */
868 if (sys == NULL) {
869 cpy_log_exception("python initialization");
870 return 1;
871 }
872 sys_path = PyObject_GetAttrString(sys, "path"); /* New reference. */
873 Py_DECREF(sys);
874 if (sys_path == NULL) {
875 cpy_log_exception("python initialization");
876 return 1;
877 }
878 module = Py_InitModule("collectd", cpy_methods); /* Borrowed reference. */
879 PyModule_AddObject(module, "Config", (PyObject *) &ConfigType); /* Steals a reference. */
880 PyModule_AddObject(module, "Values", (PyObject *) &ValuesType); /* Steals a reference. */
881 PyModule_AddObject(module, "Notification", (PyObject *) &NotificationType); /* Steals a reference. */
882 PyModule_AddIntConstant(module, "LOG_DEBUG", LOG_DEBUG);
883 PyModule_AddIntConstant(module, "LOG_INFO", LOG_INFO);
884 PyModule_AddIntConstant(module, "LOG_NOTICE", LOG_NOTICE);
885 PyModule_AddIntConstant(module, "LOG_WARNING", LOG_WARNING);
886 PyModule_AddIntConstant(module, "LOG_ERROR", LOG_ERR);
887 PyModule_AddIntConstant(module, "NOTIF_FAILURE", NOTIF_FAILURE);
888 PyModule_AddIntConstant(module, "NOTIF_WARNING", NOTIF_WARNING);
889 PyModule_AddIntConstant(module, "NOTIF_OKAY", NOTIF_OKAY);
890 for (i = 0; i < ci->children_num; ++i) {
891 oconfig_item_t *item = ci->children + i;
893 if (strcasecmp(item->key, "Interactive") == 0) {
894 if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
895 continue;
896 do_interactive = item->values[0].value.boolean;
897 } else if (strcasecmp(item->key, "Encoding") == 0) {
898 if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_STRING)
899 continue;
900 /* Why is this even necessary? And undocumented? */
901 if (PyUnicode_SetDefaultEncoding(item->values[0].value.string))
902 cpy_log_exception("setting default encoding");
903 } else if (strcasecmp(item->key, "LogTraces") == 0) {
904 if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
905 continue;
906 if (!item->values[0].value.boolean) {
907 Py_XDECREF(cpy_format_exception);
908 cpy_format_exception = NULL;
909 continue;
910 }
911 if (cpy_format_exception)
912 continue;
913 tb = PyImport_ImportModule("traceback"); /* New reference. */
914 if (tb == NULL) {
915 cpy_log_exception("python initialization");
916 continue;
917 }
918 cpy_format_exception = PyObject_GetAttrString(tb, "format_exception"); /* New reference. */
919 Py_DECREF(tb);
920 if (cpy_format_exception == NULL)
921 cpy_log_exception("python initialization");
922 } else if (strcasecmp(item->key, "ModulePath") == 0) {
923 char *dir = NULL;
924 PyObject *dir_object;
926 if (cf_util_get_string(item, &dir) != 0)
927 continue;
928 dir_object = PyString_FromString(dir); /* New reference. */
929 if (dir_object == NULL) {
930 ERROR("python plugin: Unable to convert \"%s\" to "
931 "a python object.", dir);
932 free(dir);
933 cpy_log_exception("python initialization");
934 continue;
935 }
936 if (PyList_Append(sys_path, dir_object) != 0) {
937 ERROR("python plugin: Unable to append \"%s\" to "
938 "python module path.", dir);
939 cpy_log_exception("python initialization");
940 }
941 Py_DECREF(dir_object);
942 free(dir);
943 } else if (strcasecmp(item->key, "Import") == 0) {
944 char *module_name = NULL;
945 PyObject *module;
947 if (cf_util_get_string(item, &module_name) != 0)
948 continue;
949 module = PyImport_ImportModule(module_name); /* New reference. */
950 if (module == NULL) {
951 ERROR("python plugin: Error importing module \"%s\".", module_name);
952 cpy_log_exception("importing module");
953 PyErr_Print();
954 }
955 free(module_name);
956 Py_XDECREF(module);
957 } else if (strcasecmp(item->key, "Module") == 0) {
958 char *name = NULL;
959 cpy_callback_t *c;
960 PyObject *ret;
962 if (cf_util_get_string(item, &name) != 0)
963 continue;
964 for (c = cpy_config_callbacks; c; c = c->next) {
965 if (strcasecmp(c->name + 7, name) == 0)
966 break;
967 }
968 if (c == NULL) {
969 WARNING("python plugin: Found a configuration for the \"%s\" plugin, "
970 "but the plugin isn't loaded or didn't register "
971 "a configuration callback.", name);
972 free(name);
973 continue;
974 }
975 free(name);
976 if (c->data == NULL)
977 ret = PyObject_CallFunction(c->callback, "N",
978 cpy_oconfig_to_pyconfig(item, NULL)); /* New reference. */
979 else
980 ret = PyObject_CallFunction(c->callback, "NO",
981 cpy_oconfig_to_pyconfig(item, NULL), c->data); /* New reference. */
982 if (ret == NULL)
983 cpy_log_exception("loading module");
984 else
985 Py_DECREF(ret);
986 } else {
987 WARNING("python plugin: Ignoring unknown config key \"%s\".", item->key);
988 }
989 }
990 Py_DECREF(sys_path);
991 return 0;
992 }
994 void module_register(void) {
995 plugin_register_complex_config("python", cpy_config);
996 plugin_register_init("python", cpy_init);
997 plugin_register_shutdown("python", cpy_shutdown);
998 }