X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fpyvalues.c;h=d83f541bb4a32420a11d516608494c795172acb6;hb=0d99b31e19b1442f51b04dc8636587f1fc9135eb;hp=08195f392711c94d4bb61521b6b029607826e5be;hpb=7fe44188701a53ab370ada0f33d93c692d0a91cb;p=collectd.git diff --git a/src/pyvalues.c b/src/pyvalues.c index 08195f39..d83f541b 100644 --- a/src/pyvalues.c +++ b/src/pyvalues.c @@ -1,3 +1,29 @@ +/** + * 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 + **/ + #include #include @@ -30,7 +56,7 @@ static char plugin_instance_doc[] = ""; 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; @@ -91,7 +117,7 @@ static PyMemberDef PluginData_members[] = { }; 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); } @@ -106,7 +132,7 @@ static int PluginData_setstring(PyObject *self, PyObject *value, void *data) { } 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; } @@ -127,7 +153,7 @@ static int PluginData_settype(PyObject *self, PyObject *value, void *data) { return -1; } - old = ((char *) self) + (int) data; + old = ((char *) self) + (intptr_t) data; sstrncpy(old, new, DATA_MAX_NAME_LEN); return 0; } @@ -163,7 +189,7 @@ PyTypeObject PluginDataType = { 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 */ @@ -190,7 +216,7 @@ static char interval_doc[] = "The interval is the timespan in seconds between tw "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" @@ -205,13 +231,21 @@ static char values_doc[] = "These are the actual values that get dispatched to c 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) { @@ -266,7 +300,7 @@ static int Values_init(PyObject *s, 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; @@ -298,9 +332,9 @@ static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) { 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)); @@ -362,6 +396,106 @@ static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) { 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; @@ -407,6 +541,7 @@ static PyMemberDef Values_members[] = { 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} }; @@ -451,3 +586,195 @@ PyTypeObject ValuesType = { 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 */ +};