summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 9dd3df2)
raw | patch | inline | side by side (parent: 9dd3df2)
author | Sven Trenkel <collectd@semidefinite.de> | |
Sat, 5 Dec 2009 01:10:20 +0000 (02:10 +0100) | ||
committer | Sven Trenkel <collectd@semidefinite.de> | |
Sat, 5 Dec 2009 01:10:20 +0000 (02:10 +0100) |
src/python.c | patch | blob | history | |
src/pyvalues.c | patch | blob | history |
diff --git a/src/python.c b/src/python.c
index 3b227c9bb0123e4b94ad1a954d02eaa549c7eafd..ea25829d63226d9f56f160be5f2052a530b98c25 100644 (file)
--- a/src/python.c
+++ b/src/python.c
@@ -161,8 +161,9 @@ static char reg_flush_doc[] = "register_flush(callback[, data][, name]) -> ident
"'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.";
@@ -410,6 +411,8 @@ static void cpy_log_callback(int severity, const char *message, user_data_t *dat
/* 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);
}
diff --git a/src/pyvalues.c b/src/pyvalues.c
index 32d7897ea053e688c317ca71f26c49bda4bb90ee..9542a40b07e6feae448747296e52309bcdc4c53c 100644 (file)
--- a/src/pyvalues.c
+++ b/src/pyvalues.c
@@ -212,6 +212,14 @@ static char dispatch_doc[] = "dispatch([type][, values][, plugin_instance][, typ
"If you do not submit a parameter the value saved in its member will be submitted.\n"
"If you do provide a parameter it will be used instead, without altering the member.";
+static char write_doc[] = "write([destination][, type][, values][, plugin_instance][, type_instance]"
+ "[, plugin][, host][, time][, interval]) -> None. Dispatch a value list.\n"
+ "\n"
+ "Write this instance to a single plugin or all plugins if 'destination' is obmitted.\n"
+ "This will bypass the main collectd process and all filtering and caching.\n"
+ "Other than that it works similar to 'dispatch'. In most cases 'dispatch' should be\n"
+ "used instead of 'write'.\n";
+
static char Values_doc[] = "A Values object used for dispatching values to collectd and receiving values from write callbacks.";
static PyObject *Values_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
@@ -362,6 +370,106 @@ static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
Py_RETURN_NONE;
}
+static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
+ int i, ret;
+ const data_set_t *ds;
+ Py_ssize_t size;
+ value_t *value;
+ value_list_t value_list = VALUE_LIST_INIT;
+ PyObject *values = self->values;
+ double time = self->data.time;
+ int interval = self->interval;
+ const char *host = self->data.host;
+ const char *plugin = self->data.plugin;
+ const char *plugin_instance = self->data.plugin_instance;
+ const char *type = self->data.type;
+ const char *type_instance = self->data.type_instance;
+ const char *dest = NULL;
+
+ static char *kwlist[] = {"destination", "type", "values", "plugin_instance", "type_instance",
+ "plugin", "host", "time", "interval", NULL};
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sOssssdi", kwlist,
+ &type, &values, &plugin_instance, &type_instance,
+ &plugin, &host, &time, &interval))
+ return NULL;
+
+ if (type[0] == 0) {
+ PyErr_SetString(PyExc_RuntimeError, "type not set");
+ return NULL;
+ }
+ ds = plugin_get_ds(type);
+ if (ds == NULL) {
+ PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
+ return NULL;
+ }
+ if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
+ PyErr_Format(PyExc_TypeError, "values must be list or tuple");
+ return NULL;
+ }
+ size = PySequence_Length(values);
+ if (size != ds->ds_num) {
+ PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %zd", type, ds->ds_num, size);
+ return NULL;
+ }
+ value = malloc(size * sizeof(*value));
+ for (i = 0; i < size; ++i) {
+ PyObject *item, *num;
+ item = PySequence_GetItem(values, i);
+ if (ds->ds->type == DS_TYPE_COUNTER) {
+ num = PyNumber_Long(item);
+ if (num != NULL)
+ value[i].counter = PyLong_AsUnsignedLongLong(num);
+ } else if (ds->ds->type == DS_TYPE_GAUGE) {
+ num = PyNumber_Float(item);
+ if (num != NULL)
+ value[i].gauge = PyFloat_AsDouble(num);
+ } else if (ds->ds->type == DS_TYPE_DERIVE) {
+ /* This might overflow without raising an exception.
+ * Not much we can do about it */
+ num = PyNumber_Long(item);
+ if (num != NULL)
+ value[i].derive = PyLong_AsLongLong(num);
+ } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
+ /* This might overflow without raising an exception.
+ * Not much we can do about it */
+ num = PyNumber_Long(item);
+ if (num != NULL)
+ value[i].absolute = PyLong_AsUnsignedLongLong(num);
+ } else {
+ free(value);
+ PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds->type, type);
+ return NULL;
+ }
+ if (PyErr_Occurred() != NULL) {
+ free(value);
+ return NULL;
+ }
+ }
+ value_list.values = value;
+ value_list.values_len = size;
+ value_list.time = time;
+ value_list.interval = interval;
+ sstrncpy(value_list.host, host, sizeof(value_list.host));
+ sstrncpy(value_list.plugin, plugin, sizeof(value_list.plugin));
+ sstrncpy(value_list.plugin_instance, plugin_instance, sizeof(value_list.plugin_instance));
+ sstrncpy(value_list.type, type, sizeof(value_list.type));
+ sstrncpy(value_list.type_instance, type_instance, sizeof(value_list.type_instance));
+ value_list.meta = NULL;
+ if (value_list.host[0] == 0)
+ sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
+ if (value_list.plugin[0] == 0)
+ sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
+ Py_BEGIN_ALLOW_THREADS;
+ ret = plugin_write(dest, NULL, &value_list);
+ Py_END_ALLOW_THREADS;
+ if (ret != 0) {
+ PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
+ return NULL;
+ }
+ free(value);
+ Py_RETURN_NONE;
+}
+
static PyObject *Values_repr(PyObject *s) {
PyObject *ret, *valuestring = NULL;
Values *self = (Values *) s;
static PyMethodDef Values_methods[] = {
{"dispatch", (PyCFunction) Values_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
+ {"write", (PyCFunction) Values_write, METH_VARARGS | METH_KEYWORDS, write_doc},
{NULL}
};