X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=src%2Fpython.c;h=e60ba4595f8daf5942ed3a849e8d4f3d01e1e488;hp=b106e45cbb77e74df010716a455ed619cf3aa377;hb=7111bb6df7628edce3a8e538b386fbe27633a191;hpb=267bbc64779f9c7b32e063aac0df22be61bda6ae diff --git a/src/python.c b/src/python.c index b106e45c..e60ba459 100644 --- a/src/python.c +++ b/src/python.c @@ -233,6 +233,12 @@ static char reg_shutdown_doc[] = "The callback function will be called with no parameters except for\n" " data if it was supplied."; +static char CollectdError_doc[] = + "Basic exception for collectd Python scripts.\n" + "\n" + "Throwing this exception will not cause a stacktrace to be logged, \n" + "even if LogTraces is enabled in the config."; + static pthread_t main_thread; static PyOS_sighandler_t python_sigint_handler; static _Bool do_interactive = 0; @@ -244,7 +250,7 @@ static _Bool do_interactive = 0; static PyThreadState *state; -static PyObject *sys_path, *cpy_format_exception; +static PyObject *sys_path, *cpy_format_exception, *CollectdError; static cpy_callback_t *cpy_config_callbacks; static cpy_callback_t *cpy_init_callbacks; @@ -300,7 +306,7 @@ static void cpy_build_name(char *buf, size_t size, PyObject *callback, } void cpy_log_exception(const char *context) { - int l = 0; + int l = 0, collectd_error; const char *typename = NULL, *message = NULL; PyObject *type, *value, *traceback, *tn, *m, *list; @@ -308,6 +314,7 @@ void cpy_log_exception(const char *context) { PyErr_NormalizeException(&type, &value, &traceback); if (type == NULL) return; + collectd_error = PyErr_GivenExceptionMatches(value, CollectdError); tn = PyObject_GetAttrString(type, "__name__"); /* New reference. */ m = PyObject_Str(value); /* New reference. */ if (tn != NULL) @@ -318,11 +325,17 @@ void cpy_log_exception(const char *context) { typename = "NamelessException"; if (message == NULL) message = "N/A"; - Py_BEGIN_ALLOW_THREADS ERROR("Unhandled python exception in %s: %s: %s", - context, typename, message); - Py_END_ALLOW_THREADS Py_XDECREF(tn); + Py_BEGIN_ALLOW_THREADS; + if (collectd_error) { + WARNING("%s in %s: %s", typename, context, message); + } else { + ERROR("Unhandled python exception in %s: %s: %s", context, typename, + message); + } + Py_END_ALLOW_THREADS; + Py_XDECREF(tn); Py_XDECREF(m); - if (!cpy_format_exception || !traceback) { + if (!cpy_format_exception || !traceback || collectd_error) { PyErr_Clear(); Py_DECREF(type); Py_XDECREF(value); @@ -356,10 +369,11 @@ void cpy_log_exception(const char *context) { if (cpy[strlen(cpy) - 1] == '\n') cpy[strlen(cpy) - 1] = 0; - Py_BEGIN_ALLOW_THREADS ERROR("%s", cpy); - Py_END_ALLOW_THREADS + Py_BEGIN_ALLOW_THREADS; + ERROR("%s", cpy); + Py_END_ALLOW_THREADS; - free(cpy); + free(cpy); } Py_XDECREF(list); @@ -410,9 +424,10 @@ static int cpy_write_callback(const data_set_t *ds, PyList_SetItem( list, i, PyLong_FromUnsignedLongLong(value_list->values[i].absolute)); } else { - Py_BEGIN_ALLOW_THREADS ERROR("cpy_write_callback: Unknown value type %d.", - ds->ds[i].type); - Py_END_ALLOW_THREADS Py_DECREF(list); + Py_BEGIN_ALLOW_THREADS; + ERROR("cpy_write_callback: Unknown value type %d.", ds->ds[i].type); + Py_END_ALLOW_THREADS; + Py_DECREF(list); CPY_RETURN_FROM_THREADS 0; } if (PyErr_Occurred() != NULL) { @@ -423,7 +438,7 @@ static int cpy_write_callback(const data_set_t *ds, } dict = PyDict_New(); /* New reference. */ if (value_list->meta) { - char **table; + char **table = NULL; meta_data_t *meta = value_list->meta; int num = meta_data_toc(meta, &table); @@ -446,19 +461,21 @@ static int cpy_write_callback(const data_set_t *ds, } else if (type == MD_TYPE_SIGNED_INT) { if (meta_data_get_signed_int(meta, table[i], &si)) continue; - temp = PyObject_CallFunctionObjArgs((void *)&SignedType, - PyLong_FromLongLong(si), + PyObject *sival = PyLong_FromLongLong(si); /* New reference */ + temp = PyObject_CallFunctionObjArgs((void *)&SignedType, sival, (void *)0); /* New reference. */ PyDict_SetItemString(dict, table[i], temp); Py_XDECREF(temp); + Py_XDECREF(sival); } else if (type == MD_TYPE_UNSIGNED_INT) { if (meta_data_get_unsigned_int(meta, table[i], &ui)) continue; - temp = PyObject_CallFunctionObjArgs((void *)&UnsignedType, - PyLong_FromUnsignedLongLong(ui), + PyObject *uval = PyLong_FromUnsignedLongLong(ui); /* New reference */ + temp = PyObject_CallFunctionObjArgs((void *)&UnsignedType, uval, (void *)0); /* New reference. */ PyDict_SetItemString(dict, table[i], temp); Py_XDECREF(temp); + Py_XDECREF(uval); } else if (type == MD_TYPE_DOUBLE) { if (meta_data_get_double(meta, table[i], &d)) continue; @@ -510,6 +527,39 @@ static int cpy_notification_callback(const notification_t *notification, Notification *n; CPY_LOCK_THREADS + PyObject *dict = PyDict_New(); /* New reference. */ + for (notification_meta_t *meta = notification->meta; meta != NULL; + meta = meta->next) { + PyObject *temp = NULL; + if (meta->type == NM_TYPE_STRING) { + temp = cpy_string_to_unicode_or_bytes( + meta->nm_value.nm_string); /* New reference. */ + PyDict_SetItemString(dict, meta->name, temp); + Py_XDECREF(temp); + } else if (meta->type == NM_TYPE_SIGNED_INT) { + PyObject *sival = PyLong_FromLongLong(meta->nm_value.nm_signed_int); + temp = PyObject_CallFunctionObjArgs((void *)&SignedType, sival, + (void *)0); /* New reference. */ + PyDict_SetItemString(dict, meta->name, temp); + Py_XDECREF(temp); + Py_XDECREF(sival); + } else if (meta->type == NM_TYPE_UNSIGNED_INT) { + PyObject *uval = + PyLong_FromUnsignedLongLong(meta->nm_value.nm_unsigned_int); + temp = PyObject_CallFunctionObjArgs((void *)&UnsignedType, uval, + (void *)0); /* New reference. */ + PyDict_SetItemString(dict, meta->name, temp); + Py_XDECREF(temp); + Py_XDECREF(uval); + } else if (meta->type == NM_TYPE_DOUBLE) { + temp = PyFloat_FromDouble(meta->nm_value.nm_double); /* New reference. */ + PyDict_SetItemString(dict, meta->name, temp); + Py_XDECREF(temp); + } else if (meta->type == NM_TYPE_BOOLEAN) { + PyDict_SetItemString(dict, meta->name, + meta->nm_value.nm_boolean ? Py_True : Py_False); + } + } notify = Notification_New(); /* New reference. */ n = (Notification *)notify; sstrncpy(n->data.host, notification->host, sizeof(n->data.host)); @@ -522,6 +572,8 @@ static int cpy_notification_callback(const notification_t *notification, n->data.time = CDTIME_T_TO_DOUBLE(notification->time); sstrncpy(n->message, notification->message, sizeof(n->message)); n->severity = notification->severity; + Py_CLEAR(n->meta); + n->meta = dict; /* Steals a reference. */ ret = PyObject_CallFunctionObjArgs(c->callback, n, c->data, (void *)0); /* New reference. */ Py_XDECREF(notify); @@ -651,8 +703,9 @@ static PyObject *cpy_get_dataset(PyObject *self, PyObject *args) { for (size_t i = 0; i < ds->ds_num; ++i) { tuple = PyTuple_New(4); PyTuple_SET_ITEM(tuple, 0, cpy_string_to_unicode_or_bytes(ds->ds[i].name)); - PyTuple_SET_ITEM(tuple, 1, cpy_string_to_unicode_or_bytes( - DS_TYPE_TO_STRING(ds->ds[i].type))); + PyTuple_SET_ITEM( + tuple, 1, + cpy_string_to_unicode_or_bytes(DS_TYPE_TO_STRING(ds->ds[i].type))); PyTuple_SET_ITEM(tuple, 2, float_or_none(ds->ds[i].min)); PyTuple_SET_ITEM(tuple, 3, float_or_none(ds->ds[i].max)); PyList_SET_ITEM(list, i, tuple); @@ -668,8 +721,10 @@ static PyObject *cpy_flush(PyObject *self, PyObject *args, PyObject *kwds) { if (PyArg_ParseTupleAndKeywords(args, kwds, "|etiet", kwlist, NULL, &plugin, &timeout, NULL, &identifier) == 0) return NULL; - Py_BEGIN_ALLOW_THREADS plugin_flush(plugin, timeout, identifier); - Py_END_ALLOW_THREADS PyMem_Free(plugin); + Py_BEGIN_ALLOW_THREADS; + plugin_flush(plugin, timeout, identifier); + Py_END_ALLOW_THREADS; + PyMem_Free(plugin); PyMem_Free(identifier); Py_RETURN_NONE; } @@ -720,7 +775,8 @@ static PyObject *cpy_register_generic_userdata(void *reg, void *handler, register_function(buf, handler, &(user_data_t){ - .data = c, .free_func = cpy_destroy_user_data, + .data = c, + .free_func = cpy_destroy_user_data, }); ++cpy_num_callbacks; @@ -763,7 +819,8 @@ static PyObject *cpy_register_read(PyObject *self, PyObject *args, /* group = */ "python", buf, cpy_read_callback, DOUBLE_TO_CDTIME_T(interval), &(user_data_t){ - .data = c, .free_func = cpy_destroy_user_data, + .data = c, + .free_func = cpy_destroy_user_data, }); ++cpy_num_callbacks; return cpy_string_to_unicode_or_bytes(buf); @@ -784,8 +841,8 @@ static PyObject *cpy_register_write(PyObject *self, PyObject *args, static PyObject *cpy_register_notification(PyObject *self, PyObject *args, PyObject *kwds) { return cpy_register_generic_userdata((void *)plugin_register_notification, - (void *)cpy_notification_callback, - args, kwds); + (void *)cpy_notification_callback, args, + kwds); } static PyObject *cpy_register_flush(PyObject *self, PyObject *args, @@ -803,8 +860,10 @@ static PyObject *cpy_error(PyObject *self, PyObject *args) { char *text; if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL; - Py_BEGIN_ALLOW_THREADS plugin_log(LOG_ERR, "%s", text); - Py_END_ALLOW_THREADS PyMem_Free(text); + Py_BEGIN_ALLOW_THREADS; + plugin_log(LOG_ERR, "%s", text); + Py_END_ALLOW_THREADS; + PyMem_Free(text); Py_RETURN_NONE; } @@ -812,8 +871,10 @@ static PyObject *cpy_warning(PyObject *self, PyObject *args) { char *text; if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL; - Py_BEGIN_ALLOW_THREADS plugin_log(LOG_WARNING, "%s", text); - Py_END_ALLOW_THREADS PyMem_Free(text); + Py_BEGIN_ALLOW_THREADS; + plugin_log(LOG_WARNING, "%s", text); + Py_END_ALLOW_THREADS; + PyMem_Free(text); Py_RETURN_NONE; } @@ -821,8 +882,10 @@ static PyObject *cpy_notice(PyObject *self, PyObject *args) { char *text; if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL; - Py_BEGIN_ALLOW_THREADS plugin_log(LOG_NOTICE, "%s", text); - Py_END_ALLOW_THREADS PyMem_Free(text); + Py_BEGIN_ALLOW_THREADS; + plugin_log(LOG_NOTICE, "%s", text); + Py_END_ALLOW_THREADS; + PyMem_Free(text); Py_RETURN_NONE; } @@ -830,8 +893,10 @@ static PyObject *cpy_info(PyObject *self, PyObject *args) { char *text; if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL; - Py_BEGIN_ALLOW_THREADS plugin_log(LOG_INFO, "%s", text); - Py_END_ALLOW_THREADS PyMem_Free(text); + Py_BEGIN_ALLOW_THREADS; + plugin_log(LOG_INFO, "%s", text); + Py_END_ALLOW_THREADS; + PyMem_Free(text); Py_RETURN_NONE; } @@ -840,8 +905,10 @@ static PyObject *cpy_debug(PyObject *self, PyObject *args) { char *text; if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL; - Py_BEGIN_ALLOW_THREADS plugin_log(LOG_DEBUG, "%s", text); - Py_END_ALLOW_THREADS PyMem_Free(text); + Py_BEGIN_ALLOW_THREADS; + plugin_log(LOG_DEBUG, "%s", text); + Py_END_ALLOW_THREADS; + PyMem_Free(text); #endif Py_RETURN_NONE; } @@ -944,8 +1011,7 @@ static PyObject *cpy_unregister_read(PyObject *self, PyObject *arg) { } static PyObject *cpy_unregister_write(PyObject *self, PyObject *arg) { - return cpy_unregister_generic_userdata(plugin_unregister_write, arg, - "write"); + return cpy_unregister_generic_userdata(plugin_unregister_write, arg, "write"); } static PyObject *cpy_unregister_notification(PyObject *self, PyObject *arg) { @@ -954,8 +1020,7 @@ static PyObject *cpy_unregister_notification(PyObject *self, PyObject *arg) { } static PyObject *cpy_unregister_flush(PyObject *self, PyObject *arg) { - return cpy_unregister_generic_userdata(plugin_unregister_flush, arg, - "flush"); + return cpy_unregister_generic_userdata(plugin_unregister_flush, arg, "flush"); } static PyObject *cpy_unregister_shutdown(PyObject *self, PyObject *arg) { @@ -1025,13 +1090,14 @@ static int cpy_shutdown(void) { } PyErr_Print(); - Py_BEGIN_ALLOW_THREADS cpy_unregister_list(&cpy_config_callbacks); + Py_BEGIN_ALLOW_THREADS; + cpy_unregister_list(&cpy_config_callbacks); cpy_unregister_list(&cpy_init_callbacks); cpy_unregister_list(&cpy_shutdown_callbacks); cpy_shutdown_triggered = 1; - Py_END_ALLOW_THREADS + Py_END_ALLOW_THREADS; - if (!cpy_num_callbacks) { + if (!cpy_num_callbacks) { Py_Finalize(); return 0; } @@ -1134,8 +1200,9 @@ static PyObject *cpy_oconfig_to_pyconfig(oconfig_item_t *ci, PyObject *parent) { values = PyTuple_New(ci->values_num); /* New reference. */ for (int i = 0; i < ci->values_num; ++i) { if (ci->values[i].type == OCONFIG_TYPE_STRING) { - PyTuple_SET_ITEM(values, i, cpy_string_to_unicode_or_bytes( - ci->values[i].value.string)); + PyTuple_SET_ITEM( + values, i, + cpy_string_to_unicode_or_bytes(ci->values[i].value.string)); } else if (ci->values[i].type == OCONFIG_TYPE_NUMBER) { PyTuple_SET_ITEM(values, i, PyFloat_FromDouble(ci->values[i].value.number)); @@ -1173,7 +1240,7 @@ PyMODINIT_FUNC PyInit_collectd(void) { static int cpy_init_python(void) { PyOS_sighandler_t cur_sig; - PyObject *sys; + PyObject *sys, *errordict; PyObject *module; #ifdef IS_PY3K @@ -1200,6 +1267,11 @@ static int cpy_init_python(void) { PyType_Ready(&SignedType); UnsignedType.tp_base = &PyLong_Type; PyType_Ready(&UnsignedType); + errordict = PyDict_New(); + PyDict_SetItemString( + errordict, "__doc__", + cpy_string_to_unicode_or_bytes(CollectdError_doc)); /* New reference. */ + CollectdError = PyErr_NewException("collectd.CollectdError", NULL, errordict); sys = PyImport_ImportModule("sys"); /* New reference. */ if (sys == NULL) { cpy_log_exception("python initialization"); @@ -1229,6 +1301,9 @@ static int cpy_init_python(void) { (void *)&SignedType); /* Steals a reference. */ PyModule_AddObject(module, "Unsigned", (void *)&UnsignedType); /* Steals a reference. */ + Py_XINCREF(CollectdError); + PyModule_AddObject(module, "CollectdError", + CollectdError); /* Steals a reference. */ PyModule_AddIntConstant(module, "LOG_DEBUG", LOG_DEBUG); PyModule_AddIntConstant(module, "LOG_INFO", LOG_INFO); PyModule_AddIntConstant(module, "LOG_NOTICE", LOG_NOTICE);