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 (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 (i = 0; i < size; ++i) {
553 PyObject *item, *num;
554 item = PySequence_Fast_GET_ITEM(values, (int) i); /* Borrowed reference. */
555 if (ds->ds->type == DS_TYPE_COUNTER) {
556 num = PyNumber_Long(item); /* New reference. */
558 value[i].counter = PyLong_AsUnsignedLongLong(num);
561 } else if (ds->ds->type == DS_TYPE_GAUGE) {
562 num = PyNumber_Float(item); /* New reference. */
564 value[i].gauge = PyFloat_AsDouble(num);
567 } else if (ds->ds->type == DS_TYPE_DERIVE) {
568 /* This might overflow without raising an exception.
569 * Not much we can do about it */
570 num = PyNumber_Long(item); /* New reference. */
572 value[i].derive = PyLong_AsLongLong(num);
575 } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
576 /* This might overflow without raising an exception.
577 * Not much we can do about it */
578 num = PyNumber_Long(item); /* New reference. */
580 value[i].absolute = PyLong_AsUnsignedLongLong(num);
585 PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds->type, value_list.type);
588 if (PyErr_Occurred() != NULL) {
593 value_list.values = value;
594 value_list.meta = cpy_build_meta(meta);
595 value_list.values_len = size;
596 value_list.time = DOUBLE_TO_CDTIME_T(time);
597 value_list.interval = DOUBLE_TO_CDTIME_T(interval);
598 if (value_list.host[0] == 0)
599 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
600 if (value_list.plugin[0] == 0)
601 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
602 Py_BEGIN_ALLOW_THREADS;
603 ret = plugin_dispatch_values(&value_list);
604 Py_END_ALLOW_THREADS;
605 meta_data_destroy(value_list.meta);
608 PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
614 static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
616 const data_set_t *ds;
619 value_list_t value_list = VALUE_LIST_INIT;
620 PyObject *values = self->values, *meta = self->meta;
621 double time = self->data.time, interval = self->interval;
622 char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL, *type_instance = NULL, *dest = NULL;
624 static char *kwlist[] = {"destination", "type", "values", "plugin_instance", "type_instance",
625 "plugin", "host", "time", "interval", "meta", NULL};
626 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|etOetetetetdiO", kwlist, NULL, &dest,
627 NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
628 NULL, &plugin, NULL, &host, &time, &interval, &meta))
631 sstrncpy(value_list.host, host ? host : self->data.host, sizeof(value_list.host));
632 sstrncpy(value_list.plugin, plugin ? plugin : self->data.plugin, sizeof(value_list.plugin));
633 sstrncpy(value_list.plugin_instance, plugin_instance ? plugin_instance : self->data.plugin_instance, sizeof(value_list.plugin_instance));
634 sstrncpy(value_list.type, type ? type : self->data.type, sizeof(value_list.type));
635 sstrncpy(value_list.type_instance, type_instance ? type_instance : self->data.type_instance, sizeof(value_list.type_instance));
637 if (value_list.type[0] == 0) {
638 PyErr_SetString(PyExc_RuntimeError, "type not set");
641 ds = plugin_get_ds(value_list.type);
643 PyErr_Format(PyExc_TypeError, "Dataset %s not found", value_list.type);
646 if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
647 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
650 size = (size_t) PySequence_Length(values);
651 if (size != ds->ds_num) {
652 PyErr_Format(PyExc_RuntimeError, "type %s needs %zu values, got %zu", value_list.type, ds->ds_num, size);
655 value = calloc(size, sizeof(*value));
656 for (i = 0; i < size; ++i) {
657 PyObject *item, *num;
658 item = PySequence_Fast_GET_ITEM(values, i); /* Borrowed reference. */
659 if (ds->ds->type == DS_TYPE_COUNTER) {
660 num = PyNumber_Long(item); /* New reference. */
662 value[i].counter = PyLong_AsUnsignedLongLong(num);
665 } else if (ds->ds->type == DS_TYPE_GAUGE) {
666 num = PyNumber_Float(item); /* New reference. */
668 value[i].gauge = PyFloat_AsDouble(num);
671 } else if (ds->ds->type == DS_TYPE_DERIVE) {
672 /* This might overflow without raising an exception.
673 * Not much we can do about it */
674 num = PyNumber_Long(item); /* New reference. */
676 value[i].derive = PyLong_AsLongLong(num);
679 } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
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].absolute = PyLong_AsUnsignedLongLong(num);
689 PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds->type, value_list.type);
692 if (PyErr_Occurred() != NULL) {
697 value_list.values = value;
698 value_list.values_len = size;
699 value_list.time = DOUBLE_TO_CDTIME_T(time);
700 value_list.interval = DOUBLE_TO_CDTIME_T(interval);
701 value_list.meta = cpy_build_meta(meta);
702 if (value_list.host[0] == 0)
703 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
704 if (value_list.plugin[0] == 0)
705 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
706 Py_BEGIN_ALLOW_THREADS;
707 ret = plugin_write(dest, NULL, &value_list);
708 Py_END_ALLOW_THREADS;
709 meta_data_destroy(value_list.meta);
712 PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
718 static PyObject *Values_repr(PyObject *s) {
720 static PyObject *l_interval = NULL, *l_values = NULL, *l_meta = NULL, *l_closing = NULL;
721 Values *self = (Values *) s;
723 if (l_interval == NULL)
724 l_interval = cpy_string_to_unicode_or_bytes(",interval=");
725 if (l_values == NULL)
726 l_values = cpy_string_to_unicode_or_bytes(",values=");
728 l_meta = cpy_string_to_unicode_or_bytes(",meta=");
729 if (l_closing == NULL)
730 l_closing = cpy_string_to_unicode_or_bytes(")");
732 if (l_interval == NULL || l_values == NULL || l_meta == NULL || l_closing == NULL)
735 ret = cpy_common_repr(s);
736 if (self->interval != 0) {
737 CPY_STRCAT(&ret, l_interval);
738 tmp = PyFloat_FromDouble(self->interval);
739 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
740 CPY_STRCAT_AND_DEL(&ret, tmp);
742 if (self->values && (!PyList_Check(self->values) || PySequence_Length(self->values) > 0)) {
743 CPY_STRCAT(&ret, l_values);
744 tmp = PyObject_Repr(self->values);
745 CPY_STRCAT_AND_DEL(&ret, tmp);
747 if (self->meta && (!PyDict_Check(self->meta) || PyDict_Size(self->meta) > 0)) {
748 CPY_STRCAT(&ret, l_meta);
749 tmp = PyObject_Repr(self->meta);
750 CPY_STRCAT_AND_DEL(&ret, tmp);
752 CPY_STRCAT(&ret, l_closing);
756 static int Values_traverse(PyObject *self, visitproc visit, void *arg) {
757 Values *v = (Values *) self;
763 static int Values_clear(PyObject *self) {
764 Values *v = (Values *) self;
770 static void Values_dealloc(PyObject *self) {
772 self->ob_type->tp_free(self);
775 static PyMemberDef Values_members[] = {
776 {"interval", T_DOUBLE, offsetof(Values, interval), 0, interval_doc},
777 {"values", T_OBJECT_EX, offsetof(Values, values), 0, values_doc},
778 {"meta", T_OBJECT_EX, offsetof(Values, meta), 0, meta_doc},
782 static PyMethodDef Values_methods[] = {
783 {"dispatch", (PyCFunction) Values_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
784 {"write", (PyCFunction) Values_write, METH_VARARGS | METH_KEYWORDS, write_doc},
788 PyTypeObject ValuesType = {
790 "collectd.Values", /* tp_name */
791 sizeof(Values), /* tp_basicsize */
792 0, /* Will be filled in later */
793 Values_dealloc, /* tp_dealloc */
798 Values_repr, /* tp_repr */
799 0, /* tp_as_number */
800 0, /* tp_as_sequence */
801 0, /* tp_as_mapping */
807 0, /* tp_as_buffer */
808 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
809 Values_doc, /* tp_doc */
810 Values_traverse, /* tp_traverse */
811 Values_clear, /* tp_clear */
812 0, /* tp_richcompare */
813 0, /* tp_weaklistoffset */
816 Values_methods, /* tp_methods */
817 Values_members, /* tp_members */
821 0, /* tp_descr_get */
822 0, /* tp_descr_set */
823 0, /* tp_dictoffset */
824 Values_init, /* tp_init */
826 Values_new /* tp_new */
829 static char severity_doc[] = "The severity of this notification. Assign or compare to\n"
830 "NOTIF_FAILURE, NOTIF_WARNING or NOTIF_OKAY.";
832 static char message_doc[] = "Some kind of description what's going on and why this Notification was generated.";
834 static char Notification_doc[] = "The Notification class is a wrapper around the collectd notification.\n"
835 "It can be used to notify other plugins about bad stuff happening. It works\n"
836 "similar to Values but has a severity and a message instead of interval\n"
838 "Notifications can be dispatched at any time and can be received with register_notification.";
840 static int Notification_init(PyObject *s, PyObject *args, PyObject *kwds) {
841 Notification *self = (Notification *) s;
844 char *message = NULL;
845 char *type = NULL, *plugin_instance = NULL, *type_instance = NULL, *plugin = NULL, *host = NULL;
846 static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
847 "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, &time, &severity))
854 if (type && plugin_get_ds(type) == NULL) {
855 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
861 sstrncpy(self->data.host, host ? host : "", sizeof(self->data.host));
862 sstrncpy(self->data.plugin, plugin ? plugin : "", sizeof(self->data.plugin));
863 sstrncpy(self->data.plugin_instance, plugin_instance ? plugin_instance : "", sizeof(self->data.plugin_instance));
864 sstrncpy(self->data.type, type ? type : "", sizeof(self->data.type));
865 sstrncpy(self->data.type_instance, type_instance ? type_instance : "", sizeof(self->data.type_instance));
866 sstrncpy(self->message, message ? message : "", sizeof(self->message));
867 self->data.time = time;
868 self->severity = severity;
875 static PyObject *Notification_dispatch(Notification *self, PyObject *args, PyObject *kwds) {
877 const data_set_t *ds;
878 notification_t notification;
879 double t = self->data.time;
880 int severity = self->severity;
881 char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL, *type_instance = NULL;
882 char *message = NULL;
884 static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
885 "plugin", "host", "time", "severity", NULL};
886 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist,
887 NULL, &type, NULL, &message, NULL, &plugin_instance, NULL, &type_instance,
888 NULL, &plugin, NULL, &host, &t, &severity))
891 notification.time = DOUBLE_TO_CDTIME_T(t);
892 notification.severity = severity;
893 sstrncpy(notification.message, message ? message : self->message, sizeof(notification.message));
894 sstrncpy(notification.host, host ? host : self->data.host, sizeof(notification.host));
895 sstrncpy(notification.plugin, plugin ? plugin : self->data.plugin, sizeof(notification.plugin));
896 sstrncpy(notification.plugin_instance, plugin_instance ? plugin_instance : self->data.plugin_instance, sizeof(notification.plugin_instance));
897 sstrncpy(notification.type, type ? type : self->data.type, sizeof(notification.type));
898 sstrncpy(notification.type_instance, type_instance ? type_instance : self->data.type_instance, sizeof(notification.type_instance));
899 notification.meta = NULL;
903 if (notification.type[0] == 0) {
904 PyErr_SetString(PyExc_RuntimeError, "type not set");
907 ds = plugin_get_ds(notification.type);
909 PyErr_Format(PyExc_TypeError, "Dataset %s not found", notification.type);
913 if (notification.time == 0)
914 notification.time = cdtime();
915 if (notification.host[0] == 0)
916 sstrncpy(notification.host, hostname_g, sizeof(notification.host));
917 if (notification.plugin[0] == 0)
918 sstrncpy(notification.plugin, "python", sizeof(notification.plugin));
919 Py_BEGIN_ALLOW_THREADS;
920 ret = plugin_dispatch_notification(¬ification);
921 Py_END_ALLOW_THREADS;
923 PyErr_SetString(PyExc_RuntimeError, "error dispatching notification, read the logs");
929 static PyObject *Notification_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
932 self = (Notification *) PluginData_new(type, args, kwds);
936 self->message[0] = 0;
938 return (PyObject *) self;
941 static int Notification_setstring(PyObject *self, PyObject *value, void *data) {
946 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
950 new = cpy_unicode_or_bytes_to_string(&value);
955 old = ((char *) self) + (intptr_t) data;
956 sstrncpy(old, new, NOTIF_MAX_MSG_LEN);
961 static PyObject *Notification_repr(PyObject *s) {
963 static PyObject *l_severity = NULL, *l_message = NULL, *l_closing = NULL;
964 Notification *self = (Notification *) s;
966 if (l_severity == NULL)
967 l_severity = cpy_string_to_unicode_or_bytes(",severity=");
968 if (l_message == NULL)
969 l_message = cpy_string_to_unicode_or_bytes(",message=");
970 if (l_closing == NULL)
971 l_closing = cpy_string_to_unicode_or_bytes(")");
973 if (l_severity == NULL || l_message == NULL || l_closing == NULL)
976 ret = cpy_common_repr(s);
977 if (self->severity != 0) {
978 CPY_STRCAT(&ret, l_severity);
979 tmp = PyInt_FromLong(self->severity);
980 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
981 CPY_STRCAT_AND_DEL(&ret, tmp);
983 if (self->message[0] != 0) {
984 CPY_STRCAT(&ret, l_message);
985 tmp = cpy_string_to_unicode_or_bytes(self->message);
986 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
987 CPY_STRCAT_AND_DEL(&ret, tmp);
989 CPY_STRCAT(&ret, l_closing);
993 static PyMethodDef Notification_methods[] = {
994 {"dispatch", (PyCFunction) Notification_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
998 static PyMemberDef Notification_members[] = {
999 {"severity", T_INT, offsetof(Notification, severity), 0, severity_doc},
1003 static PyGetSetDef Notification_getseters[] = {
1004 {"message", PluginData_getstring, Notification_setstring, message_doc, (void *) offsetof(Notification, message)},
1008 PyTypeObject NotificationType = {
1010 "collectd.Notification", /* tp_name */
1011 sizeof(Notification), /* tp_basicsize */
1012 0, /* Will be filled in later */
1018 Notification_repr, /* tp_repr */
1019 0, /* tp_as_number */
1020 0, /* tp_as_sequence */
1021 0, /* tp_as_mapping */
1025 0, /* tp_getattro */
1026 0, /* tp_setattro */
1027 0, /* tp_as_buffer */
1028 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1029 Notification_doc, /* tp_doc */
1030 0, /* tp_traverse */
1032 0, /* tp_richcompare */
1033 0, /* tp_weaklistoffset */
1035 0, /* tp_iternext */
1036 Notification_methods, /* tp_methods */
1037 Notification_members, /* tp_members */
1038 Notification_getseters, /* tp_getset */
1041 0, /* tp_descr_get */
1042 0, /* tp_descr_set */
1043 0, /* tp_dictoffset */
1044 Notification_init, /* tp_init */
1046 Notification_new /* tp_new */
1049 static char Signed_doc[] = "This is a long by another name. Use it in meta data dicts\n"
1050 "to choose the way it is stored in the meta data.";
1052 PyTypeObject SignedType = {
1054 "collectd.Signed", /* tp_name */
1055 sizeof(Signed), /* tp_basicsize */
1056 0, /* Will be filled in later */
1063 0, /* tp_as_number */
1064 0, /* tp_as_sequence */
1065 0, /* tp_as_mapping */
1069 0, /* tp_getattro */
1070 0, /* tp_setattro */
1071 0, /* tp_as_buffer */
1072 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1073 Signed_doc /* tp_doc */
1076 static char Unsigned_doc[] = "This is a long by another name. Use it in meta data dicts\n"
1077 "to choose the way it is stored in the meta data.";
1079 PyTypeObject UnsignedType = {
1081 "collectd.Unsigned", /* tp_name */
1082 sizeof(Unsigned), /* tp_basicsize */
1083 0, /* Will be filled in later */
1090 0, /* tp_as_number */
1091 0, /* tp_as_sequence */
1092 0, /* tp_as_mapping */
1096 0, /* tp_getattro */
1097 0, /* tp_setattro */
1098 0, /* tp_as_buffer */
1099 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1100 Unsigned_doc /* tp_doc */