Added write callbacks.
authorSven Trenkel <collectd@semidefinite.de>
Tue, 3 Nov 2009 00:32:36 +0000 (01:32 +0100)
committerSven Trenkel <collectd@semidefinite.de>
Tue, 3 Nov 2009 00:32:36 +0000 (01:32 +0100)
src/cpython.h
src/python.c

index bec6cde..4cac6c5 100644 (file)
        PyGILState_STATE gil_state;\
        gil_state = PyGILState_Ensure();
 
+#define CPY_RETURN_FROM_THREADS \
+       PyGILState_Release(gil_state);\
+       return
+
 #define CPY_RELEASE_THREADS \
        PyGILState_Release(gil_state);\
 }
index c15b0d5..56061ff 100644 (file)
@@ -32,6 +32,92 @@ static void cpy_destroy_user_data(void *data) {
        free(c);
 }
 
+static void cpy_build_name(char *buf, size_t size, PyObject *callback, const char *name) {
+       const char *module;
+       PyObject *mod = NULL, *n = NULL;
+       
+       if (name != NULL && strchr(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 (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);
+}
+
+static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_list, user_data_t *data) {
+       int i;
+       cpy_callback_t * c = data->data;
+       PyObject *ret, *v, *list;
+
+       CPY_LOCK_THREADS
+               list = PyList_New(value_list->values_len); /* New reference. */
+               if (list == NULL) {
+                       PyErr_Print();
+                       CPY_RETURN_FROM_THREADS 0;
+               }
+               for (i = 0; i < value_list->values_len; ++i) {
+                       if (ds->ds->type == DS_TYPE_COUNTER) {
+                               if ((long) value_list->values[i].counter == value_list->values[i].counter)
+                                       PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].counter));
+                               else
+                                       PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].counter));
+                       } else if (ds->ds->type == DS_TYPE_GAUGE) {
+                               PyList_SetItem(list, i, PyFloat_FromDouble(value_list->values[i].gauge));
+                       } else if (ds->ds->type == DS_TYPE_DERIVE) {
+                               if ((long) value_list->values[i].derive == value_list->values[i].derive)
+                                       PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].derive));
+                               else
+                                       PyList_SetItem(list, i, PyLong_FromLongLong(value_list->values[i].derive));
+                       } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
+                               if ((long) value_list->values[i].absolute == value_list->values[i].absolute)
+                                       PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].absolute));
+                               else
+                                       PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].absolute));
+                       } else {
+                               ERROR("cpy_write_callback: Unknown value type %d.", ds->ds->type);
+                               Py_DECREF(list);
+                               CPY_RETURN_FROM_THREADS 0;
+                       }
+                       if (PyErr_Occurred() != NULL) {
+                               PyErr_Print();
+                               CPY_RETURN_FROM_THREADS 0;
+                       }
+               }
+               v = PyObject_CallFunction((PyObject *) &ValuesType, "sOssssdi", value_list->type, list,
+                               value_list->plugin_instance, value_list->type_instance, value_list->plugin,
+                               value_list->host, (double) value_list->time, value_list->interval);
+               Py_DECREF(list);
+               ret = PyObject_CallFunctionObjArgs(c->callback, v, (void *) 0);
+               if (ret == NULL) {
+                       /* FIXME */
+                       PyErr_Print();
+               } else {
+                       Py_DECREF(ret);
+               }
+       CPY_RELEASE_THREADS
+       return 0;
+}
+
 static void cpy_log_callback(int severity, const char *message, user_data_t *data) {
        cpy_callback_t * c = data->data;
        PyObject *ret;
@@ -54,7 +140,7 @@ static void cpy_log_callback(int severity, const char *message, user_data_t *dat
 static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args, PyObject *kwds) {
        cpy_callback_t *c;
        const char *name = NULL;
-       PyObject *callback = NULL, *data = NULL;
+       PyObject *callback = NULL, *data = NULL, *mod = NULL;
        static char *kwlist[] = {"callback", "data", "name", NULL};
        
        if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oz", kwlist, &callback, &data, &name) == 0) return NULL;
@@ -63,11 +149,10 @@ static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args
                return NULL;
        }
        if (name == NULL) {
-               PyObject *mod;
-               
-               mod = PyObject_GetAttrString(callback, "__module__");
+               mod = PyObject_GetAttrString(callback, "__module__"); /* New reference. */
                if (mod != NULL) name = PyString_AsString(mod);
                if (name == NULL) {
+                       Py_XDECREF(mod);
                        PyErr_SetString(PyExc_ValueError, "No module name specified and "
                                "callback function does not have a \"__module__\" attribute.");
                        return NULL;
@@ -81,6 +166,7 @@ static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args
        c->data = data;
        c->next = *list_head;
        *list_head = c;
+       Py_XDECREF(mod);
        Py_RETURN_NONE;
 }
 
@@ -92,7 +178,11 @@ static PyObject *cpy_register_init(PyObject *self, PyObject *args, PyObject *kwd
        return cpy_register_generic(&cpy_init_callbacks, args, kwds);
 }
 
-static PyObject *cpy_register_log(PyObject *self, PyObject *args, PyObject *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) {
+       char buf[512];
+       reg_function_t *register_function = (reg_function_t *) reg;
        cpy_callback_t *c = NULL;
        user_data_t *user_data = NULL;
        const char *name = NULL;
@@ -104,29 +194,28 @@ static PyObject *cpy_register_log(PyObject *self, PyObject *args, PyObject *kwds
                PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
                return NULL;
        }
-       if (name == NULL) {
-               PyObject *mod;
-               
-               mod = PyObject_GetAttrString(callback, "__module__");
-               if (mod != NULL) name = PyString_AsString(mod);
-               if (name == NULL) {
-                       PyErr_SetString(PyExc_ValueError, "No module name specified and "
-                               "callback function does not have a \"__module__\" attribute.");
-                       return NULL;
-               }
-       }
+       cpy_build_name(buf, sizeof(buf), callback, name);
+       
        Py_INCREF(callback);
        Py_XINCREF(data);
        c = malloc(sizeof(*c));
-       c->name = strdup(name);
+       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;
-       plugin_register_log(name, cpy_log_callback, user_data);
-       Py_RETURN_NONE;
+       register_function(buf, handler, user_data);
+       return PyString_FromString(buf);
+}
+
+static PyObject *cpy_register_log(PyObject *self, PyObject *args, PyObject *kwds) {
+       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);
 }
 
 static PyObject *cpy_register_shutdown(PyObject *self, PyObject *args, PyObject *kwds) {
@@ -187,6 +276,7 @@ static PyMethodDef cpy_methods[] = {
        {"register_log", (PyCFunction) cpy_register_log, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
        {"register_init", (PyCFunction) cpy_register_init, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
        {"register_config", (PyCFunction) cpy_register_config, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
+       {"register_write", (PyCFunction) cpy_register_write, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
        {"register_shutdown", (PyCFunction) cpy_register_shutdown, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
        {0, 0, 0, 0}
 };