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>
36 #define FreeAll() do {\
38 PyMem_Free(plugin_instance);\
39 PyMem_Free(type_instance);\
44 static PyObject *cpy_common_repr(PyObject *s) {
46 static PyObject *l_type = NULL, *l_type_instance = NULL, *l_plugin = NULL, *l_plugin_instance = NULL;
47 static PyObject *l_host = NULL, *l_time = NULL;
48 PluginData *self = (PluginData *) s;
51 l_type = cpy_string_to_unicode_or_bytes("(type=");
52 if (l_type_instance == NULL)
53 l_type_instance = cpy_string_to_unicode_or_bytes(",type_instance=");
55 l_plugin = cpy_string_to_unicode_or_bytes(",plugin=");
56 if (l_plugin_instance == NULL)
57 l_plugin_instance = cpy_string_to_unicode_or_bytes(",plugin_instance=");
59 l_host = cpy_string_to_unicode_or_bytes(",host=");
61 l_time = cpy_string_to_unicode_or_bytes(",time=");
63 if (!l_type || !l_type_instance || !l_plugin || !l_plugin_instance || !l_host || !l_time)
66 ret = cpy_string_to_unicode_or_bytes(s->ob_type->tp_name);
68 CPY_STRCAT(&ret, l_type);
69 tmp = cpy_string_to_unicode_or_bytes(self->type);
70 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
71 CPY_STRCAT_AND_DEL(&ret, tmp);
73 if (self->type_instance[0] != 0) {
74 CPY_STRCAT(&ret, l_type_instance);
75 tmp = cpy_string_to_unicode_or_bytes(self->type_instance);
76 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
77 CPY_STRCAT_AND_DEL(&ret, tmp);
80 if (self->plugin[0] != 0) {
81 CPY_STRCAT(&ret, l_plugin);
82 tmp = cpy_string_to_unicode_or_bytes(self->plugin);
83 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
84 CPY_STRCAT_AND_DEL(&ret, tmp);
87 if (self->plugin_instance[0] != 0) {
88 CPY_STRCAT(&ret, l_plugin_instance);
89 tmp = cpy_string_to_unicode_or_bytes(self->plugin_instance);
90 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
91 CPY_STRCAT_AND_DEL(&ret, tmp);
94 if (self->host[0] != 0) {
95 CPY_STRCAT(&ret, l_host);
96 tmp = cpy_string_to_unicode_or_bytes(self->host);
97 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
98 CPY_STRCAT_AND_DEL(&ret, tmp);
101 if (self->time != 0) {
102 CPY_STRCAT(&ret, l_time);
103 tmp = PyFloat_FromDouble(self->time);
104 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
105 CPY_STRCAT_AND_DEL(&ret, tmp);
110 static char time_doc[] = "This is the Unix timestamp of the time this value was read.\n"
111 "For dispatching values this can be set to 0 which means \"now\".\n"
112 "This means the time the value is actually dispatched, not the time\n"
115 static char host_doc[] = "The hostname of the host this value was read from.\n"
116 "For dispatching this can be set to an empty string which means\n"
117 "the local hostname as defined in collectd.conf.";
119 static char type_doc[] = "The type of this value. This type has to be defined\n"
120 "in the types.db file. Attempting to set it to any other value\n"
121 "will raise a TypeError exception.\n"
122 "Assigning a type is mandatory, calling dispatch without doing\n"
123 "so will raise a RuntimeError exception.";
125 static char type_instance_doc[] = "";
127 static char plugin_doc[] = "The name of the plugin that read the data. Setting this\n"
128 "member to an empty string will insert \"python\" upon dispatching.";
130 static char plugin_instance_doc[] = "";
132 static char PluginData_doc[] = "This is an internal class that is the base for Values\n"
133 "and Notification. It is pretty useless by itself and is therefore not\n"
134 "exported to the collectd module.";
136 static PyObject *PluginData_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
139 self = (PluginData *) type->tp_alloc(type, 0);
146 self->plugin_instance[0] = 0;
148 self->type_instance[0] = 0;
149 return (PyObject *) self;
152 static int PluginData_init(PyObject *s, PyObject *args, PyObject *kwds) {
153 PluginData *self = (PluginData *) s;
155 char *type = NULL, *plugin_instance = NULL, *type_instance = NULL, *plugin = NULL, *host = NULL;
156 static char *kwlist[] = {"type", "plugin_instance", "type_instance",
157 "plugin", "host", "time", NULL};
159 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetd", kwlist, NULL, &type,
160 NULL, &plugin_instance, NULL, &type_instance, NULL, &plugin, NULL, &host, &time))
163 if (type && plugin_get_ds(type) == NULL) {
164 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
169 sstrncpy(self->host, host ? host : "", sizeof(self->host));
170 sstrncpy(self->plugin, plugin ? plugin : "", sizeof(self->plugin));
171 sstrncpy(self->plugin_instance, plugin_instance ? plugin_instance : "", sizeof(self->plugin_instance));
172 sstrncpy(self->type, type ? type : "", sizeof(self->type));
173 sstrncpy(self->type_instance, type_instance ? type_instance : "", sizeof(self->type_instance));
181 static PyObject *PluginData_repr(PyObject *s) {
183 static PyObject *l_closing = NULL;
185 if (l_closing == NULL)
186 l_closing = cpy_string_to_unicode_or_bytes(")");
188 if (l_closing == NULL)
191 ret = cpy_common_repr(s);
192 CPY_STRCAT(&ret, l_closing);
196 static PyMemberDef PluginData_members[] = {
197 {"time", T_DOUBLE, offsetof(PluginData, time), 0, time_doc},
201 static PyObject *PluginData_getstring(PyObject *self, void *data) {
202 const char *value = ((char *) self) + (intptr_t) data;
204 return cpy_string_to_unicode_or_bytes(value);
207 static int PluginData_setstring(PyObject *self, PyObject *value, void *data) {
212 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
216 new = cpy_unicode_or_bytes_to_string(&value);
221 old = ((char *) self) + (intptr_t) data;
222 sstrncpy(old, new, DATA_MAX_NAME_LEN);
227 static int PluginData_settype(PyObject *self, PyObject *value, void *data) {
232 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
236 new = cpy_unicode_or_bytes_to_string(&value);
242 if (plugin_get_ds(new) == NULL) {
243 PyErr_Format(PyExc_TypeError, "Dataset %s not found", new);
248 old = ((char *) self) + (intptr_t) data;
249 sstrncpy(old, new, DATA_MAX_NAME_LEN);
254 static PyGetSetDef PluginData_getseters[] = {
255 {"host", PluginData_getstring, PluginData_setstring, host_doc, (void *) offsetof(PluginData, host)},
256 {"plugin", PluginData_getstring, PluginData_setstring, plugin_doc, (void *) offsetof(PluginData, plugin)},
257 {"plugin_instance", PluginData_getstring, PluginData_setstring, plugin_instance_doc, (void *) offsetof(PluginData, plugin_instance)},
258 {"type_instance", PluginData_getstring, PluginData_setstring, type_instance_doc, (void *) offsetof(PluginData, type_instance)},
259 {"type", PluginData_getstring, PluginData_settype, type_doc, (void *) offsetof(PluginData, type)},
263 PyTypeObject PluginDataType = {
265 "collectd.PluginData", /* tp_name */
266 sizeof(PluginData), /* tp_basicsize */
267 0, /* Will be filled in later */
273 PluginData_repr, /* tp_repr */
274 0, /* tp_as_number */
275 0, /* tp_as_sequence */
276 0, /* tp_as_mapping */
282 0, /* tp_as_buffer */
283 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE /*| Py_TPFLAGS_HAVE_GC*/, /*tp_flags*/
284 PluginData_doc, /* tp_doc */
287 0, /* tp_richcompare */
288 0, /* tp_weaklistoffset */
292 PluginData_members, /* tp_members */
293 PluginData_getseters, /* tp_getset */
296 0, /* tp_descr_get */
297 0, /* tp_descr_set */
298 0, /* tp_dictoffset */
299 PluginData_init, /* tp_init */
301 PluginData_new /* tp_new */
304 static char interval_doc[] = "The interval is the timespan in seconds between two submits for\n"
305 "the same data source. This value has to be a positive integer, so you can't\n"
306 "submit more than one value per second. If this member is set to a\n"
307 "non-positive value, the default value as specified in the config file will\n"
308 "be used (default: 10).\n"
310 "If you submit values more often than the specified interval, the average\n"
311 "will be used. If you submit less values, your graphs will have gaps.";
313 static char values_doc[] = "These are the actual values that get dispatched to collectd.\n"
314 "It has to be a sequence (a tuple or list) of numbers.\n"
315 "The size of the sequence and the type of its content depend on the type\n"
316 "member in the types.db file. For more information on this read the\n"
317 "types.db man page.\n"
319 "If the sequence does not have the correct size upon dispatch a RuntimeError\n"
320 "exception will be raised. If the content of the sequence is not a number,\n"
321 "a TypeError exception will be raised.";
323 static char meta_doc[] = "These are the meta data for this Value object.\n"
324 "It has to be a dictionary of numbers, strings or bools. All keys must be\n"
325 "strings. int and long objects will be dispatched as signed integers unless\n"
326 "they are between 2**63 and 2**64-1, which will result in an unsigned integer.\n"
327 "You can force one of these storage classes by using the classes\n"
328 "collectd.Signed and collectd.Unsigned. A meta object received by a write\n"
329 "callback will always contain Signed or Unsigned objects.";
331 static char dispatch_doc[] = "dispatch([type][, values][, plugin_instance][, type_instance]"
332 "[, plugin][, host][, time][, interval]) -> None. Dispatch a value list.\n"
334 "Dispatch this instance to the collectd process. The object has members\n"
335 "for each of the possible arguments for this method. For a detailed explanation\n"
336 "of these parameters see the member of the same same.\n"
338 "If you do not submit a parameter the value saved in its member will be submitted.\n"
339 "If you do provide a parameter it will be used instead, without altering the member.";
341 static char write_doc[] = "write([destination][, type][, values][, plugin_instance][, type_instance]"
342 "[, plugin][, host][, time][, interval]) -> None. Dispatch a value list.\n"
344 "Write this instance to a single plugin or all plugins if 'destination' is omitted.\n"
345 "This will bypass the main collectd process and all filtering and caching.\n"
346 "Other than that it works similar to 'dispatch'. In most cases 'dispatch' should be\n"
347 "used instead of 'write'.\n";
349 static char Values_doc[] = "A Values object used for dispatching values to collectd and receiving values from write callbacks.";
351 static PyObject *Values_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
354 self = (Values *) PluginData_new(type, args, kwds);
358 self->values = PyList_New(0);
359 self->meta = PyDict_New();
361 return (PyObject *) self;
364 static int Values_init(PyObject *s, PyObject *args, PyObject *kwds) {
365 Values *self = (Values *) s;
366 double interval = 0, time = 0;
367 PyObject *values = NULL, *meta = NULL, *tmp;
368 char *type = NULL, *plugin_instance = NULL, *type_instance = NULL, *plugin = NULL, *host = NULL;
369 static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
370 "plugin", "host", "time", "interval", "meta", NULL};
372 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist,
373 NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
374 NULL, &plugin, NULL, &host, &time, &interval, &meta))
377 if (type && plugin_get_ds(type) == NULL) {
378 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
383 sstrncpy(self->data.host, host ? host : "", sizeof(self->data.host));
384 sstrncpy(self->data.plugin, plugin ? plugin : "", sizeof(self->data.plugin));
385 sstrncpy(self->data.plugin_instance, plugin_instance ? plugin_instance : "", sizeof(self->data.plugin_instance));
386 sstrncpy(self->data.type, type ? type : "", sizeof(self->data.type));
387 sstrncpy(self->data.type_instance, type_instance ? type_instance : "", sizeof(self->data.type_instance));
388 self->data.time = time;
392 if (values == NULL) {
393 values = PyList_New(0);
407 self->values = values;
414 self->interval = interval;
418 static meta_data_t *cpy_build_meta(PyObject *meta) {
420 meta_data_t *m = NULL;
423 if ((meta == NULL) || (meta == Py_None))
426 l = PyDict_Items(meta); /* New reference. */
428 cpy_log_exception("building meta data");
437 m = meta_data_create();
438 for (int i = 0; i < s; ++i) {
439 const char *string, *keystring;
440 PyObject *key, *value, *item, *tmp;
442 item = PyList_GET_ITEM(l, i);
443 key = PyTuple_GET_ITEM(item, 0);
445 keystring = cpy_unicode_or_bytes_to_string(&key);
451 value = PyTuple_GET_ITEM(item, 1);
453 if (value == Py_True) {
454 meta_data_add_boolean(m, keystring, 1);
455 } else if (value == Py_False) {
456 meta_data_add_boolean(m, keystring, 0);
457 } else if (PyFloat_Check(value)) {
458 meta_data_add_double(m, keystring, PyFloat_AsDouble(value));
459 } else if (PyObject_TypeCheck(value, &SignedType)) {
461 lli = PyLong_AsLongLong(value);
462 if (!PyErr_Occurred() && (lli == (int64_t) lli))
463 meta_data_add_signed_int(m, keystring, lli);
464 } else if (PyObject_TypeCheck(value, &UnsignedType)) {
465 long long unsigned llu;
466 llu = PyLong_AsUnsignedLongLong(value);
467 if (!PyErr_Occurred() && (llu == (uint64_t) llu))
468 meta_data_add_unsigned_int(m, keystring, llu);
469 } else if (PyNumber_Check(value)) {
471 long long unsigned llu;
472 tmp = PyNumber_Long(value);
473 lli = PyLong_AsLongLong(tmp);
474 if (!PyErr_Occurred() && (lli == (int64_t) lli)) {
475 meta_data_add_signed_int(m, keystring, lli);
478 llu = PyLong_AsUnsignedLongLong(tmp);
479 if (!PyErr_Occurred() && (llu == (uint64_t) llu))
480 meta_data_add_unsigned_int(m, keystring, llu);
484 string = cpy_unicode_or_bytes_to_string(&value);
486 meta_data_add_string(m, keystring, string);
489 tmp = PyObject_Str(value);
490 string = cpy_unicode_or_bytes_to_string(&tmp);
492 meta_data_add_string(m, keystring, string);
496 if (PyErr_Occurred())
497 cpy_log_exception("building meta data");
505 static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
507 const data_set_t *ds;
510 value_list_t value_list = VALUE_LIST_INIT;
511 PyObject *values = self->values, *meta = self->meta;
512 double time = self->data.time, interval = self->interval;
513 char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL, *type_instance = NULL;
515 static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
516 "plugin", "host", "time", "interval", "meta", NULL};
517 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist,
518 NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
519 NULL, &plugin, NULL, &host, &time, &interval, &meta))
522 sstrncpy(value_list.host, host ? host : self->data.host, sizeof(value_list.host));
523 sstrncpy(value_list.plugin, plugin ? plugin : self->data.plugin, sizeof(value_list.plugin));
524 sstrncpy(value_list.plugin_instance, plugin_instance ? plugin_instance : self->data.plugin_instance, sizeof(value_list.plugin_instance));
525 sstrncpy(value_list.type, type ? type : self->data.type, sizeof(value_list.type));
526 sstrncpy(value_list.type_instance, type_instance ? type_instance : self->data.type_instance, sizeof(value_list.type_instance));
528 if (value_list.type[0] == 0) {
529 PyErr_SetString(PyExc_RuntimeError, "type not set");
533 ds = plugin_get_ds(value_list.type);
535 PyErr_Format(PyExc_TypeError, "Dataset %s not found", value_list.type);
538 if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
539 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
542 if (meta != NULL && meta != Py_None && !PyDict_Check(meta)) {
543 PyErr_Format(PyExc_TypeError, "meta must be a dict");
546 size = (size_t) PySequence_Length(values);
547 if (size != ds->ds_num) {
548 PyErr_Format(PyExc_RuntimeError, "type %s needs %zu values, got %zu", value_list.type, ds->ds_num, size);
551 value = calloc(size, sizeof(*value));
552 for (size_t i = 0; i < size; ++i) {
553 PyObject *item, *num;
554 item = PySequence_Fast_GET_ITEM(values, (int) i); /* Borrowed reference. */
555 switch (ds->ds[i].type) {
556 case DS_TYPE_COUNTER:
557 num = PyNumber_Long(item); /* New reference. */
559 value[i].counter = PyLong_AsUnsignedLongLong(num);
564 num = PyNumber_Float(item); /* New reference. */
566 value[i].gauge = PyFloat_AsDouble(num);
571 /* This might overflow without raising an exception.
572 * Not much we can do about it */
573 num = PyNumber_Long(item); /* New reference. */
575 value[i].derive = PyLong_AsLongLong(num);
579 case DS_TYPE_ABSOLUTE:
580 /* This might overflow without raising an exception.
581 * Not much we can do about it */
582 num = PyNumber_Long(item); /* New reference. */
584 value[i].absolute = PyLong_AsUnsignedLongLong(num);
590 PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds[i].type, value_list.type);
593 if (PyErr_Occurred() != NULL) {
598 value_list.values = value;
599 value_list.meta = cpy_build_meta(meta);
600 value_list.values_len = size;
601 value_list.time = DOUBLE_TO_CDTIME_T(time);
602 value_list.interval = DOUBLE_TO_CDTIME_T(interval);
603 if (value_list.host[0] == 0)
604 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
605 if (value_list.plugin[0] == 0)
606 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
607 Py_BEGIN_ALLOW_THREADS;
608 ret = plugin_dispatch_values(&value_list);
609 Py_END_ALLOW_THREADS;
610 meta_data_destroy(value_list.meta);
613 PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
619 static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
621 const data_set_t *ds;
624 value_list_t value_list = VALUE_LIST_INIT;
625 PyObject *values = self->values, *meta = self->meta;
626 double time = self->data.time, interval = self->interval;
627 char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL, *type_instance = NULL, *dest = NULL;
629 static char *kwlist[] = {"destination", "type", "values", "plugin_instance", "type_instance",
630 "plugin", "host", "time", "interval", "meta", NULL};
631 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|etOetetetetdiO", kwlist, NULL, &dest,
632 NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
633 NULL, &plugin, NULL, &host, &time, &interval, &meta))
636 sstrncpy(value_list.host, host ? host : self->data.host, sizeof(value_list.host));
637 sstrncpy(value_list.plugin, plugin ? plugin : self->data.plugin, sizeof(value_list.plugin));
638 sstrncpy(value_list.plugin_instance, plugin_instance ? plugin_instance : self->data.plugin_instance, sizeof(value_list.plugin_instance));
639 sstrncpy(value_list.type, type ? type : self->data.type, sizeof(value_list.type));
640 sstrncpy(value_list.type_instance, type_instance ? type_instance : self->data.type_instance, sizeof(value_list.type_instance));
642 if (value_list.type[0] == 0) {
643 PyErr_SetString(PyExc_RuntimeError, "type not set");
646 ds = plugin_get_ds(value_list.type);
648 PyErr_Format(PyExc_TypeError, "Dataset %s not found", value_list.type);
651 if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
652 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
655 size = (size_t) PySequence_Length(values);
656 if (size != ds->ds_num) {
657 PyErr_Format(PyExc_RuntimeError, "type %s needs %zu values, got %zu", value_list.type, ds->ds_num, size);
660 value = calloc(size, sizeof(*value));
661 for (size_t i = 0; i < size; ++i) {
662 PyObject *item, *num;
663 item = PySequence_Fast_GET_ITEM(values, i); /* Borrowed reference. */
664 switch (ds->ds[i].type) {
665 case DS_TYPE_COUNTER:
666 num = PyNumber_Long(item); /* New reference. */
668 value[i].counter = PyLong_AsUnsignedLongLong(num);
673 num = PyNumber_Float(item); /* New reference. */
675 value[i].gauge = PyFloat_AsDouble(num);
680 /* This might overflow without raising an exception.
681 * Not much we can do about it */
682 num = PyNumber_Long(item); /* New reference. */
684 value[i].derive = PyLong_AsLongLong(num);
688 case DS_TYPE_ABSOLUTE:
689 /* This might overflow without raising an exception.
690 * Not much we can do about it */
691 num = PyNumber_Long(item); /* New reference. */
693 value[i].absolute = PyLong_AsUnsignedLongLong(num);
699 PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds[i].type, value_list.type);
702 if (PyErr_Occurred() != NULL) {
707 value_list.values = value;
708 value_list.values_len = size;
709 value_list.time = DOUBLE_TO_CDTIME_T(time);
710 value_list.interval = DOUBLE_TO_CDTIME_T(interval);
711 value_list.meta = cpy_build_meta(meta);
712 if (value_list.host[0] == 0)
713 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
714 if (value_list.plugin[0] == 0)
715 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
716 Py_BEGIN_ALLOW_THREADS;
717 ret = plugin_write(dest, NULL, &value_list);
718 Py_END_ALLOW_THREADS;
719 meta_data_destroy(value_list.meta);
722 PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
728 static PyObject *Values_repr(PyObject *s) {
730 static PyObject *l_interval = NULL, *l_values = NULL, *l_meta = NULL, *l_closing = NULL;
731 Values *self = (Values *) s;
733 if (l_interval == NULL)
734 l_interval = cpy_string_to_unicode_or_bytes(",interval=");
735 if (l_values == NULL)
736 l_values = cpy_string_to_unicode_or_bytes(",values=");
738 l_meta = cpy_string_to_unicode_or_bytes(",meta=");
739 if (l_closing == NULL)
740 l_closing = cpy_string_to_unicode_or_bytes(")");
742 if (l_interval == NULL || l_values == NULL || l_meta == NULL || l_closing == NULL)
745 ret = cpy_common_repr(s);
746 if (self->interval != 0) {
747 CPY_STRCAT(&ret, l_interval);
748 tmp = PyFloat_FromDouble(self->interval);
749 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
750 CPY_STRCAT_AND_DEL(&ret, tmp);
752 if (self->values && (!PyList_Check(self->values) || PySequence_Length(self->values) > 0)) {
753 CPY_STRCAT(&ret, l_values);
754 tmp = PyObject_Repr(self->values);
755 CPY_STRCAT_AND_DEL(&ret, tmp);
757 if (self->meta && (!PyDict_Check(self->meta) || PyDict_Size(self->meta) > 0)) {
758 CPY_STRCAT(&ret, l_meta);
759 tmp = PyObject_Repr(self->meta);
760 CPY_STRCAT_AND_DEL(&ret, tmp);
762 CPY_STRCAT(&ret, l_closing);
766 static int Values_traverse(PyObject *self, visitproc visit, void *arg) {
767 Values *v = (Values *) self;
773 static int Values_clear(PyObject *self) {
774 Values *v = (Values *) self;
780 static void Values_dealloc(PyObject *self) {
782 self->ob_type->tp_free(self);
785 static PyMemberDef Values_members[] = {
786 {"interval", T_DOUBLE, offsetof(Values, interval), 0, interval_doc},
787 {"values", T_OBJECT_EX, offsetof(Values, values), 0, values_doc},
788 {"meta", T_OBJECT_EX, offsetof(Values, meta), 0, meta_doc},
792 static PyMethodDef Values_methods[] = {
793 {"dispatch", (PyCFunction) Values_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
794 {"write", (PyCFunction) Values_write, METH_VARARGS | METH_KEYWORDS, write_doc},
798 PyTypeObject ValuesType = {
800 "collectd.Values", /* tp_name */
801 sizeof(Values), /* tp_basicsize */
802 0, /* Will be filled in later */
803 Values_dealloc, /* tp_dealloc */
808 Values_repr, /* tp_repr */
809 0, /* tp_as_number */
810 0, /* tp_as_sequence */
811 0, /* tp_as_mapping */
817 0, /* tp_as_buffer */
818 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
819 Values_doc, /* tp_doc */
820 Values_traverse, /* tp_traverse */
821 Values_clear, /* tp_clear */
822 0, /* tp_richcompare */
823 0, /* tp_weaklistoffset */
826 Values_methods, /* tp_methods */
827 Values_members, /* tp_members */
831 0, /* tp_descr_get */
832 0, /* tp_descr_set */
833 0, /* tp_dictoffset */
834 Values_init, /* tp_init */
836 Values_new /* tp_new */
839 static char severity_doc[] = "The severity of this notification. Assign or compare to\n"
840 "NOTIF_FAILURE, NOTIF_WARNING or NOTIF_OKAY.";
842 static char message_doc[] = "Some kind of description what's going on and why this Notification was generated.";
844 static char Notification_doc[] = "The Notification class is a wrapper around the collectd notification.\n"
845 "It can be used to notify other plugins about bad stuff happening. It works\n"
846 "similar to Values but has a severity and a message instead of interval\n"
848 "Notifications can be dispatched at any time and can be received with register_notification.";
850 static int Notification_init(PyObject *s, PyObject *args, PyObject *kwds) {
851 Notification *self = (Notification *) s;
854 char *message = NULL;
855 char *type = NULL, *plugin_instance = NULL, *type_instance = NULL, *plugin = NULL, *host = NULL;
856 static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
857 "plugin", "host", "time", "severity", NULL};
859 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist,
860 NULL, &type, NULL, &message, NULL, &plugin_instance, NULL, &type_instance,
861 NULL, &plugin, NULL, &host, &time, &severity))
864 if (type && plugin_get_ds(type) == NULL) {
865 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
871 sstrncpy(self->data.host, host ? host : "", sizeof(self->data.host));
872 sstrncpy(self->data.plugin, plugin ? plugin : "", sizeof(self->data.plugin));
873 sstrncpy(self->data.plugin_instance, plugin_instance ? plugin_instance : "", sizeof(self->data.plugin_instance));
874 sstrncpy(self->data.type, type ? type : "", sizeof(self->data.type));
875 sstrncpy(self->data.type_instance, type_instance ? type_instance : "", sizeof(self->data.type_instance));
876 sstrncpy(self->message, message ? message : "", sizeof(self->message));
877 self->data.time = time;
878 self->severity = severity;
885 static PyObject *Notification_dispatch(Notification *self, PyObject *args, PyObject *kwds) {
887 const data_set_t *ds;
888 notification_t notification;
889 double t = self->data.time;
890 int severity = self->severity;
891 char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL, *type_instance = NULL;
892 char *message = NULL;
894 static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
895 "plugin", "host", "time", "severity", NULL};
896 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist,
897 NULL, &type, NULL, &message, NULL, &plugin_instance, NULL, &type_instance,
898 NULL, &plugin, NULL, &host, &t, &severity))
901 notification.time = DOUBLE_TO_CDTIME_T(t);
902 notification.severity = severity;
903 sstrncpy(notification.message, message ? message : self->message, sizeof(notification.message));
904 sstrncpy(notification.host, host ? host : self->data.host, sizeof(notification.host));
905 sstrncpy(notification.plugin, plugin ? plugin : self->data.plugin, sizeof(notification.plugin));
906 sstrncpy(notification.plugin_instance, plugin_instance ? plugin_instance : self->data.plugin_instance, sizeof(notification.plugin_instance));
907 sstrncpy(notification.type, type ? type : self->data.type, sizeof(notification.type));
908 sstrncpy(notification.type_instance, type_instance ? type_instance : self->data.type_instance, sizeof(notification.type_instance));
909 notification.meta = NULL;
913 if (notification.type[0] == 0) {
914 PyErr_SetString(PyExc_RuntimeError, "type not set");
917 ds = plugin_get_ds(notification.type);
919 PyErr_Format(PyExc_TypeError, "Dataset %s not found", notification.type);
923 if (notification.time == 0)
924 notification.time = cdtime();
925 if (notification.host[0] == 0)
926 sstrncpy(notification.host, hostname_g, sizeof(notification.host));
927 if (notification.plugin[0] == 0)
928 sstrncpy(notification.plugin, "python", sizeof(notification.plugin));
929 Py_BEGIN_ALLOW_THREADS;
930 ret = plugin_dispatch_notification(¬ification);
931 Py_END_ALLOW_THREADS;
933 PyErr_SetString(PyExc_RuntimeError, "error dispatching notification, read the logs");
939 static PyObject *Notification_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
942 self = (Notification *) PluginData_new(type, args, kwds);
946 self->message[0] = 0;
948 return (PyObject *) self;
951 static int Notification_setstring(PyObject *self, PyObject *value, void *data) {
956 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
960 new = cpy_unicode_or_bytes_to_string(&value);
965 old = ((char *) self) + (intptr_t) data;
966 sstrncpy(old, new, NOTIF_MAX_MSG_LEN);
971 static PyObject *Notification_repr(PyObject *s) {
973 static PyObject *l_severity = NULL, *l_message = NULL, *l_closing = NULL;
974 Notification *self = (Notification *) s;
976 if (l_severity == NULL)
977 l_severity = cpy_string_to_unicode_or_bytes(",severity=");
978 if (l_message == NULL)
979 l_message = cpy_string_to_unicode_or_bytes(",message=");
980 if (l_closing == NULL)
981 l_closing = cpy_string_to_unicode_or_bytes(")");
983 if (l_severity == NULL || l_message == NULL || l_closing == NULL)
986 ret = cpy_common_repr(s);
987 if (self->severity != 0) {
988 CPY_STRCAT(&ret, l_severity);
989 tmp = PyInt_FromLong(self->severity);
990 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
991 CPY_STRCAT_AND_DEL(&ret, tmp);
993 if (self->message[0] != 0) {
994 CPY_STRCAT(&ret, l_message);
995 tmp = cpy_string_to_unicode_or_bytes(self->message);
996 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
997 CPY_STRCAT_AND_DEL(&ret, tmp);
999 CPY_STRCAT(&ret, l_closing);
1003 static PyMethodDef Notification_methods[] = {
1004 {"dispatch", (PyCFunction) Notification_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
1008 static PyMemberDef Notification_members[] = {
1009 {"severity", T_INT, offsetof(Notification, severity), 0, severity_doc},
1013 static PyGetSetDef Notification_getseters[] = {
1014 {"message", PluginData_getstring, Notification_setstring, message_doc, (void *) offsetof(Notification, message)},
1018 PyTypeObject NotificationType = {
1020 "collectd.Notification", /* tp_name */
1021 sizeof(Notification), /* tp_basicsize */
1022 0, /* Will be filled in later */
1028 Notification_repr, /* tp_repr */
1029 0, /* tp_as_number */
1030 0, /* tp_as_sequence */
1031 0, /* tp_as_mapping */
1035 0, /* tp_getattro */
1036 0, /* tp_setattro */
1037 0, /* tp_as_buffer */
1038 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1039 Notification_doc, /* tp_doc */
1040 0, /* tp_traverse */
1042 0, /* tp_richcompare */
1043 0, /* tp_weaklistoffset */
1045 0, /* tp_iternext */
1046 Notification_methods, /* tp_methods */
1047 Notification_members, /* tp_members */
1048 Notification_getseters, /* tp_getset */
1051 0, /* tp_descr_get */
1052 0, /* tp_descr_set */
1053 0, /* tp_dictoffset */
1054 Notification_init, /* tp_init */
1056 Notification_new /* tp_new */
1059 static char Signed_doc[] = "This is a long by another name. Use it in meta data dicts\n"
1060 "to choose the way it is stored in the meta data.";
1062 PyTypeObject SignedType = {
1064 "collectd.Signed", /* tp_name */
1065 sizeof(Signed), /* tp_basicsize */
1066 0, /* Will be filled in later */
1073 0, /* tp_as_number */
1074 0, /* tp_as_sequence */
1075 0, /* tp_as_mapping */
1079 0, /* tp_getattro */
1080 0, /* tp_setattro */
1081 0, /* tp_as_buffer */
1082 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1083 Signed_doc /* tp_doc */
1086 static char Unsigned_doc[] = "This is a long by another name. Use it in meta data dicts\n"
1087 "to choose the way it is stored in the meta data.";
1089 PyTypeObject UnsignedType = {
1091 "collectd.Unsigned", /* tp_name */
1092 sizeof(Unsigned), /* tp_basicsize */
1093 0, /* Will be filled in later */
1100 0, /* tp_as_number */
1101 0, /* tp_as_sequence */
1102 0, /* tp_as_mapping */
1106 0, /* tp_getattro */
1107 0, /* tp_setattro */
1108 0, /* tp_as_buffer */
1109 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1110 Unsigned_doc /* tp_doc */