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