network: comment libgcrypt initalization process
[collectd.git] / src / pyvalues.c
1 /**
2  * collectd - src/pyvalues.c
3  * Copyright (C) 2009  Sven Trenkel
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *   Sven Trenkel <collectd at semidefinite.de>  
25  **/
26
27 #include <Python.h>
28 #include <structmember.h>
29
30 #include "collectd.h"
31 #include "common.h"
32
33 #include "cpython.h"
34
35 #define FreeAll() do {\
36         PyMem_Free(type);\
37         PyMem_Free(plugin_instance);\
38         PyMem_Free(type_instance);\
39         PyMem_Free(plugin);\
40         PyMem_Free(host);\
41 } while(0)
42
43 static PyObject *cpy_common_repr(PyObject *s) {
44         PyObject *ret, *tmp;
45         static PyObject *l_type = NULL, *l_type_instance = NULL, *l_plugin = NULL, *l_plugin_instance = NULL;
46         static PyObject *l_host = NULL, *l_time = NULL;
47         PluginData *self = (PluginData *) s;
48         
49         if (l_type == NULL)
50                 l_type = cpy_string_to_unicode_or_bytes("(type=");
51         if (l_type_instance == NULL)
52                 l_type_instance = cpy_string_to_unicode_or_bytes(",type_instance=");
53         if (l_plugin == NULL)
54                 l_plugin = cpy_string_to_unicode_or_bytes(",plugin=");
55         if (l_plugin_instance == NULL)
56                 l_plugin_instance = cpy_string_to_unicode_or_bytes(",plugin_instance=");
57         if (l_host == NULL)
58                 l_host = cpy_string_to_unicode_or_bytes(",host=");
59         if (l_time == NULL)
60                 l_time = cpy_string_to_unicode_or_bytes(",time=");
61         
62         if (!l_type || !l_type_instance || !l_plugin || !l_plugin_instance || !l_host || !l_time)
63                 return NULL;
64         
65         ret = cpy_string_to_unicode_or_bytes(s->ob_type->tp_name);
66
67         CPY_STRCAT(&ret, l_type);
68         tmp = cpy_string_to_unicode_or_bytes(self->type);
69         CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
70         CPY_STRCAT_AND_DEL(&ret, tmp);
71
72         if (self->type_instance[0] != 0) {
73                 CPY_STRCAT(&ret, l_type_instance);
74                 tmp = cpy_string_to_unicode_or_bytes(self->type_instance);
75                 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
76                 CPY_STRCAT_AND_DEL(&ret, tmp);
77         }
78
79         if (self->plugin[0] != 0) {
80                 CPY_STRCAT(&ret, l_plugin);
81                 tmp = cpy_string_to_unicode_or_bytes(self->plugin);
82                 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
83                 CPY_STRCAT_AND_DEL(&ret, tmp);
84         }
85
86         if (self->plugin_instance[0] != 0) {
87                 CPY_STRCAT(&ret, l_plugin_instance);
88                 tmp = cpy_string_to_unicode_or_bytes(self->plugin_instance);
89                 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
90                 CPY_STRCAT_AND_DEL(&ret, tmp);
91         }
92
93         if (self->host[0] != 0) {
94                 CPY_STRCAT(&ret, l_host);
95                 tmp = cpy_string_to_unicode_or_bytes(self->host);
96                 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
97                 CPY_STRCAT_AND_DEL(&ret, tmp);
98         }
99
100         if (self->time != 0) {
101                 CPY_STRCAT(&ret, l_time);
102                 tmp = PyInt_FromLong(self->time);
103                 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
104                 CPY_STRCAT_AND_DEL(&ret, tmp);
105         }
106         return ret;
107 }
108
109 static char time_doc[] = "This is the Unix timestap of the time this value was read.\n"
110                 "For dispatching values this can be set to 0 which means \"now\".\n"
111                 "This means the time the value is actually dispatched, not the time\n"
112                 "it was set to 0.";
113
114 static char host_doc[] = "The hostname of the host this value was read from.\n"
115                 "For dispatching this can be set to an empty string which means\n"
116                 "the local hostname as defined in the collectd.conf.";
117
118 static char type_doc[] = "The type of this value. This type has to be defined\n"
119                 "in your types.db. Attempting to set it to any other value will\n"
120                 "raise a TypeError exception.\n"
121                 "Assigning a type is mandetory, calling dispatch without doing\n"
122                 "so will raise a RuntimeError exception.";
123
124 static char type_instance_doc[] = "";
125
126 static char plugin_doc[] = "The name of the plugin that read the data. Setting this\n"
127                 "member to an empty string will insert \"python\" upon dispatching.";
128
129 static char plugin_instance_doc[] = "";
130
131 static char PluginData_doc[] = "This is an internal class that is the base for Values\n"
132                 "and Notification. It is pretty useless by itself and was therefore not\n"
133                 "exported to the collectd module.";
134
135 static PyObject *PluginData_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
136         PluginData *self;
137         
138         self = (PluginData *) type->tp_alloc(type, 0);
139         if (self == NULL)
140                 return NULL;
141         
142         self->time = 0;
143         self->host[0] = 0;
144         self->plugin[0] = 0;
145         self->plugin_instance[0] = 0;
146         self->type[0] = 0;
147         self->type_instance[0] = 0;
148         return (PyObject *) self;
149 }
150
151 static int PluginData_init(PyObject *s, PyObject *args, PyObject *kwds) {
152         PluginData *self = (PluginData *) s;
153         double time = 0;
154         char *type = NULL, *plugin_instance = NULL, *type_instance = NULL, *plugin = NULL, *host = NULL;
155         static char *kwlist[] = {"type", "plugin_instance", "type_instance",
156                         "plugin", "host", "time", NULL};
157         
158         if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetd", kwlist, NULL, &type,
159                         NULL, &plugin_instance, NULL, &type_instance, NULL, &plugin, NULL, &host, &time))
160                 return -1;
161         
162         if (type && plugin_get_ds(type) == NULL) {
163                 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
164                 FreeAll();
165                 return -1;
166         }
167
168         sstrncpy(self->host, host ? host : "", sizeof(self->host));
169         sstrncpy(self->plugin, plugin ? plugin : "", sizeof(self->plugin));
170         sstrncpy(self->plugin_instance, plugin_instance ? plugin_instance : "", sizeof(self->plugin_instance));
171         sstrncpy(self->type, type ? type : "", sizeof(self->type));
172         sstrncpy(self->type_instance, type_instance ? type_instance : "", sizeof(self->type_instance));
173         self->time = time;
174
175         FreeAll();
176
177         return 0;
178 }
179
180 static PyObject *PluginData_repr(PyObject *s) {
181         PyObject *ret;
182         static PyObject *l_closing = NULL;
183         
184         if (l_closing == NULL)
185                 l_closing = cpy_string_to_unicode_or_bytes(")");
186         
187         if (l_closing == NULL)
188                 return NULL;
189         
190         ret = cpy_common_repr(s);
191         CPY_STRCAT(&ret, l_closing);
192         return ret;
193 }
194
195 static PyMemberDef PluginData_members[] = {
196         {"time", T_DOUBLE, offsetof(PluginData, time), 0, time_doc},
197         {NULL}
198 };
199
200 static PyObject *PluginData_getstring(PyObject *self, void *data) {
201         const char *value = ((char *) self) + (intptr_t) data;
202         
203         return cpy_string_to_unicode_or_bytes(value);
204 }
205
206 static int PluginData_setstring(PyObject *self, PyObject *value, void *data) {
207         char *old;
208         const char *new;
209         
210         if (value == NULL) {
211                 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
212                 return -1;
213         }
214         Py_INCREF(value);
215         new = cpy_unicode_or_bytes_to_string(&value);
216         if (new == NULL) {
217                 Py_DECREF(value);
218                 return -1;
219         }
220         old = ((char *) self) + (intptr_t) data;
221         sstrncpy(old, new, DATA_MAX_NAME_LEN);
222         Py_DECREF(value);
223         return 0;
224 }
225
226 static int PluginData_settype(PyObject *self, PyObject *value, void *data) {
227         char *old;
228         const char *new;
229         
230         if (value == NULL) {
231                 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
232                 return -1;
233         }
234         Py_INCREF(value);
235         new = cpy_unicode_or_bytes_to_string(&value);
236         if (new == NULL) {
237                 Py_DECREF(value);
238                 return -1;
239         }
240
241         if (plugin_get_ds(new) == NULL) {
242                 PyErr_Format(PyExc_TypeError, "Dataset %s not found", new);
243                 Py_DECREF(value);
244                 return -1;
245         }
246
247         old = ((char *) self) + (intptr_t) data;
248         sstrncpy(old, new, DATA_MAX_NAME_LEN);
249         Py_DECREF(value);
250         return 0;
251 }
252
253 static PyGetSetDef PluginData_getseters[] = {
254         {"host", PluginData_getstring, PluginData_setstring, host_doc, (void *) offsetof(PluginData, host)},
255         {"plugin", PluginData_getstring, PluginData_setstring, plugin_doc, (void *) offsetof(PluginData, plugin)},
256         {"plugin_instance", PluginData_getstring, PluginData_setstring, plugin_instance_doc, (void *) offsetof(PluginData, plugin_instance)},
257         {"type_instance", PluginData_getstring, PluginData_setstring, type_instance_doc, (void *) offsetof(PluginData, type_instance)},
258         {"type", PluginData_getstring, PluginData_settype, type_doc, (void *) offsetof(PluginData, type)},
259         {NULL}
260 };
261
262 PyTypeObject PluginDataType = {
263         CPY_INIT_TYPE
264         "collectd.PluginData",     /* tp_name */
265         sizeof(PluginData),        /* tp_basicsize */
266         0,                         /* Will be filled in later */
267         0,                         /* tp_dealloc */
268         0,                         /* tp_print */
269         0,                         /* tp_getattr */
270         0,                         /* tp_setattr */
271         0,                         /* tp_compare */
272         PluginData_repr,           /* tp_repr */
273         0,                         /* tp_as_number */
274         0,                         /* tp_as_sequence */
275         0,                         /* tp_as_mapping */
276         0,                         /* tp_hash */
277         0,                         /* tp_call */
278         0,                         /* tp_str */
279         0,                         /* tp_getattro */
280         0,                         /* tp_setattro */
281         0,                         /* tp_as_buffer */
282         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE /*| Py_TPFLAGS_HAVE_GC*/, /*tp_flags*/
283         PluginData_doc,            /* tp_doc */
284         0,                         /* tp_traverse */
285         0,                         /* tp_clear */
286         0,                         /* tp_richcompare */
287         0,                         /* tp_weaklistoffset */
288         0,                         /* tp_iter */
289         0,                         /* tp_iternext */
290         0,                         /* tp_methods */
291         PluginData_members,        /* tp_members */
292         PluginData_getseters,      /* tp_getset */
293         0,                         /* tp_base */
294         0,                         /* tp_dict */
295         0,                         /* tp_descr_get */
296         0,                         /* tp_descr_set */
297         0,                         /* tp_dictoffset */
298         PluginData_init,           /* tp_init */
299         0,                         /* tp_alloc */
300         PluginData_new             /* tp_new */
301 };
302
303 static char interval_doc[] = "The interval is the timespan in seconds between two submits for\n"
304                 "the same data source. This value has to be a positive integer, so you can't\n"
305                 "submit more than one value per second. If this member is set to a\n"
306                 "non-positive value, the default value as specified in the config file will\n"
307                 "be used (default: 10).\n"
308                 "\n"
309                 "If you submit values more often than the specified interval, the average\n"
310                 "will be used. If you submit less values, your graphs will have gaps.";
311
312 static char values_doc[] = "These are the actual values that get dispatched to collectd.\n"
313                 "It has to be a sequence (a tuple or list) of numbers.\n"
314                 "The size of the sequence and the type of its content depend on the type\n"
315                 "member your types.db file. For more information on this read the types.db\n"
316                 "man page.\n"
317                 "\n"
318                 "If the sequence does not have the correct size upon dispatch a RuntimeError\n"
319                 "exception will be raised. If the content of the sequence is not a number,\n"
320                 "a TypeError exception will be raised.";
321
322 static char meta_doc[] = "These are the meta data for this Value object.\n"
323                 "It has to be a dictionary of numbers, strings or bools. All keys must be\n"
324                 "strings. int and long objects will be dispatched as signed integers unless\n"
325                 "they are between 2**63 and 2**64-1, which will result in a unsigned integer.\n"
326                 "You can force one of these storage classes by using the classes\n"
327                 "collectd.Signed and collectd.Unsigned. A meta object received by a write\n"
328                 "callback will always contain Signed or Unsigned objects.";
329
330 static char dispatch_doc[] = "dispatch([type][, values][, plugin_instance][, type_instance]"
331                 "[, plugin][, host][, time][, interval]) -> None.  Dispatch a value list.\n"
332                 "\n"
333                 "Dispatch this instance to the collectd process. The object has members\n"
334                 "for each of the possible arguments for this method. For a detailed explanation\n"
335                 "of these parameters see the member of the same same.\n"
336                 "\n"
337                 "If you do not submit a parameter the value saved in its member will be submitted.\n"
338                 "If you do provide a parameter it will be used instead, without altering the member.";
339
340 static char write_doc[] = "write([destination][, type][, values][, plugin_instance][, type_instance]"
341                 "[, plugin][, host][, time][, interval]) -> None.  Dispatch a value list.\n"
342                 "\n"
343                 "Write this instance to a single plugin or all plugins if 'destination' is obmitted.\n"
344                 "This will bypass the main collectd process and all filtering and caching.\n"
345                 "Other than that it works similar to 'dispatch'. In most cases 'dispatch' should be\n"
346                 "used instead of 'write'.\n";
347
348 static char Values_doc[] = "A Values object used for dispatching values to collectd and receiving values from write callbacks.";
349
350 static PyObject *Values_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
351         Values *self;
352         
353         self = (Values *) PluginData_new(type, args, kwds);
354         if (self == NULL)
355                 return NULL;
356         
357         self->values = PyList_New(0);
358         self->meta = PyDict_New();
359         self->interval = 0;
360         return (PyObject *) self;
361 }
362
363 static int Values_init(PyObject *s, PyObject *args, PyObject *kwds) {
364         Values *self = (Values *) s;
365         int interval = 0;
366         double time = 0;
367         PyObject *values = NULL, *meta = NULL, *tmp;
368         char *type = NULL, *plugin_instance = NULL, *type_instance = NULL, *plugin = NULL, *host = NULL;
369         static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
370                         "plugin", "host", "time", "interval", "meta", NULL};
371         
372         if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdiO", kwlist,
373                         NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
374                         NULL, &plugin, NULL, &host, &time, &interval, &meta))
375                 return -1;
376         
377         if (type && plugin_get_ds(type) == NULL) {
378                 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
379                 FreeAll();
380                 return -1;
381         }
382
383         sstrncpy(self->data.host, host ? host : "", sizeof(self->data.host));
384         sstrncpy(self->data.plugin, plugin ? plugin : "", sizeof(self->data.plugin));
385         sstrncpy(self->data.plugin_instance, plugin_instance ? plugin_instance : "", sizeof(self->data.plugin_instance));
386         sstrncpy(self->data.type, type ? type : "", sizeof(self->data.type));
387         sstrncpy(self->data.type_instance, type_instance ? type_instance : "", sizeof(self->data.type_instance));
388         self->data.time = time;
389
390         FreeAll();
391
392         if (values == NULL) {
393                 values = PyList_New(0);
394                 PyErr_Clear();
395         } else {
396                 Py_INCREF(values);
397         }
398         
399         if (meta == NULL) {
400                 meta = PyDict_New();
401                 PyErr_Clear();
402         } else {
403                 Py_INCREF(meta);
404         }
405         
406         tmp = self->values;
407         self->values = values;
408         Py_XDECREF(tmp);
409         
410         tmp = self->meta;
411         self->meta = meta;
412         Py_XDECREF(tmp);
413
414         self->interval = interval;
415         return 0;
416 }
417
418 static meta_data_t *cpy_build_meta(PyObject *meta) {
419         int i, s;
420         meta_data_t *m = NULL;
421         PyObject *l;
422         
423         if (!meta)
424                 return NULL;
425
426         l = PyDict_Items(meta); /* New reference. */
427         if (!l) {
428                 cpy_log_exception("building meta data");
429                 return NULL;
430         }
431         m = meta_data_create();
432         s = PyList_Size(l);
433         for (i = 0; i < s; ++i) {
434                 const char *string, *keystring;
435                 PyObject *key, *value, *item, *tmp;
436                 
437                 item = PyList_GET_ITEM(l, i);
438                 key = PyTuple_GET_ITEM(item, 0);
439                 Py_INCREF(key);
440                 keystring = cpy_unicode_or_bytes_to_string(&key);
441                 if (!keystring) {
442                         PyErr_Clear();
443                         Py_XDECREF(key);
444                         continue;
445                 }
446                 value = PyTuple_GET_ITEM(item, 1);
447                 Py_INCREF(value);
448                 if (value == Py_True) {
449                         meta_data_add_boolean(m, keystring, 1);
450                 } else if (value == Py_False) {
451                         meta_data_add_boolean(m, keystring, 0);
452                 } else if (PyFloat_Check(value)) {
453                         meta_data_add_double(m, keystring, PyFloat_AsDouble(value));
454                 } else if (PyObject_TypeCheck(value, &SignedType)) {
455                         long long int lli;
456                         lli = PyLong_AsLongLong(value);
457                         if (!PyErr_Occurred() && (lli == (int64_t) lli))
458                                 meta_data_add_signed_int(m, keystring, lli);
459                 } else if (PyObject_TypeCheck(value, &UnsignedType)) {
460                         long long unsigned llu;
461                         llu = PyLong_AsUnsignedLongLong(value);
462                         if (!PyErr_Occurred() && (llu == (uint64_t) llu))
463                                 meta_data_add_unsigned_int(m, keystring, llu);
464                 } else if (PyNumber_Check(value)) {
465                         long long int lli;
466                         long long unsigned llu;
467                         tmp = PyNumber_Long(value);
468                         lli = PyLong_AsLongLong(tmp);
469                         if (!PyErr_Occurred() && (lli == (int64_t) lli)) {
470                                 meta_data_add_signed_int(m, keystring, lli);
471                         } else {
472                                 PyErr_Clear();
473                                 llu = PyLong_AsUnsignedLongLong(tmp);
474                                 if (!PyErr_Occurred() && (llu == (uint64_t) llu))
475                                         meta_data_add_unsigned_int(m, keystring, llu);
476                         }
477                         Py_XDECREF(tmp);
478                 } else {
479                         string = cpy_unicode_or_bytes_to_string(&value);
480                         if (string) {
481                                 meta_data_add_string(m, keystring, string);
482                         } else {
483                                 PyErr_Clear();
484                                 tmp = PyObject_Str(value);
485                                 string = cpy_unicode_or_bytes_to_string(&tmp);
486                                 if (string)
487                                         meta_data_add_string(m, keystring, string);
488                                 Py_XDECREF(tmp);
489                         }
490                 }
491                 if (PyErr_Occurred())
492                         cpy_log_exception("building meta data");
493                 Py_XDECREF(value);
494                 Py_DECREF(key);
495         }
496         Py_XDECREF(l);
497         return m;
498 }
499
500 static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
501         int i, ret;
502         const data_set_t *ds;
503         int size;
504         value_t *value;
505         value_list_t value_list = VALUE_LIST_INIT;
506         PyObject *values = self->values, *meta = self->meta;
507         double time = self->data.time;
508         int interval = self->interval;
509         char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL, *type_instance = NULL;
510         
511         static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
512                         "plugin", "host", "time", "interval", "meta", NULL};
513         if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdiO", kwlist,
514                         NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
515                         NULL, &plugin, NULL, &host, &time, &interval, &meta))
516                 return NULL;
517
518         sstrncpy(value_list.host, host ? host : self->data.host, sizeof(value_list.host));
519         sstrncpy(value_list.plugin, plugin ? plugin : self->data.plugin, sizeof(value_list.plugin));
520         sstrncpy(value_list.plugin_instance, plugin_instance ? plugin_instance : self->data.plugin_instance, sizeof(value_list.plugin_instance));
521         sstrncpy(value_list.type, type ? type : self->data.type, sizeof(value_list.type));
522         sstrncpy(value_list.type_instance, type_instance ? type_instance : self->data.type_instance, sizeof(value_list.type_instance));
523         FreeAll();
524         if (value_list.type[0] == 0) {
525                 PyErr_SetString(PyExc_RuntimeError, "type not set");
526                 FreeAll();
527                 return NULL;
528         }
529         ds = plugin_get_ds(value_list.type);
530         if (ds == NULL) {
531                 PyErr_Format(PyExc_TypeError, "Dataset %s not found", value_list.type);
532                 return NULL;
533         }
534         if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
535                 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
536                 return NULL;
537         }
538         if (meta != NULL && meta != Py_None && !PyDict_Check(meta)) {
539                 PyErr_Format(PyExc_TypeError, "meta must be a dict");
540                 return NULL;
541         }
542         size = (int) PySequence_Length(values);
543         if (size != ds->ds_num) {
544                 PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %i", value_list.type, ds->ds_num, size);
545                 return NULL;
546         }
547         value = malloc(size * sizeof(*value));
548         for (i = 0; i < size; ++i) {
549                 PyObject *item, *num;
550                 item = PySequence_Fast_GET_ITEM(values, i); /* Borrowed reference. */
551                 if (ds->ds->type == DS_TYPE_COUNTER) {
552                         num = PyNumber_Long(item); /* New reference. */
553                         if (num != NULL) {
554                                 value[i].counter = PyLong_AsUnsignedLongLong(num);
555                                 Py_XDECREF(num);
556                         }
557                 } else if (ds->ds->type == DS_TYPE_GAUGE) {
558                         num = PyNumber_Float(item); /* New reference. */
559                         if (num != NULL) {
560                                 value[i].gauge = PyFloat_AsDouble(num);
561                                 Py_XDECREF(num);
562                         }
563                 } else if (ds->ds->type == DS_TYPE_DERIVE) {
564                         /* This might overflow without raising an exception.
565                          * Not much we can do about it */
566                         num = PyNumber_Long(item); /* New reference. */
567                         if (num != NULL) {
568                                 value[i].derive = PyLong_AsLongLong(num);
569                                 Py_XDECREF(num);
570                         }
571                 } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
572                         /* This might overflow without raising an exception.
573                          * Not much we can do about it */
574                         num = PyNumber_Long(item); /* New reference. */
575                         if (num != NULL) {
576                                 value[i].absolute = PyLong_AsUnsignedLongLong(num);
577                                 Py_XDECREF(num);
578                         }
579                 } else {
580                         free(value);
581                         PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds->type, value_list.type);
582                         return NULL;
583                 }
584                 if (PyErr_Occurred() != NULL) {
585                         free(value);
586                         return NULL;
587                 }
588         }
589         value_list.values = value;
590         value_list.meta = cpy_build_meta(meta);
591         value_list.values_len = size;
592         value_list.time = time;
593         value_list.interval = interval;
594         if (value_list.host[0] == 0)
595                 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
596         if (value_list.plugin[0] == 0)
597                 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
598         Py_BEGIN_ALLOW_THREADS;
599         ret = plugin_dispatch_values(&value_list);
600         Py_END_ALLOW_THREADS;
601         meta_data_destroy(value_list.meta);
602         free(value);
603         if (ret != 0) {
604                 PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
605                 return NULL;
606         }
607         Py_RETURN_NONE;
608 }
609
610 static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
611         int i, ret;
612         const data_set_t *ds;
613         int size;
614         value_t *value;
615         value_list_t value_list = VALUE_LIST_INIT;
616         PyObject *values = self->values, *meta = self->meta;
617         double time = self->data.time;
618         int interval = self->interval;
619         char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL, *type_instance = NULL, *dest = NULL;
620         
621         static char *kwlist[] = {"destination", "type", "values", "plugin_instance", "type_instance",
622                         "plugin", "host", "time", "interval", "meta", NULL};
623         if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|etOetetetetdiO", kwlist, NULL, &dest,
624                         NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
625                         NULL, &plugin, NULL, &host, &time, &interval, &meta))
626                 return NULL;
627
628         sstrncpy(value_list.host, host ? host : self->data.host, sizeof(value_list.host));
629         sstrncpy(value_list.plugin, plugin ? plugin : self->data.plugin, sizeof(value_list.plugin));
630         sstrncpy(value_list.plugin_instance, plugin_instance ? plugin_instance : self->data.plugin_instance, sizeof(value_list.plugin_instance));
631         sstrncpy(value_list.type, type ? type : self->data.type, sizeof(value_list.type));
632         sstrncpy(value_list.type_instance, type_instance ? type_instance : self->data.type_instance, sizeof(value_list.type_instance));
633         FreeAll();
634         if (value_list.type[0] == 0) {
635                 PyErr_SetString(PyExc_RuntimeError, "type not set");
636                 return NULL;
637         }
638         ds = plugin_get_ds(value_list.type);
639         if (ds == NULL) {
640                 PyErr_Format(PyExc_TypeError, "Dataset %s not found", value_list.type);
641                 return NULL;
642         }
643         if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
644                 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
645                 return NULL;
646         }
647         size = (int) PySequence_Length(values);
648         if (size != ds->ds_num) {
649                 PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %i", value_list.type, ds->ds_num, size);
650                 return NULL;
651         }
652         value = malloc(size * sizeof(*value));
653         for (i = 0; i < size; ++i) {
654                 PyObject *item, *num;
655                 item = PySequence_Fast_GET_ITEM(values, i); /* Borrowed reference. */
656                 if (ds->ds->type == DS_TYPE_COUNTER) {
657                         num = PyNumber_Long(item); /* New reference. */
658                         if (num != NULL) {
659                                 value[i].counter = PyLong_AsUnsignedLongLong(num);
660                                 Py_XDECREF(num);
661                         }
662                 } else if (ds->ds->type == DS_TYPE_GAUGE) {
663                         num = PyNumber_Float(item); /* New reference. */
664                         if (num != NULL) {
665                                 value[i].gauge = PyFloat_AsDouble(num);
666                                 Py_XDECREF(num);
667                         }
668                 } else if (ds->ds->type == DS_TYPE_DERIVE) {
669                         /* This might overflow without raising an exception.
670                          * Not much we can do about it */
671                         num = PyNumber_Long(item); /* New reference. */
672                         if (num != NULL) {
673                                 value[i].derive = PyLong_AsLongLong(num);
674                                 Py_XDECREF(num);
675                         }
676                 } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
677                         /* This might overflow without raising an exception.
678                          * Not much we can do about it */
679                         num = PyNumber_Long(item); /* New reference. */
680                         if (num != NULL) {
681                                 value[i].absolute = PyLong_AsUnsignedLongLong(num);
682                                 Py_XDECREF(num);
683                         }
684                 } else {
685                         free(value);
686                         PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds->type, value_list.type);
687                         return NULL;
688                 }
689                 if (PyErr_Occurred() != NULL) {
690                         free(value);
691                         return NULL;
692                 }
693         }
694         value_list.values = value;
695         value_list.values_len = size;
696         value_list.time = time;
697         value_list.interval = interval;
698         value_list.meta = cpy_build_meta(meta);;
699         if (value_list.host[0] == 0)
700                 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
701         if (value_list.plugin[0] == 0)
702                 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
703         Py_BEGIN_ALLOW_THREADS;
704         ret = plugin_write(dest, NULL, &value_list);
705         Py_END_ALLOW_THREADS;
706         meta_data_destroy(value_list.meta);
707         free(value);
708         if (ret != 0) {
709                 PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
710                 return NULL;
711         }
712         Py_RETURN_NONE;
713 }
714
715 static PyObject *Values_repr(PyObject *s) {
716         PyObject *ret, *tmp;
717         static PyObject *l_interval = NULL, *l_values = NULL, *l_meta = NULL, *l_closing = NULL;
718         Values *self = (Values *) s;
719         
720         if (l_interval == NULL)
721                 l_interval = cpy_string_to_unicode_or_bytes(",interval=");
722         if (l_values == NULL)
723                 l_values = cpy_string_to_unicode_or_bytes(",values=");
724         if (l_meta == NULL)
725                 l_meta = cpy_string_to_unicode_or_bytes(",meta=");
726         if (l_closing == NULL)
727                 l_closing = cpy_string_to_unicode_or_bytes(")");
728         
729         if (l_interval == NULL || l_values == NULL || l_meta == NULL || l_closing == NULL)
730                 return NULL;
731         
732         ret = cpy_common_repr(s);
733         if (self->interval != 0) {
734                 CPY_STRCAT(&ret, l_interval);
735                 tmp = PyInt_FromLong(self->interval);
736                 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
737                 CPY_STRCAT_AND_DEL(&ret, tmp);
738         }
739         if (self->values && (!PyList_Check(self->values) || PySequence_Length(self->values) > 0)) {
740                 CPY_STRCAT(&ret, l_values);
741                 tmp = PyObject_Repr(self->values);
742                 CPY_STRCAT_AND_DEL(&ret, tmp);
743         }
744         if (self->meta && (!PyDict_Check(self->meta) || PyDict_Size(self->meta) > 0)) {
745                 CPY_STRCAT(&ret, l_meta);
746                 tmp = PyObject_Repr(self->meta);
747                 CPY_STRCAT_AND_DEL(&ret, tmp);
748         }
749         CPY_STRCAT(&ret, l_closing);
750         return ret;
751 }
752
753 static int Values_traverse(PyObject *self, visitproc visit, void *arg) {
754         Values *v = (Values *) self;
755         Py_VISIT(v->values);
756         Py_VISIT(v->meta);
757         return 0;
758 }
759
760 static int Values_clear(PyObject *self) {
761         Values *v = (Values *) self;
762         Py_CLEAR(v->values);
763         Py_CLEAR(v->meta);
764         return 0;
765 }
766
767 static void Values_dealloc(PyObject *self) {
768         Values_clear(self);
769         self->ob_type->tp_free(self);
770 }
771
772 static PyMemberDef Values_members[] = {
773         {"interval", T_INT, offsetof(Values, interval), 0, interval_doc},
774         {"values", T_OBJECT_EX, offsetof(Values, values), 0, values_doc},
775         {"meta", T_OBJECT_EX, offsetof(Values, meta), 0, meta_doc},
776         {NULL}
777 };
778
779 static PyMethodDef Values_methods[] = {
780         {"dispatch", (PyCFunction) Values_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
781         {"write", (PyCFunction) Values_write, METH_VARARGS | METH_KEYWORDS, write_doc},
782         {NULL}
783 };
784
785 PyTypeObject ValuesType = {
786         CPY_INIT_TYPE
787         "collectd.Values",         /* tp_name */
788         sizeof(Values),            /* tp_basicsize */
789         0,                         /* Will be filled in later */
790         Values_dealloc,            /* tp_dealloc */
791         0,                         /* tp_print */
792         0,                         /* tp_getattr */
793         0,                         /* tp_setattr */
794         0,                         /* tp_compare */
795         Values_repr,               /* tp_repr */
796         0,                         /* tp_as_number */
797         0,                         /* tp_as_sequence */
798         0,                         /* tp_as_mapping */
799         0,                         /* tp_hash */
800         0,                         /* tp_call */
801         0,                         /* tp_str */
802         0,                         /* tp_getattro */
803         0,                         /* tp_setattro */
804         0,                         /* tp_as_buffer */
805         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
806         Values_doc,                /* tp_doc */
807         Values_traverse,           /* tp_traverse */
808         Values_clear,              /* tp_clear */
809         0,                         /* tp_richcompare */
810         0,                         /* tp_weaklistoffset */
811         0,                         /* tp_iter */
812         0,                         /* tp_iternext */
813         Values_methods,            /* tp_methods */
814         Values_members,            /* tp_members */
815         0,                         /* tp_getset */
816         0,                         /* tp_base */
817         0,                         /* tp_dict */
818         0,                         /* tp_descr_get */
819         0,                         /* tp_descr_set */
820         0,                         /* tp_dictoffset */
821         Values_init,               /* tp_init */
822         0,                         /* tp_alloc */
823         Values_new                 /* tp_new */
824 };
825
826 static char severity_doc[] = "The severity of this notification. Assign or compare to\n"
827                 "NOTIF_FAILURE, NOTIF_WARNING or NOTIF_OKAY.";
828
829 static char message_doc[] = "Some kind of description what's going on and why this Notification was generated.";
830
831 static char Notification_doc[] = "The Notification class is a wrapper around the collectd notification.\n"
832                 "It can be used to notify other plugins about bad stuff happening. It works\n"
833                 "similar to Values but has a severity and a message instead of interval\n"
834                 "and time.\n"
835                 "Notifications can be dispatched at any time and can be received with register_notification.";
836
837 static int Notification_init(PyObject *s, PyObject *args, PyObject *kwds) {
838         Notification *self = (Notification *) s;
839         int severity = 0;
840         double time = 0;
841         char *message = NULL;
842         char *type = NULL, *plugin_instance = NULL, *type_instance = NULL, *plugin = NULL, *host = NULL;
843         static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
844                         "plugin", "host", "time", "severity", NULL};
845         
846         if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist,
847                         NULL, &type, NULL, &message, NULL, &plugin_instance, NULL, &type_instance,
848                         NULL, &plugin, NULL, &host, &time, &severity))
849                 return -1;
850         
851         if (type && plugin_get_ds(type) == NULL) {
852                 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
853                 FreeAll();
854                 PyMem_Free(message);
855                 return -1;
856         }
857
858         sstrncpy(self->data.host, host ? host : "", sizeof(self->data.host));
859         sstrncpy(self->data.plugin, plugin ? plugin : "", sizeof(self->data.plugin));
860         sstrncpy(self->data.plugin_instance, plugin_instance ? plugin_instance : "", sizeof(self->data.plugin_instance));
861         sstrncpy(self->data.type, type ? type : "", sizeof(self->data.type));
862         sstrncpy(self->data.type_instance, type_instance ? type_instance : "", sizeof(self->data.type_instance));
863         sstrncpy(self->message, message ? message : "", sizeof(self->message));
864         self->data.time = time;
865         self->severity = severity;
866
867         FreeAll();
868         PyMem_Free(message);
869         return 0;
870 }
871
872 static PyObject *Notification_dispatch(Notification *self, PyObject *args, PyObject *kwds) {
873         int ret;
874         const data_set_t *ds;
875         notification_t notification;
876         double t = self->data.time;
877         int severity = self->severity;
878         char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL, *type_instance = NULL;
879         char *message = NULL;
880         
881         static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
882                         "plugin", "host", "time", "severity", NULL};
883         if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist,
884                         NULL, &type, NULL, &message, NULL, &plugin_instance, NULL, &type_instance,
885                         NULL, &plugin, NULL, &host, &t, &severity))
886                 return NULL;
887
888         notification.time = t;
889         notification.severity = severity;
890         sstrncpy(notification.message, message ? message : self->message, sizeof(notification.message));
891         sstrncpy(notification.host, host ? host : self->data.host, sizeof(notification.host));
892         sstrncpy(notification.plugin, plugin ? plugin : self->data.plugin, sizeof(notification.plugin));
893         sstrncpy(notification.plugin_instance, plugin_instance ? plugin_instance : self->data.plugin_instance, sizeof(notification.plugin_instance));
894         sstrncpy(notification.type, type ? type : self->data.type, sizeof(notification.type));
895         sstrncpy(notification.type_instance, type_instance ? type_instance : self->data.type_instance, sizeof(notification.type_instance));
896         notification.meta = NULL;
897         FreeAll();
898         PyMem_Free(message);
899
900         if (notification.type[0] == 0) {
901                 PyErr_SetString(PyExc_RuntimeError, "type not set");
902                 return NULL;
903         }
904         ds = plugin_get_ds(notification.type);
905         if (ds == NULL) {
906                 PyErr_Format(PyExc_TypeError, "Dataset %s not found", notification.type);
907                 return NULL;
908         }
909
910         if (notification.time < 1)
911                 notification.time = time(0);
912         if (notification.host[0] == 0)
913                 sstrncpy(notification.host, hostname_g, sizeof(notification.host));
914         if (notification.plugin[0] == 0)
915                 sstrncpy(notification.plugin, "python", sizeof(notification.plugin));
916         Py_BEGIN_ALLOW_THREADS;
917         ret = plugin_dispatch_notification(&notification);
918         Py_END_ALLOW_THREADS;
919         if (ret != 0) {
920                 PyErr_SetString(PyExc_RuntimeError, "error dispatching notification, read the logs");
921                 return NULL;
922         }
923         Py_RETURN_NONE;
924 }
925
926 static PyObject *Notification_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
927         Notification *self;
928         
929         self = (Notification *) PluginData_new(type, args, kwds);
930         if (self == NULL)
931                 return NULL;
932         
933         self->message[0] = 0;
934         self->severity = 0;
935         return (PyObject *) self;
936 }
937
938 static int Notification_setstring(PyObject *self, PyObject *value, void *data) {
939         char *old;
940         const char *new;
941         
942         if (value == NULL) {
943                 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
944                 return -1;
945         }
946         Py_INCREF(value);
947         new = cpy_unicode_or_bytes_to_string(&value);
948         if (new == NULL) {
949                 Py_DECREF(value);
950                 return -1;
951         }
952         old = ((char *) self) + (intptr_t) data;
953         sstrncpy(old, new, NOTIF_MAX_MSG_LEN);
954         Py_DECREF(value);
955         return 0;
956 }
957
958 static PyObject *Notification_repr(PyObject *s) {
959         PyObject *ret, *tmp;
960         static PyObject *l_severity = NULL, *l_message = NULL, *l_closing = NULL;
961         Notification *self = (Notification *) s;
962         
963         if (l_severity == NULL)
964                 l_severity = cpy_string_to_unicode_or_bytes(",severity=");
965         if (l_message == NULL)
966                 l_message = cpy_string_to_unicode_or_bytes(",message=");
967         if (l_closing == NULL)
968                 l_closing = cpy_string_to_unicode_or_bytes(")");
969         
970         if (l_severity == NULL || l_message == NULL || l_closing == NULL)
971                 return NULL;
972         
973         ret = cpy_common_repr(s);
974         if (self->severity != 0) {
975                 CPY_STRCAT(&ret, l_severity);
976                 tmp = PyInt_FromLong(self->severity);
977                 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
978                 CPY_STRCAT_AND_DEL(&ret, tmp);
979         }
980         if (self->message[0] != 0) {
981                 CPY_STRCAT(&ret, l_message);
982                 tmp = cpy_string_to_unicode_or_bytes(self->message);
983                 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
984                 CPY_STRCAT_AND_DEL(&ret, tmp);
985         }
986         CPY_STRCAT(&ret, l_closing);
987         return ret;
988 }
989
990 static PyMethodDef Notification_methods[] = {
991         {"dispatch", (PyCFunction) Notification_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
992         {NULL}
993 };
994
995 static PyMemberDef Notification_members[] = {
996         {"severity", T_INT, offsetof(Notification, severity), 0, severity_doc},
997         {NULL}
998 };
999
1000 static PyGetSetDef Notification_getseters[] = {
1001         {"message", PluginData_getstring, Notification_setstring, message_doc, (void *) offsetof(Notification, message)},
1002         {NULL}
1003 };
1004
1005 PyTypeObject NotificationType = {
1006         CPY_INIT_TYPE
1007         "collectd.Notification",   /* tp_name */
1008         sizeof(Notification),      /* tp_basicsize */
1009         0,                         /* Will be filled in later */
1010         0,                         /* tp_dealloc */
1011         0,                         /* tp_print */
1012         0,                         /* tp_getattr */
1013         0,                         /* tp_setattr */
1014         0,                         /* tp_compare */
1015         Notification_repr,         /* tp_repr */
1016         0,                         /* tp_as_number */
1017         0,                         /* tp_as_sequence */
1018         0,                         /* tp_as_mapping */
1019         0,                         /* tp_hash */
1020         0,                         /* tp_call */
1021         0,                         /* tp_str */
1022         0,                         /* tp_getattro */
1023         0,                         /* tp_setattro */
1024         0,                         /* tp_as_buffer */
1025         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1026         Notification_doc,          /* tp_doc */
1027         0,                         /* tp_traverse */
1028         0,                         /* tp_clear */
1029         0,                         /* tp_richcompare */
1030         0,                         /* tp_weaklistoffset */
1031         0,                         /* tp_iter */
1032         0,                         /* tp_iternext */
1033         Notification_methods,      /* tp_methods */
1034         Notification_members,      /* tp_members */
1035         Notification_getseters,    /* tp_getset */
1036         0,                         /* tp_base */
1037         0,                         /* tp_dict */
1038         0,                         /* tp_descr_get */
1039         0,                         /* tp_descr_set */
1040         0,                         /* tp_dictoffset */
1041         Notification_init,         /* tp_init */
1042         0,                         /* tp_alloc */
1043         Notification_new           /* tp_new */
1044 };
1045
1046 static char Signed_doc[] = "This is a long by another name. Use it in meta data dicts\n"
1047                 "to choose the way it is stored in the meta data.";
1048
1049 PyTypeObject SignedType = {
1050         CPY_INIT_TYPE
1051         "collectd.Signed",         /* tp_name */
1052         sizeof(Signed),            /* tp_basicsize */
1053         0,                         /* Will be filled in later */
1054         0,                         /* tp_dealloc */
1055         0,                         /* tp_print */
1056         0,                         /* tp_getattr */
1057         0,                         /* tp_setattr */
1058         0,                         /* tp_compare */
1059         0,                         /* tp_repr */
1060         0,                         /* tp_as_number */
1061         0,                         /* tp_as_sequence */
1062         0,                         /* tp_as_mapping */
1063         0,                         /* tp_hash */
1064         0,                         /* tp_call */
1065         0,                         /* tp_str */
1066         0,                         /* tp_getattro */
1067         0,                         /* tp_setattro */
1068         0,                         /* tp_as_buffer */
1069         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1070         Signed_doc                 /* tp_doc */
1071 };
1072
1073 static char Unsigned_doc[] = "This is a long by another name. Use it in meta data dicts\n"
1074                 "to choose the way it is stored in the meta data.";
1075
1076 PyTypeObject UnsignedType = {
1077         CPY_INIT_TYPE
1078         "collectd.Unsigned",       /* tp_name */
1079         sizeof(Unsigned),          /* tp_basicsize */
1080         0,                         /* Will be filled in later */
1081         0,                         /* tp_dealloc */
1082         0,                         /* tp_print */
1083         0,                         /* tp_getattr */
1084         0,                         /* tp_setattr */
1085         0,                         /* tp_compare */
1086         0,                         /* tp_repr */
1087         0,                         /* tp_as_number */
1088         0,                         /* tp_as_sequence */
1089         0,                         /* tp_as_mapping */
1090         0,                         /* tp_hash */
1091         0,                         /* tp_call */
1092         0,                         /* tp_str */
1093         0,                         /* tp_getattro */
1094         0,                         /* tp_setattro */
1095         0,                         /* tp_as_buffer */
1096         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1097         Unsigned_doc               /* tp_doc */
1098 };