X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=src%2Fpyvalues.c;h=15c1848488e70ead655ea1d2d0744572b371cd2b;hp=0ba04360687a5906d32e1a51276137dce655b78d;hb=7111bb6df7628edce3a8e538b386fbe27633a191;hpb=21ab7512825cf8177d5eee5101344b45d0854610 diff --git a/src/pyvalues.c b/src/pyvalues.c index 0ba04360..15c18484 100644 --- a/src/pyvalues.c +++ b/src/pyvalues.c @@ -28,1073 +28,1285 @@ #include #include "collectd.h" + #include "common.h" #include "cpython.h" -#define FreeAll() do {\ - PyMem_Free(type);\ - PyMem_Free(plugin_instance);\ - PyMem_Free(type_instance);\ - PyMem_Free(plugin);\ - PyMem_Free(host);\ -} while(0) +typedef struct { + int (*add_string)(void *, const char *, const char *); + int (*add_signed_int)(void *, const char *, int64_t); + int (*add_unsigned_int)(void *, const char *, uint64_t); + int (*add_double)(void *, const char *, double); + int (*add_boolean)(void *, const char *, _Bool); +} cpy_build_meta_handler_t; + +#define FreeAll() \ + do { \ + PyMem_Free(type); \ + PyMem_Free(plugin_instance); \ + PyMem_Free(type_instance); \ + PyMem_Free(plugin); \ + PyMem_Free(host); \ + } while (0) static PyObject *cpy_common_repr(PyObject *s) { - PyObject *ret, *tmp; - static PyObject *l_type = NULL, *l_type_instance = NULL, *l_plugin = NULL, *l_plugin_instance = NULL; - static PyObject *l_host = NULL, *l_time = NULL; - PluginData *self = (PluginData *) s; - - if (l_type == NULL) - l_type = cpy_string_to_unicode_or_bytes("(type="); - if (l_type_instance == NULL) - l_type_instance = cpy_string_to_unicode_or_bytes(",type_instance="); - if (l_plugin == NULL) - l_plugin = cpy_string_to_unicode_or_bytes(",plugin="); - if (l_plugin_instance == NULL) - l_plugin_instance = cpy_string_to_unicode_or_bytes(",plugin_instance="); - if (l_host == NULL) - l_host = cpy_string_to_unicode_or_bytes(",host="); - if (l_time == NULL) - l_time = cpy_string_to_unicode_or_bytes(",time="); - - if (!l_type || !l_type_instance || !l_plugin || !l_plugin_instance || !l_host || !l_time) - return NULL; - - ret = cpy_string_to_unicode_or_bytes(s->ob_type->tp_name); - - CPY_STRCAT(&ret, l_type); - tmp = cpy_string_to_unicode_or_bytes(self->type); - CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); - CPY_STRCAT_AND_DEL(&ret, tmp); - - if (self->type_instance[0] != 0) { - CPY_STRCAT(&ret, l_type_instance); - tmp = cpy_string_to_unicode_or_bytes(self->type_instance); - CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); - CPY_STRCAT_AND_DEL(&ret, tmp); - } - - if (self->plugin[0] != 0) { - CPY_STRCAT(&ret, l_plugin); - tmp = cpy_string_to_unicode_or_bytes(self->plugin); - CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); - CPY_STRCAT_AND_DEL(&ret, tmp); - } - - if (self->plugin_instance[0] != 0) { - CPY_STRCAT(&ret, l_plugin_instance); - tmp = cpy_string_to_unicode_or_bytes(self->plugin_instance); - CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); - CPY_STRCAT_AND_DEL(&ret, tmp); - } - - if (self->host[0] != 0) { - CPY_STRCAT(&ret, l_host); - tmp = cpy_string_to_unicode_or_bytes(self->host); - CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); - CPY_STRCAT_AND_DEL(&ret, tmp); - } - - if (self->time != 0) { - CPY_STRCAT(&ret, l_time); - tmp = PyFloat_FromDouble(self->time); - CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); - CPY_STRCAT_AND_DEL(&ret, tmp); - } - return ret; + PyObject *ret, *tmp; + static PyObject *l_type = NULL, *l_type_instance = NULL, *l_plugin = NULL, + *l_plugin_instance = NULL; + static PyObject *l_host = NULL, *l_time = NULL; + PluginData *self = (PluginData *)s; + + if (l_type == NULL) + l_type = cpy_string_to_unicode_or_bytes("(type="); + if (l_type_instance == NULL) + l_type_instance = cpy_string_to_unicode_or_bytes(",type_instance="); + if (l_plugin == NULL) + l_plugin = cpy_string_to_unicode_or_bytes(",plugin="); + if (l_plugin_instance == NULL) + l_plugin_instance = cpy_string_to_unicode_or_bytes(",plugin_instance="); + if (l_host == NULL) + l_host = cpy_string_to_unicode_or_bytes(",host="); + if (l_time == NULL) + l_time = cpy_string_to_unicode_or_bytes(",time="); + + if (!l_type || !l_type_instance || !l_plugin || !l_plugin_instance || + !l_host || !l_time) + return NULL; + + ret = cpy_string_to_unicode_or_bytes(s->ob_type->tp_name); + + CPY_STRCAT(&ret, l_type); + tmp = cpy_string_to_unicode_or_bytes(self->type); + CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); + CPY_STRCAT_AND_DEL(&ret, tmp); + + if (self->type_instance[0] != 0) { + CPY_STRCAT(&ret, l_type_instance); + tmp = cpy_string_to_unicode_or_bytes(self->type_instance); + CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); + CPY_STRCAT_AND_DEL(&ret, tmp); + } + + if (self->plugin[0] != 0) { + CPY_STRCAT(&ret, l_plugin); + tmp = cpy_string_to_unicode_or_bytes(self->plugin); + CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); + CPY_STRCAT_AND_DEL(&ret, tmp); + } + + if (self->plugin_instance[0] != 0) { + CPY_STRCAT(&ret, l_plugin_instance); + tmp = cpy_string_to_unicode_or_bytes(self->plugin_instance); + CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); + CPY_STRCAT_AND_DEL(&ret, tmp); + } + + if (self->host[0] != 0) { + CPY_STRCAT(&ret, l_host); + tmp = cpy_string_to_unicode_or_bytes(self->host); + CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); + CPY_STRCAT_AND_DEL(&ret, tmp); + } + + if (self->time != 0) { + CPY_STRCAT(&ret, l_time); + tmp = PyFloat_FromDouble(self->time); + CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); + CPY_STRCAT_AND_DEL(&ret, tmp); + } + return ret; } -static char time_doc[] = "This is the Unix timestamp of the time this value was read.\n" - "For dispatching values this can be set to 0 which means \"now\".\n" - "This means the time the value is actually dispatched, not the time\n" - "it was set to 0."; +static char time_doc[] = + "This is the Unix timestamp of the time this value was read.\n" + "For dispatching values this can be set to 0 which means \"now\".\n" + "This means the time the value is actually dispatched, not the time\n" + "it was set to 0."; -static char host_doc[] = "The hostname of the host this value was read from.\n" - "For dispatching this can be set to an empty string which means\n" - "the local hostname as defined in collectd.conf."; +static char host_doc[] = + "The hostname of the host this value was read from.\n" + "For dispatching this can be set to an empty string which means\n" + "the local hostname as defined in collectd.conf."; -static char type_doc[] = "The type of this value. This type has to be defined\n" - "in the types.db file. Attempting to set it to any other value\n" - "will raise a TypeError exception.\n" - "Assigning a type is mandatory, calling dispatch without doing\n" - "so will raise a RuntimeError exception."; +static char type_doc[] = + "The type of this value. This type has to be defined\n" + "in the types.db file. Attempting to set it to any other value\n" + "will raise a TypeError exception.\n" + "Assigning a type is mandatory, calling dispatch without doing\n" + "so will raise a RuntimeError exception."; static char type_instance_doc[] = ""; -static char plugin_doc[] = "The name of the plugin that read the data. Setting this\n" - "member to an empty string will insert \"python\" upon dispatching."; +static char plugin_doc[] = + "The name of the plugin that read the data. Setting this\n" + "member to an empty string will insert \"python\" upon dispatching."; 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 is therefore not\n" - "exported to the collectd module."; - -static PyObject *PluginData_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - PluginData *self; - - self = (PluginData *) type->tp_alloc(type, 0); - if (self == NULL) - return NULL; - - self->time = 0; - self->host[0] = 0; - self->plugin[0] = 0; - self->plugin_instance[0] = 0; - self->type[0] = 0; - self->type_instance[0] = 0; - return (PyObject *) self; +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 is therefore not\n" + "exported to the collectd module."; + +static PyObject *PluginData_new(PyTypeObject *type, PyObject *args, + PyObject *kwds) { + PluginData *self; + + self = (PluginData *)type->tp_alloc(type, 0); + if (self == NULL) + return NULL; + + self->time = 0; + self->host[0] = 0; + self->plugin[0] = 0; + self->plugin_instance[0] = 0; + self->type[0] = 0; + self->type_instance[0] = 0; + return (PyObject *)self; } static int PluginData_init(PyObject *s, PyObject *args, PyObject *kwds) { - PluginData *self = (PluginData *) s; - double time = 0; - char *type = NULL, *plugin_instance = NULL, *type_instance = NULL, *plugin = NULL, *host = NULL; - static char *kwlist[] = {"type", "plugin_instance", "type_instance", - "plugin", "host", "time", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetd", kwlist, NULL, &type, - NULL, &plugin_instance, NULL, &type_instance, NULL, &plugin, NULL, &host, &time)) - return -1; - - if (type && plugin_get_ds(type) == NULL) { - PyErr_Format(PyExc_TypeError, "Dataset %s not found", type); - FreeAll(); - return -1; - } - - sstrncpy(self->host, host ? host : "", sizeof(self->host)); - sstrncpy(self->plugin, plugin ? plugin : "", sizeof(self->plugin)); - sstrncpy(self->plugin_instance, plugin_instance ? plugin_instance : "", sizeof(self->plugin_instance)); - sstrncpy(self->type, type ? type : "", sizeof(self->type)); - sstrncpy(self->type_instance, type_instance ? type_instance : "", sizeof(self->type_instance)); - self->time = time; - - FreeAll(); - - return 0; + PluginData *self = (PluginData *)s; + double time = 0; + char *type = NULL, *plugin_instance = NULL, *type_instance = NULL, + *plugin = NULL, *host = NULL; + static char *kwlist[] = { + "type", "plugin_instance", "type_instance", "plugin", "host", "time", + NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetd", kwlist, NULL, + &type, NULL, &plugin_instance, NULL, + &type_instance, NULL, &plugin, NULL, &host, + &time)) + return -1; + + if (type && plugin_get_ds(type) == NULL) { + PyErr_Format(PyExc_TypeError, "Dataset %s not found", type); + FreeAll(); + return -1; + } + + sstrncpy(self->host, host ? host : "", sizeof(self->host)); + sstrncpy(self->plugin, plugin ? plugin : "", sizeof(self->plugin)); + sstrncpy(self->plugin_instance, plugin_instance ? plugin_instance : "", + sizeof(self->plugin_instance)); + sstrncpy(self->type, type ? type : "", sizeof(self->type)); + sstrncpy(self->type_instance, type_instance ? type_instance : "", + sizeof(self->type_instance)); + self->time = time; + + FreeAll(); + + return 0; } static PyObject *PluginData_repr(PyObject *s) { - PyObject *ret; - static PyObject *l_closing = NULL; + PyObject *ret; + static PyObject *l_closing = NULL; - if (l_closing == NULL) - l_closing = cpy_string_to_unicode_or_bytes(")"); + if (l_closing == NULL) + l_closing = cpy_string_to_unicode_or_bytes(")"); - if (l_closing == NULL) - return NULL; + if (l_closing == NULL) + return NULL; - ret = cpy_common_repr(s); - CPY_STRCAT(&ret, l_closing); - return ret; + ret = cpy_common_repr(s); + CPY_STRCAT(&ret, l_closing); + return ret; } static PyMemberDef PluginData_members[] = { - {"time", T_DOUBLE, offsetof(PluginData, time), 0, time_doc}, - {NULL} -}; + {"time", T_DOUBLE, offsetof(PluginData, time), 0, time_doc}, {NULL}}; static PyObject *PluginData_getstring(PyObject *self, void *data) { - const char *value = ((char *) self) + (intptr_t) data; + const char *value = ((char *)self) + (intptr_t)data; - return cpy_string_to_unicode_or_bytes(value); + return cpy_string_to_unicode_or_bytes(value); } static int PluginData_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; - } - Py_INCREF(value); - new = cpy_unicode_or_bytes_to_string(&value); - if (new == NULL) { - Py_DECREF(value); - return -1; - } - old = ((char *) self) + (intptr_t) data; - sstrncpy(old, new, DATA_MAX_NAME_LEN); - Py_DECREF(value); - return 0; + char *old; + const char *new; + + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute"); + return -1; + } + Py_INCREF(value); + new = cpy_unicode_or_bytes_to_string(&value); + if (new == NULL) { + Py_DECREF(value); + return -1; + } + old = ((char *)self) + (intptr_t)data; + sstrncpy(old, new, DATA_MAX_NAME_LEN); + Py_DECREF(value); + return 0; } static int PluginData_settype(PyObject *self, PyObject *value, void *data) { - char *old; - const char *new; - - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute"); - return -1; - } - Py_INCREF(value); - new = cpy_unicode_or_bytes_to_string(&value); - if (new == NULL) { - Py_DECREF(value); - return -1; - } - - if (plugin_get_ds(new) == NULL) { - PyErr_Format(PyExc_TypeError, "Dataset %s not found", new); - Py_DECREF(value); - return -1; - } - - old = ((char *) self) + (intptr_t) data; - sstrncpy(old, new, DATA_MAX_NAME_LEN); - Py_DECREF(value); - return 0; + char *old; + const char *new; + + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute"); + return -1; + } + Py_INCREF(value); + new = cpy_unicode_or_bytes_to_string(&value); + if (new == NULL) { + Py_DECREF(value); + return -1; + } + + if (plugin_get_ds(new) == NULL) { + PyErr_Format(PyExc_TypeError, "Dataset %s not found", new); + Py_DECREF(value); + return -1; + } + + old = ((char *)self) + (intptr_t)data; + sstrncpy(old, new, DATA_MAX_NAME_LEN); + Py_DECREF(value); + return 0; } static PyGetSetDef PluginData_getseters[] = { - {"host", PluginData_getstring, PluginData_setstring, host_doc, (void *) offsetof(PluginData, host)}, - {"plugin", PluginData_getstring, PluginData_setstring, plugin_doc, (void *) offsetof(PluginData, plugin)}, - {"plugin_instance", PluginData_getstring, PluginData_setstring, plugin_instance_doc, (void *) offsetof(PluginData, plugin_instance)}, - {"type_instance", PluginData_getstring, PluginData_setstring, type_instance_doc, (void *) offsetof(PluginData, type_instance)}, - {"type", PluginData_getstring, PluginData_settype, type_doc, (void *) offsetof(PluginData, type)}, - {NULL} -}; + {"host", PluginData_getstring, PluginData_setstring, host_doc, + (void *)offsetof(PluginData, host)}, + {"plugin", PluginData_getstring, PluginData_setstring, plugin_doc, + (void *)offsetof(PluginData, plugin)}, + {"plugin_instance", PluginData_getstring, PluginData_setstring, + plugin_instance_doc, (void *)offsetof(PluginData, plugin_instance)}, + {"type_instance", PluginData_getstring, PluginData_setstring, + type_instance_doc, (void *)offsetof(PluginData, type_instance)}, + {"type", PluginData_getstring, PluginData_settype, type_doc, + (void *)offsetof(PluginData, type)}, + {NULL}}; PyTypeObject PluginDataType = { - CPY_INIT_TYPE - "collectd.PluginData", /* tp_name */ - sizeof(PluginData), /* tp_basicsize */ - 0, /* Will be filled in later */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - PluginData_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 /*| Py_TPFLAGS_HAVE_GC*/, /*tp_flags*/ - PluginData_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - PluginData_members, /* tp_members */ - PluginData_getseters, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - PluginData_init, /* tp_init */ - 0, /* tp_alloc */ - PluginData_new /* tp_new */ + CPY_INIT_TYPE "collectd.PluginData", /* tp_name */ + sizeof(PluginData), /* tp_basicsize */ + 0, /* Will be filled in later */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + PluginData_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 /*| Py_TPFLAGS_HAVE_GC*/, /*tp_flags*/ + PluginData_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + PluginData_members, /* tp_members */ + PluginData_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + PluginData_init, /* tp_init */ + 0, /* tp_alloc */ + PluginData_new /* tp_new */ }; -static char interval_doc[] = "The interval is the timespan in seconds between two submits for\n" - "the same data source. This value has to be a positive integer, so you can't\n" - "submit more than one value per second. If this member is set to a\n" - "non-positive value, the default value as specified in the config file will\n" - "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 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" - "The size of the sequence and the type of its content depend on the type\n" - "member in the types.db file. For more information on this read the\n" - "types.db man page.\n" - "\n" - "If the sequence does not have the correct size upon dispatch a RuntimeError\n" - "exception will be raised. If the content of the sequence is not a number,\n" - "a TypeError exception will be raised."; - -static char meta_doc[] = "These are the meta data for this Value object.\n" - "It has to be a dictionary of numbers, strings or bools. All keys must be\n" - "strings. int and long objects will be dispatched as signed integers unless\n" - "they are between 2**63 and 2**64-1, which will result in an unsigned integer.\n" - "You can force one of these storage classes by using the classes\n" - "collectd.Signed and collectd.Unsigned. A meta object received by a write\n" - "callback will always contain Signed or Unsigned objects."; - -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. 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 omitted.\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) { - Values *self; - - self = (Values *) PluginData_new(type, args, kwds); - if (self == NULL) - return NULL; - - self->values = PyList_New(0); - self->meta = PyDict_New(); - self->interval = 0; - return (PyObject *) self; +static char interval_doc[] = + "The interval is the timespan in seconds between two submits for\n" + "the same data source. This value has to be a positive integer, so you " + "can't\n" + "submit more than one value per second. If this member is set to a\n" + "non-positive value, the default value as specified in the config file " + "will\n" + "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 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" + "The size of the sequence and the type of its content depend on the type\n" + "member in the types.db file. For more information on this read the\n" + "types.db man page.\n" + "\n" + "If the sequence does not have the correct size upon dispatch a " + "RuntimeError\n" + "exception will be raised. If the content of the sequence is not a " + "number,\n" + "a TypeError exception will be raised."; + +static char meta_doc[] = + "These are the meta data for this Value object.\n" + "It has to be a dictionary of numbers, strings or bools. All keys must be\n" + "strings. int and long objects will be dispatched as signed integers " + "unless\n" + "they are between 2**63 and 2**64-1, which will result in an unsigned " + "integer.\n" + "You can force one of these storage classes by using the classes\n" + "collectd.Signed and collectd.Unsigned. A meta object received by a write\n" + "callback will always contain Signed or Unsigned objects."; + +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. 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 " + "omitted.\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) { + Values *self; + + self = (Values *)PluginData_new(type, args, kwds); + if (self == NULL) + return NULL; + + self->values = PyList_New(0); + self->meta = PyDict_New(); + self->interval = 0; + return (PyObject *)self; } static int Values_init(PyObject *s, PyObject *args, PyObject *kwds) { - Values *self = (Values *) s; - double interval = 0, time = 0; - PyObject *values = NULL, *meta = NULL, *tmp; - char *type = NULL, *plugin_instance = NULL, *type_instance = NULL, *plugin = NULL, *host = NULL; - static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance", - "plugin", "host", "time", "interval", "meta", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist, - NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance, - NULL, &plugin, NULL, &host, &time, &interval, &meta)) - return -1; - - if (type && plugin_get_ds(type) == NULL) { - PyErr_Format(PyExc_TypeError, "Dataset %s not found", type); - FreeAll(); - return -1; - } - - sstrncpy(self->data.host, host ? host : "", sizeof(self->data.host)); - sstrncpy(self->data.plugin, plugin ? plugin : "", sizeof(self->data.plugin)); - sstrncpy(self->data.plugin_instance, plugin_instance ? plugin_instance : "", sizeof(self->data.plugin_instance)); - sstrncpy(self->data.type, type ? type : "", sizeof(self->data.type)); - sstrncpy(self->data.type_instance, type_instance ? type_instance : "", sizeof(self->data.type_instance)); - self->data.time = time; - - FreeAll(); - - if (values == NULL) { - values = PyList_New(0); - PyErr_Clear(); - } else { - Py_INCREF(values); - } - - if (meta == NULL) { - meta = PyDict_New(); - PyErr_Clear(); - } else { - Py_INCREF(meta); - } - - tmp = self->values; - self->values = values; - Py_XDECREF(tmp); - - tmp = self->meta; - self->meta = meta; - Py_XDECREF(tmp); - - self->interval = interval; - return 0; + Values *self = (Values *)s; + double interval = 0, time = 0; + PyObject *values = NULL, *meta = NULL, *tmp; + char *type = NULL, *plugin_instance = NULL, *type_instance = NULL, + *plugin = NULL, *host = NULL; + static char *kwlist[] = { + "type", "values", "plugin_instance", "type_instance", "plugin", + "host", "time", "interval", "meta", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist, NULL, + &type, &values, NULL, &plugin_instance, NULL, + &type_instance, NULL, &plugin, NULL, &host, + &time, &interval, &meta)) + return -1; + + if (type && plugin_get_ds(type) == NULL) { + PyErr_Format(PyExc_TypeError, "Dataset %s not found", type); + FreeAll(); + return -1; + } + + sstrncpy(self->data.host, host ? host : "", sizeof(self->data.host)); + sstrncpy(self->data.plugin, plugin ? plugin : "", sizeof(self->data.plugin)); + sstrncpy(self->data.plugin_instance, plugin_instance ? plugin_instance : "", + sizeof(self->data.plugin_instance)); + sstrncpy(self->data.type, type ? type : "", sizeof(self->data.type)); + sstrncpy(self->data.type_instance, type_instance ? type_instance : "", + sizeof(self->data.type_instance)); + self->data.time = time; + + FreeAll(); + + if (values == NULL) { + values = PyList_New(0); + PyErr_Clear(); + } else { + Py_INCREF(values); + } + + if (meta == NULL) { + meta = PyDict_New(); + PyErr_Clear(); + } else { + Py_INCREF(meta); + } + + tmp = self->values; + self->values = values; + Py_XDECREF(tmp); + + tmp = self->meta; + self->meta = meta; + Py_XDECREF(tmp); + + self->interval = interval; + return 0; } +static int cpy_build_meta_generic(PyObject *meta, + cpy_build_meta_handler_t *meta_func, + void *m) { + int s; + PyObject *l; + + if ((meta == NULL) || (meta == Py_None)) + return -1; + + l = PyDict_Items(meta); /* New reference. */ + if (!l) { + cpy_log_exception("building meta data"); + return -1; + } + s = PyList_Size(l); + if (s <= 0) { + Py_XDECREF(l); + return -1; + } + + for (int i = 0; i < s; ++i) { + const char *string, *keystring; + PyObject *key, *value, *item, *tmp; + + item = PyList_GET_ITEM(l, i); + key = PyTuple_GET_ITEM(item, 0); + Py_INCREF(key); + keystring = cpy_unicode_or_bytes_to_string(&key); + if (!keystring) { + PyErr_Clear(); + Py_XDECREF(key); + continue; + } + value = PyTuple_GET_ITEM(item, 1); + Py_INCREF(value); + if (value == Py_True) { + meta_func->add_boolean(m, keystring, 1); + } else if (value == Py_False) { + meta_func->add_boolean(m, keystring, 0); + } else if (PyFloat_Check(value)) { + meta_func->add_double(m, keystring, PyFloat_AsDouble(value)); + } else if (PyObject_TypeCheck(value, &SignedType)) { + long long int lli; + lli = PyLong_AsLongLong(value); + if (!PyErr_Occurred() && (lli == (int64_t)lli)) + meta_func->add_signed_int(m, keystring, lli); + } else if (PyObject_TypeCheck(value, &UnsignedType)) { + long long unsigned llu; + llu = PyLong_AsUnsignedLongLong(value); + if (!PyErr_Occurred() && (llu == (uint64_t)llu)) + meta_func->add_unsigned_int(m, keystring, llu); + } else if (PyNumber_Check(value)) { + long long int lli; + long long unsigned llu; + tmp = PyNumber_Long(value); + lli = PyLong_AsLongLong(tmp); + if (!PyErr_Occurred() && (lli == (int64_t)lli)) { + meta_func->add_signed_int(m, keystring, lli); + } else { + PyErr_Clear(); + llu = PyLong_AsUnsignedLongLong(tmp); + if (!PyErr_Occurred() && (llu == (uint64_t)llu)) + meta_func->add_unsigned_int(m, keystring, llu); + } + Py_XDECREF(tmp); + } else { + string = cpy_unicode_or_bytes_to_string(&value); + if (string) { + meta_func->add_string(m, keystring, string); + } else { + PyErr_Clear(); + tmp = PyObject_Str(value); + string = cpy_unicode_or_bytes_to_string(&tmp); + if (string) + meta_func->add_string(m, keystring, string); + Py_XDECREF(tmp); + } + } + if (PyErr_Occurred()) + cpy_log_exception("building meta data"); + Py_XDECREF(value); + Py_DECREF(key); + } + Py_XDECREF(l); + return 0; +} + +#define CPY_BUILD_META_FUNC(meta_type, func, val_type) \ + static int cpy_##func(void *meta, const char *key, val_type val) { \ + return func((meta_type *)meta, key, val); \ + } + +#define CPY_BUILD_META_HANDLER(func_prefix, meta_type) \ + CPY_BUILD_META_FUNC(meta_type, func_prefix##_add_string, const char *) \ + CPY_BUILD_META_FUNC(meta_type, func_prefix##_add_signed_int, int64_t) \ + CPY_BUILD_META_FUNC(meta_type, func_prefix##_add_unsigned_int, uint64_t) \ + CPY_BUILD_META_FUNC(meta_type, func_prefix##_add_double, double) \ + CPY_BUILD_META_FUNC(meta_type, func_prefix##_add_boolean, _Bool) \ + \ + static cpy_build_meta_handler_t cpy_##func_prefix = { \ + .add_string = cpy_##func_prefix##_add_string, \ + .add_signed_int = cpy_##func_prefix##_add_signed_int, \ + .add_unsigned_int = cpy_##func_prefix##_add_unsigned_int, \ + .add_double = cpy_##func_prefix##_add_double, \ + .add_boolean = cpy_##func_prefix##_add_boolean} + +CPY_BUILD_META_HANDLER(meta_data, meta_data_t); +CPY_BUILD_META_HANDLER(plugin_notification_meta, notification_t); + static meta_data_t *cpy_build_meta(PyObject *meta) { - int i, s; - meta_data_t *m = NULL; - PyObject *l; - - if ((meta == NULL) || (meta == Py_None)) - return NULL; - - l = PyDict_Items(meta); /* New reference. */ - if (!l) { - cpy_log_exception("building meta data"); - return NULL; - } - s = PyList_Size(l); - if (s <= 0) { - Py_XDECREF(l); - return NULL; - } - - m = meta_data_create(); - for (i = 0; i < s; ++i) { - const char *string, *keystring; - PyObject *key, *value, *item, *tmp; - - item = PyList_GET_ITEM(l, i); - key = PyTuple_GET_ITEM(item, 0); - Py_INCREF(key); - keystring = cpy_unicode_or_bytes_to_string(&key); - if (!keystring) { - PyErr_Clear(); - Py_XDECREF(key); - continue; - } - value = PyTuple_GET_ITEM(item, 1); - Py_INCREF(value); - if (value == Py_True) { - meta_data_add_boolean(m, keystring, 1); - } else if (value == Py_False) { - meta_data_add_boolean(m, keystring, 0); - } else if (PyFloat_Check(value)) { - meta_data_add_double(m, keystring, PyFloat_AsDouble(value)); - } else if (PyObject_TypeCheck(value, &SignedType)) { - long long int lli; - lli = PyLong_AsLongLong(value); - if (!PyErr_Occurred() && (lli == (int64_t) lli)) - meta_data_add_signed_int(m, keystring, lli); - } else if (PyObject_TypeCheck(value, &UnsignedType)) { - long long unsigned llu; - llu = PyLong_AsUnsignedLongLong(value); - if (!PyErr_Occurred() && (llu == (uint64_t) llu)) - meta_data_add_unsigned_int(m, keystring, llu); - } else if (PyNumber_Check(value)) { - long long int lli; - long long unsigned llu; - tmp = PyNumber_Long(value); - lli = PyLong_AsLongLong(tmp); - if (!PyErr_Occurred() && (lli == (int64_t) lli)) { - meta_data_add_signed_int(m, keystring, lli); - } else { - PyErr_Clear(); - llu = PyLong_AsUnsignedLongLong(tmp); - if (!PyErr_Occurred() && (llu == (uint64_t) llu)) - meta_data_add_unsigned_int(m, keystring, llu); - } - Py_XDECREF(tmp); - } else { - string = cpy_unicode_or_bytes_to_string(&value); - if (string) { - meta_data_add_string(m, keystring, string); - } else { - PyErr_Clear(); - tmp = PyObject_Str(value); - string = cpy_unicode_or_bytes_to_string(&tmp); - if (string) - meta_data_add_string(m, keystring, string); - Py_XDECREF(tmp); - } - } - if (PyErr_Occurred()) - cpy_log_exception("building meta data"); - Py_XDECREF(value); - Py_DECREF(key); - } - Py_XDECREF(l); - return m; + meta_data_t *m = meta_data_create(); + if (cpy_build_meta_generic(meta, &cpy_meta_data, (void *)m) < 0) { + meta_data_destroy(m); + return NULL; + } + return m; +} + +static void cpy_build_notification_meta(notification_t *n, PyObject *meta) { + cpy_build_meta_generic(meta, &cpy_plugin_notification_meta, (void *)n); } static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) { - int ret; - const data_set_t *ds; - size_t size, i; - value_t *value; - value_list_t value_list = VALUE_LIST_INIT; - PyObject *values = self->values, *meta = self->meta; - double time = self->data.time, interval = self->interval; - char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL, *type_instance = NULL; - - static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance", - "plugin", "host", "time", "interval", "meta", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist, - NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance, - NULL, &plugin, NULL, &host, &time, &interval, &meta)) - return NULL; - - sstrncpy(value_list.host, host ? host : self->data.host, sizeof(value_list.host)); - sstrncpy(value_list.plugin, plugin ? plugin : self->data.plugin, sizeof(value_list.plugin)); - sstrncpy(value_list.plugin_instance, plugin_instance ? plugin_instance : self->data.plugin_instance, sizeof(value_list.plugin_instance)); - sstrncpy(value_list.type, type ? type : self->data.type, sizeof(value_list.type)); - sstrncpy(value_list.type_instance, type_instance ? type_instance : self->data.type_instance, sizeof(value_list.type_instance)); - FreeAll(); - if (value_list.type[0] == 0) { - PyErr_SetString(PyExc_RuntimeError, "type not set"); - FreeAll(); - return NULL; - } - ds = plugin_get_ds(value_list.type); - if (ds == NULL) { - PyErr_Format(PyExc_TypeError, "Dataset %s not found", value_list.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; - } - if (meta != NULL && meta != Py_None && !PyDict_Check(meta)) { - PyErr_Format(PyExc_TypeError, "meta must be a dict"); - return NULL; - } - size = (size_t) PySequence_Length(values); - if (size != ds->ds_num) { - PyErr_Format(PyExc_RuntimeError, "type %s needs %zu values, got %zu", value_list.type, ds->ds_num, size); - return NULL; - } - value = calloc(size, sizeof(*value)); - for (i = 0; i < size; ++i) { - PyObject *item, *num; - item = PySequence_Fast_GET_ITEM(values, (int) i); /* Borrowed reference. */ - if (ds->ds->type == DS_TYPE_COUNTER) { - num = PyNumber_Long(item); /* New reference. */ - if (num != NULL) { - value[i].counter = PyLong_AsUnsignedLongLong(num); - Py_XDECREF(num); - } - } else if (ds->ds->type == DS_TYPE_GAUGE) { - num = PyNumber_Float(item); /* New reference. */ - if (num != NULL) { - value[i].gauge = PyFloat_AsDouble(num); - Py_XDECREF(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); /* New reference. */ - if (num != NULL) { - value[i].derive = PyLong_AsLongLong(num); - Py_XDECREF(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); /* New reference. */ - if (num != NULL) { - value[i].absolute = PyLong_AsUnsignedLongLong(num); - Py_XDECREF(num); - } - } else { - free(value); - PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds->type, value_list.type); - return NULL; - } - if (PyErr_Occurred() != NULL) { - free(value); - return NULL; - } - } - value_list.values = value; - value_list.meta = cpy_build_meta(meta); - value_list.values_len = size; - value_list.time = DOUBLE_TO_CDTIME_T(time); - value_list.interval = DOUBLE_TO_CDTIME_T(interval); - 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_dispatch_values(&value_list); - Py_END_ALLOW_THREADS; - meta_data_destroy(value_list.meta); - free(value); - if (ret != 0) { - PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs"); - return NULL; - } - Py_RETURN_NONE; + int ret; + const data_set_t *ds; + size_t size; + value_t *value; + value_list_t value_list = VALUE_LIST_INIT; + PyObject *values = self->values, *meta = self->meta; + double time = self->data.time, interval = self->interval; + char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL, + *type_instance = NULL; + + static char *kwlist[] = { + "type", "values", "plugin_instance", "type_instance", "plugin", + "host", "time", "interval", "meta", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist, NULL, + &type, &values, NULL, &plugin_instance, NULL, + &type_instance, NULL, &plugin, NULL, &host, + &time, &interval, &meta)) + return NULL; + + sstrncpy(value_list.host, host ? host : self->data.host, + sizeof(value_list.host)); + sstrncpy(value_list.plugin, plugin ? plugin : self->data.plugin, + sizeof(value_list.plugin)); + sstrncpy(value_list.plugin_instance, + plugin_instance ? plugin_instance : self->data.plugin_instance, + sizeof(value_list.plugin_instance)); + sstrncpy(value_list.type, type ? type : self->data.type, + sizeof(value_list.type)); + sstrncpy(value_list.type_instance, + type_instance ? type_instance : self->data.type_instance, + sizeof(value_list.type_instance)); + FreeAll(); + if (value_list.type[0] == 0) { + PyErr_SetString(PyExc_RuntimeError, "type not set"); + FreeAll(); + return NULL; + } + ds = plugin_get_ds(value_list.type); + if (ds == NULL) { + PyErr_Format(PyExc_TypeError, "Dataset %s not found", value_list.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; + } + if (meta != NULL && meta != Py_None && !PyDict_Check(meta)) { + PyErr_Format(PyExc_TypeError, "meta must be a dict"); + return NULL; + } + size = (size_t)PySequence_Length(values); + if (size != ds->ds_num) { + PyErr_Format(PyExc_RuntimeError, "type %s needs %zu values, got %zu", + value_list.type, ds->ds_num, size); + return NULL; + } + value = calloc(size, sizeof(*value)); + for (size_t i = 0; i < size; ++i) { + PyObject *item, *num; + item = PySequence_Fast_GET_ITEM(values, (int)i); /* Borrowed reference. */ + switch (ds->ds[i].type) { + case DS_TYPE_COUNTER: + num = PyNumber_Long(item); /* New reference. */ + if (num != NULL) { + value[i].counter = PyLong_AsUnsignedLongLong(num); + Py_XDECREF(num); + } + break; + case DS_TYPE_GAUGE: + num = PyNumber_Float(item); /* New reference. */ + if (num != NULL) { + value[i].gauge = PyFloat_AsDouble(num); + Py_XDECREF(num); + } + break; + case DS_TYPE_DERIVE: + /* This might overflow without raising an exception. + * Not much we can do about it */ + num = PyNumber_Long(item); /* New reference. */ + if (num != NULL) { + value[i].derive = PyLong_AsLongLong(num); + Py_XDECREF(num); + } + break; + case DS_TYPE_ABSOLUTE: + /* This might overflow without raising an exception. + * Not much we can do about it */ + num = PyNumber_Long(item); /* New reference. */ + if (num != NULL) { + value[i].absolute = PyLong_AsUnsignedLongLong(num); + Py_XDECREF(num); + } + break; + default: + free(value); + PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", + ds->ds[i].type, value_list.type); + return NULL; + } + if (PyErr_Occurred() != NULL) { + free(value); + return NULL; + } + } + value_list.values = value; + value_list.meta = cpy_build_meta(meta); + value_list.values_len = size; + value_list.time = DOUBLE_TO_CDTIME_T(time); + value_list.interval = DOUBLE_TO_CDTIME_T(interval); + 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_dispatch_values(&value_list); + Py_END_ALLOW_THREADS; + meta_data_destroy(value_list.meta); + free(value); + if (ret != 0) { + PyErr_SetString(PyExc_RuntimeError, + "error dispatching values, read the logs"); + return NULL; + } + Py_RETURN_NONE; } static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) { - int ret; - const data_set_t *ds; - size_t size, i; - value_t *value; - value_list_t value_list = VALUE_LIST_INIT; - PyObject *values = self->values, *meta = self->meta; - double time = self->data.time, interval = self->interval; - char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL, *type_instance = NULL, *dest = NULL; - - static char *kwlist[] = {"destination", "type", "values", "plugin_instance", "type_instance", - "plugin", "host", "time", "interval", "meta", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|etOetetetetdiO", kwlist, NULL, &dest, - NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance, - NULL, &plugin, NULL, &host, &time, &interval, &meta)) - return NULL; - - sstrncpy(value_list.host, host ? host : self->data.host, sizeof(value_list.host)); - sstrncpy(value_list.plugin, plugin ? plugin : self->data.plugin, sizeof(value_list.plugin)); - sstrncpy(value_list.plugin_instance, plugin_instance ? plugin_instance : self->data.plugin_instance, sizeof(value_list.plugin_instance)); - sstrncpy(value_list.type, type ? type : self->data.type, sizeof(value_list.type)); - sstrncpy(value_list.type_instance, type_instance ? type_instance : self->data.type_instance, sizeof(value_list.type_instance)); - FreeAll(); - if (value_list.type[0] == 0) { - PyErr_SetString(PyExc_RuntimeError, "type not set"); - return NULL; - } - ds = plugin_get_ds(value_list.type); - if (ds == NULL) { - PyErr_Format(PyExc_TypeError, "Dataset %s not found", value_list.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 = (size_t) PySequence_Length(values); - if (size != ds->ds_num) { - PyErr_Format(PyExc_RuntimeError, "type %s needs %zu values, got %zu", value_list.type, ds->ds_num, size); - return NULL; - } - value = calloc(size, sizeof(*value)); - for (i = 0; i < size; ++i) { - PyObject *item, *num; - item = PySequence_Fast_GET_ITEM(values, i); /* Borrowed reference. */ - if (ds->ds->type == DS_TYPE_COUNTER) { - num = PyNumber_Long(item); /* New reference. */ - if (num != NULL) { - value[i].counter = PyLong_AsUnsignedLongLong(num); - Py_XDECREF(num); - } - } else if (ds->ds->type == DS_TYPE_GAUGE) { - num = PyNumber_Float(item); /* New reference. */ - if (num != NULL) { - value[i].gauge = PyFloat_AsDouble(num); - Py_XDECREF(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); /* New reference. */ - if (num != NULL) { - value[i].derive = PyLong_AsLongLong(num); - Py_XDECREF(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); /* New reference. */ - if (num != NULL) { - value[i].absolute = PyLong_AsUnsignedLongLong(num); - Py_XDECREF(num); - } - } else { - free(value); - PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds->type, value_list.type); - return NULL; - } - if (PyErr_Occurred() != NULL) { - free(value); - return NULL; - } - } - value_list.values = value; - value_list.values_len = size; - value_list.time = DOUBLE_TO_CDTIME_T(time); - value_list.interval = DOUBLE_TO_CDTIME_T(interval); - value_list.meta = cpy_build_meta(meta); - 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; - meta_data_destroy(value_list.meta); - free(value); - if (ret != 0) { - PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs"); - return NULL; - } - Py_RETURN_NONE; + int ret; + const data_set_t *ds; + size_t size; + value_t *value; + value_list_t value_list = VALUE_LIST_INIT; + PyObject *values = self->values, *meta = self->meta; + double time = self->data.time, interval = self->interval; + char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL, + *type_instance = NULL, *dest = NULL; + + static char *kwlist[] = { + "destination", "type", "values", "plugin_instance", + "type_instance", "plugin", "host", "time", + "interval", "meta", NULL}; + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "et|etOetetetetdiO", kwlist, NULL, &dest, NULL, &type, + &values, NULL, &plugin_instance, NULL, &type_instance, NULL, &plugin, + NULL, &host, &time, &interval, &meta)) + return NULL; + + sstrncpy(value_list.host, host ? host : self->data.host, + sizeof(value_list.host)); + sstrncpy(value_list.plugin, plugin ? plugin : self->data.plugin, + sizeof(value_list.plugin)); + sstrncpy(value_list.plugin_instance, + plugin_instance ? plugin_instance : self->data.plugin_instance, + sizeof(value_list.plugin_instance)); + sstrncpy(value_list.type, type ? type : self->data.type, + sizeof(value_list.type)); + sstrncpy(value_list.type_instance, + type_instance ? type_instance : self->data.type_instance, + sizeof(value_list.type_instance)); + FreeAll(); + if (value_list.type[0] == 0) { + PyErr_SetString(PyExc_RuntimeError, "type not set"); + return NULL; + } + ds = plugin_get_ds(value_list.type); + if (ds == NULL) { + PyErr_Format(PyExc_TypeError, "Dataset %s not found", value_list.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 = (size_t)PySequence_Length(values); + if (size != ds->ds_num) { + PyErr_Format(PyExc_RuntimeError, "type %s needs %zu values, got %zu", + value_list.type, ds->ds_num, size); + return NULL; + } + value = calloc(size, sizeof(*value)); + for (size_t i = 0; i < size; ++i) { + PyObject *item, *num; + item = PySequence_Fast_GET_ITEM(values, i); /* Borrowed reference. */ + switch (ds->ds[i].type) { + case DS_TYPE_COUNTER: + num = PyNumber_Long(item); /* New reference. */ + if (num != NULL) { + value[i].counter = PyLong_AsUnsignedLongLong(num); + Py_XDECREF(num); + } + break; + case DS_TYPE_GAUGE: + num = PyNumber_Float(item); /* New reference. */ + if (num != NULL) { + value[i].gauge = PyFloat_AsDouble(num); + Py_XDECREF(num); + } + break; + case DS_TYPE_DERIVE: + /* This might overflow without raising an exception. + * Not much we can do about it */ + num = PyNumber_Long(item); /* New reference. */ + if (num != NULL) { + value[i].derive = PyLong_AsLongLong(num); + Py_XDECREF(num); + } + break; + case DS_TYPE_ABSOLUTE: + /* This might overflow without raising an exception. + * Not much we can do about it */ + num = PyNumber_Long(item); /* New reference. */ + if (num != NULL) { + value[i].absolute = PyLong_AsUnsignedLongLong(num); + Py_XDECREF(num); + } + break; + default: + free(value); + PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", + ds->ds[i].type, value_list.type); + return NULL; + } + if (PyErr_Occurred() != NULL) { + free(value); + return NULL; + } + } + value_list.values = value; + value_list.values_len = size; + value_list.time = DOUBLE_TO_CDTIME_T(time); + value_list.interval = DOUBLE_TO_CDTIME_T(interval); + value_list.meta = cpy_build_meta(meta); + 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; + meta_data_destroy(value_list.meta); + free(value); + if (ret != 0) { + PyErr_SetString(PyExc_RuntimeError, + "error dispatching values, read the logs"); + return NULL; + } + Py_RETURN_NONE; } static PyObject *Values_repr(PyObject *s) { - PyObject *ret, *tmp; - static PyObject *l_interval = NULL, *l_values = NULL, *l_meta = NULL, *l_closing = NULL; - Values *self = (Values *) s; - - if (l_interval == NULL) - l_interval = cpy_string_to_unicode_or_bytes(",interval="); - if (l_values == NULL) - l_values = cpy_string_to_unicode_or_bytes(",values="); - if (l_meta == NULL) - l_meta = cpy_string_to_unicode_or_bytes(",meta="); - if (l_closing == NULL) - l_closing = cpy_string_to_unicode_or_bytes(")"); - - if (l_interval == NULL || l_values == NULL || l_meta == NULL || l_closing == NULL) - return NULL; - - ret = cpy_common_repr(s); - if (self->interval != 0) { - CPY_STRCAT(&ret, l_interval); - tmp = PyFloat_FromDouble(self->interval); - CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); - CPY_STRCAT_AND_DEL(&ret, tmp); - } - if (self->values && (!PyList_Check(self->values) || PySequence_Length(self->values) > 0)) { - CPY_STRCAT(&ret, l_values); - tmp = PyObject_Repr(self->values); - CPY_STRCAT_AND_DEL(&ret, tmp); - } - if (self->meta && (!PyDict_Check(self->meta) || PyDict_Size(self->meta) > 0)) { - CPY_STRCAT(&ret, l_meta); - tmp = PyObject_Repr(self->meta); - CPY_STRCAT_AND_DEL(&ret, tmp); - } - CPY_STRCAT(&ret, l_closing); - return ret; + PyObject *ret, *tmp; + static PyObject *l_interval = NULL, *l_values = NULL, *l_meta = NULL, + *l_closing = NULL; + Values *self = (Values *)s; + + if (l_interval == NULL) + l_interval = cpy_string_to_unicode_or_bytes(",interval="); + if (l_values == NULL) + l_values = cpy_string_to_unicode_or_bytes(",values="); + if (l_meta == NULL) + l_meta = cpy_string_to_unicode_or_bytes(",meta="); + if (l_closing == NULL) + l_closing = cpy_string_to_unicode_or_bytes(")"); + + if (l_interval == NULL || l_values == NULL || l_meta == NULL || + l_closing == NULL) + return NULL; + + ret = cpy_common_repr(s); + if (self->interval != 0) { + CPY_STRCAT(&ret, l_interval); + tmp = PyFloat_FromDouble(self->interval); + CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); + CPY_STRCAT_AND_DEL(&ret, tmp); + } + if (self->values && + (!PyList_Check(self->values) || PySequence_Length(self->values) > 0)) { + CPY_STRCAT(&ret, l_values); + tmp = PyObject_Repr(self->values); + CPY_STRCAT_AND_DEL(&ret, tmp); + } + if (self->meta && + (!PyDict_Check(self->meta) || PyDict_Size(self->meta) > 0)) { + CPY_STRCAT(&ret, l_meta); + tmp = PyObject_Repr(self->meta); + CPY_STRCAT_AND_DEL(&ret, tmp); + } + CPY_STRCAT(&ret, l_closing); + return ret; } static int Values_traverse(PyObject *self, visitproc visit, void *arg) { - Values *v = (Values *) self; - Py_VISIT(v->values); - Py_VISIT(v->meta); - return 0; + Values *v = (Values *)self; + Py_VISIT(v->values); + Py_VISIT(v->meta); + return 0; } static int Values_clear(PyObject *self) { - Values *v = (Values *) self; - Py_CLEAR(v->values); - Py_CLEAR(v->meta); - return 0; + Values *v = (Values *)self; + Py_CLEAR(v->values); + Py_CLEAR(v->meta); + return 0; } static void Values_dealloc(PyObject *self) { - Values_clear(self); - self->ob_type->tp_free(self); + Values_clear(self); + self->ob_type->tp_free(self); } static PyMemberDef Values_members[] = { - {"interval", T_DOUBLE, offsetof(Values, interval), 0, interval_doc}, - {"values", T_OBJECT_EX, offsetof(Values, values), 0, values_doc}, - {"meta", T_OBJECT_EX, offsetof(Values, meta), 0, meta_doc}, - {NULL} -}; + {"interval", T_DOUBLE, offsetof(Values, interval), 0, interval_doc}, + {"values", T_OBJECT_EX, offsetof(Values, values), 0, values_doc}, + {"meta", T_OBJECT_EX, offsetof(Values, meta), 0, meta_doc}, + {NULL}}; 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} -}; + {"dispatch", (PyCFunction)Values_dispatch, METH_VARARGS | METH_KEYWORDS, + dispatch_doc}, + {"write", (PyCFunction)Values_write, METH_VARARGS | METH_KEYWORDS, + write_doc}, + {NULL}}; PyTypeObject ValuesType = { - CPY_INIT_TYPE - "collectd.Values", /* tp_name */ - sizeof(Values), /* tp_basicsize */ - 0, /* Will be filled in later */ - Values_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - Values_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 | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ - Values_doc, /* tp_doc */ - Values_traverse, /* tp_traverse */ - Values_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Values_methods, /* tp_methods */ - Values_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - Values_init, /* tp_init */ - 0, /* tp_alloc */ - Values_new /* tp_new */ + CPY_INIT_TYPE "collectd.Values", /* tp_name */ + sizeof(Values), /* tp_basicsize */ + 0, /* Will be filled in later */ + Values_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + Values_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 | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + Values_doc, /* tp_doc */ + Values_traverse, /* tp_traverse */ + Values_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Values_methods, /* tp_methods */ + Values_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + Values_init, /* tp_init */ + 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 char notification_meta_doc[] = + "These are the meta data for the Notification object.\n" + "It has to be a dictionary of numbers, strings or bools. All keys must be\n" + "strings. int and long objects will be dispatched as signed integers " + "unless\n" + "they are between 2**63 and 2**64-1, which will result in an unsigned " + "integer.\n" + "One of these storage classes can be forced by using the classes\n" + "collectd.Signed and collectd.Unsigned. A meta object received by a\n" + "notification callback will always contain Signed or Unsigned objects."; + +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; - int severity = 0; - double time = 0; - char *message = NULL; - char *type = NULL, *plugin_instance = NULL, *type_instance = NULL, *plugin = NULL, *host = NULL; - static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance", - "plugin", "host", "time", "severity", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist, - NULL, &type, NULL, &message, NULL, &plugin_instance, NULL, &type_instance, - NULL, &plugin, NULL, &host, &time, &severity)) - return -1; - - if (type && plugin_get_ds(type) == NULL) { - PyErr_Format(PyExc_TypeError, "Dataset %s not found", type); - FreeAll(); - PyMem_Free(message); - return -1; - } - - sstrncpy(self->data.host, host ? host : "", sizeof(self->data.host)); - sstrncpy(self->data.plugin, plugin ? plugin : "", sizeof(self->data.plugin)); - sstrncpy(self->data.plugin_instance, plugin_instance ? plugin_instance : "", sizeof(self->data.plugin_instance)); - sstrncpy(self->data.type, type ? type : "", sizeof(self->data.type)); - sstrncpy(self->data.type_instance, type_instance ? type_instance : "", sizeof(self->data.type_instance)); - sstrncpy(self->message, message ? message : "", sizeof(self->message)); - self->data.time = time; - self->severity = severity; - - FreeAll(); - PyMem_Free(message); - return 0; + Notification *self = (Notification *)s; + int severity = 0; + double time = 0; + char *message = NULL; + PyObject *meta = NULL; + char *type = NULL, *plugin_instance = NULL, *type_instance = NULL, + *plugin = NULL, *host = NULL; + static char *kwlist[] = { + "type", "message", "plugin_instance", "type_instance", "plugin", + "host", "time", "severity", "meta", NULL}; + + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "|etetetetetetdiO", kwlist, NULL, &type, NULL, &message, + NULL, &plugin_instance, NULL, &type_instance, NULL, &plugin, NULL, + &host, &time, &severity, &meta)) + return -1; + + if (type && plugin_get_ds(type) == NULL) { + PyErr_Format(PyExc_TypeError, "Dataset %s not found", type); + FreeAll(); + PyMem_Free(message); + return -1; + } + + sstrncpy(self->data.host, host ? host : "", sizeof(self->data.host)); + sstrncpy(self->data.plugin, plugin ? plugin : "", sizeof(self->data.plugin)); + sstrncpy(self->data.plugin_instance, plugin_instance ? plugin_instance : "", + sizeof(self->data.plugin_instance)); + sstrncpy(self->data.type, type ? type : "", sizeof(self->data.type)); + sstrncpy(self->data.type_instance, type_instance ? type_instance : "", + sizeof(self->data.type_instance)); + sstrncpy(self->message, message ? message : "", sizeof(self->message)); + self->data.time = time; + self->severity = severity; + + FreeAll(); + PyMem_Free(message); + + if (meta == NULL) { + meta = PyDict_New(); + PyErr_Clear(); + } else { + Py_INCREF(meta); + } + + PyObject *tmp = self->meta; + self->meta = meta; + Py_XDECREF(tmp); + + 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; - char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL, *type_instance = NULL; - char *message = NULL; - - static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance", - "plugin", "host", "time", "severity", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist, - NULL, &type, NULL, &message, NULL, &plugin_instance, NULL, &type_instance, - NULL, &plugin, NULL, &host, &t, &severity)) - return NULL; - - notification.time = DOUBLE_TO_CDTIME_T(t); - notification.severity = severity; - sstrncpy(notification.message, message ? message : self->message, sizeof(notification.message)); - sstrncpy(notification.host, host ? host : self->data.host, sizeof(notification.host)); - sstrncpy(notification.plugin, plugin ? plugin : self->data.plugin, sizeof(notification.plugin)); - sstrncpy(notification.plugin_instance, plugin_instance ? plugin_instance : self->data.plugin_instance, sizeof(notification.plugin_instance)); - sstrncpy(notification.type, type ? type : self->data.type, sizeof(notification.type)); - sstrncpy(notification.type_instance, type_instance ? type_instance : self->data.type_instance, sizeof(notification.type_instance)); - notification.meta = NULL; - FreeAll(); - PyMem_Free(message); - - if (notification.type[0] == 0) { - PyErr_SetString(PyExc_RuntimeError, "type not set"); - return NULL; - } - ds = plugin_get_ds(notification.type); - if (ds == NULL) { - PyErr_Format(PyExc_TypeError, "Dataset %s not found", notification.type); - return NULL; - } - - if (notification.time == 0) - notification.time = cdtime(); - 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_dispatch(Notification *self, PyObject *args, + PyObject *kwds) { + int ret; + const data_set_t *ds; + notification_t notification; + double t = self->data.time; + PyObject *meta = self->meta; + int severity = self->severity; + char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL, + *type_instance = NULL; + char *message = NULL; + + static char *kwlist[] = { + "type", "message", "plugin_instance", "type_instance", "plugin", + "host", "time", "severity", "meta", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdiO", kwlist, NULL, + &type, NULL, &message, NULL, + &plugin_instance, NULL, &type_instance, NULL, + &plugin, NULL, &host, &t, &severity, &meta)) + return NULL; + + notification.time = DOUBLE_TO_CDTIME_T(t); + notification.severity = severity; + sstrncpy(notification.message, message ? message : self->message, + sizeof(notification.message)); + sstrncpy(notification.host, host ? host : self->data.host, + sizeof(notification.host)); + sstrncpy(notification.plugin, plugin ? plugin : self->data.plugin, + sizeof(notification.plugin)); + sstrncpy(notification.plugin_instance, + plugin_instance ? plugin_instance : self->data.plugin_instance, + sizeof(notification.plugin_instance)); + sstrncpy(notification.type, type ? type : self->data.type, + sizeof(notification.type)); + sstrncpy(notification.type_instance, + type_instance ? type_instance : self->data.type_instance, + sizeof(notification.type_instance)); + notification.meta = NULL; + FreeAll(); + PyMem_Free(message); + + if (notification.type[0] == 0) { + PyErr_SetString(PyExc_RuntimeError, "type not set"); + return NULL; + } + ds = plugin_get_ds(notification.type); + if (ds == NULL) { + PyErr_Format(PyExc_TypeError, "Dataset %s not found", notification.type); + return NULL; + } + if (meta != NULL && meta != Py_None && !PyDict_Check(meta)) { + PyErr_Format(PyExc_TypeError, "meta must be a dict"); + return NULL; + } + cpy_build_notification_meta(¬ification, meta); + + if (notification.time == 0) + notification.time = cdtime(); + 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); + if (notification.meta) + plugin_notification_meta_free(notification.meta); + 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; +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 = (Notification *)PluginData_new(type, args, kwds); + if (self == NULL) + return NULL; - self->message[0] = 0; - self->severity = 0; - return (PyObject *) self; + self->meta = PyDict_New(); + 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; - } - Py_INCREF(value); - new = cpy_unicode_or_bytes_to_string(&value); - if (new == NULL) { - Py_DECREF(value); - return -1; - } - old = ((char *) self) + (intptr_t) data; - sstrncpy(old, new, NOTIF_MAX_MSG_LEN); - Py_DECREF(value); - return 0; + char *old; + const char *new; + + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute"); + return -1; + } + Py_INCREF(value); + new = cpy_unicode_or_bytes_to_string(&value); + if (new == NULL) { + Py_DECREF(value); + return -1; + } + old = ((char *)self) + (intptr_t)data; + sstrncpy(old, new, NOTIF_MAX_MSG_LEN); + Py_DECREF(value); + return 0; } static PyObject *Notification_repr(PyObject *s) { - PyObject *ret, *tmp; - static PyObject *l_severity = NULL, *l_message = NULL, *l_closing = NULL; - Notification *self = (Notification *) s; - - if (l_severity == NULL) - l_severity = cpy_string_to_unicode_or_bytes(",severity="); - if (l_message == NULL) - l_message = cpy_string_to_unicode_or_bytes(",message="); - if (l_closing == NULL) - l_closing = cpy_string_to_unicode_or_bytes(")"); - - if (l_severity == NULL || l_message == NULL || l_closing == NULL) - return NULL; - - ret = cpy_common_repr(s); - if (self->severity != 0) { - CPY_STRCAT(&ret, l_severity); - tmp = PyInt_FromLong(self->severity); - CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); - CPY_STRCAT_AND_DEL(&ret, tmp); - } - if (self->message[0] != 0) { - CPY_STRCAT(&ret, l_message); - tmp = cpy_string_to_unicode_or_bytes(self->message); - CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); - CPY_STRCAT_AND_DEL(&ret, tmp); - } - CPY_STRCAT(&ret, l_closing); - return ret; + PyObject *ret, *tmp; + static PyObject *l_severity = NULL, *l_message = NULL, *l_meta = NULL, + *l_closing = NULL; + Notification *self = (Notification *)s; + + if (l_severity == NULL) + l_severity = cpy_string_to_unicode_or_bytes(",severity="); + if (l_message == NULL) + l_message = cpy_string_to_unicode_or_bytes(",message="); + if (l_meta == NULL) + l_meta = cpy_string_to_unicode_or_bytes(",meta="); + if (l_closing == NULL) + l_closing = cpy_string_to_unicode_or_bytes(")"); + + if (l_severity == NULL || l_message == NULL || l_meta == NULL || + l_closing == NULL) + return NULL; + + ret = cpy_common_repr(s); + if (self->severity != 0) { + CPY_STRCAT(&ret, l_severity); + tmp = PyInt_FromLong(self->severity); + CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); + CPY_STRCAT_AND_DEL(&ret, tmp); + } + if (self->message[0] != 0) { + CPY_STRCAT(&ret, l_message); + tmp = cpy_string_to_unicode_or_bytes(self->message); + CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); + CPY_STRCAT_AND_DEL(&ret, tmp); + } + if (self->meta && + (!PyDict_Check(self->meta) || PyDict_Size(self->meta) > 0)) { + CPY_STRCAT(&ret, l_meta); + tmp = PyObject_Repr(self->meta); + CPY_STRCAT_AND_DEL(&ret, tmp); + } + CPY_STRCAT(&ret, l_closing); + return ret; +} + +static int Notification_traverse(PyObject *self, visitproc visit, void *arg) { + Notification *n = (Notification *)self; + Py_VISIT(n->meta); + return 0; +} + +static int Notification_clear(PyObject *self) { + Notification *n = (Notification *)self; + Py_CLEAR(n->meta); + return 0; +} + +static void Notification_dealloc(PyObject *self) { + Notification_clear(self); + self->ob_type->tp_free(self); } static PyMethodDef Notification_methods[] = { - {"dispatch", (PyCFunction) Notification_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc}, - {NULL} -}; + {"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} -}; + {"severity", T_INT, offsetof(Notification, severity), 0, severity_doc}, + {"meta", T_OBJECT_EX, offsetof(Notification, meta), 0, + notification_meta_doc}, + {NULL}}; static PyGetSetDef Notification_getseters[] = { - {"message", PluginData_getstring, Notification_setstring, message_doc, (void *) offsetof(Notification, message)}, - {NULL} -}; + {"message", PluginData_getstring, Notification_setstring, message_doc, + (void *)offsetof(Notification, message)}, + {NULL}}; PyTypeObject NotificationType = { - CPY_INIT_TYPE - "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 */ + CPY_INIT_TYPE "collectd.Notification", /* tp_name */ + sizeof(Notification), /* tp_basicsize */ + 0, /* Will be filled in later */ + Notification_dealloc, /* 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 | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + Notification_doc, /* tp_doc */ + Notification_traverse, /* tp_traverse */ + Notification_clear, /* 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 */ }; -static char Signed_doc[] = "This is a long by another name. Use it in meta data dicts\n" - "to choose the way it is stored in the meta data."; +static char Signed_doc[] = + "This is a long by another name. Use it in meta data dicts\n" + "to choose the way it is stored in the meta data."; PyTypeObject SignedType = { - CPY_INIT_TYPE - "collectd.Signed", /* tp_name */ - sizeof(Signed), /* tp_basicsize */ - 0, /* Will be filled in later */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* 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*/ - Signed_doc /* tp_doc */ + CPY_INIT_TYPE "collectd.Signed", /* tp_name */ + sizeof(Signed), /* tp_basicsize */ + 0, /* Will be filled in later */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* 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 */ + Signed_doc /* tp_doc */ }; -static char Unsigned_doc[] = "This is a long by another name. Use it in meta data dicts\n" - "to choose the way it is stored in the meta data."; +static char Unsigned_doc[] = + "This is a long by another name. Use it in meta data dicts\n" + "to choose the way it is stored in the meta data."; PyTypeObject UnsignedType = { - CPY_INIT_TYPE - "collectd.Unsigned", /* tp_name */ - sizeof(Unsigned), /* tp_basicsize */ - 0, /* Will be filled in later */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* 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*/ - Unsigned_doc /* tp_doc */ + CPY_INIT_TYPE "collectd.Unsigned", /* tp_name */ + sizeof(Unsigned), /* tp_basicsize */ + 0, /* Will be filled in later */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* 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 */ + Unsigned_doc /* tp_doc */ };