Code

Better workaround for global plugin loading.
[collectd.git] / src / pyvalues.c
1 #include <Python.h>
2 #include <structmember.h>
4 #include "collectd.h"
5 #include "common.h"
7 #include "cpython.h"
9 static PyObject *Values_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
10         Values *self;
11         
12         self = (Values *) type->tp_alloc(type, 0);
13         if (self == NULL)
14                 return NULL;
15         
16         self->values = PyList_New(0);
17         self->time = 0;
18         self->interval = 0;
19         self->host[0] = 0;
20         self->plugin[0] = 0;
21         self->plugin_instance[0] = 0;
22         self->type[0] = 0;
23         self->type_instance[0] = 0;
24         return (PyObject *) self;
25 }
27 static int Values_init(PyObject *s, PyObject *args, PyObject *kwds) {
28         Values *self = (Values *) s;
29         int interval = 0;
30         double time = 0;
31         PyObject *values = NULL, *tmp;
32         const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
33         static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
34                         "plugin", "host", "time", "interval", NULL};
35         
36         if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sOssssdi", kwlist,
37                         &type, &values, &plugin_instance, &type_instance,
38                         &plugin, &host, &time, &interval))
39                 return -1;
40         
41         if (type[0] != 0 && plugin_get_ds(type) == NULL) {
42                 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
43                 return -1;
44         }
46         if (values == NULL) {
47                 values = PyList_New(0);
48                 PyErr_Clear();
49         } else {
50                 Py_INCREF(values);
51         }
52         
53         tmp = self->values;
54         self->values = values;
55         Py_XDECREF(tmp);
56         
57         sstrncpy(self->host, host, sizeof(self->host));
58         sstrncpy(self->plugin, plugin, sizeof(self->plugin));
59         sstrncpy(self->plugin_instance, plugin_instance, sizeof(self->plugin_instance));
60         sstrncpy(self->type, type, sizeof(self->type));
61         sstrncpy(self->type_instance, type_instance, sizeof(self->type_instance));
62         
63         self->time = time;
64         self->interval = interval;
65         return 0;
66 }
68 static PyObject *Values_repr(PyObject *s) {
69         PyObject *ret, *valuestring = NULL;
70         Values *self = (Values *) s;
71         
72         if (self->values != NULL)
73                 valuestring = PyObject_Repr(self->values);
74         if (valuestring == NULL)
75                 return NULL;
76         
77         ret = PyString_FromFormat("collectd.Values(type='%s%s%s%s%s%s%s%s%s',time=%lu,interval=%i,values=%s)", self->type,
78                         *self->type_instance ? "',type_instance='" : "", self->type_instance,
79                         *self->plugin ? "',plugin='" : "", self->plugin,
80                         *self->plugin_instance ? "',plugin_instance='" : "", self->plugin_instance,
81                         *self->host ? "',host='" : "", self->host,
82                         (long unsigned) self->time, self->interval,
83                         valuestring ? PyString_AsString(valuestring) : "[]");
84         Py_XDECREF(valuestring);
85         return ret;
86 }
88 static int Values_traverse(PyObject *self, visitproc visit, void *arg) {
89         Values *v = (Values *) self;
90         Py_VISIT(v->values);
91         return 0;
92 }
94 static int Values_clear(PyObject *self) {
95         Values *v = (Values *) self;
96         Py_CLEAR(v->values);
97         return 0;
98 }
100 static void Values_dealloc(PyObject *self) {
101         Values_clear(self);
102         self->ob_type->tp_free(self);
105 static PyMemberDef Values_members[] = {
106         {"time", T_DOUBLE, offsetof(Values, time), 0, "Parent node"},
107         {"interval", T_INT, offsetof(Values, interval), 0, "Keyword of this node"},
108         {"values", T_OBJECT_EX, offsetof(Values, values), 0, "Values after the key"},
109 //      {"Children", T_OBJECT_EX, offsetof(Config, children), 0, "Childnodes of this node"},
110         {NULL}
111 };
113 static PyObject *Values_getstring(PyObject *self, void *data) {
114         const char *value = ((char *) self) + (int) data;
115         
116         return PyString_FromString(value);
119 static int Values_setstring(PyObject *self, PyObject *value, void *data) {
120         char *old;
121         const char *new;
122         
123         if (value == NULL) {
124                 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
125                 return -1;
126         }
127         new = PyString_AsString(value);
128         if (new == NULL) return -1;
129         old = ((char *) self) + (int) data;
130         sstrncpy(old, new, DATA_MAX_NAME_LEN);
131         return 0;
134 static int Values_settype(PyObject *self, PyObject *value, void *data) {
135         char *old;
136         const char *new;
137         
138         if (value == NULL) {
139                 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
140                 return -1;
141         }
142         new = PyString_AsString(value);
143         if (new == NULL) return -1;
145         if (plugin_get_ds(new) == NULL) {
146                 PyErr_Format(PyExc_TypeError, "Dataset %s not found", new);
147                 return -1;
148         }
150         old = ((char *) self) + (int) data;
151         sstrncpy(old, new, DATA_MAX_NAME_LEN);
152         return 0;
155 static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
156         int i, ret;
157         const data_set_t *ds;
158         Py_ssize_t size;
159         value_t *value;
160         value_list_t value_list = VALUE_LIST_INIT;
161         PyObject *values = self->values;
162         double time = self->time;
163         int interval = self->interval;
164         const char *host = self->host;
165         const char *plugin = self->plugin;
166         const char *plugin_instance = self->plugin_instance;
167         const char *type = self->type;
168         const char *type_instance = self->type_instance;
169         
170         static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
171                         "plugin", "host", "time", "interval", NULL};
172         if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sOssssdi", kwlist,
173                         &type, &values, &plugin_instance, &type_instance,
174                         &plugin, &host, &time, &interval))
175                 return NULL;
177         if (type[0] == 0) {
178                 PyErr_SetString(PyExc_RuntimeError, "type not set");
179                 return NULL;
180         }
181         ds = plugin_get_ds(type);
182         if (ds == NULL) {
183                 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
184                 return NULL;
185         }
186         if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
187                 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
188                 return NULL;
189         }
190         size = PySequence_Length(values);
191         if (size != ds->ds_num) {
192                 PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %zd", type, ds->ds_num, size);
193                 return NULL;
194         }
195         value = malloc(size * sizeof(*value));
196         for (i = 0; i < size; ++i) {
197                 PyObject *item, *num;
198                 item = PySequence_GetItem(values, i);
199                 if (ds->ds->type == DS_TYPE_COUNTER) {
200                         num = PyNumber_Long(item);
201                         if (num != NULL)
202                                 value[i].counter = PyLong_AsUnsignedLongLong(num);
203                 } else if (ds->ds->type == DS_TYPE_GAUGE) {
204                         num = PyNumber_Float(item);
205                         if (num != NULL)
206                                 value[i].gauge = PyFloat_AsDouble(num);
207                 } else if (ds->ds->type == DS_TYPE_DERIVE) {
208                         /* This might overflow without raising an exception.
209                          * Not much we can do about it */
210                         num = PyNumber_Long(item);
211                         if (num != NULL)
212                                 value[i].derive = PyLong_AsLongLong(num);
213                 } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
214                         /* This might overflow without raising an exception.
215                          * Not much we can do about it */
216                         num = PyNumber_Long(item);
217                         if (num != NULL)
218                                 value[i].absolute = PyLong_AsUnsignedLongLong(num);
219                 } else {
220                         free(value);
221                         PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds->type, type);
222                         return NULL;
223                 }
224                 if (PyErr_Occurred() != NULL) {
225                         free(value);
226                         return NULL;
227                 }
228         }
229         value_list.values = value;
230         value_list.values_len = size;
231         value_list.time = time;
232         value_list.interval = interval;
233         sstrncpy(value_list.host, host, sizeof(value_list.host));
234         sstrncpy(value_list.plugin, plugin, sizeof(value_list.plugin));
235         sstrncpy(value_list.plugin_instance, plugin_instance, sizeof(value_list.plugin_instance));
236         sstrncpy(value_list.type, type, sizeof(value_list.type));
237         sstrncpy(value_list.type_instance, type_instance, sizeof(value_list.type_instance));
238         value_list.meta = NULL;
239         if (value_list.host[0] == 0)
240                 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
241         if (value_list.plugin[0] == 0)
242                 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
243         Py_BEGIN_ALLOW_THREADS;
244         ret = plugin_dispatch_values(&value_list);
245         Py_END_ALLOW_THREADS;
246         if (ret != 0) {
247                 PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
248                 return NULL;
249         }
250         free(value);
251         Py_RETURN_NONE;
254 static PyGetSetDef Values_getseters[] = {
255         {"host", Values_getstring, Values_setstring, "help text", (void *) offsetof(Values, host)},
256         {"plugin", Values_getstring, Values_setstring, "help text", (void *) offsetof(Values, plugin)},
257         {"plugin_instance", Values_getstring, Values_setstring, "help text", (void *) offsetof(Values, plugin_instance)},
258         {"type_instance", Values_getstring, Values_setstring, "help text", (void *) offsetof(Values, type_instance)},
259         {"type", Values_getstring, Values_settype, "help text", (void *) offsetof(Values, type)},
260         {NULL}
261 };
263 static PyMethodDef Values_methods[] = {
264         {"dispatch", (PyCFunction) Values_dispatch, METH_VARARGS | METH_KEYWORDS, "help text"},
265         {NULL}
266 };
268 PyTypeObject ValuesType = {
269         PyObject_HEAD_INIT(NULL)
270         0,                         /* Always 0 */
271         "collectd.Values",         /* tp_name */
272         sizeof(Values),            /* tp_basicsize */
273         0,                         /* Will be filled in later */
274         Values_dealloc,            /* tp_dealloc */
275         0,                         /* tp_print */
276         0,                         /* tp_getattr */
277         0,                         /* tp_setattr */
278         0,                         /* tp_compare */
279         Values_repr,               /* tp_repr */
280         0,                         /* tp_as_number */
281         0,                         /* tp_as_sequence */
282         0,                         /* tp_as_mapping */
283         0,                         /* tp_hash */
284         0,                         /* tp_call */
285         0,                         /* tp_str */
286         0,                         /* tp_getattro */
287         0,                         /* tp_setattro */
288         0,                         /* tp_as_buffer */
289         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
290         "Cool help text later",    /* tp_doc */
291         Values_traverse,           /* tp_traverse */
292         Values_clear,              /* tp_clear */
293         0,                         /* tp_richcompare */
294         0,                         /* tp_weaklistoffset */
295         0,                         /* tp_iter */
296         0,                         /* tp_iternext */
297         Values_methods,            /* tp_methods */
298         Values_members,            /* tp_members */
299         Values_getseters,          /* tp_getset */
300         0,                         /* tp_base */
301         0,                         /* tp_dict */
302         0,                         /* tp_descr_get */
303         0,                         /* tp_descr_set */
304         0,                         /* tp_dictoffset */
305         Values_init,               /* tp_init */
306         0,                         /* tp_alloc */
307         Values_new                 /* tp_new */
308 };