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>
39 PyMem_Free(plugin_instance); \
40 PyMem_Free(type_instance); \
45 static PyObject *cpy_common_repr(PyObject *s) {
47 static PyObject *l_type = NULL, *l_type_instance = NULL, *l_plugin = NULL,
48 *l_plugin_instance = NULL;
49 static PyObject *l_host = NULL, *l_time = NULL;
50 PluginData *self = (PluginData *)s;
53 l_type = cpy_string_to_unicode_or_bytes("(type=");
54 if (l_type_instance == NULL)
55 l_type_instance = cpy_string_to_unicode_or_bytes(",type_instance=");
57 l_plugin = cpy_string_to_unicode_or_bytes(",plugin=");
58 if (l_plugin_instance == NULL)
59 l_plugin_instance = cpy_string_to_unicode_or_bytes(",plugin_instance=");
61 l_host = cpy_string_to_unicode_or_bytes(",host=");
63 l_time = cpy_string_to_unicode_or_bytes(",time=");
65 if (!l_type || !l_type_instance || !l_plugin || !l_plugin_instance ||
69 ret = cpy_string_to_unicode_or_bytes(s->ob_type->tp_name);
71 CPY_STRCAT(&ret, l_type);
72 tmp = cpy_string_to_unicode_or_bytes(self->type);
73 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
74 CPY_STRCAT_AND_DEL(&ret, tmp);
76 if (self->type_instance[0] != 0) {
77 CPY_STRCAT(&ret, l_type_instance);
78 tmp = cpy_string_to_unicode_or_bytes(self->type_instance);
79 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
80 CPY_STRCAT_AND_DEL(&ret, tmp);
83 if (self->plugin[0] != 0) {
84 CPY_STRCAT(&ret, l_plugin);
85 tmp = cpy_string_to_unicode_or_bytes(self->plugin);
86 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
87 CPY_STRCAT_AND_DEL(&ret, tmp);
90 if (self->plugin_instance[0] != 0) {
91 CPY_STRCAT(&ret, l_plugin_instance);
92 tmp = cpy_string_to_unicode_or_bytes(self->plugin_instance);
93 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
94 CPY_STRCAT_AND_DEL(&ret, tmp);
97 if (self->host[0] != 0) {
98 CPY_STRCAT(&ret, l_host);
99 tmp = cpy_string_to_unicode_or_bytes(self->host);
100 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
101 CPY_STRCAT_AND_DEL(&ret, tmp);
104 if (self->time != 0) {
105 CPY_STRCAT(&ret, l_time);
106 tmp = PyFloat_FromDouble(self->time);
107 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
108 CPY_STRCAT_AND_DEL(&ret, tmp);
113 static char time_doc[] =
114 "This is the Unix timestamp of the time this value was read.\n"
115 "For dispatching values this can be set to 0 which means \"now\".\n"
116 "This means the time the value is actually dispatched, not the time\n"
119 static char host_doc[] =
120 "The hostname of the host this value was read from.\n"
121 "For dispatching this can be set to an empty string which means\n"
122 "the local hostname as defined in collectd.conf.";
124 static char type_doc[] =
125 "The type of this value. This type has to be defined\n"
126 "in the types.db file. Attempting to set it to any other value\n"
127 "will raise a TypeError exception.\n"
128 "Assigning a type is mandatory, calling dispatch without doing\n"
129 "so will raise a RuntimeError exception.";
131 static char type_instance_doc[] = "";
133 static char plugin_doc[] =
134 "The name of the plugin that read the data. Setting this\n"
135 "member to an empty string will insert \"python\" upon dispatching.";
137 static char plugin_instance_doc[] = "";
139 static char PluginData_doc[] =
140 "This is an internal class that is the base for Values\n"
141 "and Notification. It is pretty useless by itself and is therefore not\n"
142 "exported to the collectd module.";
144 static PyObject *PluginData_new(PyTypeObject *type, PyObject *args,
148 self = (PluginData *)type->tp_alloc(type, 0);
155 self->plugin_instance[0] = 0;
157 self->type_instance[0] = 0;
158 return (PyObject *)self;
161 static int PluginData_init(PyObject *s, PyObject *args, PyObject *kwds) {
162 PluginData *self = (PluginData *)s;
164 char *type = NULL, *plugin_instance = NULL, *type_instance = NULL,
165 *plugin = NULL, *host = NULL;
166 static char *kwlist[] = {
167 "type", "plugin_instance", "type_instance", "plugin", "host", "time",
170 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetd", kwlist, NULL,
171 &type, NULL, &plugin_instance, NULL,
172 &type_instance, NULL, &plugin, NULL, &host,
176 if (type && plugin_get_ds(type) == NULL) {
177 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
182 sstrncpy(self->host, host ? host : "", sizeof(self->host));
183 sstrncpy(self->plugin, plugin ? plugin : "", sizeof(self->plugin));
184 sstrncpy(self->plugin_instance, plugin_instance ? plugin_instance : "",
185 sizeof(self->plugin_instance));
186 sstrncpy(self->type, type ? type : "", sizeof(self->type));
187 sstrncpy(self->type_instance, type_instance ? type_instance : "",
188 sizeof(self->type_instance));
196 static PyObject *PluginData_repr(PyObject *s) {
198 static PyObject *l_closing = NULL;
200 if (l_closing == NULL)
201 l_closing = cpy_string_to_unicode_or_bytes(")");
203 if (l_closing == NULL)
206 ret = cpy_common_repr(s);
207 CPY_STRCAT(&ret, l_closing);
211 static PyMemberDef PluginData_members[] = {
212 {"time", T_DOUBLE, offsetof(PluginData, time), 0, time_doc}, {NULL}};
214 static PyObject *PluginData_getstring(PyObject *self, void *data) {
215 const char *value = ((char *)self) + (intptr_t)data;
217 return cpy_string_to_unicode_or_bytes(value);
220 static int PluginData_setstring(PyObject *self, PyObject *value, void *data) {
225 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
229 new = cpy_unicode_or_bytes_to_string(&value);
234 old = ((char *)self) + (intptr_t)data;
235 sstrncpy(old, new, DATA_MAX_NAME_LEN);
240 static int PluginData_settype(PyObject *self, PyObject *value, void *data) {
245 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
249 new = cpy_unicode_or_bytes_to_string(&value);
255 if (plugin_get_ds(new) == NULL) {
256 PyErr_Format(PyExc_TypeError, "Dataset %s not found", new);
261 old = ((char *)self) + (intptr_t)data;
262 sstrncpy(old, new, DATA_MAX_NAME_LEN);
267 static PyGetSetDef PluginData_getseters[] = {
268 {"host", PluginData_getstring, PluginData_setstring, host_doc,
269 (void *)offsetof(PluginData, host)},
270 {"plugin", PluginData_getstring, PluginData_setstring, plugin_doc,
271 (void *)offsetof(PluginData, plugin)},
272 {"plugin_instance", PluginData_getstring, PluginData_setstring,
273 plugin_instance_doc, (void *)offsetof(PluginData, plugin_instance)},
274 {"type_instance", PluginData_getstring, PluginData_setstring,
275 type_instance_doc, (void *)offsetof(PluginData, type_instance)},
276 {"type", PluginData_getstring, PluginData_settype, type_doc,
277 (void *)offsetof(PluginData, type)},
280 PyTypeObject PluginDataType = {
281 CPY_INIT_TYPE "collectd.PluginData", /* tp_name */
282 sizeof(PluginData), /* tp_basicsize */
283 0, /* Will be filled in later */
289 PluginData_repr, /* tp_repr */
290 0, /* tp_as_number */
291 0, /* tp_as_sequence */
292 0, /* tp_as_mapping */
298 0, /* tp_as_buffer */
300 Py_TPFLAGS_BASETYPE /*| Py_TPFLAGS_HAVE_GC*/, /*tp_flags*/
301 PluginData_doc, /* tp_doc */
304 0, /* tp_richcompare */
305 0, /* tp_weaklistoffset */
309 PluginData_members, /* tp_members */
310 PluginData_getseters, /* tp_getset */
313 0, /* tp_descr_get */
314 0, /* tp_descr_set */
315 0, /* tp_dictoffset */
316 PluginData_init, /* tp_init */
318 PluginData_new /* tp_new */
321 static char interval_doc[] =
322 "The interval is the timespan in seconds between two submits for\n"
323 "the same data source. This value has to be a positive integer, so you "
325 "submit more than one value per second. If this member is set to a\n"
326 "non-positive value, the default value as specified in the config file "
328 "be used (default: 10).\n"
330 "If you submit values more often than the specified interval, the average\n"
331 "will be used. If you submit less values, your graphs will have gaps.";
333 static char values_doc[] =
334 "These are the actual values that get dispatched to collectd.\n"
335 "It has to be a sequence (a tuple or list) of numbers.\n"
336 "The size of the sequence and the type of its content depend on the type\n"
337 "member in the types.db file. For more information on this read the\n"
338 "types.db man page.\n"
340 "If the sequence does not have the correct size upon dispatch a "
342 "exception will be raised. If the content of the sequence is not a "
344 "a TypeError exception will be raised.";
346 static char meta_doc[] =
347 "These are the meta data for this Value object.\n"
348 "It has to be a dictionary of numbers, strings or bools. All keys must be\n"
349 "strings. int and long objects will be dispatched as signed integers "
351 "they are between 2**63 and 2**64-1, which will result in an unsigned "
353 "You can force one of these storage classes by using the classes\n"
354 "collectd.Signed and collectd.Unsigned. A meta object received by a write\n"
355 "callback will always contain Signed or Unsigned objects.";
357 static char dispatch_doc[] =
358 "dispatch([type][, values][, plugin_instance][, type_instance]"
359 "[, plugin][, host][, time][, interval]) -> None. Dispatch a value list.\n"
361 "Dispatch this instance to the collectd process. The object has members\n"
362 "for each of the possible arguments for this method. For a detailed "
364 "of these parameters see the member of the same same.\n"
366 "If you do not submit a parameter the value saved in its member will be "
368 "If you do provide a parameter it will be used instead, without altering "
371 static char write_doc[] =
372 "write([destination][, type][, values][, plugin_instance][, type_instance]"
373 "[, plugin][, host][, time][, interval]) -> None. Dispatch a value list.\n"
375 "Write this instance to a single plugin or all plugins if 'destination' is "
377 "This will bypass the main collectd process and all filtering and "
379 "Other than that it works similar to 'dispatch'. In most cases 'dispatch' "
381 "used instead of 'write'.\n";
383 static char Values_doc[] = "A Values object used for dispatching values to "
384 "collectd and receiving values from write "
387 static PyObject *Values_new(PyTypeObject *type, PyObject *args,
391 self = (Values *)PluginData_new(type, args, kwds);
395 self->values = PyList_New(0);
396 self->meta = PyDict_New();
398 return (PyObject *)self;
401 static int Values_init(PyObject *s, PyObject *args, PyObject *kwds) {
402 Values *self = (Values *)s;
403 double interval = 0, time = 0;
404 PyObject *values = NULL, *meta = NULL, *tmp;
405 char *type = NULL, *plugin_instance = NULL, *type_instance = NULL,
406 *plugin = NULL, *host = NULL;
407 static char *kwlist[] = {
408 "type", "values", "plugin_instance", "type_instance", "plugin",
409 "host", "time", "interval", "meta", NULL};
411 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist, NULL,
412 &type, &values, NULL, &plugin_instance, NULL,
413 &type_instance, NULL, &plugin, NULL, &host,
414 &time, &interval, &meta))
417 if (type && plugin_get_ds(type) == NULL) {
418 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
423 sstrncpy(self->data.host, host ? host : "", sizeof(self->data.host));
424 sstrncpy(self->data.plugin, plugin ? plugin : "", sizeof(self->data.plugin));
425 sstrncpy(self->data.plugin_instance, plugin_instance ? plugin_instance : "",
426 sizeof(self->data.plugin_instance));
427 sstrncpy(self->data.type, type ? type : "", sizeof(self->data.type));
428 sstrncpy(self->data.type_instance, type_instance ? type_instance : "",
429 sizeof(self->data.type_instance));
430 self->data.time = time;
434 if (values == NULL) {
435 values = PyList_New(0);
449 self->values = values;
456 self->interval = interval;
460 static meta_data_t *cpy_build_meta(PyObject *meta) {
462 meta_data_t *m = NULL;
465 if ((meta == NULL) || (meta == Py_None))
468 l = PyDict_Items(meta); /* New reference. */
470 cpy_log_exception("building meta data");
479 m = meta_data_create();
480 for (int i = 0; i < s; ++i) {
481 const char *string, *keystring;
482 PyObject *key, *value, *item, *tmp;
484 item = PyList_GET_ITEM(l, i);
485 key = PyTuple_GET_ITEM(item, 0);
487 keystring = cpy_unicode_or_bytes_to_string(&key);
493 value = PyTuple_GET_ITEM(item, 1);
495 if (value == Py_True) {
496 meta_data_add_boolean(m, keystring, 1);
497 } else if (value == Py_False) {
498 meta_data_add_boolean(m, keystring, 0);
499 } else if (PyFloat_Check(value)) {
500 meta_data_add_double(m, keystring, PyFloat_AsDouble(value));
501 } else if (PyObject_TypeCheck(value, &SignedType)) {
503 lli = PyLong_AsLongLong(value);
504 if (!PyErr_Occurred() && (lli == (int64_t)lli))
505 meta_data_add_signed_int(m, keystring, lli);
506 } else if (PyObject_TypeCheck(value, &UnsignedType)) {
507 long long unsigned llu;
508 llu = PyLong_AsUnsignedLongLong(value);
509 if (!PyErr_Occurred() && (llu == (uint64_t)llu))
510 meta_data_add_unsigned_int(m, keystring, llu);
511 } else if (PyNumber_Check(value)) {
513 long long unsigned llu;
514 tmp = PyNumber_Long(value);
515 lli = PyLong_AsLongLong(tmp);
516 if (!PyErr_Occurred() && (lli == (int64_t)lli)) {
517 meta_data_add_signed_int(m, keystring, lli);
520 llu = PyLong_AsUnsignedLongLong(tmp);
521 if (!PyErr_Occurred() && (llu == (uint64_t)llu))
522 meta_data_add_unsigned_int(m, keystring, llu);
526 string = cpy_unicode_or_bytes_to_string(&value);
528 meta_data_add_string(m, keystring, string);
531 tmp = PyObject_Str(value);
532 string = cpy_unicode_or_bytes_to_string(&tmp);
534 meta_data_add_string(m, keystring, string);
538 if (PyErr_Occurred())
539 cpy_log_exception("building meta data");
547 static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
549 const data_set_t *ds;
552 value_list_t value_list = VALUE_LIST_INIT;
553 PyObject *values = self->values, *meta = self->meta;
554 double time = self->data.time, interval = self->interval;
555 char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL,
556 *type_instance = NULL;
558 static char *kwlist[] = {
559 "type", "values", "plugin_instance", "type_instance", "plugin",
560 "host", "time", "interval", "meta", NULL};
561 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist, NULL,
562 &type, &values, NULL, &plugin_instance, NULL,
563 &type_instance, NULL, &plugin, NULL, &host,
564 &time, &interval, &meta))
567 sstrncpy(value_list.host, host ? host : self->data.host,
568 sizeof(value_list.host));
569 sstrncpy(value_list.plugin, plugin ? plugin : self->data.plugin,
570 sizeof(value_list.plugin));
571 sstrncpy(value_list.plugin_instance,
572 plugin_instance ? plugin_instance : self->data.plugin_instance,
573 sizeof(value_list.plugin_instance));
574 sstrncpy(value_list.type, type ? type : self->data.type,
575 sizeof(value_list.type));
576 sstrncpy(value_list.type_instance,
577 type_instance ? type_instance : self->data.type_instance,
578 sizeof(value_list.type_instance));
580 if (value_list.type[0] == 0) {
581 PyErr_SetString(PyExc_RuntimeError, "type not set");
585 ds = plugin_get_ds(value_list.type);
587 PyErr_Format(PyExc_TypeError, "Dataset %s not found", value_list.type);
590 if (values == NULL ||
591 (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
592 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
595 if (meta != NULL && meta != Py_None && !PyDict_Check(meta)) {
596 PyErr_Format(PyExc_TypeError, "meta must be a dict");
599 size = (size_t)PySequence_Length(values);
600 if (size != ds->ds_num) {
601 PyErr_Format(PyExc_RuntimeError, "type %s needs %zu values, got %zu",
602 value_list.type, ds->ds_num, size);
605 value = calloc(size, sizeof(*value));
606 for (size_t i = 0; i < size; ++i) {
607 PyObject *item, *num;
608 item = PySequence_Fast_GET_ITEM(values, (int)i); /* Borrowed reference. */
609 switch (ds->ds[i].type) {
610 case DS_TYPE_COUNTER:
611 num = PyNumber_Long(item); /* New reference. */
613 value[i].counter = PyLong_AsUnsignedLongLong(num);
618 num = PyNumber_Float(item); /* New reference. */
620 value[i].gauge = PyFloat_AsDouble(num);
625 /* This might overflow without raising an exception.
626 * Not much we can do about it */
627 num = PyNumber_Long(item); /* New reference. */
629 value[i].derive = PyLong_AsLongLong(num);
633 case DS_TYPE_ABSOLUTE:
634 /* This might overflow without raising an exception.
635 * Not much we can do about it */
636 num = PyNumber_Long(item); /* New reference. */
638 value[i].absolute = PyLong_AsUnsignedLongLong(num);
644 PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s",
645 ds->ds[i].type, value_list.type);
648 if (PyErr_Occurred() != NULL) {
653 value_list.values = value;
654 value_list.meta = cpy_build_meta(meta);
655 value_list.values_len = size;
656 value_list.time = DOUBLE_TO_CDTIME_T(time);
657 value_list.interval = DOUBLE_TO_CDTIME_T(interval);
658 if (value_list.host[0] == 0)
659 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
660 if (value_list.plugin[0] == 0)
661 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
662 Py_BEGIN_ALLOW_THREADS;
663 ret = plugin_dispatch_values(&value_list);
664 Py_END_ALLOW_THREADS;
665 meta_data_destroy(value_list.meta);
668 PyErr_SetString(PyExc_RuntimeError,
669 "error dispatching values, read the logs");
675 static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
677 const data_set_t *ds;
680 value_list_t value_list = VALUE_LIST_INIT;
681 PyObject *values = self->values, *meta = self->meta;
682 double time = self->data.time, interval = self->interval;
683 char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL,
684 *type_instance = NULL, *dest = NULL;
686 static char *kwlist[] = {
687 "destination", "type", "values", "plugin_instance",
688 "type_instance", "plugin", "host", "time",
689 "interval", "meta", NULL};
690 if (!PyArg_ParseTupleAndKeywords(
691 args, kwds, "et|etOetetetetdiO", kwlist, NULL, &dest, NULL, &type,
692 &values, NULL, &plugin_instance, NULL, &type_instance, NULL, &plugin,
693 NULL, &host, &time, &interval, &meta))
696 sstrncpy(value_list.host, host ? host : self->data.host,
697 sizeof(value_list.host));
698 sstrncpy(value_list.plugin, plugin ? plugin : self->data.plugin,
699 sizeof(value_list.plugin));
700 sstrncpy(value_list.plugin_instance,
701 plugin_instance ? plugin_instance : self->data.plugin_instance,
702 sizeof(value_list.plugin_instance));
703 sstrncpy(value_list.type, type ? type : self->data.type,
704 sizeof(value_list.type));
705 sstrncpy(value_list.type_instance,
706 type_instance ? type_instance : self->data.type_instance,
707 sizeof(value_list.type_instance));
709 if (value_list.type[0] == 0) {
710 PyErr_SetString(PyExc_RuntimeError, "type not set");
713 ds = plugin_get_ds(value_list.type);
715 PyErr_Format(PyExc_TypeError, "Dataset %s not found", value_list.type);
718 if (values == NULL ||
719 (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
720 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
723 size = (size_t)PySequence_Length(values);
724 if (size != ds->ds_num) {
725 PyErr_Format(PyExc_RuntimeError, "type %s needs %zu values, got %zu",
726 value_list.type, ds->ds_num, size);
729 value = calloc(size, sizeof(*value));
730 for (size_t i = 0; i < size; ++i) {
731 PyObject *item, *num;
732 item = PySequence_Fast_GET_ITEM(values, i); /* Borrowed reference. */
733 switch (ds->ds[i].type) {
734 case DS_TYPE_COUNTER:
735 num = PyNumber_Long(item); /* New reference. */
737 value[i].counter = PyLong_AsUnsignedLongLong(num);
742 num = PyNumber_Float(item); /* New reference. */
744 value[i].gauge = PyFloat_AsDouble(num);
749 /* This might overflow without raising an exception.
750 * Not much we can do about it */
751 num = PyNumber_Long(item); /* New reference. */
753 value[i].derive = PyLong_AsLongLong(num);
757 case DS_TYPE_ABSOLUTE:
758 /* This might overflow without raising an exception.
759 * Not much we can do about it */
760 num = PyNumber_Long(item); /* New reference. */
762 value[i].absolute = PyLong_AsUnsignedLongLong(num);
768 PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s",
769 ds->ds[i].type, value_list.type);
772 if (PyErr_Occurred() != NULL) {
777 value_list.values = value;
778 value_list.values_len = size;
779 value_list.time = DOUBLE_TO_CDTIME_T(time);
780 value_list.interval = DOUBLE_TO_CDTIME_T(interval);
781 value_list.meta = cpy_build_meta(meta);
782 if (value_list.host[0] == 0)
783 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
784 if (value_list.plugin[0] == 0)
785 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
786 Py_BEGIN_ALLOW_THREADS;
787 ret = plugin_write(dest, NULL, &value_list);
788 Py_END_ALLOW_THREADS;
789 meta_data_destroy(value_list.meta);
792 PyErr_SetString(PyExc_RuntimeError,
793 "error dispatching values, read the logs");
799 static PyObject *Values_repr(PyObject *s) {
801 static PyObject *l_interval = NULL, *l_values = NULL, *l_meta = NULL,
803 Values *self = (Values *)s;
805 if (l_interval == NULL)
806 l_interval = cpy_string_to_unicode_or_bytes(",interval=");
807 if (l_values == NULL)
808 l_values = cpy_string_to_unicode_or_bytes(",values=");
810 l_meta = cpy_string_to_unicode_or_bytes(",meta=");
811 if (l_closing == NULL)
812 l_closing = cpy_string_to_unicode_or_bytes(")");
814 if (l_interval == NULL || l_values == NULL || l_meta == NULL ||
818 ret = cpy_common_repr(s);
819 if (self->interval != 0) {
820 CPY_STRCAT(&ret, l_interval);
821 tmp = PyFloat_FromDouble(self->interval);
822 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
823 CPY_STRCAT_AND_DEL(&ret, tmp);
826 (!PyList_Check(self->values) || PySequence_Length(self->values) > 0)) {
827 CPY_STRCAT(&ret, l_values);
828 tmp = PyObject_Repr(self->values);
829 CPY_STRCAT_AND_DEL(&ret, tmp);
832 (!PyDict_Check(self->meta) || PyDict_Size(self->meta) > 0)) {
833 CPY_STRCAT(&ret, l_meta);
834 tmp = PyObject_Repr(self->meta);
835 CPY_STRCAT_AND_DEL(&ret, tmp);
837 CPY_STRCAT(&ret, l_closing);
841 static int Values_traverse(PyObject *self, visitproc visit, void *arg) {
842 Values *v = (Values *)self;
848 static int Values_clear(PyObject *self) {
849 Values *v = (Values *)self;
855 static void Values_dealloc(PyObject *self) {
857 self->ob_type->tp_free(self);
860 static PyMemberDef Values_members[] = {
861 {"interval", T_DOUBLE, offsetof(Values, interval), 0, interval_doc},
862 {"values", T_OBJECT_EX, offsetof(Values, values), 0, values_doc},
863 {"meta", T_OBJECT_EX, offsetof(Values, meta), 0, meta_doc},
866 static PyMethodDef Values_methods[] = {
867 {"dispatch", (PyCFunction)Values_dispatch, METH_VARARGS | METH_KEYWORDS,
869 {"write", (PyCFunction)Values_write, METH_VARARGS | METH_KEYWORDS,
873 PyTypeObject ValuesType = {
874 CPY_INIT_TYPE "collectd.Values", /* tp_name */
875 sizeof(Values), /* tp_basicsize */
876 0, /* Will be filled in later */
877 Values_dealloc, /* tp_dealloc */
882 Values_repr, /* tp_repr */
883 0, /* tp_as_number */
884 0, /* tp_as_sequence */
885 0, /* tp_as_mapping */
891 0, /* tp_as_buffer */
892 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
893 Values_doc, /* tp_doc */
894 Values_traverse, /* tp_traverse */
895 Values_clear, /* tp_clear */
896 0, /* tp_richcompare */
897 0, /* tp_weaklistoffset */
900 Values_methods, /* tp_methods */
901 Values_members, /* tp_members */
905 0, /* tp_descr_get */
906 0, /* tp_descr_set */
907 0, /* tp_dictoffset */
908 Values_init, /* tp_init */
910 Values_new /* tp_new */
913 static char severity_doc[] =
914 "The severity of this notification. Assign or compare to\n"
915 "NOTIF_FAILURE, NOTIF_WARNING or NOTIF_OKAY.";
917 static char message_doc[] = "Some kind of description what's going on and why "
918 "this Notification was generated.";
920 static char Notification_doc[] =
921 "The Notification class is a wrapper around the collectd notification.\n"
922 "It can be used to notify other plugins about bad stuff happening. It "
924 "similar to Values but has a severity and a message instead of interval\n"
926 "Notifications can be dispatched at any time and can be received with "
927 "register_notification.";
929 static int Notification_init(PyObject *s, PyObject *args, PyObject *kwds) {
930 Notification *self = (Notification *)s;
933 char *message = NULL;
934 char *type = NULL, *plugin_instance = NULL, *type_instance = NULL,
935 *plugin = NULL, *host = NULL;
936 static char *kwlist[] = {"type", "message", "plugin_instance",
937 "type_instance", "plugin", "host",
938 "time", "severity", NULL};
940 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist, NULL,
941 &type, NULL, &message, NULL,
942 &plugin_instance, NULL, &type_instance, NULL,
943 &plugin, NULL, &host, &time, &severity))
946 if (type && plugin_get_ds(type) == NULL) {
947 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
953 sstrncpy(self->data.host, host ? host : "", sizeof(self->data.host));
954 sstrncpy(self->data.plugin, plugin ? plugin : "", sizeof(self->data.plugin));
955 sstrncpy(self->data.plugin_instance, plugin_instance ? plugin_instance : "",
956 sizeof(self->data.plugin_instance));
957 sstrncpy(self->data.type, type ? type : "", sizeof(self->data.type));
958 sstrncpy(self->data.type_instance, type_instance ? type_instance : "",
959 sizeof(self->data.type_instance));
960 sstrncpy(self->message, message ? message : "", sizeof(self->message));
961 self->data.time = time;
962 self->severity = severity;
969 static PyObject *Notification_dispatch(Notification *self, PyObject *args,
972 const data_set_t *ds;
973 notification_t notification;
974 double t = self->data.time;
975 int severity = self->severity;
976 char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL,
977 *type_instance = NULL;
978 char *message = NULL;
980 static char *kwlist[] = {"type", "message", "plugin_instance",
981 "type_instance", "plugin", "host",
982 "time", "severity", NULL};
983 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist, NULL,
984 &type, NULL, &message, NULL,
985 &plugin_instance, NULL, &type_instance, NULL,
986 &plugin, NULL, &host, &t, &severity))
989 notification.time = DOUBLE_TO_CDTIME_T(t);
990 notification.severity = severity;
991 sstrncpy(notification.message, message ? message : self->message,
992 sizeof(notification.message));
993 sstrncpy(notification.host, host ? host : self->data.host,
994 sizeof(notification.host));
995 sstrncpy(notification.plugin, plugin ? plugin : self->data.plugin,
996 sizeof(notification.plugin));
997 sstrncpy(notification.plugin_instance,
998 plugin_instance ? plugin_instance : self->data.plugin_instance,
999 sizeof(notification.plugin_instance));
1000 sstrncpy(notification.type, type ? type : self->data.type,
1001 sizeof(notification.type));
1002 sstrncpy(notification.type_instance,
1003 type_instance ? type_instance : self->data.type_instance,
1004 sizeof(notification.type_instance));
1005 notification.meta = NULL;
1007 PyMem_Free(message);
1009 if (notification.type[0] == 0) {
1010 PyErr_SetString(PyExc_RuntimeError, "type not set");
1013 ds = plugin_get_ds(notification.type);
1015 PyErr_Format(PyExc_TypeError, "Dataset %s not found", notification.type);
1019 if (notification.time == 0)
1020 notification.time = cdtime();
1021 if (notification.host[0] == 0)
1022 sstrncpy(notification.host, hostname_g, sizeof(notification.host));
1023 if (notification.plugin[0] == 0)
1024 sstrncpy(notification.plugin, "python", sizeof(notification.plugin));
1025 Py_BEGIN_ALLOW_THREADS;
1026 ret = plugin_dispatch_notification(¬ification);
1027 Py_END_ALLOW_THREADS;
1029 PyErr_SetString(PyExc_RuntimeError,
1030 "error dispatching notification, read the logs");
1036 static PyObject *Notification_new(PyTypeObject *type, PyObject *args,
1040 self = (Notification *)PluginData_new(type, args, kwds);
1044 self->message[0] = 0;
1046 return (PyObject *)self;
1049 static int Notification_setstring(PyObject *self, PyObject *value, void *data) {
1053 if (value == NULL) {
1054 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
1058 new = cpy_unicode_or_bytes_to_string(&value);
1063 old = ((char *)self) + (intptr_t)data;
1064 sstrncpy(old, new, NOTIF_MAX_MSG_LEN);
1069 static PyObject *Notification_repr(PyObject *s) {
1070 PyObject *ret, *tmp;
1071 static PyObject *l_severity = NULL, *l_message = NULL, *l_closing = NULL;
1072 Notification *self = (Notification *)s;
1074 if (l_severity == NULL)
1075 l_severity = cpy_string_to_unicode_or_bytes(",severity=");
1076 if (l_message == NULL)
1077 l_message = cpy_string_to_unicode_or_bytes(",message=");
1078 if (l_closing == NULL)
1079 l_closing = cpy_string_to_unicode_or_bytes(")");
1081 if (l_severity == NULL || l_message == NULL || l_closing == NULL)
1084 ret = cpy_common_repr(s);
1085 if (self->severity != 0) {
1086 CPY_STRCAT(&ret, l_severity);
1087 tmp = PyInt_FromLong(self->severity);
1088 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
1089 CPY_STRCAT_AND_DEL(&ret, tmp);
1091 if (self->message[0] != 0) {
1092 CPY_STRCAT(&ret, l_message);
1093 tmp = cpy_string_to_unicode_or_bytes(self->message);
1094 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
1095 CPY_STRCAT_AND_DEL(&ret, tmp);
1097 CPY_STRCAT(&ret, l_closing);
1101 static PyMethodDef Notification_methods[] = {
1102 {"dispatch", (PyCFunction)Notification_dispatch,
1103 METH_VARARGS | METH_KEYWORDS, dispatch_doc},
1106 static PyMemberDef Notification_members[] = {
1107 {"severity", T_INT, offsetof(Notification, severity), 0, severity_doc},
1110 static PyGetSetDef Notification_getseters[] = {
1111 {"message", PluginData_getstring, Notification_setstring, message_doc,
1112 (void *)offsetof(Notification, message)},
1115 PyTypeObject NotificationType = {
1116 CPY_INIT_TYPE "collectd.Notification", /* tp_name */
1117 sizeof(Notification), /* tp_basicsize */
1118 0, /* Will be filled in later */
1124 Notification_repr, /* tp_repr */
1125 0, /* tp_as_number */
1126 0, /* tp_as_sequence */
1127 0, /* tp_as_mapping */
1131 0, /* tp_getattro */
1132 0, /* tp_setattro */
1133 0, /* tp_as_buffer */
1134 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1135 Notification_doc, /* tp_doc */
1136 0, /* tp_traverse */
1138 0, /* tp_richcompare */
1139 0, /* tp_weaklistoffset */
1141 0, /* tp_iternext */
1142 Notification_methods, /* tp_methods */
1143 Notification_members, /* tp_members */
1144 Notification_getseters, /* tp_getset */
1147 0, /* tp_descr_get */
1148 0, /* tp_descr_set */
1149 0, /* tp_dictoffset */
1150 Notification_init, /* tp_init */
1152 Notification_new /* tp_new */
1155 static char Signed_doc[] =
1156 "This is a long by another name. Use it in meta data dicts\n"
1157 "to choose the way it is stored in the meta data.";
1159 PyTypeObject SignedType = {
1160 CPY_INIT_TYPE "collectd.Signed", /* tp_name */
1161 sizeof(Signed), /* tp_basicsize */
1162 0, /* Will be filled in later */
1169 0, /* tp_as_number */
1170 0, /* tp_as_sequence */
1171 0, /* tp_as_mapping */
1175 0, /* tp_getattro */
1176 0, /* tp_setattro */
1177 0, /* tp_as_buffer */
1178 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1179 Signed_doc /* tp_doc */
1182 static char Unsigned_doc[] =
1183 "This is a long by another name. Use it in meta data dicts\n"
1184 "to choose the way it is stored in the meta data.";
1186 PyTypeObject UnsignedType = {
1187 CPY_INIT_TYPE "collectd.Unsigned", /* tp_name */
1188 sizeof(Unsigned), /* tp_basicsize */
1189 0, /* Will be filled in later */
1196 0, /* tp_as_number */
1197 0, /* tp_as_sequence */
1198 0, /* tp_as_mapping */
1202 0, /* tp_getattro */
1203 0, /* tp_setattro */
1204 0, /* tp_as_buffer */
1205 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1206 Unsigned_doc /* tp_doc */