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 "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 graphs 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. The object has 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 */
455 static char severity_doc[] = "The severity of this notification. Assign or compare to\n"
456 "NOTIF_FAILURE, NOTIF_WARNING or NOTIF_OKAY.";
458 static char message_doc[] = "Some kind of description what's going on and why this Notification was generated.";
460 static char Notification_doc[] = "The Notification class is a wrapper around the collectd notification.\n"
461 "It can be used to notify other plugins about bad stuff happening. It works\n"
462 "similar to Values but has a severity and a message instead of interval\n"
464 "Notifications can be dispatched at any time and can be received with register_notification.";
466 static int Notification_init(PyObject *s, PyObject *args, PyObject *kwds) {
467 Notification *self = (Notification *) s;
469 int severity = 0, ret;
471 const char *message = "";
472 const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
473 static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
474 "plugin", "host", "time", "severity", NULL};
476 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ssssssdi", kwlist,
477 &type, &message, &plugin_instance, &type_instance,
478 &plugin, &host, &time, &severity))
481 tmp = Py_BuildValue("sssssd", type, plugin_instance, type_instance, plugin, host, time);
484 ret = PluginDataType.tp_init(s, tmp, NULL);
489 sstrncpy(self->message, message, sizeof(self->message));
490 self->severity = severity;
494 static PyObject *Notification_dispatch(Notification *self, PyObject *args, PyObject *kwds) {
496 const data_set_t *ds;
497 notification_t notification;
498 double t = self->data.time;
499 int severity = self->severity;
500 const char *host = self->data.host;
501 const char *plugin = self->data.plugin;
502 const char *plugin_instance = self->data.plugin_instance;
503 const char *type = self->data.type;
504 const char *type_instance = self->data.type_instance;
505 const char *message = self->message;
507 static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
508 "plugin", "host", "time", "severity", NULL};
509 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ssssssdi", kwlist,
510 &type, &message, &plugin_instance, &type_instance,
511 &plugin, &host, &t, &severity))
515 PyErr_SetString(PyExc_RuntimeError, "type not set");
518 ds = plugin_get_ds(type);
520 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
524 notification.time = t;
525 notification.severity = severity;
526 sstrncpy(notification.message, message, sizeof(notification.message));
527 sstrncpy(notification.host, host, sizeof(notification.host));
528 sstrncpy(notification.plugin, plugin, sizeof(notification.plugin));
529 sstrncpy(notification.plugin_instance, plugin_instance, sizeof(notification.plugin_instance));
530 sstrncpy(notification.type, type, sizeof(notification.type));
531 sstrncpy(notification.type_instance, type_instance, sizeof(notification.type_instance));
532 notification.meta = NULL;
533 if (notification.time < 1)
534 notification.time = time(0);
535 if (notification.host[0] == 0)
536 sstrncpy(notification.host, hostname_g, sizeof(notification.host));
537 if (notification.plugin[0] == 0)
538 sstrncpy(notification.plugin, "python", sizeof(notification.plugin));
539 Py_BEGIN_ALLOW_THREADS;
540 ret = plugin_dispatch_notification(¬ification);
541 Py_END_ALLOW_THREADS;
543 PyErr_SetString(PyExc_RuntimeError, "error dispatching notification, read the logs");
549 static PyObject *Notification_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
552 self = (Notification *) PluginData_new(type, args, kwds);
556 self->message[0] = 0;
558 return (PyObject *) self;
561 static int Notification_setstring(PyObject *self, PyObject *value, void *data) {
566 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
569 new = PyString_AsString(value);
570 if (new == NULL) return -1;
571 old = ((char *) self) + (int) data;
572 sstrncpy(old, new, NOTIF_MAX_MSG_LEN);
576 static PyObject *Notification_repr(PyObject *s) {
578 Notification *self = (Notification *) s;
580 ret = PyString_FromFormat("collectd.Values(type='%s%s%s%s%s%s%s%s%s%s%s',time=%lu,interval=%i)", self->data.type,
581 *self->data.type_instance ? "',type_instance='" : "", self->data.type_instance,
582 *self->data.plugin ? "',plugin='" : "", self->data.plugin,
583 *self->data.plugin_instance ? "',plugin_instance='" : "", self->data.plugin_instance,
584 *self->data.host ? "',host='" : "", self->data.host,
585 *self->message ? "',message='" : "", self->message,
586 (long unsigned) self->data.time, self->severity);
590 static PyMethodDef Notification_methods[] = {
591 {"dispatch", (PyCFunction) Notification_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
595 static PyMemberDef Notification_members[] = {
596 {"severity", T_INT, offsetof(Notification, severity), 0, severity_doc},
600 static PyGetSetDef Notification_getseters[] = {
601 {"message", PluginData_getstring, Notification_setstring, message_doc, (void *) offsetof(Notification, message)},
605 PyTypeObject NotificationType = {
606 PyObject_HEAD_INIT(NULL)
608 "collectd.Notification", /* tp_name */
609 sizeof(Notification), /* tp_basicsize */
610 0, /* Will be filled in later */
616 Notification_repr, /* tp_repr */
617 0, /* tp_as_number */
618 0, /* tp_as_sequence */
619 0, /* tp_as_mapping */
625 0, /* tp_as_buffer */
626 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
627 Notification_doc, /* tp_doc */
630 0, /* tp_richcompare */
631 0, /* tp_weaklistoffset */
634 Notification_methods, /* tp_methods */
635 Notification_members, /* tp_members */
636 Notification_getseters, /* tp_getset */
639 0, /* tp_descr_get */
640 0, /* tp_descr_set */
641 0, /* tp_dictoffset */
642 Notification_init, /* tp_init */
644 Notification_new /* tp_new */