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, "|etetetetetd", kwlist, NULL, &type,
85 NULL, &plugin_instance, NULL, &type_instance, NULL, &plugin, NULL, &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;
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) {
584 PyObject *ret, *valuestring = NULL;
585 Values *self = (Values *) s;
587 if (self->values != NULL)
588 valuestring = PyObject_Repr(self->values);
589 if (valuestring == NULL)
592 ret = PyString_FromFormat("collectd.Values(type='%s%s%s%s%s%s%s%s%s',time=%lu,interval=%i,values=%s)", self->data.type,
593 *self->data.type_instance ? "',type_instance='" : "", self->data.type_instance,
594 *self->data.plugin ? "',plugin='" : "", self->data.plugin,
595 *self->data.plugin_instance ? "',plugin_instance='" : "", self->data.plugin_instance,
596 *self->data.host ? "',host='" : "", self->data.host,
597 (long unsigned) self->data.time, self->interval,
598 valuestring ? cpy_unicode_or_bytes_to_string(valuestring) : "[]");
599 Py_XDECREF(valuestring);
603 static int Values_traverse(PyObject *self, visitproc visit, void *arg) {
604 Values *v = (Values *) self;
609 static int Values_clear(PyObject *self) {
610 Values *v = (Values *) self;
615 static void Values_dealloc(PyObject *self) {
617 self->ob_type->tp_free(self);
620 static PyMemberDef Values_members[] = {
621 {"interval", T_INT, offsetof(Values, interval), 0, interval_doc},
622 {"values", T_OBJECT_EX, offsetof(Values, values), 0, values_doc},
626 static PyMethodDef Values_methods[] = {
627 {"dispatch", (PyCFunction) Values_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
628 {"write", (PyCFunction) Values_write, METH_VARARGS | METH_KEYWORDS, write_doc},
632 PyTypeObject ValuesType = {
634 "collectd.Values", /* tp_name */
635 sizeof(Values), /* tp_basicsize */
636 0, /* Will be filled in later */
637 Values_dealloc, /* tp_dealloc */
642 0/*Values_repr*/, /* tp_repr */
643 0, /* tp_as_number */
644 0, /* tp_as_sequence */
645 0, /* tp_as_mapping */
651 0, /* tp_as_buffer */
652 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
653 Values_doc, /* tp_doc */
654 Values_traverse, /* tp_traverse */
655 Values_clear, /* tp_clear */
656 0, /* tp_richcompare */
657 0, /* tp_weaklistoffset */
660 Values_methods, /* tp_methods */
661 Values_members, /* tp_members */
665 0, /* tp_descr_get */
666 0, /* tp_descr_set */
667 0, /* tp_dictoffset */
668 Values_init, /* tp_init */
670 Values_new /* tp_new */
673 static char severity_doc[] = "The severity of this notification. Assign or compare to\n"
674 "NOTIF_FAILURE, NOTIF_WARNING or NOTIF_OKAY.";
676 static char message_doc[] = "Some kind of description what's going on and why this Notification was generated.";
678 static char Notification_doc[] = "The Notification class is a wrapper around the collectd notification.\n"
679 "It can be used to notify other plugins about bad stuff happening. It works\n"
680 "similar to Values but has a severity and a message instead of interval\n"
682 "Notifications can be dispatched at any time and can be received with register_notification.";
684 static int Notification_init(PyObject *s, PyObject *args, PyObject *kwds) {
685 Notification *self = (Notification *) s;
688 const char *message = "";
689 const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
690 static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
691 "plugin", "host", "time", "severity", NULL};
693 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist,
694 NULL, &type, NULL, &message, NULL, &plugin_instance, NULL, &type_instance,
695 NULL, &plugin, NULL, &host, &time, &severity))
698 if (type[0] != 0 && plugin_get_ds(type) == NULL) {
699 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
703 sstrncpy(self->data.host, host, sizeof(self->data.host));
704 sstrncpy(self->data.plugin, plugin, sizeof(self->data.plugin));
705 sstrncpy(self->data.plugin_instance, plugin_instance, sizeof(self->data.plugin_instance));
706 sstrncpy(self->data.type, type, sizeof(self->data.type));
707 sstrncpy(self->data.type_instance, type_instance, sizeof(self->data.type_instance));
708 self->data.time = time;
710 sstrncpy(self->message, message, sizeof(self->message));
711 self->severity = severity;
715 static PyObject *Notification_dispatch(Notification *self, PyObject *args, PyObject *kwds) {
717 const data_set_t *ds;
718 notification_t notification;
719 double t = self->data.time;
720 int severity = self->severity;
721 const char *host = self->data.host;
722 const char *plugin = self->data.plugin;
723 const char *plugin_instance = self->data.plugin_instance;
724 const char *type = self->data.type;
725 const char *type_instance = self->data.type_instance;
726 const char *message = self->message;
728 static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
729 "plugin", "host", "time", "severity", NULL};
730 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist,
731 NULL, &type, NULL, &message, NULL, &plugin_instance, NULL, &type_instance,
732 NULL, &plugin, NULL, &host, &t, &severity))
736 PyErr_SetString(PyExc_RuntimeError, "type not set");
739 ds = plugin_get_ds(type);
741 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
745 notification.time = t;
746 notification.severity = severity;
747 sstrncpy(notification.message, message, sizeof(notification.message));
748 sstrncpy(notification.host, host, sizeof(notification.host));
749 sstrncpy(notification.plugin, plugin, sizeof(notification.plugin));
750 sstrncpy(notification.plugin_instance, plugin_instance, sizeof(notification.plugin_instance));
751 sstrncpy(notification.type, type, sizeof(notification.type));
752 sstrncpy(notification.type_instance, type_instance, sizeof(notification.type_instance));
753 notification.meta = NULL;
754 if (notification.time < 1)
755 notification.time = time(0);
756 if (notification.host[0] == 0)
757 sstrncpy(notification.host, hostname_g, sizeof(notification.host));
758 if (notification.plugin[0] == 0)
759 sstrncpy(notification.plugin, "python", sizeof(notification.plugin));
760 Py_BEGIN_ALLOW_THREADS;
761 ret = plugin_dispatch_notification(¬ification);
762 Py_END_ALLOW_THREADS;
764 PyErr_SetString(PyExc_RuntimeError, "error dispatching notification, read the logs");
770 static PyObject *Notification_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
773 self = (Notification *) PluginData_new(type, args, kwds);
777 self->message[0] = 0;
779 return (PyObject *) self;
782 static int Notification_setstring(PyObject *self, PyObject *value, void *data) {
787 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
791 new = cpy_unicode_or_bytes_to_string(&value);
796 old = ((char *) self) + (intptr_t) data;
797 sstrncpy(old, new, NOTIF_MAX_MSG_LEN);
802 /*static PyObject *Notification_repr(PyObject *s) {
804 Notification *self = (Notification *) s;
806 ret = PyString_FromFormat("collectd.Values(type='%s%s%s%s%s%s%s%s%s%s%s',time=%lu,interval=%i)", self->data.type,
807 *self->data.type_instance ? "',type_instance='" : "", self->data.type_instance,
808 *self->data.plugin ? "',plugin='" : "", self->data.plugin,
809 *self->data.plugin_instance ? "',plugin_instance='" : "", self->data.plugin_instance,
810 *self->data.host ? "',host='" : "", self->data.host,
811 *self->message ? "',message='" : "", self->message,
812 (long unsigned) self->data.time, self->severity);
816 static PyMethodDef Notification_methods[] = {
817 {"dispatch", (PyCFunction) Notification_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
821 static PyMemberDef Notification_members[] = {
822 {"severity", T_INT, offsetof(Notification, severity), 0, severity_doc},
826 static PyGetSetDef Notification_getseters[] = {
827 {"message", PluginData_getstring, Notification_setstring, message_doc, (void *) offsetof(Notification, message)},
831 PyTypeObject NotificationType = {
833 "collectd.Notification", /* tp_name */
834 sizeof(Notification), /* tp_basicsize */
835 0, /* Will be filled in later */
841 0/*Notification_repr*/, /* tp_repr */
842 0, /* tp_as_number */
843 0, /* tp_as_sequence */
844 0, /* tp_as_mapping */
850 0, /* tp_as_buffer */
851 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
852 Notification_doc, /* tp_doc */
855 0, /* tp_richcompare */
856 0, /* tp_weaklistoffset */
859 Notification_methods, /* tp_methods */
860 Notification_members, /* tp_members */
861 Notification_getseters, /* tp_getset */
864 0, /* tp_descr_get */
865 0, /* tp_descr_set */
866 0, /* tp_dictoffset */
867 Notification_init, /* tp_init */
869 Notification_new /* tp_new */