From f7cf0dad2e933ac6066ca5f27645ee577f065710 Mon Sep 17 00:00:00 2001 From: Sven Trenkel Date: Fri, 29 Jan 2010 14:12:41 +0100 Subject: [PATCH] python: Full meta data support. --- src/cpython.h | 14 +++-- src/python.c | 12 +++- src/pyvalues.c | 147 +++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 155 insertions(+), 18 deletions(-) diff --git a/src/cpython.h b/src/cpython.h index df7fc6a4..b5a1754a 100644 --- a/src/cpython.h +++ b/src/cpython.h @@ -155,7 +155,9 @@ static inline PyObject *cpy_string_to_unicode_or_bytes(const char *buf) { #endif } - /* Python object declarations. */ +void cpy_log_exception(const char *context); + +/* Python object declarations. */ typedef struct { PyObject_HEAD /* No semicolon! */ @@ -164,7 +166,6 @@ typedef struct { PyObject *values; /* Sequence */ PyObject *children; /* Sequence */ } Config; - PyTypeObject ConfigType; typedef struct { @@ -176,7 +177,6 @@ typedef struct { char type[DATA_MAX_NAME_LEN]; char type_instance[DATA_MAX_NAME_LEN]; } PluginData; - PyTypeObject PluginDataType; typedef struct { @@ -185,7 +185,6 @@ typedef struct { PyObject *meta; /* dict */ int interval; } Values; - PyTypeObject ValuesType; typedef struct { @@ -193,5 +192,10 @@ typedef struct { int severity; char message[NOTIF_MAX_MSG_LEN]; } Notification; - PyTypeObject NotificationType; + +typedef PyLongObject Signed; +PyTypeObject SignedType; + +typedef PyLongObject Unsigned; +PyTypeObject UnsignedType; diff --git a/src/python.c b/src/python.c index a1e6a7e2..d193d2d1 100644 --- a/src/python.c +++ b/src/python.c @@ -259,7 +259,7 @@ static void cpy_build_name(char *buf, size_t size, PyObject *callback, const cha PyErr_Clear(); } -static void cpy_log_exception(const char *context) { +void cpy_log_exception(const char *context) { int l = 0, i; const char *typename = NULL, *message = NULL; PyObject *type, *value, *traceback, *tn, *m, *list; @@ -400,13 +400,13 @@ static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_li } else if (type == MD_TYPE_SIGNED_INT) { if (meta_data_get_signed_int(meta, table[i], &si)) continue; - temp = PyLong_FromLongLong(si); + temp = PyObject_CallFunctionObjArgs((void *) &SignedType, PyLong_FromLongLong(si), (void *) 0); PyDict_SetItemString(dict, table[i], temp); Py_XDECREF(temp); } else if (type == MD_TYPE_UNSIGNED_INT) { if (meta_data_get_unsigned_int(meta, table[i], &ui)) continue; - temp = PyLong_FromUnsignedLongLong(ui); + temp = PyObject_CallFunctionObjArgs((void *) &UnsignedType, PyLong_FromUnsignedLongLong(ui), (void *) 0); PyDict_SetItemString(dict, table[i], temp); Py_XDECREF(temp); } else if (type == MD_TYPE_DOUBLE) { @@ -990,6 +990,10 @@ static int cpy_config(oconfig_item_t *ci) { PyType_Ready(&ValuesType); NotificationType.tp_base = &PluginDataType; PyType_Ready(&NotificationType); + SignedType.tp_base = &PyLong_Type; + PyType_Ready(&SignedType); + UnsignedType.tp_base = &PyLong_Type; + PyType_Ready(&UnsignedType); sys = PyImport_ImportModule("sys"); /* New reference. */ if (sys == NULL) { cpy_log_exception("python initialization"); @@ -1009,6 +1013,8 @@ static int cpy_config(oconfig_item_t *ci) { PyModule_AddObject(module, "Config", (void *) &ConfigType); /* Steals a reference. */ PyModule_AddObject(module, "Values", (void *) &ValuesType); /* Steals a reference. */ PyModule_AddObject(module, "Notification", (void *) &NotificationType); /* Steals a reference. */ + PyModule_AddObject(module, "Signed", (void *) &SignedType); /* Steals a reference. */ + PyModule_AddObject(module, "Unsigned", (void *) &UnsignedType); /* Steals a reference. */ PyModule_AddIntConstant(module, "LOG_DEBUG", LOG_DEBUG); PyModule_AddIntConstant(module, "LOG_INFO", LOG_INFO); PyModule_AddIntConstant(module, "LOG_NOTICE", LOG_NOTICE); diff --git a/src/pyvalues.c b/src/pyvalues.c index ed0270f5..a928cbc2 100644 --- a/src/pyvalues.c +++ b/src/pyvalues.c @@ -393,13 +393,90 @@ static int Values_init(PyObject *s, PyObject *args, PyObject *kwds) { return 0; } +static meta_data_t *cpy_build_meta(PyObject *meta) { + int i, s; + meta_data_t *m = NULL; + PyObject *l; + + if (!meta) + return NULL; + + m = meta_data_create(); + l = PyDict_Items(meta); + s = PyList_Size(l); + 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(keystring); + } + return m; +} + static PyObject *Values_dispatch(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; + PyObject *values = self->values, *meta = self->meta; double time = self->data.time; int interval = self->interval; const char *host = self->data.host; @@ -409,10 +486,10 @@ static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) { const char *type_instance = self->data.type_instance; static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance", - "plugin", "host", "time", "interval", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdi", kwlist, + "plugin", "host", "time", "interval", "meta", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdiO", kwlist, NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance, - NULL, &plugin, NULL, &host, &time, &interval)) + NULL, &plugin, NULL, &host, &time, &interval, &meta)) return NULL; if (type[0] == 0) { @@ -428,6 +505,10 @@ static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) { 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 = (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); @@ -468,6 +549,7 @@ static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) { } } value_list.values = value; + value_list.meta = cpy_build_meta(meta); value_list.values_len = size; value_list.time = time; value_list.interval = interval; @@ -476,7 +558,6 @@ static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) { 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) @@ -498,7 +579,7 @@ static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) { int size; value_t *value; value_list_t value_list = VALUE_LIST_INIT; - PyObject *values = self->values; + PyObject *values = self->values, *meta = self->meta; double time = self->data.time; int interval = self->interval; const char *host = self->data.host; @@ -509,10 +590,10 @@ static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) { const char *dest = NULL; static char *kwlist[] = {"destination", "type", "values", "plugin_instance", "type_instance", - "plugin", "host", "time", "interval", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdi", kwlist, + "plugin", "host", "time", "interval", "meta", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdiO", kwlist, NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance, - NULL, &plugin, NULL, &host, &time, &interval)) + NULL, &plugin, NULL, &host, &time, &interval, &meta)) return NULL; if (type[0] == 0) { @@ -576,7 +657,7 @@ static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) { 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; + 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) @@ -919,3 +1000,49 @@ PyTypeObject NotificationType = { 0, /* tp_alloc */ Notification_new /* tp_new */ }; + +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*/ +}; + +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*/ +}; -- 2.30.2