2 * collectd - src/pyvalues.c
3 * Copyright (C) 2009 Sven Trenkel
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
24 * Sven Trenkel <collectd at semidefinite.de>
28 #include <structmember.h>
35 #define FreeAll() do {\
37 PyMem_Free(plugin_instance);\
38 PyMem_Free(type_instance);\
43 static PyObject *cpy_common_repr(PyObject *s) {
45 static PyObject *l_type = NULL, *l_type_instance = NULL, *l_plugin = NULL, *l_plugin_instance = NULL;
46 static PyObject *l_host = NULL, *l_time = NULL;
47 PluginData *self = (PluginData *) s;
50 l_type = cpy_string_to_unicode_or_bytes("(type=");
51 if (l_type_instance == NULL)
52 l_type_instance = cpy_string_to_unicode_or_bytes(",type_instance=");
54 l_plugin = cpy_string_to_unicode_or_bytes(",plugin=");
55 if (l_plugin_instance == NULL)
56 l_plugin_instance = cpy_string_to_unicode_or_bytes(",plugin_instance=");
58 l_host = cpy_string_to_unicode_or_bytes(",host=");
60 l_time = cpy_string_to_unicode_or_bytes(",time=");
62 if (!l_type || !l_type_instance || !l_plugin || !l_plugin_instance || !l_host || !l_time)
65 ret = cpy_string_to_unicode_or_bytes(s->ob_type->tp_name);
67 CPY_STRCAT(&ret, l_type);
68 tmp = cpy_string_to_unicode_or_bytes(self->type);
69 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
70 CPY_STRCAT_AND_DEL(&ret, tmp);
72 if (self->type_instance[0] != 0) {
73 CPY_STRCAT(&ret, l_type_instance);
74 tmp = cpy_string_to_unicode_or_bytes(self->type_instance);
75 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
76 CPY_STRCAT_AND_DEL(&ret, tmp);
79 if (self->plugin[0] != 0) {
80 CPY_STRCAT(&ret, l_plugin);
81 tmp = cpy_string_to_unicode_or_bytes(self->plugin);
82 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
83 CPY_STRCAT_AND_DEL(&ret, tmp);
86 if (self->plugin_instance[0] != 0) {
87 CPY_STRCAT(&ret, l_plugin_instance);
88 tmp = cpy_string_to_unicode_or_bytes(self->plugin_instance);
89 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
90 CPY_STRCAT_AND_DEL(&ret, tmp);
93 if (self->host[0] != 0) {
94 CPY_STRCAT(&ret, l_host);
95 tmp = cpy_string_to_unicode_or_bytes(self->host);
96 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
97 CPY_STRCAT_AND_DEL(&ret, tmp);
100 if (self->time != 0) {
101 CPY_STRCAT(&ret, l_time);
102 tmp = PyFloat_FromDouble(self->time);
103 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
104 CPY_STRCAT_AND_DEL(&ret, tmp);
109 static char time_doc[] = "This is the Unix timestap of the time this value was read.\n"
110 "For dispatching values this can be set to 0 which means \"now\".\n"
111 "This means the time the value is actually dispatched, not the time\n"
114 static char host_doc[] = "The hostname of the host this value was read from.\n"
115 "For dispatching this can be set to an empty string which means\n"
116 "the local hostname as defined in the collectd.conf.";
118 static char type_doc[] = "The type of this value. This type has to be defined\n"
119 "in your types.db. Attempting to set it to any other value will\n"
120 "raise a TypeError exception.\n"
121 "Assigning a type is mandetory, calling dispatch without doing\n"
122 "so will raise a RuntimeError exception.";
124 static char type_instance_doc[] = "";
126 static char plugin_doc[] = "The name of the plugin that read the data. Setting this\n"
127 "member to an empty string will insert \"python\" upon dispatching.";
129 static char plugin_instance_doc[] = "";
131 static char PluginData_doc[] = "This is an internal class that is the base for Values\n"
132 "and Notification. It is pretty useless by itself and was therefore not\n"
133 "exported to the collectd module.";
135 static PyObject *PluginData_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
138 self = (PluginData *) type->tp_alloc(type, 0);
145 self->plugin_instance[0] = 0;
147 self->type_instance[0] = 0;
148 return (PyObject *) self;
151 static int PluginData_init(PyObject *s, PyObject *args, PyObject *kwds) {
152 PluginData *self = (PluginData *) s;
154 char *type = NULL, *plugin_instance = NULL, *type_instance = NULL, *plugin = NULL, *host = NULL;
155 static char *kwlist[] = {"type", "plugin_instance", "type_instance",
156 "plugin", "host", "time", NULL};
158 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetd", kwlist, NULL, &type,
159 NULL, &plugin_instance, NULL, &type_instance, NULL, &plugin, NULL, &host, &time))
162 if (type && plugin_get_ds(type) == NULL) {
163 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
168 sstrncpy(self->host, host ? host : "", sizeof(self->host));
169 sstrncpy(self->plugin, plugin ? plugin : "", sizeof(self->plugin));
170 sstrncpy(self->plugin_instance, plugin_instance ? plugin_instance : "", sizeof(self->plugin_instance));
171 sstrncpy(self->type, type ? type : "", sizeof(self->type));
172 sstrncpy(self->type_instance, type_instance ? type_instance : "", sizeof(self->type_instance));
180 static PyObject *PluginData_repr(PyObject *s) {
182 static PyObject *l_closing = NULL;
184 if (l_closing == NULL)
185 l_closing = cpy_string_to_unicode_or_bytes(")");
187 if (l_closing == NULL)
190 ret = cpy_common_repr(s);
191 CPY_STRCAT(&ret, l_closing);
195 static PyMemberDef PluginData_members[] = {
196 {"time", T_DOUBLE, offsetof(PluginData, time), 0, time_doc},
200 static PyObject *PluginData_getstring(PyObject *self, void *data) {
201 const char *value = ((char *) self) + (intptr_t) data;
203 return cpy_string_to_unicode_or_bytes(value);
206 static int PluginData_setstring(PyObject *self, PyObject *value, void *data) {
211 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
215 new = cpy_unicode_or_bytes_to_string(&value);
220 old = ((char *) self) + (intptr_t) data;
221 sstrncpy(old, new, DATA_MAX_NAME_LEN);
226 static int PluginData_settype(PyObject *self, PyObject *value, void *data) {
231 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
235 new = cpy_unicode_or_bytes_to_string(&value);
241 if (plugin_get_ds(new) == NULL) {
242 PyErr_Format(PyExc_TypeError, "Dataset %s not found", new);
247 old = ((char *) self) + (intptr_t) data;
248 sstrncpy(old, new, DATA_MAX_NAME_LEN);
253 static PyGetSetDef PluginData_getseters[] = {
254 {"host", PluginData_getstring, PluginData_setstring, host_doc, (void *) offsetof(PluginData, host)},
255 {"plugin", PluginData_getstring, PluginData_setstring, plugin_doc, (void *) offsetof(PluginData, plugin)},
256 {"plugin_instance", PluginData_getstring, PluginData_setstring, plugin_instance_doc, (void *) offsetof(PluginData, plugin_instance)},
257 {"type_instance", PluginData_getstring, PluginData_setstring, type_instance_doc, (void *) offsetof(PluginData, type_instance)},
258 {"type", PluginData_getstring, PluginData_settype, type_doc, (void *) offsetof(PluginData, type)},
262 PyTypeObject PluginDataType = {
264 "collectd.PluginData", /* tp_name */
265 sizeof(PluginData), /* tp_basicsize */
266 0, /* Will be filled in later */
272 PluginData_repr, /* tp_repr */
273 0, /* tp_as_number */
274 0, /* tp_as_sequence */
275 0, /* tp_as_mapping */
281 0, /* tp_as_buffer */
282 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE /*| Py_TPFLAGS_HAVE_GC*/, /*tp_flags*/
283 PluginData_doc, /* tp_doc */
286 0, /* tp_richcompare */
287 0, /* tp_weaklistoffset */
291 PluginData_members, /* tp_members */
292 PluginData_getseters, /* tp_getset */
295 0, /* tp_descr_get */
296 0, /* tp_descr_set */
297 0, /* tp_dictoffset */
298 PluginData_init, /* tp_init */
300 PluginData_new /* tp_new */
303 static char interval_doc[] = "The interval is the timespan in seconds between two submits for\n"
304 "the same data source. This value has to be a positive integer, so you can't\n"
305 "submit more than one value per second. If this member is set to a\n"
306 "non-positive value, the default value as specified in the config file will\n"
307 "be used (default: 10).\n"
309 "If you submit values more often than the specified interval, the average\n"
310 "will be used. If you submit less values, your graphs will have gaps.";
312 static char values_doc[] = "These are the actual values that get dispatched to collectd.\n"
313 "It has to be a sequence (a tuple or list) of numbers.\n"
314 "The size of the sequence and the type of its content depend on the type\n"
315 "member your types.db file. For more information on this read the types.db\n"
318 "If the sequence does not have the correct size upon dispatch a RuntimeError\n"
319 "exception will be raised. If the content of the sequence is not a number,\n"
320 "a TypeError exception will be raised.";
322 static char meta_doc[] = "These are the meta data for this Value object.\n"
323 "It has to be a dictionary of numbers, strings or bools. All keys must be\n"
324 "strings. int and long objects will be dispatched as signed integers unless\n"
325 "they are between 2**63 and 2**64-1, which will result in a unsigned integer.\n"
326 "You can force one of these storage classes by using the classes\n"
327 "collectd.Signed and collectd.Unsigned. A meta object received by a write\n"
328 "callback will always contain Signed or Unsigned objects.";
330 static char dispatch_doc[] = "dispatch([type][, values][, plugin_instance][, type_instance]"
331 "[, plugin][, host][, time][, interval]) -> None. Dispatch a value list.\n"
333 "Dispatch this instance to the collectd process. The object has members\n"
334 "for each of the possible arguments for this method. For a detailed explanation\n"
335 "of these parameters see the member of the same same.\n"
337 "If you do not submit a parameter the value saved in its member will be submitted.\n"
338 "If you do provide a parameter it will be used instead, without altering the member.";
340 static char write_doc[] = "write([destination][, type][, values][, plugin_instance][, type_instance]"
341 "[, plugin][, host][, time][, interval]) -> None. Dispatch a value list.\n"
343 "Write this instance to a single plugin or all plugins if 'destination' is obmitted.\n"
344 "This will bypass the main collectd process and all filtering and caching.\n"
345 "Other than that it works similar to 'dispatch'. In most cases 'dispatch' should be\n"
346 "used instead of 'write'.\n";
348 static char Values_doc[] = "A Values object used for dispatching values to collectd and receiving values from write callbacks.";
350 static PyObject *Values_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
353 self = (Values *) PluginData_new(type, args, kwds);
357 self->values = PyList_New(0);
358 self->meta = PyDict_New();
360 return (PyObject *) self;
363 static int Values_init(PyObject *s, PyObject *args, PyObject *kwds) {
364 Values *self = (Values *) s;
365 double interval = 0, time = 0;
366 PyObject *values = NULL, *meta = NULL, *tmp;
367 char *type = NULL, *plugin_instance = NULL, *type_instance = NULL, *plugin = NULL, *host = NULL;
368 static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
369 "plugin", "host", "time", "interval", "meta", NULL};
371 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist,
372 NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
373 NULL, &plugin, NULL, &host, &time, &interval, &meta))
376 if (type && plugin_get_ds(type) == NULL) {
377 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
382 sstrncpy(self->data.host, host ? host : "", sizeof(self->data.host));
383 sstrncpy(self->data.plugin, plugin ? plugin : "", sizeof(self->data.plugin));
384 sstrncpy(self->data.plugin_instance, plugin_instance ? plugin_instance : "", sizeof(self->data.plugin_instance));
385 sstrncpy(self->data.type, type ? type : "", sizeof(self->data.type));
386 sstrncpy(self->data.type_instance, type_instance ? type_instance : "", sizeof(self->data.type_instance));
387 self->data.time = time;
391 if (values == NULL) {
392 values = PyList_New(0);
406 self->values = values;
413 self->interval = interval;
417 static meta_data_t *cpy_build_meta(PyObject *meta) {
419 meta_data_t *m = NULL;
422 if ((meta == NULL) || (meta == Py_None))
425 l = PyDict_Items(meta); /* New reference. */
427 cpy_log_exception("building meta data");
436 m = meta_data_create();
437 for (i = 0; i < s; ++i) {
438 const char *string, *keystring;
439 PyObject *key, *value, *item, *tmp;
441 item = PyList_GET_ITEM(l, i);
442 key = PyTuple_GET_ITEM(item, 0);
444 keystring = cpy_unicode_or_bytes_to_string(&key);
450 value = PyTuple_GET_ITEM(item, 1);
452 if (value == Py_True) {
453 meta_data_add_boolean(m, keystring, 1);
454 } else if (value == Py_False) {
455 meta_data_add_boolean(m, keystring, 0);
456 } else if (PyFloat_Check(value)) {
457 meta_data_add_double(m, keystring, PyFloat_AsDouble(value));
458 } else if (PyObject_TypeCheck(value, &SignedType)) {
460 lli = PyLong_AsLongLong(value);
461 if (!PyErr_Occurred() && (lli == (int64_t) lli))
462 meta_data_add_signed_int(m, keystring, lli);
463 } else if (PyObject_TypeCheck(value, &UnsignedType)) {
464 long long unsigned llu;
465 llu = PyLong_AsUnsignedLongLong(value);
466 if (!PyErr_Occurred() && (llu == (uint64_t) llu))
467 meta_data_add_unsigned_int(m, keystring, llu);
468 } else if (PyNumber_Check(value)) {
470 long long unsigned llu;
471 tmp = PyNumber_Long(value);
472 lli = PyLong_AsLongLong(tmp);
473 if (!PyErr_Occurred() && (lli == (int64_t) lli)) {
474 meta_data_add_signed_int(m, keystring, lli);
477 llu = PyLong_AsUnsignedLongLong(tmp);
478 if (!PyErr_Occurred() && (llu == (uint64_t) llu))
479 meta_data_add_unsigned_int(m, keystring, llu);
483 string = cpy_unicode_or_bytes_to_string(&value);
485 meta_data_add_string(m, keystring, string);
488 tmp = PyObject_Str(value);
489 string = cpy_unicode_or_bytes_to_string(&tmp);
491 meta_data_add_string(m, keystring, string);
495 if (PyErr_Occurred())
496 cpy_log_exception("building meta data");
504 static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
506 const data_set_t *ds;
509 value_list_t value_list = VALUE_LIST_INIT;
510 PyObject *values = self->values, *meta = self->meta;
511 double time = self->data.time, interval = self->interval;
512 char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL, *type_instance = NULL;
514 static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
515 "plugin", "host", "time", "interval", "meta", NULL};
516 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist,
517 NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
518 NULL, &plugin, NULL, &host, &time, &interval, &meta))
521 sstrncpy(value_list.host, host ? host : self->data.host, sizeof(value_list.host));
522 sstrncpy(value_list.plugin, plugin ? plugin : self->data.plugin, sizeof(value_list.plugin));
523 sstrncpy(value_list.plugin_instance, plugin_instance ? plugin_instance : self->data.plugin_instance, sizeof(value_list.plugin_instance));
524 sstrncpy(value_list.type, type ? type : self->data.type, sizeof(value_list.type));
525 sstrncpy(value_list.type_instance, type_instance ? type_instance : self->data.type_instance, sizeof(value_list.type_instance));
527 if (value_list.type[0] == 0) {
528 PyErr_SetString(PyExc_RuntimeError, "type not set");
532 ds = plugin_get_ds(value_list.type);
534 PyErr_Format(PyExc_TypeError, "Dataset %s not found", value_list.type);
537 if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
538 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
541 if (meta != NULL && meta != Py_None && !PyDict_Check(meta)) {
542 PyErr_Format(PyExc_TypeError, "meta must be a dict");
545 size = (int) PySequence_Length(values);
546 if (size != ds->ds_num) {
547 PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %i", value_list.type, ds->ds_num, size);
550 value = malloc(size * sizeof(*value));
551 for (i = 0; i < size; ++i) {
552 PyObject *item, *num;
553 item = PySequence_Fast_GET_ITEM(values, i); /* Borrowed reference. */
554 switch (ds->ds[i].type) {
555 case DS_TYPE_COUNTER:
556 num = PyNumber_Long(item); /* New reference. */
558 value[i].counter = PyLong_AsUnsignedLongLong(num);
563 num = PyNumber_Float(item); /* New reference. */
565 value[i].gauge = PyFloat_AsDouble(num);
570 /* This might overflow without raising an exception.
571 * Not much we can do about it */
572 num = PyNumber_Long(item); /* New reference. */
574 value[i].derive = PyLong_AsLongLong(num);
578 case DS_TYPE_ABSOLUTE:
579 /* This might overflow without raising an exception.
580 * Not much we can do about it */
581 num = PyNumber_Long(item); /* New reference. */
583 value[i].absolute = PyLong_AsUnsignedLongLong(num);
589 PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds[i].type, value_list.type);
592 if (PyErr_Occurred() != NULL) {
597 value_list.values = value;
598 value_list.meta = cpy_build_meta(meta);
599 value_list.values_len = size;
600 value_list.time = DOUBLE_TO_CDTIME_T(time);
601 value_list.interval = DOUBLE_TO_CDTIME_T(interval);
602 if (value_list.host[0] == 0)
603 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
604 if (value_list.plugin[0] == 0)
605 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
606 Py_BEGIN_ALLOW_THREADS;
607 ret = plugin_dispatch_values(&value_list);
608 Py_END_ALLOW_THREADS;
609 meta_data_destroy(value_list.meta);
612 PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
618 static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
620 const data_set_t *ds;
623 value_list_t value_list = VALUE_LIST_INIT;
624 PyObject *values = self->values, *meta = self->meta;
625 double time = self->data.time, interval = self->interval;
626 char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL, *type_instance = NULL, *dest = NULL;
628 static char *kwlist[] = {"destination", "type", "values", "plugin_instance", "type_instance",
629 "plugin", "host", "time", "interval", "meta", NULL};
630 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|etOetetetetdiO", kwlist, NULL, &dest,
631 NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
632 NULL, &plugin, NULL, &host, &time, &interval, &meta))
635 sstrncpy(value_list.host, host ? host : self->data.host, sizeof(value_list.host));
636 sstrncpy(value_list.plugin, plugin ? plugin : self->data.plugin, sizeof(value_list.plugin));
637 sstrncpy(value_list.plugin_instance, plugin_instance ? plugin_instance : self->data.plugin_instance, sizeof(value_list.plugin_instance));
638 sstrncpy(value_list.type, type ? type : self->data.type, sizeof(value_list.type));
639 sstrncpy(value_list.type_instance, type_instance ? type_instance : self->data.type_instance, sizeof(value_list.type_instance));
641 if (value_list.type[0] == 0) {
642 PyErr_SetString(PyExc_RuntimeError, "type not set");
645 ds = plugin_get_ds(value_list.type);
647 PyErr_Format(PyExc_TypeError, "Dataset %s not found", value_list.type);
650 if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
651 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
654 size = (int) PySequence_Length(values);
655 if (size != ds->ds_num) {
656 PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %i", value_list.type, ds->ds_num, size);
659 value = malloc(size * sizeof(*value));
660 for (i = 0; i < size; ++i) {
661 PyObject *item, *num;
662 item = PySequence_Fast_GET_ITEM(values, i); /* Borrowed reference. */
663 switch (ds->ds[i].type) {
664 case DS_TYPE_COUNTER:
665 num = PyNumber_Long(item); /* New reference. */
667 value[i].counter = PyLong_AsUnsignedLongLong(num);
672 num = PyNumber_Float(item); /* New reference. */
674 value[i].gauge = PyFloat_AsDouble(num);
679 /* This might overflow without raising an exception.
680 * Not much we can do about it */
681 num = PyNumber_Long(item); /* New reference. */
683 value[i].derive = PyLong_AsLongLong(num);
687 case DS_TYPE_ABSOLUTE:
688 /* This might overflow without raising an exception.
689 * Not much we can do about it */
690 num = PyNumber_Long(item); /* New reference. */
692 value[i].absolute = PyLong_AsUnsignedLongLong(num);
698 PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds[i].type, value_list.type);
701 if (PyErr_Occurred() != NULL) {
706 value_list.values = value;
707 value_list.values_len = size;
708 value_list.time = DOUBLE_TO_CDTIME_T(time);
709 value_list.interval = DOUBLE_TO_CDTIME_T(interval);
710 value_list.meta = cpy_build_meta(meta);;
711 if (value_list.host[0] == 0)
712 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
713 if (value_list.plugin[0] == 0)
714 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
715 Py_BEGIN_ALLOW_THREADS;
716 ret = plugin_write(dest, NULL, &value_list);
717 Py_END_ALLOW_THREADS;
718 meta_data_destroy(value_list.meta);
721 PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
727 static PyObject *Values_repr(PyObject *s) {
729 static PyObject *l_interval = NULL, *l_values = NULL, *l_meta = NULL, *l_closing = NULL;
730 Values *self = (Values *) s;
732 if (l_interval == NULL)
733 l_interval = cpy_string_to_unicode_or_bytes(",interval=");
734 if (l_values == NULL)
735 l_values = cpy_string_to_unicode_or_bytes(",values=");
737 l_meta = cpy_string_to_unicode_or_bytes(",meta=");
738 if (l_closing == NULL)
739 l_closing = cpy_string_to_unicode_or_bytes(")");
741 if (l_interval == NULL || l_values == NULL || l_meta == NULL || l_closing == NULL)
744 ret = cpy_common_repr(s);
745 if (self->interval != 0) {
746 CPY_STRCAT(&ret, l_interval);
747 tmp = PyFloat_FromDouble(self->interval);
748 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
749 CPY_STRCAT_AND_DEL(&ret, tmp);
751 if (self->values && (!PyList_Check(self->values) || PySequence_Length(self->values) > 0)) {
752 CPY_STRCAT(&ret, l_values);
753 tmp = PyObject_Repr(self->values);
754 CPY_STRCAT_AND_DEL(&ret, tmp);
756 if (self->meta && (!PyDict_Check(self->meta) || PyDict_Size(self->meta) > 0)) {
757 CPY_STRCAT(&ret, l_meta);
758 tmp = PyObject_Repr(self->meta);
759 CPY_STRCAT_AND_DEL(&ret, tmp);
761 CPY_STRCAT(&ret, l_closing);
765 static int Values_traverse(PyObject *self, visitproc visit, void *arg) {
766 Values *v = (Values *) self;
772 static int Values_clear(PyObject *self) {
773 Values *v = (Values *) self;
779 static void Values_dealloc(PyObject *self) {
781 self->ob_type->tp_free(self);
784 static PyMemberDef Values_members[] = {
785 {"interval", T_DOUBLE, offsetof(Values, interval), 0, interval_doc},
786 {"values", T_OBJECT_EX, offsetof(Values, values), 0, values_doc},
787 {"meta", T_OBJECT_EX, offsetof(Values, meta), 0, meta_doc},
791 static PyMethodDef Values_methods[] = {
792 {"dispatch", (PyCFunction) Values_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
793 {"write", (PyCFunction) Values_write, METH_VARARGS | METH_KEYWORDS, write_doc},
797 PyTypeObject ValuesType = {
799 "collectd.Values", /* tp_name */
800 sizeof(Values), /* tp_basicsize */
801 0, /* Will be filled in later */
802 Values_dealloc, /* tp_dealloc */
807 Values_repr, /* tp_repr */
808 0, /* tp_as_number */
809 0, /* tp_as_sequence */
810 0, /* tp_as_mapping */
816 0, /* tp_as_buffer */
817 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
818 Values_doc, /* tp_doc */
819 Values_traverse, /* tp_traverse */
820 Values_clear, /* tp_clear */
821 0, /* tp_richcompare */
822 0, /* tp_weaklistoffset */
825 Values_methods, /* tp_methods */
826 Values_members, /* tp_members */
830 0, /* tp_descr_get */
831 0, /* tp_descr_set */
832 0, /* tp_dictoffset */
833 Values_init, /* tp_init */
835 Values_new /* tp_new */
838 static char severity_doc[] = "The severity of this notification. Assign or compare to\n"
839 "NOTIF_FAILURE, NOTIF_WARNING or NOTIF_OKAY.";
841 static char message_doc[] = "Some kind of description what's going on and why this Notification was generated.";
843 static char Notification_doc[] = "The Notification class is a wrapper around the collectd notification.\n"
844 "It can be used to notify other plugins about bad stuff happening. It works\n"
845 "similar to Values but has a severity and a message instead of interval\n"
847 "Notifications can be dispatched at any time and can be received with register_notification.";
849 static int Notification_init(PyObject *s, PyObject *args, PyObject *kwds) {
850 Notification *self = (Notification *) s;
853 char *message = NULL;
854 char *type = NULL, *plugin_instance = NULL, *type_instance = NULL, *plugin = NULL, *host = NULL;
855 static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
856 "plugin", "host", "time", "severity", NULL};
858 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist,
859 NULL, &type, NULL, &message, NULL, &plugin_instance, NULL, &type_instance,
860 NULL, &plugin, NULL, &host, &time, &severity))
863 if (type && plugin_get_ds(type) == NULL) {
864 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
870 sstrncpy(self->data.host, host ? host : "", sizeof(self->data.host));
871 sstrncpy(self->data.plugin, plugin ? plugin : "", sizeof(self->data.plugin));
872 sstrncpy(self->data.plugin_instance, plugin_instance ? plugin_instance : "", sizeof(self->data.plugin_instance));
873 sstrncpy(self->data.type, type ? type : "", sizeof(self->data.type));
874 sstrncpy(self->data.type_instance, type_instance ? type_instance : "", sizeof(self->data.type_instance));
875 sstrncpy(self->message, message ? message : "", sizeof(self->message));
876 self->data.time = time;
877 self->severity = severity;
884 static PyObject *Notification_dispatch(Notification *self, PyObject *args, PyObject *kwds) {
886 const data_set_t *ds;
887 notification_t notification;
888 double t = self->data.time;
889 int severity = self->severity;
890 char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL, *type_instance = NULL;
891 char *message = NULL;
893 static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
894 "plugin", "host", "time", "severity", NULL};
895 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist,
896 NULL, &type, NULL, &message, NULL, &plugin_instance, NULL, &type_instance,
897 NULL, &plugin, NULL, &host, &t, &severity))
900 notification.time = DOUBLE_TO_CDTIME_T(t);
901 notification.severity = severity;
902 sstrncpy(notification.message, message ? message : self->message, sizeof(notification.message));
903 sstrncpy(notification.host, host ? host : self->data.host, sizeof(notification.host));
904 sstrncpy(notification.plugin, plugin ? plugin : self->data.plugin, sizeof(notification.plugin));
905 sstrncpy(notification.plugin_instance, plugin_instance ? plugin_instance : self->data.plugin_instance, sizeof(notification.plugin_instance));
906 sstrncpy(notification.type, type ? type : self->data.type, sizeof(notification.type));
907 sstrncpy(notification.type_instance, type_instance ? type_instance : self->data.type_instance, sizeof(notification.type_instance));
908 notification.meta = NULL;
912 if (notification.type[0] == 0) {
913 PyErr_SetString(PyExc_RuntimeError, "type not set");
916 ds = plugin_get_ds(notification.type);
918 PyErr_Format(PyExc_TypeError, "Dataset %s not found", notification.type);
922 if (notification.time == 0)
923 notification.time = cdtime();
924 if (notification.host[0] == 0)
925 sstrncpy(notification.host, hostname_g, sizeof(notification.host));
926 if (notification.plugin[0] == 0)
927 sstrncpy(notification.plugin, "python", sizeof(notification.plugin));
928 Py_BEGIN_ALLOW_THREADS;
929 ret = plugin_dispatch_notification(¬ification);
930 Py_END_ALLOW_THREADS;
932 PyErr_SetString(PyExc_RuntimeError, "error dispatching notification, read the logs");
938 static PyObject *Notification_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
941 self = (Notification *) PluginData_new(type, args, kwds);
945 self->message[0] = 0;
947 return (PyObject *) self;
950 static int Notification_setstring(PyObject *self, PyObject *value, void *data) {
955 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
959 new = cpy_unicode_or_bytes_to_string(&value);
964 old = ((char *) self) + (intptr_t) data;
965 sstrncpy(old, new, NOTIF_MAX_MSG_LEN);
970 static PyObject *Notification_repr(PyObject *s) {
972 static PyObject *l_severity = NULL, *l_message = NULL, *l_closing = NULL;
973 Notification *self = (Notification *) s;
975 if (l_severity == NULL)
976 l_severity = cpy_string_to_unicode_or_bytes(",severity=");
977 if (l_message == NULL)
978 l_message = cpy_string_to_unicode_or_bytes(",message=");
979 if (l_closing == NULL)
980 l_closing = cpy_string_to_unicode_or_bytes(")");
982 if (l_severity == NULL || l_message == NULL || l_closing == NULL)
985 ret = cpy_common_repr(s);
986 if (self->severity != 0) {
987 CPY_STRCAT(&ret, l_severity);
988 tmp = PyInt_FromLong(self->severity);
989 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
990 CPY_STRCAT_AND_DEL(&ret, tmp);
992 if (self->message[0] != 0) {
993 CPY_STRCAT(&ret, l_message);
994 tmp = cpy_string_to_unicode_or_bytes(self->message);
995 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
996 CPY_STRCAT_AND_DEL(&ret, tmp);
998 CPY_STRCAT(&ret, l_closing);
1002 static PyMethodDef Notification_methods[] = {
1003 {"dispatch", (PyCFunction) Notification_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
1007 static PyMemberDef Notification_members[] = {
1008 {"severity", T_INT, offsetof(Notification, severity), 0, severity_doc},
1012 static PyGetSetDef Notification_getseters[] = {
1013 {"message", PluginData_getstring, Notification_setstring, message_doc, (void *) offsetof(Notification, message)},
1017 PyTypeObject NotificationType = {
1019 "collectd.Notification", /* tp_name */
1020 sizeof(Notification), /* tp_basicsize */
1021 0, /* Will be filled in later */
1027 Notification_repr, /* tp_repr */
1028 0, /* tp_as_number */
1029 0, /* tp_as_sequence */
1030 0, /* tp_as_mapping */
1034 0, /* tp_getattro */
1035 0, /* tp_setattro */
1036 0, /* tp_as_buffer */
1037 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1038 Notification_doc, /* tp_doc */
1039 0, /* tp_traverse */
1041 0, /* tp_richcompare */
1042 0, /* tp_weaklistoffset */
1044 0, /* tp_iternext */
1045 Notification_methods, /* tp_methods */
1046 Notification_members, /* tp_members */
1047 Notification_getseters, /* tp_getset */
1050 0, /* tp_descr_get */
1051 0, /* tp_descr_set */
1052 0, /* tp_dictoffset */
1053 Notification_init, /* tp_init */
1055 Notification_new /* tp_new */
1058 static char Signed_doc[] = "This is a long by another name. Use it in meta data dicts\n"
1059 "to choose the way it is stored in the meta data.";
1061 PyTypeObject SignedType = {
1063 "collectd.Signed", /* tp_name */
1064 sizeof(Signed), /* tp_basicsize */
1065 0, /* Will be filled in later */
1072 0, /* tp_as_number */
1073 0, /* tp_as_sequence */
1074 0, /* tp_as_mapping */
1078 0, /* tp_getattro */
1079 0, /* tp_setattro */
1080 0, /* tp_as_buffer */
1081 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1082 Signed_doc /* tp_doc */
1085 static char Unsigned_doc[] = "This is a long by another name. Use it in meta data dicts\n"
1086 "to choose the way it is stored in the meta data.";
1088 PyTypeObject UnsignedType = {
1090 "collectd.Unsigned", /* tp_name */
1091 sizeof(Unsigned), /* tp_basicsize */
1092 0, /* Will be filled in later */
1099 0, /* tp_as_number */
1100 0, /* tp_as_sequence */
1101 0, /* tp_as_mapping */
1105 0, /* tp_getattro */
1106 0, /* tp_setattro */
1107 0, /* tp_as_buffer */
1108 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1109 Unsigned_doc /* tp_doc */