2 #include <structmember.h>
9 static char time_doc[] = "This is the Unix timestap of the time this value was read.\n"
10 "For dispatching values this can be set to 0 which means \"now\".\n"
11 "This means the time the value is actually dispatched, not the time\n"
14 static char host_doc[] = "The hostname of the host this value was read from.\n"
15 "For dispatching this can be set to an empty string which means\n"
16 "the local hostname as defined in the collectd.conf.";
18 static char type_doc[] = "The type of this value. This type has to be defined\n"
19 "in your types.db. Attempting to set it to any other value will\n"
20 "raise a TypeError exception.\n"
21 "Assigning a type is mandetory, calling dispatch without doing\n"
22 "so will raise a RuntimeError exception.";
24 static char type_instance_doc[] = "";
26 static char plugin_doc[] = "The name of the plugin that read the data. Setting this\n"
27 "member to an empty string will insert \"python\" upon dispatching.";
29 static char plugin_instance_doc[] = "";
31 static char PluginData_doc[] = "This is an internal class that is the base for Values\n"
32 "and Notification. It is pretty useless by itself and was therefore not\n"
33 "not exported to the collectd module.";
35 static PyObject *PluginData_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
38 self = (PluginData *) type->tp_alloc(type, 0);
45 self->plugin_instance[0] = 0;
47 self->type_instance[0] = 0;
48 return (PyObject *) self;
51 static int PluginData_init(PyObject *s, PyObject *args, PyObject *kwds) {
52 PluginData *self = (PluginData *) s;
54 const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
55 static char *kwlist[] = {"type", "plugin_instance", "type_instance",
56 "plugin", "host", "time", NULL};
58 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sssssd", kwlist, &type,
59 &plugin_instance, &type_instance, &plugin, &host, &time))
62 if (type[0] != 0 && plugin_get_ds(type) == NULL) {
63 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
67 sstrncpy(self->host, host, sizeof(self->host));
68 sstrncpy(self->plugin, plugin, sizeof(self->plugin));
69 sstrncpy(self->plugin_instance, plugin_instance, sizeof(self->plugin_instance));
70 sstrncpy(self->type, type, sizeof(self->type));
71 sstrncpy(self->type_instance, type_instance, sizeof(self->type_instance));
77 static PyObject *PluginData_repr(PyObject *s) {
78 PluginData *self = (PluginData *) s;
80 return PyString_FromFormat("collectd.Values(type='%s%s%s%s%s%s%s%s%s',time=%lu)", self->type,
81 *self->type_instance ? "',type_instance='" : "", self->type_instance,
82 *self->plugin ? "',plugin='" : "", self->plugin,
83 *self->plugin_instance ? "',plugin_instance='" : "", self->plugin_instance,
84 *self->host ? "',host='" : "", self->host,
85 (long unsigned) self->time);
88 static PyMemberDef PluginData_members[] = {
89 {"time", T_DOUBLE, offsetof(PluginData, time), 0, time_doc},
93 static PyObject *PluginData_getstring(PyObject *self, void *data) {
94 const char *value = ((char *) self) + (int) data;
96 return PyString_FromString(value);
99 static int PluginData_setstring(PyObject *self, PyObject *value, void *data) {
104 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
107 new = PyString_AsString(value);
108 if (new == NULL) return -1;
109 old = ((char *) self) + (int) data;
110 sstrncpy(old, new, DATA_MAX_NAME_LEN);
114 static int PluginData_settype(PyObject *self, PyObject *value, void *data) {
119 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
122 new = PyString_AsString(value);
123 if (new == NULL) return -1;
125 if (plugin_get_ds(new) == NULL) {
126 PyErr_Format(PyExc_TypeError, "Dataset %s not found", new);
130 old = ((char *) self) + (int) data;
131 sstrncpy(old, new, DATA_MAX_NAME_LEN);
135 static PyGetSetDef PluginData_getseters[] = {
136 {"host", PluginData_getstring, PluginData_setstring, host_doc, (void *) offsetof(PluginData, host)},
137 {"plugin", PluginData_getstring, PluginData_setstring, plugin_doc, (void *) offsetof(PluginData, plugin)},
138 {"plugin_instance", PluginData_getstring, PluginData_setstring, plugin_instance_doc, (void *) offsetof(PluginData, plugin_instance)},
139 {"type_instance", PluginData_getstring, PluginData_setstring, type_instance_doc, (void *) offsetof(PluginData, type_instance)},
140 {"type", PluginData_getstring, PluginData_settype, type_doc, (void *) offsetof(PluginData, type)},
144 PyTypeObject PluginDataType = {
145 PyObject_HEAD_INIT(NULL)
147 "collectd.PluginData", /* tp_name */
148 sizeof(PluginData), /* tp_basicsize */
149 0, /* Will be filled in later */
155 PluginData_repr, /* tp_repr */
156 0, /* tp_as_number */
157 0, /* tp_as_sequence */
158 0, /* tp_as_mapping */
164 0, /* tp_as_buffer */
165 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE /*| Py_TPFLAGS_HAVE_GC*/, /*tp_flags*/
166 PluginData_doc , /* tp_doc */
169 0, /* tp_richcompare */
170 0, /* tp_weaklistoffset */
174 PluginData_members, /* tp_members */
175 PluginData_getseters, /* tp_getset */
178 0, /* tp_descr_get */
179 0, /* tp_descr_set */
180 0, /* tp_dictoffset */
181 PluginData_init, /* tp_init */
183 PluginData_new /* tp_new */
186 static char interval_doc[] = "The interval is the timespan in seconds between two submits for\n"
187 "the same data source. This value has to be a positive integer, so you can't\n"
188 "submit more than one value per second. If this member is set to a\n"
189 "non-positive value, the default value as specified in the config file will\n"
190 "be used (default: 10).\n"
192 "If you submit values more often than the specified interval, the average\n"
193 "will be used. If you submit less values, your graphes will have gaps.";
195 static char values_doc[] = "These are the actual values that get dispatched to collectd.\n"
196 "It has to be a sequence (a tuple or list) of numbers.\n"
197 "The size of the sequence and the type of its content depend on the type\n"
198 "member your types.db file. For more information on this read the types.db\n"
201 "If the sequence does not have the correct size upon dispatch a RuntimeError\n"
202 "exception will be raised. If the content of the sequence is not a number,\n"
203 "a TypeError exception will be raised.";
205 static char dispatch_doc[] = "dispatch([type][, values][, plugin_instance][, type_instance]"
206 "[, plugin][, host][, time][, interval]) -> None. Dispatch a value list.\n"
208 "Dispatch this instance to the collectd process. A values object a members\n"
209 "for each of the possible arguments for this method. For a detailed explanation\n"
210 "of these parameters see the member of the same same.\n"
212 "If you do not submit a parameter the value saved in its member will be submitted.\n"
213 "If you do provide a parameter it will be used instead, without altering the member.";
215 static char Values_doc[] = "A Values object used for dispatching values to collectd and receiving values from write callbacks.";
217 static PyObject *Values_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
220 self = (Values *) PluginData_new(type, args, kwds);
224 self->values = PyList_New(0);
226 return (PyObject *) self;
229 static int Values_init(PyObject *s, PyObject *args, PyObject *kwds) {
230 Values *self = (Values *) s;
231 int interval = 0, ret;
233 PyObject *values = NULL, *tmp;
234 const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
235 static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
236 "plugin", "host", "time", "interval", NULL};
238 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sOssssdi", kwlist,
239 &type, &values, &plugin_instance, &type_instance,
240 &plugin, &host, &time, &interval))
243 tmp = Py_BuildValue("sssssd", type, plugin_instance, type_instance, plugin, host, time);
246 ret = PluginDataType.tp_init(s, tmp, NULL);
251 if (values == NULL) {
252 values = PyList_New(0);
259 self->values = values;
262 self->interval = interval;
266 static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
268 const data_set_t *ds;
271 value_list_t value_list = VALUE_LIST_INIT;
272 PyObject *values = self->values;
273 double time = self->data.time;
274 int interval = self->interval;
275 const char *host = self->data.host;
276 const char *plugin = self->data.plugin;
277 const char *plugin_instance = self->data.plugin_instance;
278 const char *type = self->data.type;
279 const char *type_instance = self->data.type_instance;
281 static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
282 "plugin", "host", "time", "interval", NULL};
283 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sOssssdi", kwlist,
284 &type, &values, &plugin_instance, &type_instance,
285 &plugin, &host, &time, &interval))
289 PyErr_SetString(PyExc_RuntimeError, "type not set");
292 ds = plugin_get_ds(type);
294 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
297 if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
298 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
301 size = PySequence_Length(values);
302 if (size != ds->ds_num) {
303 PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %zd", type, ds->ds_num, size);
306 value = malloc(size * sizeof(*value));
307 for (i = 0; i < size; ++i) {
308 PyObject *item, *num;
309 item = PySequence_GetItem(values, i);
310 if (ds->ds->type == DS_TYPE_COUNTER) {
311 num = PyNumber_Long(item);
313 value[i].counter = PyLong_AsUnsignedLongLong(num);
314 } else if (ds->ds->type == DS_TYPE_GAUGE) {
315 num = PyNumber_Float(item);
317 value[i].gauge = PyFloat_AsDouble(num);
318 } else if (ds->ds->type == DS_TYPE_DERIVE) {
319 /* This might overflow without raising an exception.
320 * Not much we can do about it */
321 num = PyNumber_Long(item);
323 value[i].derive = PyLong_AsLongLong(num);
324 } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
325 /* This might overflow without raising an exception.
326 * Not much we can do about it */
327 num = PyNumber_Long(item);
329 value[i].absolute = PyLong_AsUnsignedLongLong(num);
332 PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds->type, type);
335 if (PyErr_Occurred() != NULL) {
340 value_list.values = value;
341 value_list.values_len = size;
342 value_list.time = time;
343 value_list.interval = interval;
344 sstrncpy(value_list.host, host, sizeof(value_list.host));
345 sstrncpy(value_list.plugin, plugin, sizeof(value_list.plugin));
346 sstrncpy(value_list.plugin_instance, plugin_instance, sizeof(value_list.plugin_instance));
347 sstrncpy(value_list.type, type, sizeof(value_list.type));
348 sstrncpy(value_list.type_instance, type_instance, sizeof(value_list.type_instance));
349 value_list.meta = NULL;
350 if (value_list.host[0] == 0)
351 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
352 if (value_list.plugin[0] == 0)
353 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
354 Py_BEGIN_ALLOW_THREADS;
355 ret = plugin_dispatch_values(&value_list);
356 Py_END_ALLOW_THREADS;
358 PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
365 static PyObject *Values_repr(PyObject *s) {
366 PyObject *ret, *valuestring = NULL;
367 Values *self = (Values *) s;
369 if (self->values != NULL)
370 valuestring = PyObject_Repr(self->values);
371 if (valuestring == NULL)
374 ret = PyString_FromFormat("collectd.Values(type='%s%s%s%s%s%s%s%s%s',time=%lu,interval=%i,values=%s)", self->data.type,
375 *self->data.type_instance ? "',type_instance='" : "", self->data.type_instance,
376 *self->data.plugin ? "',plugin='" : "", self->data.plugin,
377 *self->data.plugin_instance ? "',plugin_instance='" : "", self->data.plugin_instance,
378 *self->data.host ? "',host='" : "", self->data.host,
379 (long unsigned) self->data.time, self->interval,
380 valuestring ? PyString_AsString(valuestring) : "[]");
381 Py_XDECREF(valuestring);
385 static int Values_traverse(PyObject *self, visitproc visit, void *arg) {
386 Values *v = (Values *) self;
391 static int Values_clear(PyObject *self) {
392 Values *v = (Values *) self;
397 static void Values_dealloc(PyObject *self) {
399 self->ob_type->tp_free(self);
402 static PyMemberDef Values_members[] = {
403 {"interval", T_INT, offsetof(Values, interval), 0, interval_doc},
404 {"values", T_OBJECT_EX, offsetof(Values, values), 0, values_doc},
408 static PyMethodDef Values_methods[] = {
409 {"dispatch", (PyCFunction) Values_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
413 PyTypeObject ValuesType = {
414 PyObject_HEAD_INIT(NULL)
416 "collectd.Values", /* tp_name */
417 sizeof(Values), /* tp_basicsize */
418 0, /* Will be filled in later */
419 Values_dealloc, /* tp_dealloc */
424 Values_repr, /* tp_repr */
425 0, /* tp_as_number */
426 0, /* tp_as_sequence */
427 0, /* tp_as_mapping */
433 0, /* tp_as_buffer */
434 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
435 Values_doc, /* tp_doc */
436 Values_traverse, /* tp_traverse */
437 Values_clear, /* tp_clear */
438 0, /* tp_richcompare */
439 0, /* tp_weaklistoffset */
442 Values_methods, /* tp_methods */
443 Values_members, /* tp_members */
447 0, /* tp_descr_get */
448 0, /* tp_descr_set */
449 0, /* tp_dictoffset */
450 Values_init, /* tp_init */
452 Values_new /* tp_new */