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;
12 self = (Values *) type->tp_alloc(type, 0);
13 if (self == NULL)
14 return NULL;
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};
36 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sOssssdi", kwlist,
37 &type, &values, &plugin_instance, &type_instance,
38 &plugin, &host, &time, &interval))
39 return -1;
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 }
53 tmp = self->values;
54 self->values = values;
55 Py_XDECREF(tmp);
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));
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;
72 if (self->values != NULL)
73 valuestring = PyObject_Repr(self->values);
74 if (valuestring == NULL)
75 return NULL;
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);
103 }
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;
116 return PyString_FromString(value);
117 }
119 static int Values_setstring(PyObject *self, PyObject *value, void *data) {
120 char *old;
121 const char *new;
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;
132 }
134 static int Values_settype(PyObject *self, PyObject *value, void *data) {
135 char *old;
136 const char *new;
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;
153 }
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;
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;
252 }
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 };