+/**
+ * collectd - src/pyvalues.c
+ * Copyright (C) 2009 Sven Trenkel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Sven Trenkel <collectd at semidefinite.de>
+ **/
+
#include <Python.h>
#include <structmember.h>
static char PluginData_doc[] = "This is an internal class that is the base for Values\n"
"and Notification. It is pretty useless by itself and was therefore not\n"
- "not exported to the collectd module.";
+ "exported to the collectd module.";
static PyObject *PluginData_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
PluginData *self;
};
static PyObject *PluginData_getstring(PyObject *self, void *data) {
- const char *value = ((char *) self) + (int) data;
+ const char *value = ((char *) self) + (intptr_t) data;
return PyString_FromString(value);
}
}
new = PyString_AsString(value);
if (new == NULL) return -1;
- old = ((char *) self) + (int) data;
+ old = ((char *) self) + (intptr_t) data;
sstrncpy(old, new, DATA_MAX_NAME_LEN);
return 0;
}
return -1;
}
- old = ((char *) self) + (int) data;
+ old = ((char *) self) + (intptr_t) data;
sstrncpy(old, new, DATA_MAX_NAME_LEN);
return 0;
}
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE /*| Py_TPFLAGS_HAVE_GC*/, /*tp_flags*/
- PluginData_doc , /* tp_doc */
+ PluginData_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
"be used (default: 10).\n"
"\n"
"If you submit values more often than the specified interval, the average\n"
- "will be used. If you submit less values, your graphes will have gaps.";
+ "will be used. If you submit less values, your graphs will have gaps.";
static char values_doc[] = "These are the actual values that get dispatched to collectd.\n"
"It has to be a sequence (a tuple or list) of numbers.\n"
static char dispatch_doc[] = "dispatch([type][, values][, plugin_instance][, type_instance]"
"[, plugin][, host][, time][, interval]) -> None. Dispatch a value list.\n"
"\n"
- "Dispatch this instance to the collectd process. A values object a members\n"
+ "Dispatch this instance to the collectd process. The object has members\n"
"for each of the possible arguments for this method. For a detailed explanation\n"
"of these parameters see the member of the same same.\n"
"\n"
"If you do not submit a parameter the value saved in its member will be submitted.\n"
"If you do provide a parameter it will be used instead, without altering the member.";
+static char write_doc[] = "write([destination][, type][, values][, plugin_instance][, type_instance]"
+ "[, plugin][, host][, time][, interval]) -> None. Dispatch a value list.\n"
+ "\n"
+ "Write this instance to a single plugin or all plugins if 'destination' is obmitted.\n"
+ "This will bypass the main collectd process and all filtering and caching.\n"
+ "Other than that it works similar to 'dispatch'. In most cases 'dispatch' should be\n"
+ "used instead of 'write'.\n";
+
static char Values_doc[] = "A Values object used for dispatching values to collectd and receiving values from write callbacks.";
static PyObject *Values_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
int i, ret;
const data_set_t *ds;
- Py_ssize_t size;
+ int size;
value_t *value;
value_list_t value_list = VALUE_LIST_INIT;
PyObject *values = self->values;
PyErr_Format(PyExc_TypeError, "values must be list or tuple");
return NULL;
}
- size = PySequence_Length(values);
+ size = (int) PySequence_Length(values);
if (size != ds->ds_num) {
- PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %zd", type, ds->ds_num, size);
+ PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %i", type, ds->ds_num, size);
return NULL;
}
value = malloc(size * sizeof(*value));
Py_RETURN_NONE;
}
+static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
+ int i, ret;
+ const data_set_t *ds;
+ int size;
+ value_t *value;
+ value_list_t value_list = VALUE_LIST_INIT;
+ PyObject *values = self->values;
+ double time = self->data.time;
+ int interval = self->interval;
+ const char *host = self->data.host;
+ const char *plugin = self->data.plugin;
+ const char *plugin_instance = self->data.plugin_instance;
+ const char *type = self->data.type;
+ const char *type_instance = self->data.type_instance;
+ const char *dest = NULL;
+
+ static char *kwlist[] = {"destination", "type", "values", "plugin_instance", "type_instance",
+ "plugin", "host", "time", "interval", NULL};
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sOssssdi", kwlist,
+ &type, &values, &plugin_instance, &type_instance,
+ &plugin, &host, &time, &interval))
+ return NULL;
+
+ if (type[0] == 0) {
+ PyErr_SetString(PyExc_RuntimeError, "type not set");
+ return NULL;
+ }
+ ds = plugin_get_ds(type);
+ if (ds == NULL) {
+ PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
+ return NULL;
+ }
+ if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
+ PyErr_Format(PyExc_TypeError, "values must be list or tuple");
+ return NULL;
+ }
+ size = (int) PySequence_Length(values);
+ if (size != ds->ds_num) {
+ PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %i", type, ds->ds_num, size);
+ return NULL;
+ }
+ value = malloc(size * sizeof(*value));
+ for (i = 0; i < size; ++i) {
+ PyObject *item, *num;
+ item = PySequence_GetItem(values, i);
+ if (ds->ds->type == DS_TYPE_COUNTER) {
+ num = PyNumber_Long(item);
+ if (num != NULL)
+ value[i].counter = PyLong_AsUnsignedLongLong(num);
+ } else if (ds->ds->type == DS_TYPE_GAUGE) {
+ num = PyNumber_Float(item);
+ if (num != NULL)
+ value[i].gauge = PyFloat_AsDouble(num);
+ } else if (ds->ds->type == DS_TYPE_DERIVE) {
+ /* This might overflow without raising an exception.
+ * Not much we can do about it */
+ num = PyNumber_Long(item);
+ if (num != NULL)
+ value[i].derive = PyLong_AsLongLong(num);
+ } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
+ /* This might overflow without raising an exception.
+ * Not much we can do about it */
+ num = PyNumber_Long(item);
+ if (num != NULL)
+ value[i].absolute = PyLong_AsUnsignedLongLong(num);
+ } else {
+ free(value);
+ PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds->type, type);
+ return NULL;
+ }
+ if (PyErr_Occurred() != NULL) {
+ free(value);
+ return NULL;
+ }
+ }
+ value_list.values = value;
+ value_list.values_len = size;
+ value_list.time = time;
+ value_list.interval = interval;
+ sstrncpy(value_list.host, host, sizeof(value_list.host));
+ sstrncpy(value_list.plugin, plugin, sizeof(value_list.plugin));
+ sstrncpy(value_list.plugin_instance, plugin_instance, sizeof(value_list.plugin_instance));
+ sstrncpy(value_list.type, type, sizeof(value_list.type));
+ sstrncpy(value_list.type_instance, type_instance, sizeof(value_list.type_instance));
+ value_list.meta = NULL;
+ if (value_list.host[0] == 0)
+ sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
+ if (value_list.plugin[0] == 0)
+ sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
+ Py_BEGIN_ALLOW_THREADS;
+ ret = plugin_write(dest, NULL, &value_list);
+ Py_END_ALLOW_THREADS;
+ if (ret != 0) {
+ PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
+ return NULL;
+ }
+ free(value);
+ Py_RETURN_NONE;
+}
+
static PyObject *Values_repr(PyObject *s) {
PyObject *ret, *valuestring = NULL;
Values *self = (Values *) s;
static PyMethodDef Values_methods[] = {
{"dispatch", (PyCFunction) Values_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
+ {"write", (PyCFunction) Values_write, METH_VARARGS | METH_KEYWORDS, write_doc},
{NULL}
};
0, /* tp_alloc */
Values_new /* tp_new */
};
+
+static char severity_doc[] = "The severity of this notification. Assign or compare to\n"
+ "NOTIF_FAILURE, NOTIF_WARNING or NOTIF_OKAY.";
+
+static char message_doc[] = "Some kind of description what's going on and why this Notification was generated.";
+
+static char Notification_doc[] = "The Notification class is a wrapper around the collectd notification.\n"
+ "It can be used to notify other plugins about bad stuff happening. It works\n"
+ "similar to Values but has a severity and a message instead of interval\n"
+ "and time.\n"
+ "Notifications can be dispatched at any time and can be received with register_notification.";
+
+static int Notification_init(PyObject *s, PyObject *args, PyObject *kwds) {
+ Notification *self = (Notification *) s;
+ PyObject *tmp;
+ int severity = 0, ret;
+ double time = 0;
+ const char *message = "";
+ const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
+ static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
+ "plugin", "host", "time", "severity", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ssssssdi", kwlist,
+ &type, &message, &plugin_instance, &type_instance,
+ &plugin, &host, &time, &severity))
+ return -1;
+
+ tmp = Py_BuildValue("sssssd", type, plugin_instance, type_instance, plugin, host, time);
+ if (tmp == NULL)
+ return -1;
+ ret = PluginDataType.tp_init(s, tmp, NULL);
+ Py_DECREF(tmp);
+ if (ret != 0)
+ return -1;
+
+ sstrncpy(self->message, message, sizeof(self->message));
+ self->severity = severity;
+ return 0;
+}
+
+static PyObject *Notification_dispatch(Notification *self, PyObject *args, PyObject *kwds) {
+ int ret;
+ const data_set_t *ds;
+ notification_t notification;
+ double t = self->data.time;
+ int severity = self->severity;
+ const char *host = self->data.host;
+ const char *plugin = self->data.plugin;
+ const char *plugin_instance = self->data.plugin_instance;
+ const char *type = self->data.type;
+ const char *type_instance = self->data.type_instance;
+ const char *message = self->message;
+
+ static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
+ "plugin", "host", "time", "severity", NULL};
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ssssssdi", kwlist,
+ &type, &message, &plugin_instance, &type_instance,
+ &plugin, &host, &t, &severity))
+ return NULL;
+
+ if (type[0] == 0) {
+ PyErr_SetString(PyExc_RuntimeError, "type not set");
+ return NULL;
+ }
+ ds = plugin_get_ds(type);
+ if (ds == NULL) {
+ PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
+ return NULL;
+ }
+
+ notification.time = t;
+ notification.severity = severity;
+ sstrncpy(notification.message, message, sizeof(notification.message));
+ sstrncpy(notification.host, host, sizeof(notification.host));
+ sstrncpy(notification.plugin, plugin, sizeof(notification.plugin));
+ sstrncpy(notification.plugin_instance, plugin_instance, sizeof(notification.plugin_instance));
+ sstrncpy(notification.type, type, sizeof(notification.type));
+ sstrncpy(notification.type_instance, type_instance, sizeof(notification.type_instance));
+ notification.meta = NULL;
+ if (notification.time < 1)
+ notification.time = time(0);
+ if (notification.host[0] == 0)
+ sstrncpy(notification.host, hostname_g, sizeof(notification.host));
+ if (notification.plugin[0] == 0)
+ sstrncpy(notification.plugin, "python", sizeof(notification.plugin));
+ Py_BEGIN_ALLOW_THREADS;
+ ret = plugin_dispatch_notification(¬ification);
+ Py_END_ALLOW_THREADS;
+ if (ret != 0) {
+ PyErr_SetString(PyExc_RuntimeError, "error dispatching notification, read the logs");
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *Notification_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ Notification *self;
+
+ self = (Notification *) PluginData_new(type, args, kwds);
+ if (self == NULL)
+ return NULL;
+
+ self->message[0] = 0;
+ self->severity = 0;
+ return (PyObject *) self;
+}
+
+static int Notification_setstring(PyObject *self, PyObject *value, void *data) {
+ char *old;
+ const char *new;
+
+ if (value == NULL) {
+ PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
+ return -1;
+ }
+ new = PyString_AsString(value);
+ if (new == NULL) return -1;
+ old = ((char *) self) + (intptr_t) data;
+ sstrncpy(old, new, NOTIF_MAX_MSG_LEN);
+ return 0;
+}
+
+static PyObject *Notification_repr(PyObject *s) {
+ PyObject *ret;
+ Notification *self = (Notification *) s;
+
+ ret = PyString_FromFormat("collectd.Values(type='%s%s%s%s%s%s%s%s%s%s%s',time=%lu,interval=%i)", self->data.type,
+ *self->data.type_instance ? "',type_instance='" : "", self->data.type_instance,
+ *self->data.plugin ? "',plugin='" : "", self->data.plugin,
+ *self->data.plugin_instance ? "',plugin_instance='" : "", self->data.plugin_instance,
+ *self->data.host ? "',host='" : "", self->data.host,
+ *self->message ? "',message='" : "", self->message,
+ (long unsigned) self->data.time, self->severity);
+ return ret;
+}
+
+static PyMethodDef Notification_methods[] = {
+ {"dispatch", (PyCFunction) Notification_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
+ {NULL}
+};
+
+static PyMemberDef Notification_members[] = {
+ {"severity", T_INT, offsetof(Notification, severity), 0, severity_doc},
+ {NULL}
+};
+
+static PyGetSetDef Notification_getseters[] = {
+ {"message", PluginData_getstring, Notification_setstring, message_doc, (void *) offsetof(Notification, message)},
+ {NULL}
+};
+
+PyTypeObject NotificationType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* Always 0 */
+ "collectd.Notification", /* tp_name */
+ sizeof(Notification), /* tp_basicsize */
+ 0, /* Will be filled in later */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ Notification_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ Notification_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ Notification_methods, /* tp_methods */
+ Notification_members, /* tp_members */
+ Notification_getseters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ Notification_init, /* tp_init */
+ 0, /* tp_alloc */
+ Notification_new /* tp_new */
+};