#include "cpython.h"
+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(host); \
} while (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 \
+}
+
static PyObject *cpy_common_repr(PyObject *s) {
PyObject *ret, *tmp;
static PyObject *l_type = NULL, *l_type_instance = NULL, *l_plugin = NULL,
return 0;
}
-static meta_data_t *cpy_build_meta(PyObject *meta) {
+static int cpy_build_meta(PyObject *meta, cpy_build_meta_handler_t *meta_func,
+ void *m) {
int s;
- meta_data_t *m = NULL;
PyObject *l;
if ((meta == NULL) || (meta == Py_None))
- return NULL;
+ return -1;
l = PyDict_Items(meta); /* New reference. */
if (!l) {
cpy_log_exception("building meta data");
- return NULL;
+ return -1;
}
s = PyList_Size(l);
if (s <= 0) {
Py_XDECREF(l);
- return NULL;
+ return -1;
}
- m = meta_data_create();
for (int i = 0; i < s; ++i) {
const char *string, *keystring;
PyObject *key, *value, *item, *tmp;
value = PyTuple_GET_ITEM(item, 1);
Py_INCREF(value);
if (value == Py_True) {
- meta_data_add_boolean(m, keystring, 1);
+ meta_func->add_boolean(m, keystring, 1);
} else if (value == Py_False) {
- meta_data_add_boolean(m, keystring, 0);
+ meta_func->add_boolean(m, keystring, 0);
} else if (PyFloat_Check(value)) {
- meta_data_add_double(m, keystring, PyFloat_AsDouble(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_data_add_signed_int(m, keystring, 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_data_add_unsigned_int(m, keystring, 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_data_add_signed_int(m, keystring, lli);
+ meta_func->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);
+ meta_func->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);
+ 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_data_add_string(m, keystring, string);
+ meta_func->add_string(m, keystring, string);
Py_XDECREF(tmp);
}
}
Py_DECREF(key);
}
Py_XDECREF(l);
+ return 0;
+}
+
+CPY_BUILD_META_HANDLER(meta_data, meta_data_t);
+CPY_BUILD_META_HANDLER(plugin_notification_meta, notification_t);
+
+static meta_data_t *cpy_build_value_meta(PyObject *meta) {
+ meta_data_t *m = meta_data_create();
+ cpy_build_meta(meta, &cpy_meta_data, (void *)m);
return m;
}
+static void cpy_build_notification_meta(notification_t *n, PyObject *meta) {
+ cpy_build_meta(meta, &cpy_plugin_notification_meta, (void *)n);
+}
+
static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
int ret;
const data_set_t *ds;
}
}
value_list.values = value;
- value_list.meta = cpy_build_meta(meta);
+ value_list.meta = cpy_build_value_meta(meta);
value_list.values_len = size;
value_list.time = DOUBLE_TO_CDTIME_T(time);
value_list.interval = DOUBLE_TO_CDTIME_T(interval);
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);
+ value_list.meta = cpy_build_value_meta(meta);
if (value_list.host[0] == 0)
sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
if (value_list.plugin[0] == 0)
Values_new /* tp_new */
};
+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.";
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", NULL};
+ "time", "severity", "meta",
+ NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist, NULL,
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdiO", kwlist, NULL,
&type, NULL, &message, NULL,
&plugin_instance, NULL, &type_instance, NULL,
- &plugin, NULL, &host, &time, &severity))
+ &plugin, NULL, &host, &time, &severity, &meta))
return -1;
if (type && plugin_get_ds(type) == NULL) {
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;
}
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;
static char *kwlist[] = {"type", "message", "plugin_instance",
"type_instance", "plugin", "host",
- "time", "severity", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist, NULL,
+ "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))
+ &plugin, NULL, &host, &t, &severity, &meta))
return NULL;
notification.time = DOUBLE_TO_CDTIME_T(t);
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();
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,
if (self == NULL)
return NULL;
+ self->meta = PyDict_New();
self->message[0] = 0;
self->severity = 0;
return (PyObject *)self;
static PyObject *Notification_repr(PyObject *s) {
PyObject *ret, *tmp;
- static PyObject *l_severity = NULL, *l_message = NULL, *l_closing = NULL;
+ 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_closing == NULL)
+ if (l_severity == NULL || l_message == NULL || l_meta == NULL ||
+ l_closing == NULL)
return NULL;
ret = cpy_common_repr(s);
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},
static PyMemberDef Notification_members[] = {
{"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[] = {
CPY_INIT_TYPE "collectd.Notification", /* tp_name */
sizeof(Notification), /* tp_basicsize */
0, /* Will be filled in later */
- 0, /* tp_dealloc */
+ Notification_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
Notification_doc, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
+ Notification_traverse, /* tp_traverse */
+ Notification_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */