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 = PyFloat_FromDouble(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. All keys must be\n"
313 "strings. int and long objects will be dispatched as signed integers unless\n"
314 "they are between 2**63 and 2**64-1, which will result in a unsigned integer.\n"
315 "You can force one of these storage classes by using the classes\n"
316 "collectd.Signed and collectd.Unsigned. A meta object received by a write\n"
317 "callback will always contain Signed or Unsigned objects.";
319 static char dispatch_doc[] = "dispatch([type][, values][, plugin_instance][, type_instance]"
320 "[, plugin][, host][, time][, interval]) -> None. Dispatch a value list.\n"
322 "Dispatch this instance to the collectd process. The object has members\n"
323 "for each of the possible arguments for this method. For a detailed explanation\n"
324 "of these parameters see the member of the same same.\n"
326 "If you do not submit a parameter the value saved in its member will be submitted.\n"
327 "If you do provide a parameter it will be used instead, without altering the member.";
329 static char write_doc[] = "write([destination][, type][, values][, plugin_instance][, type_instance]"
330 "[, plugin][, host][, time][, interval]) -> None. Dispatch a value list.\n"
332 "Write this instance to a single plugin or all plugins if 'destination' is obmitted.\n"
333 "This will bypass the main collectd process and all filtering and caching.\n"
334 "Other than that it works similar to 'dispatch'. In most cases 'dispatch' should be\n"
335 "used instead of 'write'.\n";
337 static char Values_doc[] = "A Values object used for dispatching values to collectd and receiving values from write callbacks.";
339 static PyObject *Values_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
342 self = (Values *) PluginData_new(type, args, kwds);
346 self->values = PyList_New(0);
347 self->meta = PyDict_New();
349 return (PyObject *) self;
352 static int Values_init(PyObject *s, PyObject *args, PyObject *kwds) {
353 Values *self = (Values *) s;
354 double interval = 0, time = 0;
355 PyObject *values = NULL, *meta = NULL, *tmp;
356 const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
357 static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
358 "plugin", "host", "time", "interval", "meta", NULL};
360 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist,
361 NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
362 NULL, &plugin, NULL, &host, &time, &interval, &meta))
365 if (type[0] != 0 && plugin_get_ds(type) == NULL) {
366 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
370 sstrncpy(self->data.host, host, sizeof(self->data.host));
371 sstrncpy(self->data.plugin, plugin, sizeof(self->data.plugin));
372 sstrncpy(self->data.plugin_instance, plugin_instance, sizeof(self->data.plugin_instance));
373 sstrncpy(self->data.type, type, sizeof(self->data.type));
374 sstrncpy(self->data.type_instance, type_instance, sizeof(self->data.type_instance));
375 self->data.time = time;
377 if (values == NULL) {
378 values = PyList_New(0);
392 self->values = values;
399 self->interval = interval;
403 static meta_data_t *cpy_build_meta(PyObject *meta) {
405 meta_data_t *m = NULL;
411 m = meta_data_create();
412 l = PyDict_Items(meta);
414 for (i = 0; i < s; ++i) {
415 const char *string, *keystring;
416 PyObject *key, *value, *item, *tmp;
418 item = PyList_GET_ITEM(l, i);
419 key = PyTuple_GET_ITEM(item, 0);
421 keystring = cpy_unicode_or_bytes_to_string(&key);
427 value = PyTuple_GET_ITEM(item, 1);
429 if (value == Py_True) {
430 meta_data_add_boolean(m, keystring, 1);
431 } else if (value == Py_False) {
432 meta_data_add_boolean(m, keystring, 0);
433 } else if (PyFloat_Check(value)) {
434 meta_data_add_double(m, keystring, PyFloat_AsDouble(value));
435 } else if (PyObject_TypeCheck(value, &SignedType)) {
437 lli = PyLong_AsLongLong(value);
438 if (!PyErr_Occurred() && (lli == (int64_t) lli))
439 meta_data_add_signed_int(m, keystring, lli);
440 } else if (PyObject_TypeCheck(value, &UnsignedType)) {
441 long long unsigned llu;
442 llu = PyLong_AsUnsignedLongLong(value);
443 if (!PyErr_Occurred() && (llu == (uint64_t) llu))
444 meta_data_add_unsigned_int(m, keystring, llu);
445 } else if (PyNumber_Check(value)) {
447 long long unsigned llu;
448 tmp = PyNumber_Long(value);
449 lli = PyLong_AsLongLong(tmp);
450 if (!PyErr_Occurred() && (lli == (int64_t) lli)) {
451 meta_data_add_signed_int(m, keystring, lli);
454 llu = PyLong_AsUnsignedLongLong(tmp);
455 if (!PyErr_Occurred() && (llu == (uint64_t) llu))
456 meta_data_add_unsigned_int(m, keystring, llu);
460 string = cpy_unicode_or_bytes_to_string(&value);
462 meta_data_add_string(m, keystring, string);
465 tmp = PyObject_Str(value);
466 string = cpy_unicode_or_bytes_to_string(&tmp);
468 meta_data_add_string(m, keystring, string);
472 if (PyErr_Occurred())
473 cpy_log_exception("building meta data");
480 static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
482 const data_set_t *ds;
485 value_list_t value_list = VALUE_LIST_INIT;
486 PyObject *values = self->values, *meta = self->meta;
487 double time = self->data.time, interval = self->interval;
488 const char *host = self->data.host;
489 const char *plugin = self->data.plugin;
490 const char *plugin_instance = self->data.plugin_instance;
491 const char *type = self->data.type;
492 const char *type_instance = self->data.type_instance;
494 static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
495 "plugin", "host", "time", "interval", "meta", NULL};
496 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist,
497 NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
498 NULL, &plugin, NULL, &host, &time, &interval, &meta))
502 PyErr_SetString(PyExc_RuntimeError, "type not set");
505 ds = plugin_get_ds(type);
507 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
510 if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
511 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
514 if (meta != NULL && meta != Py_None && !PyDict_Check(meta)) {
515 PyErr_Format(PyExc_TypeError, "meta must be a dict");
518 size = (int) PySequence_Length(values);
519 if (size != ds->ds_num) {
520 PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %i", type, ds->ds_num, size);
523 value = malloc(size * sizeof(*value));
524 for (i = 0; i < size; ++i) {
525 PyObject *item, *num;
526 item = PySequence_GetItem(values, i);
527 if (ds->ds->type == DS_TYPE_COUNTER) {
528 num = PyNumber_Long(item);
530 value[i].counter = PyLong_AsUnsignedLongLong(num);
531 } else if (ds->ds->type == DS_TYPE_GAUGE) {
532 num = PyNumber_Float(item);
534 value[i].gauge = PyFloat_AsDouble(num);
535 } else if (ds->ds->type == DS_TYPE_DERIVE) {
536 /* This might overflow without raising an exception.
537 * Not much we can do about it */
538 num = PyNumber_Long(item);
540 value[i].derive = PyLong_AsLongLong(num);
541 } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
542 /* This might overflow without raising an exception.
543 * Not much we can do about it */
544 num = PyNumber_Long(item);
546 value[i].absolute = PyLong_AsUnsignedLongLong(num);
549 PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds->type, type);
552 if (PyErr_Occurred() != NULL) {
557 value_list.values = value;
558 value_list.meta = cpy_build_meta(meta);
559 value_list.values_len = size;
560 value_list.time = DOUBLE_TO_CDTIME_T(time);
561 value_list.interval = DOUBLE_TO_CDTIME_T(interval);
562 sstrncpy(value_list.host, host, sizeof(value_list.host));
563 sstrncpy(value_list.plugin, plugin, sizeof(value_list.plugin));
564 sstrncpy(value_list.plugin_instance, plugin_instance, sizeof(value_list.plugin_instance));
565 sstrncpy(value_list.type, type, sizeof(value_list.type));
566 sstrncpy(value_list.type_instance, type_instance, sizeof(value_list.type_instance));
567 if (value_list.host[0] == 0)
568 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
569 if (value_list.plugin[0] == 0)
570 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
571 Py_BEGIN_ALLOW_THREADS;
572 ret = plugin_dispatch_values(&value_list);
573 Py_END_ALLOW_THREADS;
575 PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
582 static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
584 const data_set_t *ds;
587 value_list_t value_list = VALUE_LIST_INIT;
588 PyObject *values = self->values, *meta = self->meta;
589 double time = self->data.time, interval = self->interval;
590 const char *host = self->data.host;
591 const char *plugin = self->data.plugin;
592 const char *plugin_instance = self->data.plugin_instance;
593 const char *type = self->data.type;
594 const char *type_instance = self->data.type_instance;
595 const char *dest = NULL;
597 static char *kwlist[] = {"destination", "type", "values", "plugin_instance", "type_instance",
598 "plugin", "host", "time", "interval", "meta", NULL};
599 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist,
600 NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
601 NULL, &plugin, NULL, &host, &time, &interval, &meta))
605 PyErr_SetString(PyExc_RuntimeError, "type not set");
608 ds = plugin_get_ds(type);
610 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
613 if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
614 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
617 size = (int) PySequence_Length(values);
618 if (size != ds->ds_num) {
619 PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %i", type, ds->ds_num, size);
622 value = malloc(size * sizeof(*value));
623 for (i = 0; i < size; ++i) {
624 PyObject *item, *num;
625 item = PySequence_GetItem(values, i);
626 if (ds->ds->type == DS_TYPE_COUNTER) {
627 num = PyNumber_Long(item);
629 value[i].counter = PyLong_AsUnsignedLongLong(num);
630 } else if (ds->ds->type == DS_TYPE_GAUGE) {
631 num = PyNumber_Float(item);
633 value[i].gauge = PyFloat_AsDouble(num);
634 } else if (ds->ds->type == DS_TYPE_DERIVE) {
635 /* This might overflow without raising an exception.
636 * Not much we can do about it */
637 num = PyNumber_Long(item);
639 value[i].derive = PyLong_AsLongLong(num);
640 } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
641 /* This might overflow without raising an exception.
642 * Not much we can do about it */
643 num = PyNumber_Long(item);
645 value[i].absolute = PyLong_AsUnsignedLongLong(num);
648 PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds->type, type);
651 if (PyErr_Occurred() != NULL) {
656 value_list.values = value;
657 value_list.values_len = size;
658 value_list.time = DOUBLE_TO_CDTIME_T(time);
659 value_list.interval = DOUBLE_TO_CDTIME_T(interval);
660 sstrncpy(value_list.host, host, sizeof(value_list.host));
661 sstrncpy(value_list.plugin, plugin, sizeof(value_list.plugin));
662 sstrncpy(value_list.plugin_instance, plugin_instance, sizeof(value_list.plugin_instance));
663 sstrncpy(value_list.type, type, sizeof(value_list.type));
664 sstrncpy(value_list.type_instance, type_instance, sizeof(value_list.type_instance));
665 value_list.meta = cpy_build_meta(meta);;
666 if (value_list.host[0] == 0)
667 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
668 if (value_list.plugin[0] == 0)
669 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
670 Py_BEGIN_ALLOW_THREADS;
671 ret = plugin_write(dest, NULL, &value_list);
672 Py_END_ALLOW_THREADS;
674 PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
681 static PyObject *Values_repr(PyObject *s) {
683 static PyObject *l_interval = NULL, *l_values = NULL, *l_meta = NULL, *l_closing = NULL;
684 Values *self = (Values *) s;
686 if (l_interval == NULL)
687 l_interval = cpy_string_to_unicode_or_bytes(",interval=");
688 if (l_values == NULL)
689 l_values = cpy_string_to_unicode_or_bytes(",values=");
691 l_meta = cpy_string_to_unicode_or_bytes(",meta=");
692 if (l_closing == NULL)
693 l_closing = cpy_string_to_unicode_or_bytes(")");
695 if (l_interval == NULL || l_values == NULL || l_meta == NULL || l_closing == NULL)
698 ret = cpy_common_repr(s);
699 if (self->interval != 0) {
700 CPY_STRCAT(&ret, l_interval);
701 tmp = PyFloat_FromDouble(self->interval);
702 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
703 CPY_STRCAT_AND_DEL(&ret, tmp);
705 if (self->values && (!PyList_Check(self->values) || PySequence_Length(self->values) > 0)) {
706 CPY_STRCAT(&ret, l_values);
707 tmp = PyObject_Repr(self->values);
708 CPY_STRCAT_AND_DEL(&ret, tmp);
710 if (self->meta && (!PyDict_Check(self->meta) || PyDict_Size(self->meta) > 0)) {
711 CPY_STRCAT(&ret, l_meta);
712 tmp = PyObject_Repr(self->meta);
713 CPY_STRCAT_AND_DEL(&ret, tmp);
715 CPY_STRCAT(&ret, l_closing);
719 static int Values_traverse(PyObject *self, visitproc visit, void *arg) {
720 Values *v = (Values *) self;
726 static int Values_clear(PyObject *self) {
727 Values *v = (Values *) self;
733 static void Values_dealloc(PyObject *self) {
735 self->ob_type->tp_free(self);
738 static PyMemberDef Values_members[] = {
739 {"interval", T_INT, offsetof(Values, interval), 0, interval_doc},
740 {"values", T_OBJECT_EX, offsetof(Values, values), 0, values_doc},
741 {"meta", T_OBJECT_EX, offsetof(Values, meta), 0, meta_doc},
745 static PyMethodDef Values_methods[] = {
746 {"dispatch", (PyCFunction) Values_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
747 {"write", (PyCFunction) Values_write, METH_VARARGS | METH_KEYWORDS, write_doc},
751 PyTypeObject ValuesType = {
753 "collectd.Values", /* tp_name */
754 sizeof(Values), /* tp_basicsize */
755 0, /* Will be filled in later */
756 Values_dealloc, /* tp_dealloc */
761 Values_repr, /* tp_repr */
762 0, /* tp_as_number */
763 0, /* tp_as_sequence */
764 0, /* tp_as_mapping */
770 0, /* tp_as_buffer */
771 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
772 Values_doc, /* tp_doc */
773 Values_traverse, /* tp_traverse */
774 Values_clear, /* tp_clear */
775 0, /* tp_richcompare */
776 0, /* tp_weaklistoffset */
779 Values_methods, /* tp_methods */
780 Values_members, /* tp_members */
784 0, /* tp_descr_get */
785 0, /* tp_descr_set */
786 0, /* tp_dictoffset */
787 Values_init, /* tp_init */
789 Values_new /* tp_new */
792 static char severity_doc[] = "The severity of this notification. Assign or compare to\n"
793 "NOTIF_FAILURE, NOTIF_WARNING or NOTIF_OKAY.";
795 static char message_doc[] = "Some kind of description what's going on and why this Notification was generated.";
797 static char Notification_doc[] = "The Notification class is a wrapper around the collectd notification.\n"
798 "It can be used to notify other plugins about bad stuff happening. It works\n"
799 "similar to Values but has a severity and a message instead of interval\n"
801 "Notifications can be dispatched at any time and can be received with register_notification.";
803 static int Notification_init(PyObject *s, PyObject *args, PyObject *kwds) {
804 Notification *self = (Notification *) s;
807 const char *message = "";
808 const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
809 static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
810 "plugin", "host", "time", "severity", NULL};
812 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist,
813 NULL, &type, NULL, &message, NULL, &plugin_instance, NULL, &type_instance,
814 NULL, &plugin, NULL, &host, &time, &severity))
817 if (type[0] != 0 && plugin_get_ds(type) == NULL) {
818 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
822 sstrncpy(self->data.host, host, sizeof(self->data.host));
823 sstrncpy(self->data.plugin, plugin, sizeof(self->data.plugin));
824 sstrncpy(self->data.plugin_instance, plugin_instance, sizeof(self->data.plugin_instance));
825 sstrncpy(self->data.type, type, sizeof(self->data.type));
826 sstrncpy(self->data.type_instance, type_instance, sizeof(self->data.type_instance));
827 self->data.time = time;
829 sstrncpy(self->message, message, sizeof(self->message));
830 self->severity = severity;
834 static PyObject *Notification_dispatch(Notification *self, PyObject *args, PyObject *kwds) {
836 const data_set_t *ds;
837 notification_t notification;
838 double t = self->data.time;
839 int severity = self->severity;
840 const char *host = self->data.host;
841 const char *plugin = self->data.plugin;
842 const char *plugin_instance = self->data.plugin_instance;
843 const char *type = self->data.type;
844 const char *type_instance = self->data.type_instance;
845 const char *message = self->message;
847 static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
848 "plugin", "host", "time", "severity", NULL};
849 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist,
850 NULL, &type, NULL, &message, NULL, &plugin_instance, NULL, &type_instance,
851 NULL, &plugin, NULL, &host, &t, &severity))
855 PyErr_SetString(PyExc_RuntimeError, "type not set");
858 ds = plugin_get_ds(type);
860 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
864 notification.time = DOUBLE_TO_CDTIME_T(t);
865 notification.severity = severity;
866 sstrncpy(notification.message, message, sizeof(notification.message));
867 sstrncpy(notification.host, host, sizeof(notification.host));
868 sstrncpy(notification.plugin, plugin, sizeof(notification.plugin));
869 sstrncpy(notification.plugin_instance, plugin_instance, sizeof(notification.plugin_instance));
870 sstrncpy(notification.type, type, sizeof(notification.type));
871 sstrncpy(notification.type_instance, type_instance, sizeof(notification.type_instance));
872 notification.meta = NULL;
873 if (notification.time == 0)
874 notification.time = cdtime();
875 if (notification.host[0] == 0)
876 sstrncpy(notification.host, hostname_g, sizeof(notification.host));
877 if (notification.plugin[0] == 0)
878 sstrncpy(notification.plugin, "python", sizeof(notification.plugin));
879 Py_BEGIN_ALLOW_THREADS;
880 ret = plugin_dispatch_notification(¬ification);
881 Py_END_ALLOW_THREADS;
883 PyErr_SetString(PyExc_RuntimeError, "error dispatching notification, read the logs");
889 static PyObject *Notification_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
892 self = (Notification *) PluginData_new(type, args, kwds);
896 self->message[0] = 0;
898 return (PyObject *) self;
901 static int Notification_setstring(PyObject *self, PyObject *value, void *data) {
906 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
910 new = cpy_unicode_or_bytes_to_string(&value);
915 old = ((char *) self) + (intptr_t) data;
916 sstrncpy(old, new, NOTIF_MAX_MSG_LEN);
921 static PyObject *Notification_repr(PyObject *s) {
923 static PyObject *l_severity = NULL, *l_message = NULL, *l_closing = NULL;
924 Notification *self = (Notification *) s;
926 if (l_severity == NULL)
927 l_severity = cpy_string_to_unicode_or_bytes(",severity=");
928 if (l_message == NULL)
929 l_message = cpy_string_to_unicode_or_bytes(",message=");
930 if (l_closing == NULL)
931 l_closing = cpy_string_to_unicode_or_bytes(")");
933 if (l_severity == NULL || l_message == NULL || l_closing == NULL)
936 ret = cpy_common_repr(s);
937 if (self->severity != 0) {
938 CPY_STRCAT(&ret, l_severity);
939 tmp = PyInt_FromLong(self->severity);
940 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
941 CPY_STRCAT_AND_DEL(&ret, tmp);
943 if (self->message[0] != 0) {
944 CPY_STRCAT(&ret, l_message);
945 tmp = cpy_string_to_unicode_or_bytes(self->message);
946 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
947 CPY_STRCAT_AND_DEL(&ret, tmp);
949 CPY_STRCAT(&ret, l_closing);
953 static PyMethodDef Notification_methods[] = {
954 {"dispatch", (PyCFunction) Notification_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
958 static PyMemberDef Notification_members[] = {
959 {"severity", T_INT, offsetof(Notification, severity), 0, severity_doc},
963 static PyGetSetDef Notification_getseters[] = {
964 {"message", PluginData_getstring, Notification_setstring, message_doc, (void *) offsetof(Notification, message)},
968 PyTypeObject NotificationType = {
970 "collectd.Notification", /* tp_name */
971 sizeof(Notification), /* tp_basicsize */
972 0, /* Will be filled in later */
978 Notification_repr, /* tp_repr */
979 0, /* tp_as_number */
980 0, /* tp_as_sequence */
981 0, /* tp_as_mapping */
987 0, /* tp_as_buffer */
988 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
989 Notification_doc, /* tp_doc */
992 0, /* tp_richcompare */
993 0, /* tp_weaklistoffset */
996 Notification_methods, /* tp_methods */
997 Notification_members, /* tp_members */
998 Notification_getseters, /* tp_getset */
1001 0, /* tp_descr_get */
1002 0, /* tp_descr_set */
1003 0, /* tp_dictoffset */
1004 Notification_init, /* tp_init */
1006 Notification_new /* tp_new */
1009 static char Signed_doc[] = "This is a long by another name. Use it in meta data dicts\n"
1010 "to choose the way it is stored in the meta data.";
1012 PyTypeObject SignedType = {
1014 "collectd.Signed", /* tp_name */
1015 sizeof(Signed), /* tp_basicsize */
1016 0, /* Will be filled in later */
1023 0, /* tp_as_number */
1024 0, /* tp_as_sequence */
1025 0, /* tp_as_mapping */
1029 0, /* tp_getattro */
1030 0, /* tp_setattro */
1031 0, /* tp_as_buffer */
1032 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1033 Signed_doc /* tp_doc */
1036 static char Unsigned_doc[] = "This is a long by another name. Use it in meta data dicts\n"
1037 "to choose the way it is stored in the meta data.";
1039 PyTypeObject UnsignedType = {
1041 "collectd.Unsigned", /* tp_name */
1042 sizeof(Unsigned), /* tp_basicsize */
1043 0, /* Will be filled in later */
1050 0, /* tp_as_number */
1051 0, /* tp_as_sequence */
1052 0, /* tp_as_mapping */
1056 0, /* tp_getattro */
1057 0, /* tp_setattro */
1058 0, /* tp_as_buffer */
1059 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1060 Unsigned_doc /* tp_doc */