diff --git a/src/python.c b/src/python.c
index 10ac8f0d149f815fa9d00e54bdda3e0123246029..c7524143424aecbb87fa3c037eabb9f8fee5016a 100644 (file)
--- a/src/python.c
+++ b/src/python.c
static char log_doc[] = "This function sends a string to all logging plugins.";
+static char get_ds_doc[] = "get_dataset(name) -> definition\n"
+ "\n"
+ "Returns the definition of a dataset specified by name.\n"
+ "\n"
+ "'name' is a string specifying the dataset to query.\n"
+ "'definition' is a list of 4-tuples. Every tuple represents a \n"
+ " data source within the data set and its 4 values are the \n"
+ " name, type, min and max value.\n"
+ " 'name' is a string.\n"
+ " 'type' is a string that is equal to either DS_TYPE_COUNTER,\n"
+ " DS_TYPE_GAUGE, DS_TYPE_DERIVE or DS_TYPE_ABSOLUTE.\n"
+ " 'min' and 'max' are either a float or None.";
+
static char flush_doc[] = "flush([plugin][, timeout][, identifier]) -> None\n"
"\n"
"Flushes the cache of another plugin.";
Py_XDECREF(traceback);
return;
}
- list = PyObject_CallFunction(cpy_format_exception, "NNN", type, value, traceback); /* New reference. */
+ list = PyObject_CallFunction(cpy_format_exception, "NNN", type, value, traceback); /* New reference. Steals references from "type", "value" and "traceback". */
if (list)
l = PyObject_Length(list);
+
for (i = 0; i < l; ++i) {
- char *s;
PyObject *line;
-
+ char const *msg;
+ char *cpy;
+
line = PyList_GET_ITEM(list, i); /* Borrowed reference. */
Py_INCREF(line);
- s = strdup(cpy_unicode_or_bytes_to_string(&line));
+
+ msg = cpy_unicode_or_bytes_to_string(&line);
Py_DECREF(line);
- if (s[strlen(s) - 1] == '\n')
- s[strlen(s) - 1] = 0;
+ if (msg == NULL)
+ continue;
+
+ cpy = strdup(msg);
+ if (cpy == NULL)
+ continue;
+
+ if (cpy[strlen(cpy) - 1] == '\n')
+ cpy[strlen(cpy) - 1] = 0;
+
Py_BEGIN_ALLOW_THREADS
- ERROR("%s", s);
+ ERROR("%s", cpy);
Py_END_ALLOW_THREADS
- free(s);
+
+ free(cpy);
}
+
Py_XDECREF(list);
PyErr_Clear();
- Py_DECREF(type);
- Py_XDECREF(value);
- Py_XDECREF(traceback);
}
static int cpy_read_callback(user_data_t *data) {
@@ -376,7 +399,7 @@ static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_li
}
dict = PyDict_New(); /* New reference. */
if (value_list->meta) {
- int i, num;
+ int num;
char **table;
meta_data_t *meta = value_list->meta;
@@ -537,7 +560,12 @@ static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args
Py_INCREF(callback);
Py_XINCREF(data);
+
c = malloc(sizeof(*c));
+ if (c == NULL)
+ return NULL;
+ memset (c, 0, sizeof (*c));
+
c->name = strdup(buf);
c->callback = callback;
c->data = data;
@@ -548,7 +576,39 @@ static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args
return cpy_string_to_unicode_or_bytes(buf);
}
-static PyObject *cpy_flush(cpy_callback_t **list_head, PyObject *args, PyObject *kwds) {
+static PyObject *float_or_none(float number) {
+ if (isnan(number)) {
+ Py_RETURN_NONE;
+ }
+ return PyFloat_FromDouble(number);
+}
+
+static PyObject *cpy_get_dataset(PyObject *self, PyObject *args) {
+ int i;
+ char *name;
+ const data_set_t *ds;
+ PyObject *list, *tuple;
+
+ if (PyArg_ParseTuple(args, "et", NULL, &name) == 0) return NULL;
+ ds = plugin_get_ds(name);
+ PyMem_Free(name);
+ if (ds == NULL) {
+ PyErr_Format(PyExc_TypeError, "Dataset %s not found", name);
+ return NULL;
+ }
+ list = PyList_New(ds->ds_num); /* New reference. */
+ for (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, 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);
+ }
+ return list;
+}
+
+static PyObject *cpy_flush(PyObject *self, PyObject *args, PyObject *kwds) {
int timeout = -1;
char *plugin = NULL, *identifier = NULL;
static char *kwlist[] = {"plugin", "timeout", "identifier", NULL};
@@ -576,7 +636,7 @@ static PyObject *cpy_register_generic_userdata(void *reg, void *handler, PyObjec
char buf[512];
reg_function_t *register_function = (reg_function_t *) reg;
cpy_callback_t *c = NULL;
- user_data_t *user_data = NULL;
+ user_data_t user_data;
char *name = NULL;
PyObject *callback = NULL, *data = NULL;
static char *kwlist[] = {"callback", "data", "name", NULL};
@@ -592,22 +652,29 @@ static PyObject *cpy_register_generic_userdata(void *reg, void *handler, PyObjec
Py_INCREF(callback);
Py_XINCREF(data);
+
c = malloc(sizeof(*c));
+ if (c == NULL)
+ return NULL;
+ memset (c, 0, sizeof (*c));
+
c->name = strdup(buf);
c->callback = callback;
c->data = data;
c->next = NULL;
- user_data = malloc(sizeof(*user_data));
- user_data->free_func = cpy_destroy_user_data;
- user_data->data = c;
- register_function(buf, handler, user_data);
+
+ memset (&user_data, 0, sizeof (user_data));
+ user_data.free_func = cpy_destroy_user_data;
+ user_data.data = c;
+
+ register_function(buf, handler, &user_data);
return cpy_string_to_unicode_or_bytes(buf);
}
static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwds) {
char buf[512];
cpy_callback_t *c = NULL;
- user_data_t *user_data = NULL;
+ user_data_t user_data;
double interval = 0;
char *name = NULL;
PyObject *callback = NULL, *data = NULL;
@@ -625,18 +692,26 @@ static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwd
Py_INCREF(callback);
Py_XINCREF(data);
+
c = malloc(sizeof(*c));
+ if (c == NULL)
+ return NULL;
+ memset (c, 0, sizeof (*c));
+
c->name = strdup(buf);
c->callback = callback;
c->data = data;
c->next = NULL;
- user_data = malloc(sizeof(*user_data));
- user_data->free_func = cpy_destroy_user_data;
- user_data->data = c;
+
+ memset (&user_data, 0, sizeof (user_data));
+ user_data.free_func = cpy_destroy_user_data;
+ user_data.data = c;
+
ts.tv_sec = interval;
ts.tv_nsec = (interval - ts.tv_sec) * 1000000000;
- plugin_register_complex_read(/* group = */ NULL, buf,
- cpy_read_callback, &ts, user_data);
+ plugin_register_complex_read(/* group = */ "python", buf,
+ cpy_read_callback, &ts, &user_data);
+
return cpy_string_to_unicode_or_bytes(buf);
}
@@ -736,7 +811,7 @@ static PyObject *cpy_unregister_generic(cpy_callback_t **list_head, PyObject *ar
for (tmp = *list_head; tmp; prev = tmp, tmp = tmp->next)
if (strcmp(name, tmp->name) == 0)
break;
-
+
Py_DECREF(arg);
if (tmp == NULL) {
PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
{"notice", cpy_notice, METH_VARARGS, log_doc},
{"warning", cpy_warning, METH_VARARGS, log_doc},
{"error", cpy_error, METH_VARARGS, log_doc},
+ {"get_dataset", (PyCFunction) cpy_get_dataset, METH_VARARGS, get_ds_doc},
{"flush", (PyCFunction) cpy_flush, METH_VARARGS | METH_KEYWORDS, flush_doc},
{"register_log", (PyCFunction) cpy_register_log, METH_VARARGS | METH_KEYWORDS, reg_log_doc},
{"register_init", (PyCFunction) cpy_register_init, METH_VARARGS | METH_KEYWORDS, reg_init_doc},
}
#endif
-static int cpy_init_python() {
- char *argv = "";
+static int cpy_init_python(void) {
PyObject *sys;
PyObject *module;
#ifdef IS_PY3K
+ wchar_t *argv = L"";
/* Add a builtin module, before Py_Initialize */
PyImport_AppendInittab("collectd", PyInit_collectd);
+#else
+ char *argv = "";
#endif
Py_Initialize();
PyModule_AddIntConstant(module, "NOTIF_FAILURE", NOTIF_FAILURE);
PyModule_AddIntConstant(module, "NOTIF_WARNING", NOTIF_WARNING);
PyModule_AddIntConstant(module, "NOTIF_OKAY", NOTIF_OKAY);
+ PyModule_AddStringConstant(module, "DS_TYPE_COUNTER", DS_TYPE_TO_STRING(DS_TYPE_COUNTER));
+ PyModule_AddStringConstant(module, "DS_TYPE_GAUGE", DS_TYPE_TO_STRING(DS_TYPE_GAUGE));
+ PyModule_AddStringConstant(module, "DS_TYPE_DERIVE", DS_TYPE_TO_STRING(DS_TYPE_DERIVE));
+ PyModule_AddStringConstant(module, "DS_TYPE_ABSOLUTE", DS_TYPE_TO_STRING(DS_TYPE_ABSOLUTE));
return 0;
}
} else if (strcasecmp(item->key, "Encoding") == 0) {
if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_STRING)
continue;
+#ifdef IS_PY3K
+ NOTICE("python: \"Encoding\" was used in the config file but Python3 was used, which does not support changing encodings. Ignoring this.");
+#else
/* Why is this even necessary? And undocumented? */
if (PyUnicode_SetDefaultEncoding(item->values[0].value.string))
cpy_log_exception("setting default encoding");
+#endif
} else if (strcasecmp(item->key, "LogTraces") == 0) {
if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
continue;
cpy_log_exception("python initialization");
continue;
}
- if (PyList_Append(sys_path, dir_object) != 0) {
- ERROR("python plugin: Unable to append \"%s\" to "
+ if (PyList_Insert(sys_path, 0, dir_object) != 0) {
+ ERROR("python plugin: Unable to prepend \"%s\" to "
"python module path.", dir);
cpy_log_exception("python initialization");
}