2 * collectd - src/pyvalues.c
3 * Copyright (C) 2009 Sven Trenkel
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
24 * Sven Trenkel <collectd at semidefinite.de>
28 #include <structmember.h>
35 static char time_doc[] = "This is the Unix timestap of the time this value was read.\n"
36 "For dispatching values this can be set to 0 which means \"now\".\n"
37 "This means the time the value is actually dispatched, not the time\n"
40 static char host_doc[] = "The hostname of the host this value was read from.\n"
41 "For dispatching this can be set to an empty string which means\n"
42 "the local hostname as defined in the collectd.conf.";
44 static char type_doc[] = "The type of this value. This type has to be defined\n"
45 "in your types.db. Attempting to set it to any other value will\n"
46 "raise a TypeError exception.\n"
47 "Assigning a type is mandetory, calling dispatch without doing\n"
48 "so will raise a RuntimeError exception.";
50 static char type_instance_doc[] = "";
52 static char plugin_doc[] = "The name of the plugin that read the data. Setting this\n"
53 "member to an empty string will insert \"python\" upon dispatching.";
55 static char plugin_instance_doc[] = "";
57 static char PluginData_doc[] = "This is an internal class that is the base for Values\n"
58 "and Notification. It is pretty useless by itself and was therefore not\n"
59 "exported to the collectd module.";
61 static PyObject *PluginData_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
64 self = (PluginData *) type->tp_alloc(type, 0);
71 self->plugin_instance[0] = 0;
73 self->type_instance[0] = 0;
74 return (PyObject *) self;
77 static int PluginData_init(PyObject *s, PyObject *args, PyObject *kwds) {
78 PluginData *self = (PluginData *) s;
80 const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
81 static char *kwlist[] = {"type", "plugin_instance", "type_instance",
82 "plugin", "host", "time", NULL};
84 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sssssd", kwlist, &type,
85 &plugin_instance, &type_instance, &plugin, &host, &time))
88 if (type[0] != 0 && plugin_get_ds(type) == NULL) {
89 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
93 sstrncpy(self->host, host, sizeof(self->host));
94 sstrncpy(self->plugin, plugin, sizeof(self->plugin));
95 sstrncpy(self->plugin_instance, plugin_instance, sizeof(self->plugin_instance));
96 sstrncpy(self->type, type, sizeof(self->type));
97 sstrncpy(self->type_instance, type_instance, sizeof(self->type_instance));
103 static PyObject *PluginData_repr(PyObject *s) {
105 static PyObject *l_type = NULL, *l_type_instance = NULL, *l_plugin = NULL, *l_plugin_instance = NULL;
106 static PyObject *l_host = NULL, *l_time = NULL, *l_closing = NULL;
107 PluginData *self = (PluginData *) s;
110 l_type = cpy_string_to_unicode_or_bytes("(type=");
111 if (l_type_instance == NULL)
112 l_type_instance = cpy_string_to_unicode_or_bytes(",type_instance=");
113 if (l_plugin == NULL)
114 l_plugin = cpy_string_to_unicode_or_bytes(",plugin=");
115 if (l_plugin_instance == NULL)
116 l_plugin_instance = cpy_string_to_unicode_or_bytes(",plugin_instance=");
118 l_host = cpy_string_to_unicode_or_bytes(",host=");
120 l_time = cpy_string_to_unicode_or_bytes(",time=");
121 if (l_closing == NULL)
122 l_closing = cpy_string_to_unicode_or_bytes(")");
124 if (!l_type || !l_type_instance || !l_plugin || !l_plugin_instance || !l_host || !l_time)
127 ret = cpy_string_to_unicode_or_bytes(s->ob_type->tp_name);
129 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, l_type);
130 tmp = cpy_string_to_unicode_or_bytes(self->type);
131 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
133 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, tmp);
136 if (self->type_instance[0] != 0) {
137 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, l_type_instance);
138 tmp = cpy_string_to_unicode_or_bytes(self->type_instance);
139 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
141 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, tmp);
145 if (self->plugin[0] != 0) {
146 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, l_plugin);
147 tmp = cpy_string_to_unicode_or_bytes(self->plugin);
148 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
150 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, tmp);
154 if (self->plugin_instance[0] != 0) {
155 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, l_plugin_instance);
156 tmp = cpy_string_to_unicode_or_bytes(self->plugin_instance);
157 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
159 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, tmp);
163 if (self->host[0] != 0) {
164 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, l_host);
165 tmp = cpy_string_to_unicode_or_bytes(self->host);
166 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
168 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, tmp);
172 if (self->time != 0) {
173 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, l_time);
174 tmp = PyInt_FromLong(self->time);
175 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
177 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, tmp);
180 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, l_closing);
184 static PyMemberDef PluginData_members[] = {
185 {"time", T_DOUBLE, offsetof(PluginData, time), 0, time_doc},
189 static PyObject *PluginData_getstring(PyObject *self, void *data) {
190 const char *value = ((char *) self) + (intptr_t) data;
192 return cpy_string_to_unicode_or_bytes(value);
195 static int PluginData_setstring(PyObject *self, PyObject *value, void *data) {
200 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
204 new = cpy_unicode_or_bytes_to_string(&value);
209 old = ((char *) self) + (intptr_t) data;
210 sstrncpy(old, new, DATA_MAX_NAME_LEN);
215 static int PluginData_settype(PyObject *self, PyObject *value, void *data) {
220 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
224 new = cpy_unicode_or_bytes_to_string(&value);
230 if (plugin_get_ds(new) == NULL) {
231 PyErr_Format(PyExc_TypeError, "Dataset %s not found", new);
236 old = ((char *) self) + (intptr_t) data;
237 sstrncpy(old, new, DATA_MAX_NAME_LEN);
242 static PyGetSetDef PluginData_getseters[] = {
243 {"host", PluginData_getstring, PluginData_setstring, host_doc, (void *) offsetof(PluginData, host)},
244 {"plugin", PluginData_getstring, PluginData_setstring, plugin_doc, (void *) offsetof(PluginData, plugin)},
245 {"plugin_instance", PluginData_getstring, PluginData_setstring, plugin_instance_doc, (void *) offsetof(PluginData, plugin_instance)},
246 {"type_instance", PluginData_getstring, PluginData_setstring, type_instance_doc, (void *) offsetof(PluginData, type_instance)},
247 {"type", PluginData_getstring, PluginData_settype, type_doc, (void *) offsetof(PluginData, type)},
251 PyTypeObject PluginDataType = {
253 "collectd.PluginData", /* tp_name */
254 sizeof(PluginData), /* tp_basicsize */
255 0, /* Will be filled in later */
261 PluginData_repr, /* tp_repr */
262 0, /* tp_as_number */
263 0, /* tp_as_sequence */
264 0, /* tp_as_mapping */
270 0, /* tp_as_buffer */
271 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE /*| Py_TPFLAGS_HAVE_GC*/, /*tp_flags*/
272 PluginData_doc, /* tp_doc */
275 0, /* tp_richcompare */
276 0, /* tp_weaklistoffset */
280 PluginData_members, /* tp_members */
281 PluginData_getseters, /* tp_getset */
284 0, /* tp_descr_get */
285 0, /* tp_descr_set */
286 0, /* tp_dictoffset */
287 PluginData_init, /* tp_init */
289 PluginData_new /* tp_new */
292 static char interval_doc[] = "The interval is the timespan in seconds between two submits for\n"
293 "the same data source. This value has to be a positive integer, so you can't\n"
294 "submit more than one value per second. If this member is set to a\n"
295 "non-positive value, the default value as specified in the config file will\n"
296 "be used (default: 10).\n"
298 "If you submit values more often than the specified interval, the average\n"
299 "will be used. If you submit less values, your graphs will have gaps.";
301 static char values_doc[] = "These are the actual values that get dispatched to collectd.\n"
302 "It has to be a sequence (a tuple or list) of numbers.\n"
303 "The size of the sequence and the type of its content depend on the type\n"
304 "member your types.db file. For more information on this read the types.db\n"
307 "If the sequence does not have the correct size upon dispatch a RuntimeError\n"
308 "exception will be raised. If the content of the sequence is not a number,\n"
309 "a TypeError exception will be raised.";
311 static char dispatch_doc[] = "dispatch([type][, values][, plugin_instance][, type_instance]"
312 "[, plugin][, host][, time][, interval]) -> None. Dispatch a value list.\n"
314 "Dispatch this instance to the collectd process. The object has members\n"
315 "for each of the possible arguments for this method. For a detailed explanation\n"
316 "of these parameters see the member of the same same.\n"
318 "If you do not submit a parameter the value saved in its member will be submitted.\n"
319 "If you do provide a parameter it will be used instead, without altering the member.";
321 static char write_doc[] = "write([destination][, type][, values][, plugin_instance][, type_instance]"
322 "[, plugin][, host][, time][, interval]) -> None. Dispatch a value list.\n"
324 "Write this instance to a single plugin or all plugins if 'destination' is obmitted.\n"
325 "This will bypass the main collectd process and all filtering and caching.\n"
326 "Other than that it works similar to 'dispatch'. In most cases 'dispatch' should be\n"
327 "used instead of 'write'.\n";
329 static char Values_doc[] = "A Values object used for dispatching values to collectd and receiving values from write callbacks.";
331 static PyObject *Values_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
334 self = (Values *) PluginData_new(type, args, kwds);
338 self->values = PyList_New(0);
340 return (PyObject *) self;
343 static int Values_init(PyObject *s, PyObject *args, PyObject *kwds) {
344 Values *self = (Values *) s;
345 int interval = 0, ret;
347 PyObject *values = NULL, *tmp;
348 const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
349 static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
350 "plugin", "host", "time", "interval", NULL};
352 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sOssssdi", kwlist,
353 &type, &values, &plugin_instance, &type_instance,
354 &plugin, &host, &time, &interval))
357 tmp = Py_BuildValue("sssssd", type, plugin_instance, type_instance, plugin, host, time);
360 ret = PluginDataType.tp_init(s, tmp, NULL);
365 if (values == NULL) {
366 values = PyList_New(0);
373 self->values = values;
376 self->interval = interval;
380 static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
382 const data_set_t *ds;
385 value_list_t value_list = VALUE_LIST_INIT;
386 PyObject *values = self->values;
387 double time = self->data.time;
388 int interval = self->interval;
389 const char *host = self->data.host;
390 const char *plugin = self->data.plugin;
391 const char *plugin_instance = self->data.plugin_instance;
392 const char *type = self->data.type;
393 const char *type_instance = self->data.type_instance;
395 static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
396 "plugin", "host", "time", "interval", NULL};
397 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sOzsssdi", kwlist,
398 &type, &values, &plugin_instance, &type_instance,
399 &plugin, &host, &time, &interval))
403 PyErr_SetString(PyExc_RuntimeError, "type not set");
406 ds = plugin_get_ds(type);
408 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
411 if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
412 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
415 size = (int) PySequence_Length(values);
416 if (size != ds->ds_num) {
417 PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %i", type, ds->ds_num, size);
420 value = malloc(size * sizeof(*value));
421 for (i = 0; i < size; ++i) {
422 PyObject *item, *num;
423 item = PySequence_GetItem(values, i);
424 if (ds->ds->type == DS_TYPE_COUNTER) {
425 num = PyNumber_Long(item);
427 value[i].counter = PyLong_AsUnsignedLongLong(num);
428 } else if (ds->ds->type == DS_TYPE_GAUGE) {
429 num = PyNumber_Float(item);
431 value[i].gauge = PyFloat_AsDouble(num);
432 } else if (ds->ds->type == DS_TYPE_DERIVE) {
433 /* This might overflow without raising an exception.
434 * Not much we can do about it */
435 num = PyNumber_Long(item);
437 value[i].derive = PyLong_AsLongLong(num);
438 } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
439 /* This might overflow without raising an exception.
440 * Not much we can do about it */
441 num = PyNumber_Long(item);
443 value[i].absolute = PyLong_AsUnsignedLongLong(num);
446 PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds->type, type);
449 if (PyErr_Occurred() != NULL) {
454 value_list.values = value;
455 value_list.values_len = size;
456 value_list.time = time;
457 value_list.interval = interval;
458 sstrncpy(value_list.host, host, sizeof(value_list.host));
459 sstrncpy(value_list.plugin, plugin, sizeof(value_list.plugin));
460 sstrncpy(value_list.plugin_instance, plugin_instance, sizeof(value_list.plugin_instance));
461 sstrncpy(value_list.type, type, sizeof(value_list.type));
462 sstrncpy(value_list.type_instance, type_instance, sizeof(value_list.type_instance));
463 value_list.meta = NULL;
464 if (value_list.host[0] == 0)
465 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
466 if (value_list.plugin[0] == 0)
467 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
468 Py_BEGIN_ALLOW_THREADS;
469 ret = plugin_dispatch_values(&value_list);
470 Py_END_ALLOW_THREADS;
472 PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
479 static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
481 const data_set_t *ds;
484 value_list_t value_list = VALUE_LIST_INIT;
485 PyObject *values = self->values;
486 double time = self->data.time;
487 int interval = self->interval;
488 const char *host = self->data.host;
489 const char *plugin = self->data.plugin;
490 const char *plugin_instance = self->data.plugin_instance;
491 const char *type = self->data.type;
492 const char *type_instance = self->data.type_instance;
493 const char *dest = NULL;
495 static char *kwlist[] = {"destination", "type", "values", "plugin_instance", "type_instance",
496 "plugin", "host", "time", "interval", NULL};
497 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sOssssdi", kwlist,
498 &type, &values, &plugin_instance, &type_instance,
499 &plugin, &host, &time, &interval))
503 PyErr_SetString(PyExc_RuntimeError, "type not set");
506 ds = plugin_get_ds(type);
508 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
511 if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
512 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
515 size = (int) PySequence_Length(values);
516 if (size != ds->ds_num) {
517 PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %i", type, ds->ds_num, size);
520 value = malloc(size * sizeof(*value));
521 for (i = 0; i < size; ++i) {
522 PyObject *item, *num;
523 item = PySequence_GetItem(values, i);
524 if (ds->ds->type == DS_TYPE_COUNTER) {
525 num = PyNumber_Long(item);
527 value[i].counter = PyLong_AsUnsignedLongLong(num);
528 } else if (ds->ds->type == DS_TYPE_GAUGE) {
529 num = PyNumber_Float(item);
531 value[i].gauge = PyFloat_AsDouble(num);
532 } else if (ds->ds->type == DS_TYPE_DERIVE) {
533 /* This might overflow without raising an exception.
534 * Not much we can do about it */
535 num = PyNumber_Long(item);
537 value[i].derive = PyLong_AsLongLong(num);
538 } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
539 /* This might overflow without raising an exception.
540 * Not much we can do about it */
541 num = PyNumber_Long(item);
543 value[i].absolute = PyLong_AsUnsignedLongLong(num);
546 PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds->type, type);
549 if (PyErr_Occurred() != NULL) {
554 value_list.values = value;
555 value_list.values_len = size;
556 value_list.time = time;
557 value_list.interval = interval;
558 sstrncpy(value_list.host, host, sizeof(value_list.host));
559 sstrncpy(value_list.plugin, plugin, sizeof(value_list.plugin));
560 sstrncpy(value_list.plugin_instance, plugin_instance, sizeof(value_list.plugin_instance));
561 sstrncpy(value_list.type, type, sizeof(value_list.type));
562 sstrncpy(value_list.type_instance, type_instance, sizeof(value_list.type_instance));
563 value_list.meta = NULL;
564 if (value_list.host[0] == 0)
565 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
566 if (value_list.plugin[0] == 0)
567 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
568 Py_BEGIN_ALLOW_THREADS;
569 ret = plugin_write(dest, NULL, &value_list);
570 Py_END_ALLOW_THREADS;
572 PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
579 /*static PyObject *Values_repr(PyObject *s) {
580 PyObject *ret, *valuestring = NULL;
581 Values *self = (Values *) s;
583 if (self->values != NULL)
584 valuestring = PyObject_Repr(self->values);
585 if (valuestring == NULL)
588 ret = PyString_FromFormat("collectd.Values(type='%s%s%s%s%s%s%s%s%s',time=%lu,interval=%i,values=%s)", self->data.type,
589 *self->data.type_instance ? "',type_instance='" : "", self->data.type_instance,
590 *self->data.plugin ? "',plugin='" : "", self->data.plugin,
591 *self->data.plugin_instance ? "',plugin_instance='" : "", self->data.plugin_instance,
592 *self->data.host ? "',host='" : "", self->data.host,
593 (long unsigned) self->data.time, self->interval,
594 valuestring ? cpy_unicode_or_bytes_to_string(valuestring) : "[]");
595 Py_XDECREF(valuestring);
599 static int Values_traverse(PyObject *self, visitproc visit, void *arg) {
600 Values *v = (Values *) self;
605 static int Values_clear(PyObject *self) {
606 Values *v = (Values *) self;
611 static void Values_dealloc(PyObject *self) {
613 self->ob_type->tp_free(self);
616 static PyMemberDef Values_members[] = {
617 {"interval", T_INT, offsetof(Values, interval), 0, interval_doc},
618 {"values", T_OBJECT_EX, offsetof(Values, values), 0, values_doc},
622 static PyMethodDef Values_methods[] = {
623 {"dispatch", (PyCFunction) Values_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
624 {"write", (PyCFunction) Values_write, METH_VARARGS | METH_KEYWORDS, write_doc},
628 PyTypeObject ValuesType = {
630 "collectd.Values", /* tp_name */
631 sizeof(Values), /* tp_basicsize */
632 0, /* Will be filled in later */
633 Values_dealloc, /* tp_dealloc */
638 0/*Values_repr*/, /* tp_repr */
639 0, /* tp_as_number */
640 0, /* tp_as_sequence */
641 0, /* tp_as_mapping */
647 0, /* tp_as_buffer */
648 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
649 Values_doc, /* tp_doc */
650 Values_traverse, /* tp_traverse */
651 Values_clear, /* tp_clear */
652 0, /* tp_richcompare */
653 0, /* tp_weaklistoffset */
656 Values_methods, /* tp_methods */
657 Values_members, /* tp_members */
661 0, /* tp_descr_get */
662 0, /* tp_descr_set */
663 0, /* tp_dictoffset */
664 Values_init, /* tp_init */
666 Values_new /* tp_new */
669 static char severity_doc[] = "The severity of this notification. Assign or compare to\n"
670 "NOTIF_FAILURE, NOTIF_WARNING or NOTIF_OKAY.";
672 static char message_doc[] = "Some kind of description what's going on and why this Notification was generated.";
674 static char Notification_doc[] = "The Notification class is a wrapper around the collectd notification.\n"
675 "It can be used to notify other plugins about bad stuff happening. It works\n"
676 "similar to Values but has a severity and a message instead of interval\n"
678 "Notifications can be dispatched at any time and can be received with register_notification.";
680 static int Notification_init(PyObject *s, PyObject *args, PyObject *kwds) {
681 Notification *self = (Notification *) s;
683 int severity = 0, ret;
685 const char *message = "";
686 const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
687 static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
688 "plugin", "host", "time", "severity", NULL};
690 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ssssssdi", kwlist,
691 &type, &message, &plugin_instance, &type_instance,
692 &plugin, &host, &time, &severity))
695 tmp = Py_BuildValue("sssssd", type, plugin_instance, type_instance, plugin, host, time);
698 ret = PluginDataType.tp_init(s, tmp, NULL);
703 sstrncpy(self->message, message, sizeof(self->message));
704 self->severity = severity;
708 static PyObject *Notification_dispatch(Notification *self, PyObject *args, PyObject *kwds) {
710 const data_set_t *ds;
711 notification_t notification;
712 double t = self->data.time;
713 int severity = self->severity;
714 const char *host = self->data.host;
715 const char *plugin = self->data.plugin;
716 const char *plugin_instance = self->data.plugin_instance;
717 const char *type = self->data.type;
718 const char *type_instance = self->data.type_instance;
719 const char *message = self->message;
721 static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
722 "plugin", "host", "time", "severity", NULL};
723 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ssssssdi", kwlist,
724 &type, &message, &plugin_instance, &type_instance,
725 &plugin, &host, &t, &severity))
729 PyErr_SetString(PyExc_RuntimeError, "type not set");
732 ds = plugin_get_ds(type);
734 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
738 notification.time = t;
739 notification.severity = severity;
740 sstrncpy(notification.message, message, sizeof(notification.message));
741 sstrncpy(notification.host, host, sizeof(notification.host));
742 sstrncpy(notification.plugin, plugin, sizeof(notification.plugin));
743 sstrncpy(notification.plugin_instance, plugin_instance, sizeof(notification.plugin_instance));
744 sstrncpy(notification.type, type, sizeof(notification.type));
745 sstrncpy(notification.type_instance, type_instance, sizeof(notification.type_instance));
746 notification.meta = NULL;
747 if (notification.time < 1)
748 notification.time = time(0);
749 if (notification.host[0] == 0)
750 sstrncpy(notification.host, hostname_g, sizeof(notification.host));
751 if (notification.plugin[0] == 0)
752 sstrncpy(notification.plugin, "python", sizeof(notification.plugin));
753 Py_BEGIN_ALLOW_THREADS;
754 ret = plugin_dispatch_notification(¬ification);
755 Py_END_ALLOW_THREADS;
757 PyErr_SetString(PyExc_RuntimeError, "error dispatching notification, read the logs");
763 static PyObject *Notification_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
766 self = (Notification *) PluginData_new(type, args, kwds);
770 self->message[0] = 0;
772 return (PyObject *) self;
775 static int Notification_setstring(PyObject *self, PyObject *value, void *data) {
780 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
784 new = cpy_unicode_or_bytes_to_string(&value);
789 old = ((char *) self) + (intptr_t) data;
790 sstrncpy(old, new, NOTIF_MAX_MSG_LEN);
795 /*static PyObject *Notification_repr(PyObject *s) {
797 Notification *self = (Notification *) s;
799 ret = PyString_FromFormat("collectd.Values(type='%s%s%s%s%s%s%s%s%s%s%s',time=%lu,interval=%i)", self->data.type,
800 *self->data.type_instance ? "',type_instance='" : "", self->data.type_instance,
801 *self->data.plugin ? "',plugin='" : "", self->data.plugin,
802 *self->data.plugin_instance ? "',plugin_instance='" : "", self->data.plugin_instance,
803 *self->data.host ? "',host='" : "", self->data.host,
804 *self->message ? "',message='" : "", self->message,
805 (long unsigned) self->data.time, self->severity);
809 static PyMethodDef Notification_methods[] = {
810 {"dispatch", (PyCFunction) Notification_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
814 static PyMemberDef Notification_members[] = {
815 {"severity", T_INT, offsetof(Notification, severity), 0, severity_doc},
819 static PyGetSetDef Notification_getseters[] = {
820 {"message", PluginData_getstring, Notification_setstring, message_doc, (void *) offsetof(Notification, message)},
824 PyTypeObject NotificationType = {
826 "collectd.Notification", /* tp_name */
827 sizeof(Notification), /* tp_basicsize */
828 0, /* Will be filled in later */
834 0/*Notification_repr*/, /* tp_repr */
835 0, /* tp_as_number */
836 0, /* tp_as_sequence */
837 0, /* tp_as_mapping */
843 0, /* tp_as_buffer */
844 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
845 Notification_doc, /* tp_doc */
848 0, /* tp_richcompare */
849 0, /* tp_weaklistoffset */
852 Notification_methods, /* tp_methods */
853 Notification_members, /* tp_members */
854 Notification_getseters, /* tp_getset */
857 0, /* tp_descr_get */
858 0, /* tp_descr_set */
859 0, /* tp_dictoffset */
860 Notification_init, /* tp_init */
862 Notification_new /* tp_new */