Bumped version to 4.9.2; Updated ChangeLog.
[collectd.git] / src / pyvalues.c
index 32d7897..d83f541 100644 (file)
@@ -1,3 +1,29 @@
+/**
+ * collectd - src/pyvalues.c
+ * Copyright (C) 2009  Sven Trenkel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *   Sven Trenkel <collectd at semidefinite.de>  
+ **/
+
 #include <Python.h>
 #include <structmember.h>
 
@@ -91,7 +117,7 @@ static PyMemberDef PluginData_members[] = {
 };
 
 static PyObject *PluginData_getstring(PyObject *self, void *data) {
-       const char *value = ((char *) self) + (int) data;
+       const char *value = ((char *) self) + (intptr_t) data;
        
        return PyString_FromString(value);
 }
@@ -106,7 +132,7 @@ static int PluginData_setstring(PyObject *self, PyObject *value, void *data) {
        }
        new = PyString_AsString(value);
        if (new == NULL) return -1;
-       old = ((char *) self) + (int) data;
+       old = ((char *) self) + (intptr_t) data;
        sstrncpy(old, new, DATA_MAX_NAME_LEN);
        return 0;
 }
@@ -127,7 +153,7 @@ static int PluginData_settype(PyObject *self, PyObject *value, void *data) {
                return -1;
        }
 
-       old = ((char *) self) + (int) data;
+       old = ((char *) self) + (intptr_t) data;
        sstrncpy(old, new, DATA_MAX_NAME_LEN);
        return 0;
 }
@@ -212,6 +238,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) {
@@ -266,7 +300,7 @@ static int Values_init(PyObject *s, PyObject *args, PyObject *kwds) {
 static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
        int i, ret;
        const data_set_t *ds;
-       Py_ssize_t size;
+       int size;
        value_t *value;
        value_list_t value_list = VALUE_LIST_INIT;
        PyObject *values = self->values;
@@ -298,9 +332,9 @@ static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
                PyErr_Format(PyExc_TypeError, "values must be list or tuple");
                return NULL;
        }
-       size = PySequence_Length(values);
+       size = (int) PySequence_Length(values);
        if (size != ds->ds_num) {
-               PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %zd", type, ds->ds_num, size);
+               PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %i", type, ds->ds_num, size);
                return NULL;
        }
        value = malloc(size * sizeof(*value));
@@ -362,6 +396,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;
+       int 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 = (int) PySequence_Length(values);
+       if (size != ds->ds_num) {
+               PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %i", 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 +541,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}
 };
 
@@ -568,7 +703,7 @@ static int Notification_setstring(PyObject *self, PyObject *value, void *data) {
        }
        new = PyString_AsString(value);
        if (new == NULL) return -1;
-       old = ((char *) self) + (int) data;
+       old = ((char *) self) + (intptr_t) data;
        sstrncpy(old, new, NOTIF_MAX_MSG_LEN);
        return 0;
 }