From 89eebe98be9968c165800503971782e28a40ce00 Mon Sep 17 00:00:00 2001 From: Sven Trenkel Date: Sat, 5 Dec 2009 02:10:20 +0100 Subject: [PATCH] Added write method to Values. --- src/python.c | 7 +++- src/pyvalues.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 2 deletions(-) diff --git a/src/python.c b/src/python.c index 3b227c9b..ea25829d 100644 --- 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 32d7897e..9542a40b 100644 --- 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; @@ -407,6 +515,7 @@ static PyMemberDef Values_members[] = { 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} }; -- 2.30.2