2 * collectd - src/pyvalues.c
3 * Copyright (C) 2009 Sven Trenkel
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
24 * Sven Trenkel <collectd at semidefinite.de>
28 #include <structmember.h>
35 static PyObject *cpy_common_repr(PyObject *s) {
37 static PyObject *l_type = NULL, *l_type_instance = NULL, *l_plugin = NULL, *l_plugin_instance = NULL;
38 static PyObject *l_host = NULL, *l_time = NULL;
39 PluginData *self = (PluginData *) s;
42 l_type = cpy_string_to_unicode_or_bytes("(type=");
43 if (l_type_instance == NULL)
44 l_type_instance = cpy_string_to_unicode_or_bytes(",type_instance=");
46 l_plugin = cpy_string_to_unicode_or_bytes(",plugin=");
47 if (l_plugin_instance == NULL)
48 l_plugin_instance = cpy_string_to_unicode_or_bytes(",plugin_instance=");
50 l_host = cpy_string_to_unicode_or_bytes(",host=");
52 l_time = cpy_string_to_unicode_or_bytes(",time=");
54 if (!l_type || !l_type_instance || !l_plugin || !l_plugin_instance || !l_host || !l_time)
57 ret = cpy_string_to_unicode_or_bytes(s->ob_type->tp_name);
59 CPY_STRCAT(&ret, l_type);
60 tmp = cpy_string_to_unicode_or_bytes(self->type);
61 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
62 CPY_STRCAT_AND_DEL(&ret, tmp);
64 if (self->type_instance[0] != 0) {
65 CPY_STRCAT(&ret, l_type_instance);
66 tmp = cpy_string_to_unicode_or_bytes(self->type_instance);
67 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
68 CPY_STRCAT_AND_DEL(&ret, tmp);
71 if (self->plugin[0] != 0) {
72 CPY_STRCAT(&ret, l_plugin);
73 tmp = cpy_string_to_unicode_or_bytes(self->plugin);
74 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
75 CPY_STRCAT_AND_DEL(&ret, tmp);
78 if (self->plugin_instance[0] != 0) {
79 CPY_STRCAT(&ret, l_plugin_instance);
80 tmp = cpy_string_to_unicode_or_bytes(self->plugin_instance);
81 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
82 CPY_STRCAT_AND_DEL(&ret, tmp);
85 if (self->host[0] != 0) {
86 CPY_STRCAT(&ret, l_host);
87 tmp = cpy_string_to_unicode_or_bytes(self->host);
88 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
89 CPY_STRCAT_AND_DEL(&ret, tmp);
92 if (self->time != 0) {
93 CPY_STRCAT(&ret, l_time);
94 tmp = PyInt_FromLong(self->time);
95 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
96 CPY_STRCAT_AND_DEL(&ret, tmp);
101 static char time_doc[] = "This is the Unix timestap of the time this value was read.\n"
102 "For dispatching values this can be set to 0 which means \"now\".\n"
103 "This means the time the value is actually dispatched, not the time\n"
106 static char host_doc[] = "The hostname of the host this value was read from.\n"
107 "For dispatching this can be set to an empty string which means\n"
108 "the local hostname as defined in the collectd.conf.";
110 static char type_doc[] = "The type of this value. This type has to be defined\n"
111 "in your types.db. Attempting to set it to any other value will\n"
112 "raise a TypeError exception.\n"
113 "Assigning a type is mandetory, calling dispatch without doing\n"
114 "so will raise a RuntimeError exception.";
116 static char type_instance_doc[] = "";
118 static char plugin_doc[] = "The name of the plugin that read the data. Setting this\n"
119 "member to an empty string will insert \"python\" upon dispatching.";
121 static char plugin_instance_doc[] = "";
123 static char PluginData_doc[] = "This is an internal class that is the base for Values\n"
124 "and Notification. It is pretty useless by itself and was therefore not\n"
125 "exported to the collectd module.";
127 static PyObject *PluginData_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
130 self = (PluginData *) type->tp_alloc(type, 0);
137 self->plugin_instance[0] = 0;
139 self->type_instance[0] = 0;
140 return (PyObject *) self;
143 static int PluginData_init(PyObject *s, PyObject *args, PyObject *kwds) {
144 PluginData *self = (PluginData *) s;
146 const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
147 static char *kwlist[] = {"type", "plugin_instance", "type_instance",
148 "plugin", "host", "time", NULL};
150 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetd", kwlist, NULL, &type,
151 NULL, &plugin_instance, NULL, &type_instance, NULL, &plugin, NULL, &host, &time))
154 if (type[0] != 0 && plugin_get_ds(type) == NULL) {
155 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
159 sstrncpy(self->host, host, sizeof(self->host));
160 sstrncpy(self->plugin, plugin, sizeof(self->plugin));
161 sstrncpy(self->plugin_instance, plugin_instance, sizeof(self->plugin_instance));
162 sstrncpy(self->type, type, sizeof(self->type));
163 sstrncpy(self->type_instance, type_instance, sizeof(self->type_instance));
169 static PyObject *PluginData_repr(PyObject *s) {
171 static PyObject *l_closing = NULL;
173 if (l_closing == NULL)
174 l_closing = cpy_string_to_unicode_or_bytes(")");
176 if (l_closing == NULL)
179 ret = cpy_common_repr(s);
180 CPY_STRCAT(&ret, l_closing);
184 static PyMemberDef PluginData_members[] = {
185 {"time", T_DOUBLE, offsetof(PluginData, time), 0, time_doc},
189 static PyObject *PluginData_getstring(PyObject *self, void *data) {
190 const char *value = ((char *) self) + (intptr_t) data;
192 return cpy_string_to_unicode_or_bytes(value);
195 static int PluginData_setstring(PyObject *self, PyObject *value, void *data) {
200 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
204 new = cpy_unicode_or_bytes_to_string(&value);
209 old = ((char *) self) + (intptr_t) data;
210 sstrncpy(old, new, DATA_MAX_NAME_LEN);
215 static int PluginData_settype(PyObject *self, PyObject *value, void *data) {
220 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
224 new = cpy_unicode_or_bytes_to_string(&value);
230 if (plugin_get_ds(new) == NULL) {
231 PyErr_Format(PyExc_TypeError, "Dataset %s not found", new);
236 old = ((char *) self) + (intptr_t) data;
237 sstrncpy(old, new, DATA_MAX_NAME_LEN);
242 static PyGetSetDef PluginData_getseters[] = {
243 {"host", PluginData_getstring, PluginData_setstring, host_doc, (void *) offsetof(PluginData, host)},
244 {"plugin", PluginData_getstring, PluginData_setstring, plugin_doc, (void *) offsetof(PluginData, plugin)},
245 {"plugin_instance", PluginData_getstring, PluginData_setstring, plugin_instance_doc, (void *) offsetof(PluginData, plugin_instance)},
246 {"type_instance", PluginData_getstring, PluginData_setstring, type_instance_doc, (void *) offsetof(PluginData, type_instance)},
247 {"type", PluginData_getstring, PluginData_settype, type_doc, (void *) offsetof(PluginData, type)},
251 PyTypeObject PluginDataType = {
253 "collectd.PluginData", /* tp_name */
254 sizeof(PluginData), /* tp_basicsize */
255 0, /* Will be filled in later */
261 PluginData_repr, /* tp_repr */
262 0, /* tp_as_number */
263 0, /* tp_as_sequence */
264 0, /* tp_as_mapping */
270 0, /* tp_as_buffer */
271 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE /*| Py_TPFLAGS_HAVE_GC*/, /*tp_flags*/
272 PluginData_doc, /* tp_doc */
275 0, /* tp_richcompare */
276 0, /* tp_weaklistoffset */
280 PluginData_members, /* tp_members */
281 PluginData_getseters, /* tp_getset */
284 0, /* tp_descr_get */
285 0, /* tp_descr_set */
286 0, /* tp_dictoffset */
287 PluginData_init, /* tp_init */
289 PluginData_new /* tp_new */
292 static char interval_doc[] = "The interval is the timespan in seconds between two submits for\n"
293 "the same data source. This value has to be a positive integer, so you can't\n"
294 "submit more than one value per second. If this member is set to a\n"
295 "non-positive value, the default value as specified in the config file will\n"
296 "be used (default: 10).\n"
298 "If you submit values more often than the specified interval, the average\n"
299 "will be used. If you submit less values, your graphs will have gaps.";
301 static char values_doc[] = "These are the actual values that get dispatched to collectd.\n"
302 "It has to be a sequence (a tuple or list) of numbers.\n"
303 "The size of the sequence and the type of its content depend on the type\n"
304 "member your types.db file. For more information on this read the types.db\n"
307 "If the sequence does not have the correct size upon dispatch a RuntimeError\n"
308 "exception will be raised. If the content of the sequence is not a number,\n"
309 "a TypeError exception will be raised.";
311 static char meta_doc[] = "These are the meta data for this Value object.\n"
312 "It has to be a dictionary of numbers, strings or bools.\n"
313 "If the dict contains anything else a TypeError exception will be raised.";
315 static char dispatch_doc[] = "dispatch([type][, values][, plugin_instance][, type_instance]"
316 "[, plugin][, host][, time][, interval]) -> None. Dispatch a value list.\n"
318 "Dispatch this instance to the collectd process. The object has members\n"
319 "for each of the possible arguments for this method. For a detailed explanation\n"
320 "of these parameters see the member of the same same.\n"
322 "If you do not submit a parameter the value saved in its member will be submitted.\n"
323 "If you do provide a parameter it will be used instead, without altering the member.";
325 static char write_doc[] = "write([destination][, type][, values][, plugin_instance][, type_instance]"
326 "[, plugin][, host][, time][, interval]) -> None. Dispatch a value list.\n"
328 "Write this instance to a single plugin or all plugins if 'destination' is obmitted.\n"
329 "This will bypass the main collectd process and all filtering and caching.\n"
330 "Other than that it works similar to 'dispatch'. In most cases 'dispatch' should be\n"
331 "used instead of 'write'.\n";
333 static char Values_doc[] = "A Values object used for dispatching values to collectd and receiving values from write callbacks.";
335 static PyObject *Values_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
338 self = (Values *) PluginData_new(type, args, kwds);
342 self->values = PyList_New(0);
344 return (PyObject *) self;
347 static int Values_init(PyObject *s, PyObject *args, PyObject *kwds) {
348 Values *self = (Values *) s;
351 PyObject *values = NULL, *meta = NULL, *tmp;
352 const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
353 static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
354 "plugin", "host", "time", "interval", "meta", NULL};
356 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdiO", kwlist,
357 NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
358 NULL, &plugin, NULL, &host, &time, &interval, &meta))
361 if (type[0] != 0 && plugin_get_ds(type) == NULL) {
362 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
366 sstrncpy(self->data.host, host, sizeof(self->data.host));
367 sstrncpy(self->data.plugin, plugin, sizeof(self->data.plugin));
368 sstrncpy(self->data.plugin_instance, plugin_instance, sizeof(self->data.plugin_instance));
369 sstrncpy(self->data.type, type, sizeof(self->data.type));
370 sstrncpy(self->data.type_instance, type_instance, sizeof(self->data.type_instance));
371 self->data.time = time;
373 if (values == NULL) {
374 values = PyList_New(0);
388 self->values = values;
392 self->interval = interval;
396 static meta_data_t *cpy_build_meta(PyObject *meta) {
398 meta_data_t *m = NULL;
404 m = meta_data_create();
405 l = PyDict_Items(meta);
407 for (i = 0; i < s; ++i) {
408 const char *string, *keystring;
409 PyObject *key, *value, *item, *tmp;
411 item = PyList_GET_ITEM(l, i);
412 key = PyTuple_GET_ITEM(item, 0);
414 keystring = cpy_unicode_or_bytes_to_string(&key);
420 value = PyTuple_GET_ITEM(item, 1);
422 if (value == Py_True) {
423 meta_data_add_boolean(m, keystring, 1);
424 } else if (value == Py_False) {
425 meta_data_add_boolean(m, keystring, 0);
426 } else if (PyFloat_Check(value)) {
427 meta_data_add_double(m, keystring, PyFloat_AsDouble(value));
428 } else if (PyObject_TypeCheck(value, &SignedType)) {
430 lli = PyLong_AsLongLong(value);
431 if (!PyErr_Occurred() && (lli == (int64_t) lli))
432 meta_data_add_signed_int(m, keystring, lli);
433 } else if (PyObject_TypeCheck(value, &UnsignedType)) {
434 long long unsigned llu;
435 llu = PyLong_AsUnsignedLongLong(value);
436 if (!PyErr_Occurred() && (llu == (uint64_t) llu))
437 meta_data_add_unsigned_int(m, keystring, llu);
438 } else if (PyNumber_Check(value)) {
440 long long unsigned llu;
441 tmp = PyNumber_Long(value);
442 lli = PyLong_AsLongLong(tmp);
443 if (!PyErr_Occurred() && (lli == (int64_t) lli)) {
444 meta_data_add_signed_int(m, keystring, lli);
447 llu = PyLong_AsUnsignedLongLong(tmp);
448 if (!PyErr_Occurred() && (llu == (uint64_t) llu))
449 meta_data_add_unsigned_int(m, keystring, llu);
453 string = cpy_unicode_or_bytes_to_string(&value);
455 meta_data_add_string(m, keystring, string);
458 tmp = PyObject_Str(value);
459 string = cpy_unicode_or_bytes_to_string(&tmp);
461 meta_data_add_string(m, keystring, string);
465 if (PyErr_Occurred())
466 cpy_log_exception("building meta data");
468 Py_DECREF(keystring);
473 static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
475 const data_set_t *ds;
478 value_list_t value_list = VALUE_LIST_INIT;
479 PyObject *values = self->values, *meta = self->meta;
480 double time = self->data.time;
481 int interval = self->interval;
482 const char *host = self->data.host;
483 const char *plugin = self->data.plugin;
484 const char *plugin_instance = self->data.plugin_instance;
485 const char *type = self->data.type;
486 const char *type_instance = self->data.type_instance;
488 static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
489 "plugin", "host", "time", "interval", "meta", NULL};
490 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdiO", kwlist,
491 NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
492 NULL, &plugin, NULL, &host, &time, &interval, &meta))
496 PyErr_SetString(PyExc_RuntimeError, "type not set");
499 ds = plugin_get_ds(type);
501 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
504 if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
505 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
508 if (meta != NULL && meta != Py_None && !PyDict_Check(meta)) {
509 PyErr_Format(PyExc_TypeError, "meta must be a dict");
512 size = (int) PySequence_Length(values);
513 if (size != ds->ds_num) {
514 PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %i", type, ds->ds_num, size);
517 value = malloc(size * sizeof(*value));
518 for (i = 0; i < size; ++i) {
519 PyObject *item, *num;
520 item = PySequence_GetItem(values, i);
521 if (ds->ds->type == DS_TYPE_COUNTER) {
522 num = PyNumber_Long(item);
524 value[i].counter = PyLong_AsUnsignedLongLong(num);
525 } else if (ds->ds->type == DS_TYPE_GAUGE) {
526 num = PyNumber_Float(item);
528 value[i].gauge = PyFloat_AsDouble(num);
529 } else if (ds->ds->type == DS_TYPE_DERIVE) {
530 /* This might overflow without raising an exception.
531 * Not much we can do about it */
532 num = PyNumber_Long(item);
534 value[i].derive = PyLong_AsLongLong(num);
535 } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
536 /* This might overflow without raising an exception.
537 * Not much we can do about it */
538 num = PyNumber_Long(item);
540 value[i].absolute = PyLong_AsUnsignedLongLong(num);
543 PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds->type, type);
546 if (PyErr_Occurred() != NULL) {
551 value_list.values = value;
552 value_list.meta = cpy_build_meta(meta);
553 value_list.values_len = size;
554 value_list.time = time;
555 value_list.interval = interval;
556 sstrncpy(value_list.host, host, sizeof(value_list.host));
557 sstrncpy(value_list.plugin, plugin, sizeof(value_list.plugin));
558 sstrncpy(value_list.plugin_instance, plugin_instance, sizeof(value_list.plugin_instance));
559 sstrncpy(value_list.type, type, sizeof(value_list.type));
560 sstrncpy(value_list.type_instance, type_instance, sizeof(value_list.type_instance));
561 if (value_list.host[0] == 0)
562 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
563 if (value_list.plugin[0] == 0)
564 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
565 Py_BEGIN_ALLOW_THREADS;
566 ret = plugin_dispatch_values(&value_list);
567 Py_END_ALLOW_THREADS;
569 PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
576 static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
578 const data_set_t *ds;
581 value_list_t value_list = VALUE_LIST_INIT;
582 PyObject *values = self->values, *meta = self->meta;
583 double time = self->data.time;
584 int interval = self->interval;
585 const char *host = self->data.host;
586 const char *plugin = self->data.plugin;
587 const char *plugin_instance = self->data.plugin_instance;
588 const char *type = self->data.type;
589 const char *type_instance = self->data.type_instance;
590 const char *dest = NULL;
592 static char *kwlist[] = {"destination", "type", "values", "plugin_instance", "type_instance",
593 "plugin", "host", "time", "interval", "meta", NULL};
594 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdiO", kwlist,
595 NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
596 NULL, &plugin, NULL, &host, &time, &interval, &meta))
600 PyErr_SetString(PyExc_RuntimeError, "type not set");
603 ds = plugin_get_ds(type);
605 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
608 if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
609 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
612 size = (int) PySequence_Length(values);
613 if (size != ds->ds_num) {
614 PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %i", type, ds->ds_num, size);
617 value = malloc(size * sizeof(*value));
618 for (i = 0; i < size; ++i) {
619 PyObject *item, *num;
620 item = PySequence_GetItem(values, i);
621 if (ds->ds->type == DS_TYPE_COUNTER) {
622 num = PyNumber_Long(item);
624 value[i].counter = PyLong_AsUnsignedLongLong(num);
625 } else if (ds->ds->type == DS_TYPE_GAUGE) {
626 num = PyNumber_Float(item);
628 value[i].gauge = PyFloat_AsDouble(num);
629 } else if (ds->ds->type == DS_TYPE_DERIVE) {
630 /* This might overflow without raising an exception.
631 * Not much we can do about it */
632 num = PyNumber_Long(item);
634 value[i].derive = PyLong_AsLongLong(num);
635 } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
636 /* This might overflow without raising an exception.
637 * Not much we can do about it */
638 num = PyNumber_Long(item);
640 value[i].absolute = PyLong_AsUnsignedLongLong(num);
643 PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds->type, type);
646 if (PyErr_Occurred() != NULL) {
651 value_list.values = value;
652 value_list.values_len = size;
653 value_list.time = time;
654 value_list.interval = interval;
655 sstrncpy(value_list.host, host, sizeof(value_list.host));
656 sstrncpy(value_list.plugin, plugin, sizeof(value_list.plugin));
657 sstrncpy(value_list.plugin_instance, plugin_instance, sizeof(value_list.plugin_instance));
658 sstrncpy(value_list.type, type, sizeof(value_list.type));
659 sstrncpy(value_list.type_instance, type_instance, sizeof(value_list.type_instance));
660 value_list.meta = cpy_build_meta(meta);;
661 if (value_list.host[0] == 0)
662 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
663 if (value_list.plugin[0] == 0)
664 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
665 Py_BEGIN_ALLOW_THREADS;
666 ret = plugin_write(dest, NULL, &value_list);
667 Py_END_ALLOW_THREADS;
669 PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
676 static PyObject *Values_repr(PyObject *s) {
678 static PyObject *l_interval = NULL, *l_values = NULL, *l_meta = NULL, *l_closing = NULL;
679 Values *self = (Values *) s;
681 if (l_interval == NULL)
682 l_interval = cpy_string_to_unicode_or_bytes(",interval=");
683 if (l_values == NULL)
684 l_values = cpy_string_to_unicode_or_bytes(",values=");
686 l_meta = cpy_string_to_unicode_or_bytes(",meta=");
687 if (l_closing == NULL)
688 l_closing = cpy_string_to_unicode_or_bytes(")");
690 if (l_interval == NULL || l_values == NULL || l_meta == NULL || l_closing == NULL)
693 ret = cpy_common_repr(s);
694 if (self->interval != 0) {
695 CPY_STRCAT(&ret, l_interval);
696 tmp = PyInt_FromLong(self->interval);
697 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
698 CPY_STRCAT_AND_DEL(&ret, tmp);
700 if (self->values && (!PyList_Check(self->values) || PySequence_Length(self->values) > 0)) {
701 CPY_STRCAT(&ret, l_values);
702 tmp = PyObject_Repr(self->values);
703 CPY_STRCAT_AND_DEL(&ret, tmp);
705 if (self->meta && (!PyDict_Check(self->meta) || PyDict_Size(self->meta) > 0)) {
706 CPY_STRCAT(&ret, l_meta);
707 tmp = PyObject_Repr(self->meta);
708 CPY_STRCAT_AND_DEL(&ret, tmp);
710 CPY_STRCAT(&ret, l_closing);
714 static int Values_traverse(PyObject *self, visitproc visit, void *arg) {
715 Values *v = (Values *) self;
721 static int Values_clear(PyObject *self) {
722 Values *v = (Values *) self;
728 static void Values_dealloc(PyObject *self) {
730 self->ob_type->tp_free(self);
733 static PyMemberDef Values_members[] = {
734 {"interval", T_INT, offsetof(Values, interval), 0, interval_doc},
735 {"values", T_OBJECT_EX, offsetof(Values, values), 0, values_doc},
736 {"meta", T_OBJECT_EX, offsetof(Values, meta), 0, meta_doc},
740 static PyMethodDef Values_methods[] = {
741 {"dispatch", (PyCFunction) Values_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
742 {"write", (PyCFunction) Values_write, METH_VARARGS | METH_KEYWORDS, write_doc},
746 PyTypeObject ValuesType = {
748 "collectd.Values", /* tp_name */
749 sizeof(Values), /* tp_basicsize */
750 0, /* Will be filled in later */
751 Values_dealloc, /* tp_dealloc */
756 Values_repr, /* tp_repr */
757 0, /* tp_as_number */
758 0, /* tp_as_sequence */
759 0, /* tp_as_mapping */
765 0, /* tp_as_buffer */
766 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
767 Values_doc, /* tp_doc */
768 Values_traverse, /* tp_traverse */
769 Values_clear, /* tp_clear */
770 0, /* tp_richcompare */
771 0, /* tp_weaklistoffset */
774 Values_methods, /* tp_methods */
775 Values_members, /* tp_members */
779 0, /* tp_descr_get */
780 0, /* tp_descr_set */
781 0, /* tp_dictoffset */
782 Values_init, /* tp_init */
784 Values_new /* tp_new */
787 static char severity_doc[] = "The severity of this notification. Assign or compare to\n"
788 "NOTIF_FAILURE, NOTIF_WARNING or NOTIF_OKAY.";
790 static char message_doc[] = "Some kind of description what's going on and why this Notification was generated.";
792 static char Notification_doc[] = "The Notification class is a wrapper around the collectd notification.\n"
793 "It can be used to notify other plugins about bad stuff happening. It works\n"
794 "similar to Values but has a severity and a message instead of interval\n"
796 "Notifications can be dispatched at any time and can be received with register_notification.";
798 static int Notification_init(PyObject *s, PyObject *args, PyObject *kwds) {
799 Notification *self = (Notification *) s;
802 const char *message = "";
803 const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
804 static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
805 "plugin", "host", "time", "severity", NULL};
807 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist,
808 NULL, &type, NULL, &message, NULL, &plugin_instance, NULL, &type_instance,
809 NULL, &plugin, NULL, &host, &time, &severity))
812 if (type[0] != 0 && plugin_get_ds(type) == NULL) {
813 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
817 sstrncpy(self->data.host, host, sizeof(self->data.host));
818 sstrncpy(self->data.plugin, plugin, sizeof(self->data.plugin));
819 sstrncpy(self->data.plugin_instance, plugin_instance, sizeof(self->data.plugin_instance));
820 sstrncpy(self->data.type, type, sizeof(self->data.type));
821 sstrncpy(self->data.type_instance, type_instance, sizeof(self->data.type_instance));
822 self->data.time = time;
824 sstrncpy(self->message, message, sizeof(self->message));
825 self->severity = severity;
829 static PyObject *Notification_dispatch(Notification *self, PyObject *args, PyObject *kwds) {
831 const data_set_t *ds;
832 notification_t notification;
833 double t = self->data.time;
834 int severity = self->severity;
835 const char *host = self->data.host;
836 const char *plugin = self->data.plugin;
837 const char *plugin_instance = self->data.plugin_instance;
838 const char *type = self->data.type;
839 const char *type_instance = self->data.type_instance;
840 const char *message = self->message;
842 static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
843 "plugin", "host", "time", "severity", NULL};
844 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist,
845 NULL, &type, NULL, &message, NULL, &plugin_instance, NULL, &type_instance,
846 NULL, &plugin, NULL, &host, &t, &severity))
850 PyErr_SetString(PyExc_RuntimeError, "type not set");
853 ds = plugin_get_ds(type);
855 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
859 notification.time = t;
860 notification.severity = severity;
861 sstrncpy(notification.message, message, sizeof(notification.message));
862 sstrncpy(notification.host, host, sizeof(notification.host));
863 sstrncpy(notification.plugin, plugin, sizeof(notification.plugin));
864 sstrncpy(notification.plugin_instance, plugin_instance, sizeof(notification.plugin_instance));
865 sstrncpy(notification.type, type, sizeof(notification.type));
866 sstrncpy(notification.type_instance, type_instance, sizeof(notification.type_instance));
867 notification.meta = NULL;
868 if (notification.time < 1)
869 notification.time = time(0);
870 if (notification.host[0] == 0)
871 sstrncpy(notification.host, hostname_g, sizeof(notification.host));
872 if (notification.plugin[0] == 0)
873 sstrncpy(notification.plugin, "python", sizeof(notification.plugin));
874 Py_BEGIN_ALLOW_THREADS;
875 ret = plugin_dispatch_notification(¬ification);
876 Py_END_ALLOW_THREADS;
878 PyErr_SetString(PyExc_RuntimeError, "error dispatching notification, read the logs");
884 static PyObject *Notification_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
887 self = (Notification *) PluginData_new(type, args, kwds);
891 self->message[0] = 0;
893 return (PyObject *) self;
896 static int Notification_setstring(PyObject *self, PyObject *value, void *data) {
901 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
905 new = cpy_unicode_or_bytes_to_string(&value);
910 old = ((char *) self) + (intptr_t) data;
911 sstrncpy(old, new, NOTIF_MAX_MSG_LEN);
916 static PyObject *Notification_repr(PyObject *s) {
918 static PyObject *l_severity = NULL, *l_message = NULL, *l_closing = NULL;
919 Notification *self = (Notification *) s;
921 if (l_severity == NULL)
922 l_severity = cpy_string_to_unicode_or_bytes(",severity=");
923 if (l_message == NULL)
924 l_message = cpy_string_to_unicode_or_bytes(",message=");
925 if (l_closing == NULL)
926 l_closing = cpy_string_to_unicode_or_bytes(")");
928 if (l_severity == NULL || l_message == NULL || l_closing == NULL)
931 ret = cpy_common_repr(s);
932 if (self->severity != 0) {
933 CPY_STRCAT(&ret, l_severity);
934 tmp = PyInt_FromLong(self->severity);
935 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
936 CPY_STRCAT_AND_DEL(&ret, tmp);
938 if (self->message[0] != 0) {
939 CPY_STRCAT(&ret, l_message);
940 tmp = cpy_string_to_unicode_or_bytes(self->message);
941 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
942 CPY_STRCAT_AND_DEL(&ret, tmp);
944 CPY_STRCAT(&ret, l_closing);
948 static PyMethodDef Notification_methods[] = {
949 {"dispatch", (PyCFunction) Notification_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
953 static PyMemberDef Notification_members[] = {
954 {"severity", T_INT, offsetof(Notification, severity), 0, severity_doc},
958 static PyGetSetDef Notification_getseters[] = {
959 {"message", PluginData_getstring, Notification_setstring, message_doc, (void *) offsetof(Notification, message)},
963 PyTypeObject NotificationType = {
965 "collectd.Notification", /* tp_name */
966 sizeof(Notification), /* tp_basicsize */
967 0, /* Will be filled in later */
973 Notification_repr, /* tp_repr */
974 0, /* tp_as_number */
975 0, /* tp_as_sequence */
976 0, /* tp_as_mapping */
982 0, /* tp_as_buffer */
983 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
984 Notification_doc, /* tp_doc */
987 0, /* tp_richcompare */
988 0, /* tp_weaklistoffset */
991 Notification_methods, /* tp_methods */
992 Notification_members, /* tp_members */
993 Notification_getseters, /* tp_getset */
996 0, /* tp_descr_get */
997 0, /* tp_descr_set */
998 0, /* tp_dictoffset */
999 Notification_init, /* tp_init */
1001 Notification_new /* tp_new */
1004 PyTypeObject SignedType = {
1006 "collectd.Signed", /* tp_name */
1007 sizeof(Signed), /* tp_basicsize */
1008 0, /* Will be filled in later */
1015 0, /* tp_as_number */
1016 0, /* tp_as_sequence */
1017 0, /* tp_as_mapping */
1021 0, /* tp_getattro */
1022 0, /* tp_setattro */
1023 0, /* tp_as_buffer */
1024 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1027 PyTypeObject UnsignedType = {
1029 "collectd.Unsigned", /* tp_name */
1030 sizeof(Unsigned), /* tp_basicsize */
1031 0, /* Will be filled in later */
1038 0, /* tp_as_number */
1039 0, /* tp_as_sequence */
1040 0, /* tp_as_mapping */
1044 0, /* tp_getattro */
1045 0, /* tp_setattro */
1046 0, /* tp_as_buffer */
1047 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/