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 PyObject *cpy_common_repr(PyObject *s) {
37 static PyObject *l_type = NULL, *l_type_instance = NULL, *l_plugin = NULL, *l_plugin_instance = NULL;
38 static PyObject *l_host = NULL, *l_time = NULL;
39 PluginData *self = (PluginData *) s;
42 l_type = cpy_string_to_unicode_or_bytes("(type=");
43 if (l_type_instance == NULL)
44 l_type_instance = cpy_string_to_unicode_or_bytes(",type_instance=");
46 l_plugin = cpy_string_to_unicode_or_bytes(",plugin=");
47 if (l_plugin_instance == NULL)
48 l_plugin_instance = cpy_string_to_unicode_or_bytes(",plugin_instance=");
50 l_host = cpy_string_to_unicode_or_bytes(",host=");
52 l_time = cpy_string_to_unicode_or_bytes(",time=");
54 if (!l_type || !l_type_instance || !l_plugin || !l_plugin_instance || !l_host || !l_time)
57 ret = cpy_string_to_unicode_or_bytes(s->ob_type->tp_name);
59 CPY_STRCAT(&ret, l_type);
60 tmp = cpy_string_to_unicode_or_bytes(self->type);
61 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
62 CPY_STRCAT_AND_DEL(&ret, tmp);
64 if (self->type_instance[0] != 0) {
65 CPY_STRCAT(&ret, l_type_instance);
66 tmp = cpy_string_to_unicode_or_bytes(self->type_instance);
67 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
68 CPY_STRCAT_AND_DEL(&ret, tmp);
71 if (self->plugin[0] != 0) {
72 CPY_STRCAT(&ret, l_plugin);
73 tmp = cpy_string_to_unicode_or_bytes(self->plugin);
74 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
75 CPY_STRCAT_AND_DEL(&ret, tmp);
78 if (self->plugin_instance[0] != 0) {
79 CPY_STRCAT(&ret, l_plugin_instance);
80 tmp = cpy_string_to_unicode_or_bytes(self->plugin_instance);
81 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
82 CPY_STRCAT_AND_DEL(&ret, tmp);
85 if (self->host[0] != 0) {
86 CPY_STRCAT(&ret, l_host);
87 tmp = cpy_string_to_unicode_or_bytes(self->host);
88 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
89 CPY_STRCAT_AND_DEL(&ret, tmp);
92 if (self->time != 0) {
93 CPY_STRCAT(&ret, l_time);
94 tmp = PyInt_FromLong(self->time);
95 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
96 CPY_STRCAT_AND_DEL(&ret, tmp);
101 static char time_doc[] = "This is the Unix timestap of the time this value was read.\n"
102 "For dispatching values this can be set to 0 which means \"now\".\n"
103 "This means the time the value is actually dispatched, not the time\n"
106 static char host_doc[] = "The hostname of the host this value was read from.\n"
107 "For dispatching this can be set to an empty string which means\n"
108 "the local hostname as defined in the collectd.conf.";
110 static char type_doc[] = "The type of this value. This type has to be defined\n"
111 "in your types.db. Attempting to set it to any other value will\n"
112 "raise a TypeError exception.\n"
113 "Assigning a type is mandetory, calling dispatch without doing\n"
114 "so will raise a RuntimeError exception.";
116 static char type_instance_doc[] = "";
118 static char plugin_doc[] = "The name of the plugin that read the data. Setting this\n"
119 "member to an empty string will insert \"python\" upon dispatching.";
121 static char plugin_instance_doc[] = "";
123 static char PluginData_doc[] = "This is an internal class that is the base for Values\n"
124 "and Notification. It is pretty useless by itself and was therefore not\n"
125 "exported to the collectd module.";
127 static PyObject *PluginData_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
130 self = (PluginData *) type->tp_alloc(type, 0);
137 self->plugin_instance[0] = 0;
139 self->type_instance[0] = 0;
140 return (PyObject *) self;
143 static int PluginData_init(PyObject *s, PyObject *args, PyObject *kwds) {
144 PluginData *self = (PluginData *) s;
146 const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
147 static char *kwlist[] = {"type", "plugin_instance", "type_instance",
148 "plugin", "host", "time", NULL};
150 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetd", kwlist, NULL, &type,
151 NULL, &plugin_instance, NULL, &type_instance, NULL, &plugin, NULL, &host, &time))
154 if (type[0] != 0 && plugin_get_ds(type) == NULL) {
155 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
159 sstrncpy(self->host, host, sizeof(self->host));
160 sstrncpy(self->plugin, plugin, sizeof(self->plugin));
161 sstrncpy(self->plugin_instance, plugin_instance, sizeof(self->plugin_instance));
162 sstrncpy(self->type, type, sizeof(self->type));
163 sstrncpy(self->type_instance, type_instance, sizeof(self->type_instance));
169 static PyObject *PluginData_repr(PyObject *s) {
171 static PyObject *l_closing = NULL;
173 if (l_closing == NULL)
174 l_closing = cpy_string_to_unicode_or_bytes(")");
176 if (l_closing == NULL)
179 ret = cpy_common_repr(s);
180 CPY_STRCAT(&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;
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, "|etOetetetetdi", kwlist,
353 NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
354 NULL, &plugin, NULL, &host, &time, &interval))
357 if (type[0] != 0 && plugin_get_ds(type) == NULL) {
358 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
362 sstrncpy(self->data.host, host, sizeof(self->data.host));
363 sstrncpy(self->data.plugin, plugin, sizeof(self->data.plugin));
364 sstrncpy(self->data.plugin_instance, plugin_instance, sizeof(self->data.plugin_instance));
365 sstrncpy(self->data.type, type, sizeof(self->data.type));
366 sstrncpy(self->data.type_instance, type_instance, sizeof(self->data.type_instance));
367 self->data.time = time;
369 if (values == NULL) {
370 values = PyList_New(0);
377 self->values = values;
380 self->interval = interval;
384 static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
386 const data_set_t *ds;
389 value_list_t value_list = VALUE_LIST_INIT;
390 PyObject *values = self->values;
391 double time = self->data.time;
392 int interval = self->interval;
393 const char *host = self->data.host;
394 const char *plugin = self->data.plugin;
395 const char *plugin_instance = self->data.plugin_instance;
396 const char *type = self->data.type;
397 const char *type_instance = self->data.type_instance;
399 static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
400 "plugin", "host", "time", "interval", NULL};
401 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdi", kwlist,
402 NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
403 NULL, &plugin, NULL, &host, &time, &interval))
407 PyErr_SetString(PyExc_RuntimeError, "type not set");
410 ds = plugin_get_ds(type);
412 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
415 if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
416 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
419 size = (int) PySequence_Length(values);
420 if (size != ds->ds_num) {
421 PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %i", type, ds->ds_num, size);
424 value = malloc(size * sizeof(*value));
425 for (i = 0; i < size; ++i) {
426 PyObject *item, *num;
427 item = PySequence_GetItem(values, i);
428 if (ds->ds->type == DS_TYPE_COUNTER) {
429 num = PyNumber_Long(item);
431 value[i].counter = PyLong_AsUnsignedLongLong(num);
432 } else if (ds->ds->type == DS_TYPE_GAUGE) {
433 num = PyNumber_Float(item);
435 value[i].gauge = PyFloat_AsDouble(num);
436 } else if (ds->ds->type == DS_TYPE_DERIVE) {
437 /* This might overflow without raising an exception.
438 * Not much we can do about it */
439 num = PyNumber_Long(item);
441 value[i].derive = PyLong_AsLongLong(num);
442 } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
443 /* This might overflow without raising an exception.
444 * Not much we can do about it */
445 num = PyNumber_Long(item);
447 value[i].absolute = PyLong_AsUnsignedLongLong(num);
450 PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds->type, type);
453 if (PyErr_Occurred() != NULL) {
458 value_list.values = value;
459 value_list.values_len = size;
460 value_list.time = time;
461 value_list.interval = interval;
462 sstrncpy(value_list.host, host, sizeof(value_list.host));
463 sstrncpy(value_list.plugin, plugin, sizeof(value_list.plugin));
464 sstrncpy(value_list.plugin_instance, plugin_instance, sizeof(value_list.plugin_instance));
465 sstrncpy(value_list.type, type, sizeof(value_list.type));
466 sstrncpy(value_list.type_instance, type_instance, sizeof(value_list.type_instance));
467 value_list.meta = NULL;
468 if (value_list.host[0] == 0)
469 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
470 if (value_list.plugin[0] == 0)
471 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
472 Py_BEGIN_ALLOW_THREADS;
473 ret = plugin_dispatch_values(&value_list);
474 Py_END_ALLOW_THREADS;
476 PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
483 static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
485 const data_set_t *ds;
488 value_list_t value_list = VALUE_LIST_INIT;
489 PyObject *values = self->values;
490 double time = self->data.time;
491 int interval = self->interval;
492 const char *host = self->data.host;
493 const char *plugin = self->data.plugin;
494 const char *plugin_instance = self->data.plugin_instance;
495 const char *type = self->data.type;
496 const char *type_instance = self->data.type_instance;
497 const char *dest = NULL;
499 static char *kwlist[] = {"destination", "type", "values", "plugin_instance", "type_instance",
500 "plugin", "host", "time", "interval", NULL};
501 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdi", kwlist,
502 NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
503 NULL, &plugin, NULL, &host, &time, &interval))
507 PyErr_SetString(PyExc_RuntimeError, "type not set");
510 ds = plugin_get_ds(type);
512 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
515 if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
516 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
519 size = (int) PySequence_Length(values);
520 if (size != ds->ds_num) {
521 PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %i", type, ds->ds_num, size);
524 value = malloc(size * sizeof(*value));
525 for (i = 0; i < size; ++i) {
526 PyObject *item, *num;
527 item = PySequence_GetItem(values, i);
528 if (ds->ds->type == DS_TYPE_COUNTER) {
529 num = PyNumber_Long(item);
531 value[i].counter = PyLong_AsUnsignedLongLong(num);
532 } else if (ds->ds->type == DS_TYPE_GAUGE) {
533 num = PyNumber_Float(item);
535 value[i].gauge = PyFloat_AsDouble(num);
536 } else if (ds->ds->type == DS_TYPE_DERIVE) {
537 /* This might overflow without raising an exception.
538 * Not much we can do about it */
539 num = PyNumber_Long(item);
541 value[i].derive = PyLong_AsLongLong(num);
542 } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
543 /* This might overflow without raising an exception.
544 * Not much we can do about it */
545 num = PyNumber_Long(item);
547 value[i].absolute = PyLong_AsUnsignedLongLong(num);
550 PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds->type, type);
553 if (PyErr_Occurred() != NULL) {
558 value_list.values = value;
559 value_list.values_len = size;
560 value_list.time = time;
561 value_list.interval = interval;
562 sstrncpy(value_list.host, host, sizeof(value_list.host));
563 sstrncpy(value_list.plugin, plugin, sizeof(value_list.plugin));
564 sstrncpy(value_list.plugin_instance, plugin_instance, sizeof(value_list.plugin_instance));
565 sstrncpy(value_list.type, type, sizeof(value_list.type));
566 sstrncpy(value_list.type_instance, type_instance, sizeof(value_list.type_instance));
567 value_list.meta = NULL;
568 if (value_list.host[0] == 0)
569 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
570 if (value_list.plugin[0] == 0)
571 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
572 Py_BEGIN_ALLOW_THREADS;
573 ret = plugin_write(dest, NULL, &value_list);
574 Py_END_ALLOW_THREADS;
576 PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
583 static PyObject *Values_repr(PyObject *s) {
585 static PyObject *l_interval = NULL, *l_values = NULL, *l_closing = NULL;
586 Values *self = (Values *) s;
588 if (l_interval == NULL)
589 l_interval = cpy_string_to_unicode_or_bytes(",interval=");
590 if (l_values == NULL)
591 l_values = cpy_string_to_unicode_or_bytes(",values=");
592 if (l_closing == NULL)
593 l_closing = cpy_string_to_unicode_or_bytes(")");
595 if (l_interval == NULL || l_values == NULL || l_closing == NULL)
598 ret = cpy_common_repr(s);
599 if (self->interval != 0) {
600 CPY_STRCAT(&ret, l_interval);
601 tmp = PyInt_FromLong(self->interval);
602 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
603 CPY_STRCAT_AND_DEL(&ret, tmp);
605 if (self->values != NULL && PySequence_Length(self->values) > 0) {
606 CPY_STRCAT(&ret, l_values);
607 tmp = PyObject_Repr(self->values);
608 CPY_STRCAT_AND_DEL(&ret, tmp);
610 CPY_STRCAT(&ret, l_closing);
614 static int Values_traverse(PyObject *self, visitproc visit, void *arg) {
615 Values *v = (Values *) self;
620 static int Values_clear(PyObject *self) {
621 Values *v = (Values *) self;
626 static void Values_dealloc(PyObject *self) {
628 self->ob_type->tp_free(self);
631 static PyMemberDef Values_members[] = {
632 {"interval", T_INT, offsetof(Values, interval), 0, interval_doc},
633 {"values", T_OBJECT_EX, offsetof(Values, values), 0, values_doc},
637 static PyMethodDef Values_methods[] = {
638 {"dispatch", (PyCFunction) Values_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
639 {"write", (PyCFunction) Values_write, METH_VARARGS | METH_KEYWORDS, write_doc},
643 PyTypeObject ValuesType = {
645 "collectd.Values", /* tp_name */
646 sizeof(Values), /* tp_basicsize */
647 0, /* Will be filled in later */
648 Values_dealloc, /* tp_dealloc */
653 Values_repr, /* tp_repr */
654 0, /* tp_as_number */
655 0, /* tp_as_sequence */
656 0, /* tp_as_mapping */
662 0, /* tp_as_buffer */
663 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
664 Values_doc, /* tp_doc */
665 Values_traverse, /* tp_traverse */
666 Values_clear, /* tp_clear */
667 0, /* tp_richcompare */
668 0, /* tp_weaklistoffset */
671 Values_methods, /* tp_methods */
672 Values_members, /* tp_members */
676 0, /* tp_descr_get */
677 0, /* tp_descr_set */
678 0, /* tp_dictoffset */
679 Values_init, /* tp_init */
681 Values_new /* tp_new */
684 static char severity_doc[] = "The severity of this notification. Assign or compare to\n"
685 "NOTIF_FAILURE, NOTIF_WARNING or NOTIF_OKAY.";
687 static char message_doc[] = "Some kind of description what's going on and why this Notification was generated.";
689 static char Notification_doc[] = "The Notification class is a wrapper around the collectd notification.\n"
690 "It can be used to notify other plugins about bad stuff happening. It works\n"
691 "similar to Values but has a severity and a message instead of interval\n"
693 "Notifications can be dispatched at any time and can be received with register_notification.";
695 static int Notification_init(PyObject *s, PyObject *args, PyObject *kwds) {
696 Notification *self = (Notification *) s;
699 const char *message = "";
700 const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
701 static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
702 "plugin", "host", "time", "severity", NULL};
704 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist,
705 NULL, &type, NULL, &message, NULL, &plugin_instance, NULL, &type_instance,
706 NULL, &plugin, NULL, &host, &time, &severity))
709 if (type[0] != 0 && plugin_get_ds(type) == NULL) {
710 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
714 sstrncpy(self->data.host, host, sizeof(self->data.host));
715 sstrncpy(self->data.plugin, plugin, sizeof(self->data.plugin));
716 sstrncpy(self->data.plugin_instance, plugin_instance, sizeof(self->data.plugin_instance));
717 sstrncpy(self->data.type, type, sizeof(self->data.type));
718 sstrncpy(self->data.type_instance, type_instance, sizeof(self->data.type_instance));
719 self->data.time = time;
721 sstrncpy(self->message, message, sizeof(self->message));
722 self->severity = severity;
726 static PyObject *Notification_dispatch(Notification *self, PyObject *args, PyObject *kwds) {
728 const data_set_t *ds;
729 notification_t notification;
730 double t = self->data.time;
731 int severity = self->severity;
732 const char *host = self->data.host;
733 const char *plugin = self->data.plugin;
734 const char *plugin_instance = self->data.plugin_instance;
735 const char *type = self->data.type;
736 const char *type_instance = self->data.type_instance;
737 const char *message = self->message;
739 static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
740 "plugin", "host", "time", "severity", NULL};
741 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist,
742 NULL, &type, NULL, &message, NULL, &plugin_instance, NULL, &type_instance,
743 NULL, &plugin, NULL, &host, &t, &severity))
747 PyErr_SetString(PyExc_RuntimeError, "type not set");
750 ds = plugin_get_ds(type);
752 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
756 notification.time = t;
757 notification.severity = severity;
758 sstrncpy(notification.message, message, sizeof(notification.message));
759 sstrncpy(notification.host, host, sizeof(notification.host));
760 sstrncpy(notification.plugin, plugin, sizeof(notification.plugin));
761 sstrncpy(notification.plugin_instance, plugin_instance, sizeof(notification.plugin_instance));
762 sstrncpy(notification.type, type, sizeof(notification.type));
763 sstrncpy(notification.type_instance, type_instance, sizeof(notification.type_instance));
764 notification.meta = NULL;
765 if (notification.time < 1)
766 notification.time = time(0);
767 if (notification.host[0] == 0)
768 sstrncpy(notification.host, hostname_g, sizeof(notification.host));
769 if (notification.plugin[0] == 0)
770 sstrncpy(notification.plugin, "python", sizeof(notification.plugin));
771 Py_BEGIN_ALLOW_THREADS;
772 ret = plugin_dispatch_notification(¬ification);
773 Py_END_ALLOW_THREADS;
775 PyErr_SetString(PyExc_RuntimeError, "error dispatching notification, read the logs");
781 static PyObject *Notification_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
784 self = (Notification *) PluginData_new(type, args, kwds);
788 self->message[0] = 0;
790 return (PyObject *) self;
793 static int Notification_setstring(PyObject *self, PyObject *value, void *data) {
798 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
802 new = cpy_unicode_or_bytes_to_string(&value);
807 old = ((char *) self) + (intptr_t) data;
808 sstrncpy(old, new, NOTIF_MAX_MSG_LEN);
813 static PyObject *Notification_repr(PyObject *s) {
815 static PyObject *l_severity = NULL, *l_message = NULL, *l_closing = NULL;
816 Notification *self = (Notification *) s;
818 if (l_severity == NULL)
819 l_severity = cpy_string_to_unicode_or_bytes(",severity=");
820 if (l_message == NULL)
821 l_message = cpy_string_to_unicode_or_bytes(",message=");
822 if (l_closing == NULL)
823 l_closing = cpy_string_to_unicode_or_bytes(")");
825 if (l_severity == NULL || l_message == NULL || l_closing == NULL)
828 ret = cpy_common_repr(s);
829 if (self->severity != 0) {
830 CPY_STRCAT(&ret, l_severity);
831 tmp = PyInt_FromLong(self->severity);
832 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
833 CPY_STRCAT_AND_DEL(&ret, tmp);
835 if (self->message[0] != 0) {
836 CPY_STRCAT(&ret, l_message);
837 tmp = cpy_string_to_unicode_or_bytes(self->message);
838 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
839 CPY_STRCAT_AND_DEL(&ret, tmp);
841 CPY_STRCAT(&ret, l_closing);
845 static PyMethodDef Notification_methods[] = {
846 {"dispatch", (PyCFunction) Notification_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
850 static PyMemberDef Notification_members[] = {
851 {"severity", T_INT, offsetof(Notification, severity), 0, severity_doc},
855 static PyGetSetDef Notification_getseters[] = {
856 {"message", PluginData_getstring, Notification_setstring, message_doc, (void *) offsetof(Notification, message)},
860 PyTypeObject NotificationType = {
862 "collectd.Notification", /* tp_name */
863 sizeof(Notification), /* tp_basicsize */
864 0, /* Will be filled in later */
870 Notification_repr, /* tp_repr */
871 0, /* tp_as_number */
872 0, /* tp_as_sequence */
873 0, /* tp_as_mapping */
879 0, /* tp_as_buffer */
880 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
881 Notification_doc, /* tp_doc */
884 0, /* tp_richcompare */
885 0, /* tp_weaklistoffset */
888 Notification_methods, /* tp_methods */
889 Notification_members, /* tp_members */
890 Notification_getseters, /* tp_getset */
893 0, /* tp_descr_get */
894 0, /* tp_descr_set */
895 0, /* tp_dictoffset */
896 Notification_init, /* tp_init */
898 Notification_new /* tp_new */