"'data' is an optional object that will be passed back to the callback\n"
" function every time it is called.\n"
"'name' is an optional identifier for this callback. The default name\n"
- " is 'python.<module>.<name>'. If 'name' contains a '.' it\n"
- " replaces both module and name, otherwise it replaces only name.\n"
+ " is 'python.<module>'.\n"
" Every callback needs a unique identifier, so if you want to\n"
- " register one function multiple time you need to specify a name\n"
- " here.\n"
+ " register this callback multiple time from the same module you need\n"
+ " to specify a name here.\n"
"'identifier' is the full identifier assigned to this callback.\n"
"\n"
"The callback function will be called with two or three parameters:\n"
"'data' is an optional object that will be passed back to the callback\n"
" function when it is called.\n"
"'name' is an optional identifier for this callback. The default name\n"
- " is 'python.<module>.<name>'. If 'name' contains a '.' it\n"
- " replaces both module and name, otherwise it replaces only name.\n"
+ " is 'python.<module>'.\n"
" Every callback needs a unique identifier, so if you want to\n"
- " register one function multiple time you need to specify a name\n"
- " here.\n"
+ " register this callback multiple time from the same module you need\n"
+ " to specify a name here.\n"
"'identifier' is the full identifier assigned to this callback.\n"
"\n"
"The callback function will be called without parameters, except for\n"
"'data' is an optional object that will be passed back to the callback\n"
" function every time it is called.\n"
"'name' is an optional identifier for this callback. The default name\n"
- " is 'python.<module>'. Every callback needs a unique identifier,\n"
- " so if you want to register one function multiple time you need to\n"
- " specify a name here.\n"
+ " is 'python.<module>'.\n"
+ " Every callback needs a unique identifier, so if you want to\n"
+ " register this callback multiple time from the same module you need\n"
+ " to specify a name here.\n"
"'identifier' is the full identifier assigned to this callback.\n"
"\n"
"The callback function will be called with one or two parameters:\n"
"'data' is an optional object that will be passed back to the callback\n"
" function every time it is called.\n"
"'name' is an optional identifier for this callback. The default name\n"
- " is 'python.<module>.<name>'. If 'name' contains a '.' it\n"
- " replaces both module and name, otherwise it replaces only name.\n"
+ " is 'python.<module>'.\n"
" Every callback needs a unique identifier, so if you want to\n"
- " register one function multiple time you need to specify a name\n"
- " here.\n"
+ " register this callback multiple time from the same module you need\n"
+ " to specify a name here.\n"
"'identifier' is the full identifier assigned to this callback.\n"
"\n"
"The callback function will be called without parameters, except for\n"
"'data' is an optional object that will be passed back to the callback\n"
" function every time it is called.\n"
"'name' is an optional identifier for this callback. The default name\n"
- " is 'python.<module>.<name>'. If 'name' contains a '.' it\n"
- " replaces both module and name, otherwise it replaces only name.\n"
+ " is 'python.<module>'.\n"
" Every callback needs a unique identifier, so if you want to\n"
- " register one function multiple time you need to specify a name\n"
- " here.\n"
+ " register this callback multiple time from the same module you need\n"
+ " to specify a name here.\n"
"'identifier' is the full identifier assigned to this callback.\n"
"\n"
"The callback function will be called with one or two parameters:\n"
"'data' is an optional object that will be passed back to the callback\n"
" function every time it is called.\n"
"'name' is an optional identifier for this callback. The default name\n"
- " is 'python.<module>.<name>'. If 'name' contains a '.' it\n"
- " replaces both module and name, otherwise it replaces only name.\n"
+ " is 'python.<module>'.\n"
" Every callback needs a unique identifier, so if you want to\n"
- " register one function multiple time you need to specify a name\n"
- " here.\n"
+ " register this callback multiple time from the same module you need\n"
+ " to specify a name here.\n"
"'identifier' is the full identifier assigned to this callback.\n"
"\n"
"The callback function will be called with one or two parameters:\n"
"'data' is an optional object that will be passed back to the callback\n"
" function every time it is called.\n"
"'name' is an optional identifier for this callback. The default name\n"
- " is 'python.<module>'. Every callback needs a unique identifier,\n"
- " so if you want to register one function multiple time you need to\n"
- " specify a name here.\n"
+ " is 'python.<module>'.\n"
+ " Every callback needs a unique identifier, so if you want to\n"
+ " register this callback multiple time from the same module you need\n"
+ " to specify a name here.\n"
"'identifier' is the full identifier assigned to this callback.\n"
"\n"
"The callback function will be called with two or three parameters:\n"
- "timeout: ???.\n"
- "id: ???.\n"
+ "timeout: Indicates that only data older than 'timeout' seconds is to\n"
+ " be flushed.\n"
+ "id: Specifies which values are to be flushed.\n"
"data: The optional data parameter passed to the register function.\n"
" If the parameter was obmitted it will be obmitted here, too.";
"'data' is an optional object that will be passed back to the callback\n"
" function if it is called.\n"
"'name' is an optional identifier for this callback. The default name\n"
- " is 'python.<module>.<name>'. If 'name' contains a '.' it\n"
- " replaces both module and name, otherwise it replaces only name.\n"
+ " is 'python.<module>'.\n"
" Every callback needs a unique identifier, so if you want to\n"
- " register one function multiple time you need to specify a name\n"
- " here.\n"
+ " register this callback multiple time from the same module you need\n"
+ " to specify a name here.\n"
"'identifier' is the full identifier assigned to this callback.\n"
"\n"
"The callback function will be called with no parameters except for\n"
/* You must hold the GIL to call this function!
* But if you managed to extract the callback parameter then you probably already do. */
-static void cpy_build_name(char *buf, size_t size, PyObject *callback, const char *name, int short_name) {
- const char *module;
- PyObject *mod = NULL, *n = NULL;
+static void cpy_build_name(char *buf, size_t size, PyObject *callback, const char *name) {
+ const char *module = NULL;
+ PyObject *mod = NULL;
- if (name != NULL && (strchr(name, '.') != NULL || short_name)) {
+ if (name != NULL) {
snprintf(buf, size, "python.%s", name);
return;
}
mod = PyObject_GetAttrString(callback, "__module__"); /* New reference. */
if (mod != NULL)
module = PyString_AsString(mod);
- else
- module = "collectd";
- if (short_name) {
+ if (module != NULL) {
snprintf(buf, size, "python.%s", module);
Py_XDECREF(mod);
+ PyErr_Clear();
return;
}
-
- if (name != NULL) {
- snprintf(buf, size, "python.%s.%s", module, name);
- Py_XDECREF(mod);
- return;
- }
-
- n = PyObject_GetAttrString(callback, "__name__"); /* New reference. */
- if (n != NULL)
- name = PyString_AsString(n);
-
- if (name != NULL)
- snprintf(buf, size, "python.%s.%s", module, name);
- else
- snprintf(buf, size, "python.%s.%p", module, callback);
Py_XDECREF(mod);
- Py_XDECREF(n);
+
+ snprintf(buf, size, "python.%p", callback);
+ PyErr_Clear();
}
static 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_XDECREF(m);
if (!cpy_format_exception) {
Py_DECREF(line);
if (s[strlen(s) - 1] == '\n')
s[strlen(s) - 1] = 0;
+ Py_BEGIN_ALLOW_THREADS
ERROR("%s", s);
+ Py_END_ALLOW_THREADS
free(s);
}
Py_XDECREF(list);
Py_DECREF(ret);
}
CPY_RELEASE_THREADS
+ if (ret == NULL)
+ return 1;
return 0;
}
else
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->type);
+ Py_END_ALLOW_THREADS
Py_DECREF(list);
CPY_RETURN_FROM_THREADS 0;
}
/* Do we really want to trigger a log callback because a log callback failed?
* Probably not. */
PyErr_Print();
+ /* In case someone wanted to be clever, replaced stderr and failed at that. */
+ PyErr_Clear();
} else {
Py_DECREF(ret);
}
CPY_RELEASE_THREADS
}
-static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args, PyObject *kwds, int short_name) {
+static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args, PyObject *kwds) {
char buf[512];
cpy_callback_t *c;
const char *name = NULL;
PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
return NULL;
}
- cpy_build_name(buf, sizeof(buf), callback, name, short_name);
+ cpy_build_name(buf, sizeof(buf), callback, name);
Py_INCREF(callback);
Py_XINCREF(data);
}
static PyObject *cpy_register_config(PyObject *self, PyObject *args, PyObject *kwds) {
- return cpy_register_generic(&cpy_config_callbacks, args, kwds, 1);
+ return cpy_register_generic(&cpy_config_callbacks, args, kwds);
}
static PyObject *cpy_register_init(PyObject *self, PyObject *args, PyObject *kwds) {
- return cpy_register_generic(&cpy_init_callbacks, args, kwds, 0);
+ return cpy_register_generic(&cpy_init_callbacks, args, kwds);
}
typedef int reg_function_t(const char *name, void *callback, void *data);
-static PyObject *cpy_register_generic_userdata(void *reg, void *handler, PyObject *args, PyObject *kwds, int short_name) {
+static PyObject *cpy_register_generic_userdata(void *reg, void *handler, PyObject *args, PyObject *kwds) {
char buf[512];
reg_function_t *register_function = (reg_function_t *) reg;
cpy_callback_t *c = NULL;
PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
return NULL;
}
- cpy_build_name(buf, sizeof(buf), callback, name, short_name);
+ cpy_build_name(buf, sizeof(buf), callback, name);
Py_INCREF(callback);
Py_XINCREF(data);
PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
return NULL;
}
- cpy_build_name(buf, sizeof(buf), callback, name, 0);
+ cpy_build_name(buf, sizeof(buf), callback, name);
Py_INCREF(callback);
Py_XINCREF(data);
}
static PyObject *cpy_register_log(PyObject *self, PyObject *args, PyObject *kwds) {
- return cpy_register_generic_userdata(plugin_register_log, cpy_log_callback, args, kwds, 0);
+ return cpy_register_generic_userdata(plugin_register_log, cpy_log_callback, args, kwds);
}
static PyObject *cpy_register_write(PyObject *self, PyObject *args, PyObject *kwds) {
- return cpy_register_generic_userdata(plugin_register_write, cpy_write_callback, args, kwds, 0);
+ return cpy_register_generic_userdata(plugin_register_write, cpy_write_callback, args, kwds);
}
static PyObject *cpy_register_notification(PyObject *self, PyObject *args, PyObject *kwds) {
- return cpy_register_generic_userdata(plugin_register_notification, cpy_notification_callback, args, kwds, 0);
+ return cpy_register_generic_userdata(plugin_register_notification, cpy_notification_callback, args, kwds);
}
static PyObject *cpy_register_flush(PyObject *self, PyObject *args, PyObject *kwds) {
- return cpy_register_generic_userdata(plugin_register_flush, cpy_flush_callback, args, kwds, 1);
+ return cpy_register_generic_userdata(plugin_register_flush, cpy_flush_callback, args, kwds);
}
static PyObject *cpy_register_shutdown(PyObject *self, PyObject *args, PyObject *kwds) {
- return cpy_register_generic(&cpy_shutdown_callbacks, args, kwds, 0);
+ return cpy_register_generic(&cpy_shutdown_callbacks, args, kwds);
}
static PyObject *cpy_error(PyObject *self, PyObject *args) {
#ifdef COLLECT_DEBUG
const char *text;
if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
+ Py_BEGIN_ALLOW_THREADS
plugin_log(LOG_DEBUG, "%s", text);
+ Py_END_ALLOW_THREADS
#endif
Py_RETURN_NONE;
}
-static PyObject *cpy_unregister_generic(cpy_callback_t **list_head, PyObject *arg, const char *desc, int short_name) {
+static PyObject *cpy_unregister_generic(cpy_callback_t **list_head, PyObject *arg, const char *desc) {
char buf[512];
const char *name;
cpy_callback_t *prev = NULL, *tmp;
- if (PyString_Check(arg)) {
+ if (PyUnicode_Check(arg)) {
+ arg = PyUnicode_AsEncodedString(arg, NULL, NULL);
+ if (arg == NULL)
+ return NULL;
+ name = PyString_AsString(arg);
+ Py_DECREF(arg);
+ } else if (PyString_Check(arg)) {
name = PyString_AsString(arg);
} else {
if (!PyCallable_Check(arg)) {
PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
return NULL;
}
- cpy_build_name(buf, sizeof(buf), arg, NULL, short_name);
+ cpy_build_name(buf, sizeof(buf), arg, NULL);
name = buf;
}
for (tmp = *list_head; tmp; prev = tmp, tmp = tmp->next)
PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
return NULL;
}
- /* Yes, this is actually save. To call this function the calles has to
+ /* Yes, this is actually save. To call this function the caller has to
* hold the GIL. Well, save as long as there is only one GIL anyway ... */
if (prev == NULL)
*list_head = tmp->next;
typedef int cpy_unregister_function_t(const char *name);
-static PyObject *cpy_unregister_generic_userdata(cpy_unregister_function_t *unreg, PyObject *arg, const char *desc, int short_name) {
+static PyObject *cpy_unregister_generic_userdata(cpy_unregister_function_t *unreg, PyObject *arg, const char *desc) {
char buf[512];
const char *name;
- if (PyString_Check(arg)) {
+ if (PyUnicode_Check(arg)) {
+ arg = PyUnicode_AsEncodedString(arg, NULL, NULL);
+ if (arg == NULL)
+ return NULL;
+ name = PyString_AsString(arg);
+ Py_DECREF(arg);
+ } else if (PyString_Check(arg)) {
name = PyString_AsString(arg);
} else {
if (!PyCallable_Check(arg)) {
PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
return NULL;
}
- cpy_build_name(buf, sizeof(buf), arg, NULL, short_name);
+ cpy_build_name(buf, sizeof(buf), arg, NULL);
name = buf;
}
if (unreg(name) == 0)
}
static PyObject *cpy_unregister_log(PyObject *self, PyObject *arg) {
- return cpy_unregister_generic_userdata(plugin_unregister_log, arg, "log", 0);
+ return cpy_unregister_generic_userdata(plugin_unregister_log, arg, "log");
}
static PyObject *cpy_unregister_init(PyObject *self, PyObject *arg) {
- return cpy_unregister_generic(&cpy_init_callbacks, arg, "init", 0);
+ return cpy_unregister_generic(&cpy_init_callbacks, arg, "init");
}
static PyObject *cpy_unregister_config(PyObject *self, PyObject *arg) {
- return cpy_unregister_generic(&cpy_config_callbacks, arg, "config", 1);
+ return cpy_unregister_generic(&cpy_config_callbacks, arg, "config");
}
static PyObject *cpy_unregister_read(PyObject *self, PyObject *arg) {
- return cpy_unregister_generic_userdata(plugin_unregister_read, arg, "read", 0);
+ return cpy_unregister_generic_userdata(plugin_unregister_read, arg, "read");
}
static PyObject *cpy_unregister_write(PyObject *self, PyObject *arg) {
- return cpy_unregister_generic_userdata(plugin_unregister_write, arg, "write", 0);
+ return cpy_unregister_generic_userdata(plugin_unregister_write, arg, "write");
}
static PyObject *cpy_unregister_notification(PyObject *self, PyObject *arg) {
- return cpy_unregister_generic_userdata(plugin_unregister_notification, arg, "notification", 0);
+ return cpy_unregister_generic_userdata(plugin_unregister_notification, arg, "notification");
}
static PyObject *cpy_unregister_flush(PyObject *self, PyObject *arg) {
- return cpy_unregister_generic_userdata(plugin_unregister_flush, arg, "flush", 1);
+ return cpy_unregister_generic_userdata(plugin_unregister_flush, arg, "flush");
}
static PyObject *cpy_unregister_shutdown(PyObject *self, PyObject *arg) {
- return cpy_unregister_generic(&cpy_shutdown_callbacks, arg, "shutdown", 0);
+ return cpy_unregister_generic(&cpy_shutdown_callbacks, arg, "shutdown");
}
static PyMethodDef cpy_methods[] = {
if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
continue;
do_interactive = item->values[0].value.boolean;
+ } else if (strcasecmp(item->key, "Encoding") == 0) {
+ if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_STRING)
+ continue;
+ /* Why is this even necessary? And undocumented? */
+ if (PyUnicode_SetDefaultEncoding(item->values[0].value.string))
+ cpy_log_exception("setting default encoding");
} else if (strcasecmp(item->key, "LogTraces") == 0) {
if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
continue;