intel_rdt: update unit-tests for process monitoring
[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
32 #include "utils/common/common.h"
33
34 #include "cpython.h"
35
36 typedef struct {
37   int (*add_string)(void *, const char *, const char *);
38   int (*add_signed_int)(void *, const char *, int64_t);
39   int (*add_unsigned_int)(void *, const char *, uint64_t);
40   int (*add_double)(void *, const char *, double);
41   int (*add_boolean)(void *, const char *, bool);
42 } cpy_build_meta_handler_t;
43
44 #define FreeAll()                                                              \
45   do {                                                                         \
46     PyMem_Free(type);                                                          \
47     PyMem_Free(plugin_instance);                                               \
48     PyMem_Free(type_instance);                                                 \
49     PyMem_Free(plugin);                                                        \
50     PyMem_Free(host);                                                          \
51   } while (0)
52
53 static PyObject *cpy_common_repr(PyObject *s) {
54   PyObject *ret, *tmp;
55   static PyObject *l_type, *l_type_instance, *l_plugin, *l_plugin_instance;
56   static PyObject *l_host, *l_time;
57   PluginData *self = (PluginData *)s;
58
59   if (l_type == NULL)
60     l_type = cpy_string_to_unicode_or_bytes("(type=");
61   if (l_type_instance == NULL)
62     l_type_instance = cpy_string_to_unicode_or_bytes(",type_instance=");
63   if (l_plugin == NULL)
64     l_plugin = cpy_string_to_unicode_or_bytes(",plugin=");
65   if (l_plugin_instance == NULL)
66     l_plugin_instance = cpy_string_to_unicode_or_bytes(",plugin_instance=");
67   if (l_host == NULL)
68     l_host = cpy_string_to_unicode_or_bytes(",host=");
69   if (l_time == NULL)
70     l_time = cpy_string_to_unicode_or_bytes(",time=");
71
72   if (!l_type || !l_type_instance || !l_plugin || !l_plugin_instance ||
73       !l_host || !l_time)
74     return NULL;
75
76   ret = cpy_string_to_unicode_or_bytes(s->ob_type->tp_name);
77
78   CPY_STRCAT(&ret, l_type);
79   tmp = cpy_string_to_unicode_or_bytes(self->type);
80   CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
81   CPY_STRCAT_AND_DEL(&ret, tmp);
82
83   if (self->type_instance[0] != 0) {
84     CPY_STRCAT(&ret, l_type_instance);
85     tmp = cpy_string_to_unicode_or_bytes(self->type_instance);
86     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
87     CPY_STRCAT_AND_DEL(&ret, tmp);
88   }
89
90   if (self->plugin[0] != 0) {
91     CPY_STRCAT(&ret, l_plugin);
92     tmp = cpy_string_to_unicode_or_bytes(self->plugin);
93     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
94     CPY_STRCAT_AND_DEL(&ret, tmp);
95   }
96
97   if (self->plugin_instance[0] != 0) {
98     CPY_STRCAT(&ret, l_plugin_instance);
99     tmp = cpy_string_to_unicode_or_bytes(self->plugin_instance);
100     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
101     CPY_STRCAT_AND_DEL(&ret, tmp);
102   }
103
104   if (self->host[0] != 0) {
105     CPY_STRCAT(&ret, l_host);
106     tmp = cpy_string_to_unicode_or_bytes(self->host);
107     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
108     CPY_STRCAT_AND_DEL(&ret, tmp);
109   }
110
111   if (self->time != 0) {
112     CPY_STRCAT(&ret, l_time);
113     tmp = PyFloat_FromDouble(self->time);
114     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
115     CPY_STRCAT_AND_DEL(&ret, tmp);
116   }
117   return ret;
118 }
119
120 static char time_doc[] =
121     "This is the Unix timestamp of the time this value was read.\n"
122     "For dispatching values this can be set to 0 which means \"now\".\n"
123     "This means the time the value is actually dispatched, not the time\n"
124     "it was set to 0.";
125
126 static char host_doc[] =
127     "The hostname of the host this value was read from.\n"
128     "For dispatching this can be set to an empty string which means\n"
129     "the local hostname as defined in collectd.conf.";
130
131 static char type_doc[] =
132     "The type of this value. This type has to be defined\n"
133     "in the types.db file. Attempting to set it to any other value\n"
134     "will raise a TypeError exception.\n"
135     "Assigning a type is mandatory, calling dispatch without doing\n"
136     "so will raise a RuntimeError exception.";
137
138 static char type_instance_doc[] = "";
139
140 static char plugin_doc[] =
141     "The name of the plugin that read the data. Setting this\n"
142     "member to an empty string will insert \"python\" upon dispatching.";
143
144 static char plugin_instance_doc[] = "";
145
146 static char PluginData_doc[] =
147     "This is an internal class that is the base for Values\n"
148     "and Notification. It is pretty useless by itself and is therefore not\n"
149     "exported to the collectd module.";
150
151 static PyObject *PluginData_new(PyTypeObject *type, PyObject *args,
152                                 PyObject *kwds) {
153   PluginData *self;
154
155   self = (PluginData *)type->tp_alloc(type, 0);
156   if (self == NULL)
157     return NULL;
158
159   self->time = 0;
160   self->host[0] = 0;
161   self->plugin[0] = 0;
162   self->plugin_instance[0] = 0;
163   self->type[0] = 0;
164   self->type_instance[0] = 0;
165   return (PyObject *)self;
166 }
167
168 static int PluginData_init(PyObject *s, PyObject *args, PyObject *kwds) {
169   PluginData *self = (PluginData *)s;
170   double time = 0;
171   char *type = NULL, *plugin_instance = NULL, *type_instance = NULL,
172        *plugin = NULL, *host = NULL;
173   static char *kwlist[] = {
174       "type", "plugin_instance", "type_instance", "plugin", "host", "time",
175       NULL};
176
177   if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetd", kwlist, NULL,
178                                    &type, NULL, &plugin_instance, NULL,
179                                    &type_instance, NULL, &plugin, NULL, &host,
180                                    &time))
181     return -1;
182
183   if (type && plugin_get_ds(type) == NULL) {
184     PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
185     FreeAll();
186     return -1;
187   }
188
189   sstrncpy(self->host, host ? host : "", sizeof(self->host));
190   sstrncpy(self->plugin, plugin ? plugin : "", sizeof(self->plugin));
191   sstrncpy(self->plugin_instance, plugin_instance ? plugin_instance : "",
192            sizeof(self->plugin_instance));
193   sstrncpy(self->type, type ? type : "", sizeof(self->type));
194   sstrncpy(self->type_instance, type_instance ? type_instance : "",
195            sizeof(self->type_instance));
196   self->time = time;
197
198   FreeAll();
199
200   return 0;
201 }
202
203 static PyObject *PluginData_repr(PyObject *s) {
204   PyObject *ret;
205   static PyObject *l_closing;
206
207   if (l_closing == NULL)
208     l_closing = cpy_string_to_unicode_or_bytes(")");
209
210   if (l_closing == NULL)
211     return NULL;
212
213   ret = cpy_common_repr(s);
214   CPY_STRCAT(&ret, l_closing);
215   return ret;
216 }
217
218 static PyMemberDef PluginData_members[] = {
219     {"time", T_DOUBLE, offsetof(PluginData, time), 0, time_doc}, {NULL}};
220
221 static PyObject *PluginData_getstring(PyObject *self, void *data) {
222   const char *value = ((char *)self) + (intptr_t)data;
223
224   return cpy_string_to_unicode_or_bytes(value);
225 }
226
227 static int PluginData_setstring(PyObject *self, PyObject *value, void *data) {
228   char *old;
229   const char *new;
230
231   if (value == NULL) {
232     PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
233     return -1;
234   }
235   Py_INCREF(value);
236   new = cpy_unicode_or_bytes_to_string(&value);
237   if (new == NULL) {
238     Py_DECREF(value);
239     return -1;
240   }
241   old = ((char *)self) + (intptr_t)data;
242   sstrncpy(old, new, DATA_MAX_NAME_LEN);
243   Py_DECREF(value);
244   return 0;
245 }
246
247 static int PluginData_settype(PyObject *self, PyObject *value, void *data) {
248   char *old;
249   const char *new;
250
251   if (value == NULL) {
252     PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
253     return -1;
254   }
255   Py_INCREF(value);
256   new = cpy_unicode_or_bytes_to_string(&value);
257   if (new == NULL) {
258     Py_DECREF(value);
259     return -1;
260   }
261
262   if (plugin_get_ds(new) == NULL) {
263     PyErr_Format(PyExc_TypeError, "Dataset %s not found", new);
264     Py_DECREF(value);
265     return -1;
266   }
267
268   old = ((char *)self) + (intptr_t)data;
269   sstrncpy(old, new, DATA_MAX_NAME_LEN);
270   Py_DECREF(value);
271   return 0;
272 }
273
274 static PyGetSetDef PluginData_getseters[] = {
275     {"host", PluginData_getstring, PluginData_setstring, host_doc,
276      (void *)offsetof(PluginData, host)},
277     {"plugin", PluginData_getstring, PluginData_setstring, plugin_doc,
278      (void *)offsetof(PluginData, plugin)},
279     {"plugin_instance", PluginData_getstring, PluginData_setstring,
280      plugin_instance_doc, (void *)offsetof(PluginData, plugin_instance)},
281     {"type_instance", PluginData_getstring, PluginData_setstring,
282      type_instance_doc, (void *)offsetof(PluginData, type_instance)},
283     {"type", PluginData_getstring, PluginData_settype, type_doc,
284      (void *)offsetof(PluginData, type)},
285     {NULL}};
286
287 PyTypeObject PluginDataType = {
288     CPY_INIT_TYPE "collectd.PluginData", /* tp_name */
289     sizeof(PluginData),                  /* tp_basicsize */
290     0,                                   /* Will be filled in later */
291     0,                                   /* tp_dealloc */
292     0,                                   /* tp_print */
293     0,                                   /* tp_getattr */
294     0,                                   /* tp_setattr */
295     0,                                   /* tp_compare */
296     PluginData_repr,                     /* tp_repr */
297     0,                                   /* tp_as_number */
298     0,                                   /* tp_as_sequence */
299     0,                                   /* tp_as_mapping */
300     0,                                   /* tp_hash */
301     0,                                   /* tp_call */
302     0,                                   /* tp_str */
303     0,                                   /* tp_getattro */
304     0,                                   /* tp_setattro */
305     0,                                   /* tp_as_buffer */
306     Py_TPFLAGS_DEFAULT |
307         Py_TPFLAGS_BASETYPE /*| Py_TPFLAGS_HAVE_GC*/, /*tp_flags*/
308     PluginData_doc,                                   /* tp_doc */
309     0,                                                /* tp_traverse */
310     0,                                                /* tp_clear */
311     0,                                                /* tp_richcompare */
312     0,                                                /* tp_weaklistoffset */
313     0,                                                /* tp_iter */
314     0,                                                /* tp_iternext */
315     0,                                                /* tp_methods */
316     PluginData_members,                               /* tp_members */
317     PluginData_getseters,                             /* tp_getset */
318     0,                                                /* tp_base */
319     0,                                                /* tp_dict */
320     0,                                                /* tp_descr_get */
321     0,                                                /* tp_descr_set */
322     0,                                                /* tp_dictoffset */
323     PluginData_init,                                  /* tp_init */
324     0,                                                /* tp_alloc */
325     PluginData_new                                    /* tp_new */
326 };
327
328 static char interval_doc[] =
329     "The interval is the timespan in seconds between two submits for\n"
330     "the same data source. This value has to be a positive integer, so you "
331     "can't\n"
332     "submit more than one value per second. If this member is set to a\n"
333     "non-positive value, the default value as specified in the config file "
334     "will\n"
335     "be used (default: 10).\n"
336     "\n"
337     "If you submit values more often than the specified interval, the average\n"
338     "will be used. If you submit less values, your graphs will have gaps.";
339
340 static char values_doc[] =
341     "These are the actual values that get dispatched to collectd.\n"
342     "It has to be a sequence (a tuple or list) of numbers.\n"
343     "The size of the sequence and the type of its content depend on the type\n"
344     "member in the types.db file. For more information on this read the\n"
345     "types.db man page.\n"
346     "\n"
347     "If the sequence does not have the correct size upon dispatch a "
348     "RuntimeError\n"
349     "exception will be raised. If the content of the sequence is not a "
350     "number,\n"
351     "a TypeError exception will be raised.";
352
353 static char meta_doc[] =
354     "These are the meta data for this Value object.\n"
355     "It has to be a dictionary of numbers, strings or bools. All keys must be\n"
356     "strings. int and long objects will be dispatched as signed integers "
357     "unless\n"
358     "they are between 2**63 and 2**64-1, which will result in an unsigned "
359     "integer.\n"
360     "You can force one of these storage classes by using the classes\n"
361     "collectd.Signed and collectd.Unsigned. A meta object received by a write\n"
362     "callback will always contain Signed or Unsigned objects.";
363
364 static char dispatch_doc[] =
365     "dispatch([type][, values][, plugin_instance][, type_instance]"
366     "[, plugin][, host][, time][, interval]) -> None.  Dispatch a value list.\n"
367     "\n"
368     "Dispatch this instance to the collectd process. The object has members\n"
369     "for each of the possible arguments for this method. For a detailed "
370     "explanation\n"
371     "of these parameters see the member of the same same.\n"
372     "\n"
373     "If you do not submit a parameter the value saved in its member will be "
374     "submitted.\n"
375     "If you do provide a parameter it will be used instead, without altering "
376     "the member.";
377
378 static char write_doc[] =
379     "write([destination][, type][, values][, plugin_instance][, type_instance]"
380     "[, plugin][, host][, time][, interval]) -> None.  Dispatch a value list.\n"
381     "\n"
382     "Write this instance to a single plugin or all plugins if 'destination' is "
383     "omitted.\n"
384     "This will bypass the main collectd process and all filtering and "
385     "caching.\n"
386     "Other than that it works similar to 'dispatch'. In most cases 'dispatch' "
387     "should be\n"
388     "used instead of 'write'.\n";
389
390 static char Values_doc[] = "A Values object used for dispatching values to "
391                            "collectd and receiving values from write "
392                            "callbacks.";
393
394 static PyObject *Values_new(PyTypeObject *type, PyObject *args,
395                             PyObject *kwds) {
396   Values *self;
397
398   self = (Values *)PluginData_new(type, args, kwds);
399   if (self == NULL)
400     return NULL;
401
402   self->values = PyList_New(0);
403   self->meta = PyDict_New();
404   self->interval = 0;
405   return (PyObject *)self;
406 }
407
408 static int Values_init(PyObject *s, PyObject *args, PyObject *kwds) {
409   Values *self = (Values *)s;
410   double interval = 0, time = 0;
411   PyObject *values = NULL, *meta = NULL, *tmp;
412   char *type = NULL, *plugin_instance = NULL, *type_instance = NULL,
413        *plugin = NULL, *host = NULL;
414   static char *kwlist[] = {
415       "type", "values", "plugin_instance", "type_instance", "plugin",
416       "host", "time",   "interval",        "meta",          NULL};
417
418   if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist, NULL,
419                                    &type, &values, NULL, &plugin_instance, NULL,
420                                    &type_instance, NULL, &plugin, NULL, &host,
421                                    &time, &interval, &meta))
422     return -1;
423
424   if (type && plugin_get_ds(type) == NULL) {
425     PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
426     FreeAll();
427     return -1;
428   }
429
430   sstrncpy(self->data.host, host ? host : "", sizeof(self->data.host));
431   sstrncpy(self->data.plugin, plugin ? plugin : "", sizeof(self->data.plugin));
432   sstrncpy(self->data.plugin_instance, plugin_instance ? plugin_instance : "",
433            sizeof(self->data.plugin_instance));
434   sstrncpy(self->data.type, type ? type : "", sizeof(self->data.type));
435   sstrncpy(self->data.type_instance, type_instance ? type_instance : "",
436            sizeof(self->data.type_instance));
437   self->data.time = time;
438
439   FreeAll();
440
441   if (values == NULL) {
442     values = PyList_New(0);
443     PyErr_Clear();
444   } else {
445     Py_INCREF(values);
446   }
447
448   if (meta == NULL) {
449     meta = PyDict_New();
450     PyErr_Clear();
451   } else {
452     Py_INCREF(meta);
453   }
454
455   tmp = self->values;
456   self->values = values;
457   Py_XDECREF(tmp);
458
459   tmp = self->meta;
460   self->meta = meta;
461   Py_XDECREF(tmp);
462
463   self->interval = interval;
464   return 0;
465 }
466
467 static int cpy_build_meta_generic(PyObject *meta,
468                                   cpy_build_meta_handler_t *meta_func,
469                                   void *m) {
470   int s;
471   PyObject *l;
472
473   if ((meta == NULL) || (meta == Py_None))
474     return -1;
475
476   l = PyDict_Items(meta); /* New reference. */
477   if (!l) {
478     cpy_log_exception("building meta data");
479     return -1;
480   }
481   s = PyList_Size(l);
482   if (s <= 0) {
483     Py_XDECREF(l);
484     return -1;
485   }
486
487   for (int i = 0; i < s; ++i) {
488     const char *string, *keystring;
489     PyObject *key, *value, *item, *tmp;
490
491     item = PyList_GET_ITEM(l, i);
492     key = PyTuple_GET_ITEM(item, 0);
493     Py_INCREF(key);
494     keystring = cpy_unicode_or_bytes_to_string(&key);
495     if (!keystring) {
496       PyErr_Clear();
497       Py_XDECREF(key);
498       continue;
499     }
500     value = PyTuple_GET_ITEM(item, 1);
501     Py_INCREF(value);
502     if (value == Py_True) {
503       meta_func->add_boolean(m, keystring, 1);
504     } else if (value == Py_False) {
505       meta_func->add_boolean(m, keystring, 0);
506     } else if (PyFloat_Check(value)) {
507       meta_func->add_double(m, keystring, PyFloat_AsDouble(value));
508     } else if (PyObject_TypeCheck(value, &SignedType)) {
509       long long int lli;
510       lli = PyLong_AsLongLong(value);
511       if (!PyErr_Occurred() && (lli == (int64_t)lli))
512         meta_func->add_signed_int(m, keystring, lli);
513     } else if (PyObject_TypeCheck(value, &UnsignedType)) {
514       long long unsigned llu;
515       llu = PyLong_AsUnsignedLongLong(value);
516       if (!PyErr_Occurred() && (llu == (uint64_t)llu))
517         meta_func->add_unsigned_int(m, keystring, llu);
518     } else if (PyNumber_Check(value)) {
519       long long int lli;
520       long long unsigned llu;
521       tmp = PyNumber_Long(value);
522       lli = PyLong_AsLongLong(tmp);
523       if (!PyErr_Occurred() && (lli == (int64_t)lli)) {
524         meta_func->add_signed_int(m, keystring, lli);
525       } else {
526         PyErr_Clear();
527         llu = PyLong_AsUnsignedLongLong(tmp);
528         if (!PyErr_Occurred() && (llu == (uint64_t)llu))
529           meta_func->add_unsigned_int(m, keystring, llu);
530       }
531       Py_XDECREF(tmp);
532     } else {
533       string = cpy_unicode_or_bytes_to_string(&value);
534       if (string) {
535         meta_func->add_string(m, keystring, string);
536       } else {
537         PyErr_Clear();
538         tmp = PyObject_Str(value);
539         string = cpy_unicode_or_bytes_to_string(&tmp);
540         if (string)
541           meta_func->add_string(m, keystring, string);
542         Py_XDECREF(tmp);
543       }
544     }
545     if (PyErr_Occurred())
546       cpy_log_exception("building meta data");
547     Py_XDECREF(value);
548     Py_DECREF(key);
549   }
550   Py_XDECREF(l);
551   return 0;
552 }
553
554 #define CPY_BUILD_META_FUNC(meta_type, func, val_type)                         \
555   static int cpy_##func(void *meta, const char *key, val_type val) {           \
556     return func((meta_type *)meta, key, val);                                  \
557   }
558
559 #define CPY_BUILD_META_HANDLER(func_prefix, meta_type)                         \
560   CPY_BUILD_META_FUNC(meta_type, func_prefix##_add_string, const char *)       \
561   CPY_BUILD_META_FUNC(meta_type, func_prefix##_add_signed_int, int64_t)        \
562   CPY_BUILD_META_FUNC(meta_type, func_prefix##_add_unsigned_int, uint64_t)     \
563   CPY_BUILD_META_FUNC(meta_type, func_prefix##_add_double, double)             \
564   CPY_BUILD_META_FUNC(meta_type, func_prefix##_add_boolean, bool)              \
565                                                                                \
566   static cpy_build_meta_handler_t cpy_##func_prefix = {                        \
567       .add_string = cpy_##func_prefix##_add_string,                            \
568       .add_signed_int = cpy_##func_prefix##_add_signed_int,                    \
569       .add_unsigned_int = cpy_##func_prefix##_add_unsigned_int,                \
570       .add_double = cpy_##func_prefix##_add_double,                            \
571       .add_boolean = cpy_##func_prefix##_add_boolean}
572
573 CPY_BUILD_META_HANDLER(meta_data, meta_data_t);
574 CPY_BUILD_META_HANDLER(plugin_notification_meta, notification_t);
575
576 static meta_data_t *cpy_build_meta(PyObject *meta) {
577   meta_data_t *m = meta_data_create();
578   if (cpy_build_meta_generic(meta, &cpy_meta_data, (void *)m) < 0) {
579     meta_data_destroy(m);
580     return NULL;
581   }
582   return m;
583 }
584
585 static void cpy_build_notification_meta(notification_t *n, PyObject *meta) {
586   cpy_build_meta_generic(meta, &cpy_plugin_notification_meta, (void *)n);
587 }
588
589 static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
590   int ret;
591   const data_set_t *ds;
592   size_t size;
593   value_t *value;
594   value_list_t value_list = VALUE_LIST_INIT;
595   PyObject *values = self->values, *meta = self->meta;
596   double time = self->data.time, interval = self->interval;
597   char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL,
598        *type_instance = NULL;
599
600   static char *kwlist[] = {
601       "type", "values", "plugin_instance", "type_instance", "plugin",
602       "host", "time",   "interval",        "meta",          NULL};
603   if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist, NULL,
604                                    &type, &values, NULL, &plugin_instance, NULL,
605                                    &type_instance, NULL, &plugin, NULL, &host,
606                                    &time, &interval, &meta))
607     return NULL;
608
609   sstrncpy(value_list.host, host ? host : self->data.host,
610            sizeof(value_list.host));
611   sstrncpy(value_list.plugin, plugin ? plugin : self->data.plugin,
612            sizeof(value_list.plugin));
613   sstrncpy(value_list.plugin_instance,
614            plugin_instance ? plugin_instance : self->data.plugin_instance,
615            sizeof(value_list.plugin_instance));
616   sstrncpy(value_list.type, type ? type : self->data.type,
617            sizeof(value_list.type));
618   sstrncpy(value_list.type_instance,
619            type_instance ? type_instance : self->data.type_instance,
620            sizeof(value_list.type_instance));
621   FreeAll();
622   if (value_list.type[0] == 0) {
623     PyErr_SetString(PyExc_RuntimeError, "type not set");
624     FreeAll();
625     return NULL;
626   }
627   ds = plugin_get_ds(value_list.type);
628   if (ds == NULL) {
629     PyErr_Format(PyExc_TypeError, "Dataset %s not found", value_list.type);
630     return NULL;
631   }
632   if (values == NULL ||
633       (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
634     PyErr_Format(PyExc_TypeError, "values must be list or tuple");
635     return NULL;
636   }
637   if (meta != NULL && meta != Py_None && !PyDict_Check(meta)) {
638     PyErr_Format(PyExc_TypeError, "meta must be a dict");
639     return NULL;
640   }
641   size = (size_t)PySequence_Length(values);
642   if (size != ds->ds_num) {
643     PyErr_Format(PyExc_RuntimeError,
644                  "type %s needs %" PRIsz " values, got %" PRIsz,
645                  value_list.type, ds->ds_num, size);
646     return NULL;
647   }
648   value = calloc(size, sizeof(*value));
649   for (size_t i = 0; i < size; ++i) {
650     PyObject *item, *num;
651     item = PySequence_Fast_GET_ITEM(values, (int)i); /* Borrowed reference. */
652     switch (ds->ds[i].type) {
653     case DS_TYPE_COUNTER:
654       num = PyNumber_Long(item); /* New reference. */
655       if (num != NULL) {
656         value[i].counter = PyLong_AsUnsignedLongLong(num);
657         Py_XDECREF(num);
658       }
659       break;
660     case DS_TYPE_GAUGE:
661       num = PyNumber_Float(item); /* New reference. */
662       if (num != NULL) {
663         value[i].gauge = PyFloat_AsDouble(num);
664         Py_XDECREF(num);
665       }
666       break;
667     case DS_TYPE_DERIVE:
668       /* This might overflow without raising an exception.
669        * Not much we can do about it */
670       num = PyNumber_Long(item); /* New reference. */
671       if (num != NULL) {
672         value[i].derive = PyLong_AsLongLong(num);
673         Py_XDECREF(num);
674       }
675       break;
676     case 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       break;
685     default:
686       free(value);
687       PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s",
688                    ds->ds[i].type, value_list.type);
689       return NULL;
690     }
691     if (PyErr_Occurred() != NULL) {
692       free(value);
693       return NULL;
694     }
695   }
696   value_list.values = value;
697   value_list.meta = cpy_build_meta(meta);
698   value_list.values_len = size;
699   value_list.time = DOUBLE_TO_CDTIME_T(time);
700   value_list.interval = DOUBLE_TO_CDTIME_T(interval);
701   if (value_list.host[0] == 0)
702     sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
703   if (value_list.plugin[0] == 0)
704     sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
705   Py_BEGIN_ALLOW_THREADS;
706   ret = plugin_dispatch_values(&value_list);
707   Py_END_ALLOW_THREADS;
708   meta_data_destroy(value_list.meta);
709   free(value);
710   if (ret != 0) {
711     PyErr_SetString(PyExc_RuntimeError,
712                     "error dispatching values, read the logs");
713     return NULL;
714   }
715   Py_RETURN_NONE;
716 }
717
718 static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
719   int ret;
720   const data_set_t *ds;
721   size_t size;
722   value_t *value;
723   value_list_t value_list = VALUE_LIST_INIT;
724   PyObject *values = self->values, *meta = self->meta;
725   double time = self->data.time, interval = self->interval;
726   char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL,
727        *type_instance = NULL, *dest = NULL;
728
729   static char *kwlist[] = {
730       "destination",   "type",   "values", "plugin_instance",
731       "type_instance", "plugin", "host",   "time",
732       "interval",      "meta",   NULL};
733   if (!PyArg_ParseTupleAndKeywords(
734           args, kwds, "et|etOetetetetdiO", kwlist, NULL, &dest, NULL, &type,
735           &values, NULL, &plugin_instance, NULL, &type_instance, NULL, &plugin,
736           NULL, &host, &time, &interval, &meta))
737     return NULL;
738
739   sstrncpy(value_list.host, host ? host : self->data.host,
740            sizeof(value_list.host));
741   sstrncpy(value_list.plugin, plugin ? plugin : self->data.plugin,
742            sizeof(value_list.plugin));
743   sstrncpy(value_list.plugin_instance,
744            plugin_instance ? plugin_instance : self->data.plugin_instance,
745            sizeof(value_list.plugin_instance));
746   sstrncpy(value_list.type, type ? type : self->data.type,
747            sizeof(value_list.type));
748   sstrncpy(value_list.type_instance,
749            type_instance ? type_instance : self->data.type_instance,
750            sizeof(value_list.type_instance));
751   FreeAll();
752   if (value_list.type[0] == 0) {
753     PyErr_SetString(PyExc_RuntimeError, "type not set");
754     return NULL;
755   }
756   ds = plugin_get_ds(value_list.type);
757   if (ds == NULL) {
758     PyErr_Format(PyExc_TypeError, "Dataset %s not found", value_list.type);
759     return NULL;
760   }
761   if (values == NULL ||
762       (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
763     PyErr_Format(PyExc_TypeError, "values must be list or tuple");
764     return NULL;
765   }
766   size = (size_t)PySequence_Length(values);
767   if (size != ds->ds_num) {
768     PyErr_Format(PyExc_RuntimeError,
769                  "type %s needs %" PRIsz " values, got %" PRIsz,
770                  value_list.type, ds->ds_num, size);
771     return NULL;
772   }
773   value = calloc(size, sizeof(*value));
774   for (size_t i = 0; i < size; ++i) {
775     PyObject *item, *num;
776     item = PySequence_Fast_GET_ITEM(values, i); /* Borrowed reference. */
777     switch (ds->ds[i].type) {
778     case DS_TYPE_COUNTER:
779       num = PyNumber_Long(item); /* New reference. */
780       if (num != NULL) {
781         value[i].counter = PyLong_AsUnsignedLongLong(num);
782         Py_XDECREF(num);
783       }
784       break;
785     case DS_TYPE_GAUGE:
786       num = PyNumber_Float(item); /* New reference. */
787       if (num != NULL) {
788         value[i].gauge = PyFloat_AsDouble(num);
789         Py_XDECREF(num);
790       }
791       break;
792     case DS_TYPE_DERIVE:
793       /* This might overflow without raising an exception.
794        * Not much we can do about it */
795       num = PyNumber_Long(item); /* New reference. */
796       if (num != NULL) {
797         value[i].derive = PyLong_AsLongLong(num);
798         Py_XDECREF(num);
799       }
800       break;
801     case DS_TYPE_ABSOLUTE:
802       /* This might overflow without raising an exception.
803        * Not much we can do about it */
804       num = PyNumber_Long(item); /* New reference. */
805       if (num != NULL) {
806         value[i].absolute = PyLong_AsUnsignedLongLong(num);
807         Py_XDECREF(num);
808       }
809       break;
810     default:
811       free(value);
812       PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s",
813                    ds->ds[i].type, value_list.type);
814       return NULL;
815     }
816     if (PyErr_Occurred() != NULL) {
817       free(value);
818       return NULL;
819     }
820   }
821   value_list.values = value;
822   value_list.values_len = size;
823   value_list.time = DOUBLE_TO_CDTIME_T(time);
824   value_list.interval = DOUBLE_TO_CDTIME_T(interval);
825   value_list.meta = cpy_build_meta(meta);
826   if (value_list.host[0] == 0)
827     sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
828   if (value_list.plugin[0] == 0)
829     sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
830   Py_BEGIN_ALLOW_THREADS;
831   ret = plugin_write(dest, NULL, &value_list);
832   Py_END_ALLOW_THREADS;
833   meta_data_destroy(value_list.meta);
834   free(value);
835   if (ret != 0) {
836     PyErr_SetString(PyExc_RuntimeError,
837                     "error dispatching values, read the logs");
838     return NULL;
839   }
840   Py_RETURN_NONE;
841 }
842
843 static PyObject *Values_repr(PyObject *s) {
844   PyObject *ret, *tmp;
845   static PyObject *l_interval, *l_values, *l_meta, *l_closing;
846   Values *self = (Values *)s;
847
848   if (l_interval == NULL)
849     l_interval = cpy_string_to_unicode_or_bytes(",interval=");
850   if (l_values == NULL)
851     l_values = cpy_string_to_unicode_or_bytes(",values=");
852   if (l_meta == NULL)
853     l_meta = cpy_string_to_unicode_or_bytes(",meta=");
854   if (l_closing == NULL)
855     l_closing = cpy_string_to_unicode_or_bytes(")");
856
857   if (l_interval == NULL || l_values == NULL || l_meta == NULL ||
858       l_closing == NULL)
859     return NULL;
860
861   ret = cpy_common_repr(s);
862   if (self->interval != 0) {
863     CPY_STRCAT(&ret, l_interval);
864     tmp = PyFloat_FromDouble(self->interval);
865     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
866     CPY_STRCAT_AND_DEL(&ret, tmp);
867   }
868   if (self->values &&
869       (!PyList_Check(self->values) || PySequence_Length(self->values) > 0)) {
870     CPY_STRCAT(&ret, l_values);
871     tmp = PyObject_Repr(self->values);
872     CPY_STRCAT_AND_DEL(&ret, tmp);
873   }
874   if (self->meta &&
875       (!PyDict_Check(self->meta) || PyDict_Size(self->meta) > 0)) {
876     CPY_STRCAT(&ret, l_meta);
877     tmp = PyObject_Repr(self->meta);
878     CPY_STRCAT_AND_DEL(&ret, tmp);
879   }
880   CPY_STRCAT(&ret, l_closing);
881   return ret;
882 }
883
884 static int Values_traverse(PyObject *self, visitproc visit, void *arg) {
885   Values *v = (Values *)self;
886   Py_VISIT(v->values);
887   Py_VISIT(v->meta);
888   return 0;
889 }
890
891 static int Values_clear(PyObject *self) {
892   Values *v = (Values *)self;
893   Py_CLEAR(v->values);
894   Py_CLEAR(v->meta);
895   return 0;
896 }
897
898 static void Values_dealloc(PyObject *self) {
899   Values_clear(self);
900   self->ob_type->tp_free(self);
901 }
902
903 static PyMemberDef Values_members[] = {
904     {"interval", T_DOUBLE, offsetof(Values, interval), 0, interval_doc},
905     {"values", T_OBJECT_EX, offsetof(Values, values), 0, values_doc},
906     {"meta", T_OBJECT_EX, offsetof(Values, meta), 0, meta_doc},
907     {NULL}};
908
909 static PyMethodDef Values_methods[] = {
910     {"dispatch", (PyCFunction)Values_dispatch, METH_VARARGS | METH_KEYWORDS,
911      dispatch_doc},
912     {"write", (PyCFunction)Values_write, METH_VARARGS | METH_KEYWORDS,
913      write_doc},
914     {NULL}};
915
916 PyTypeObject ValuesType = {
917     CPY_INIT_TYPE "collectd.Values", /* tp_name */
918     sizeof(Values),                  /* tp_basicsize */
919     0,                               /* Will be filled in later */
920     Values_dealloc,                  /* tp_dealloc */
921     0,                               /* tp_print */
922     0,                               /* tp_getattr */
923     0,                               /* tp_setattr */
924     0,                               /* tp_compare */
925     Values_repr,                     /* tp_repr */
926     0,                               /* tp_as_number */
927     0,                               /* tp_as_sequence */
928     0,                               /* tp_as_mapping */
929     0,                               /* tp_hash */
930     0,                               /* tp_call */
931     0,                               /* tp_str */
932     0,                               /* tp_getattro */
933     0,                               /* tp_setattro */
934     0,                               /* tp_as_buffer */
935     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
936     Values_doc,                                                    /* tp_doc */
937     Values_traverse, /* tp_traverse */
938     Values_clear,    /* tp_clear */
939     0,               /* tp_richcompare */
940     0,               /* tp_weaklistoffset */
941     0,               /* tp_iter */
942     0,               /* tp_iternext */
943     Values_methods,  /* tp_methods */
944     Values_members,  /* tp_members */
945     0,               /* tp_getset */
946     0,               /* tp_base */
947     0,               /* tp_dict */
948     0,               /* tp_descr_get */
949     0,               /* tp_descr_set */
950     0,               /* tp_dictoffset */
951     Values_init,     /* tp_init */
952     0,               /* tp_alloc */
953     Values_new       /* tp_new */
954 };
955
956 static char notification_meta_doc[] =
957     "These are the meta data for the Notification object.\n"
958     "It has to be a dictionary of numbers, strings or bools. All keys must be\n"
959     "strings. int and long objects will be dispatched as signed integers "
960     "unless\n"
961     "they are between 2**63 and 2**64-1, which will result in an unsigned "
962     "integer.\n"
963     "One of these storage classes can be forced by using the classes\n"
964     "collectd.Signed and collectd.Unsigned. A meta object received by a\n"
965     "notification callback will always contain Signed or Unsigned objects.";
966
967 static char severity_doc[] =
968     "The severity of this notification. Assign or compare to\n"
969     "NOTIF_FAILURE, NOTIF_WARNING or NOTIF_OKAY.";
970
971 static char message_doc[] = "Some kind of description what's going on and why "
972                             "this Notification was generated.";
973
974 static char Notification_doc[] =
975     "The Notification class is a wrapper around the collectd notification.\n"
976     "It can be used to notify other plugins about bad stuff happening. It "
977     "works\n"
978     "similar to Values but has a severity and a message instead of interval\n"
979     "and time.\n"
980     "Notifications can be dispatched at any time and can be received with "
981     "register_notification.";
982
983 static int Notification_init(PyObject *s, PyObject *args, PyObject *kwds) {
984   Notification *self = (Notification *)s;
985   int severity = 0;
986   double time = 0;
987   char *message = NULL;
988   PyObject *meta = NULL;
989   char *type = NULL, *plugin_instance = NULL, *type_instance = NULL,
990        *plugin = NULL, *host = NULL;
991   static char *kwlist[] = {
992       "type", "message", "plugin_instance", "type_instance", "plugin",
993       "host", "time",    "severity",        "meta",          NULL};
994
995   if (!PyArg_ParseTupleAndKeywords(
996           args, kwds, "|etetetetetetdiO", kwlist, NULL, &type, NULL, &message,
997           NULL, &plugin_instance, NULL, &type_instance, NULL, &plugin, NULL,
998           &host, &time, &severity, &meta))
999     return -1;
1000
1001   if (type && plugin_get_ds(type) == NULL) {
1002     PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
1003     FreeAll();
1004     PyMem_Free(message);
1005     return -1;
1006   }
1007
1008   sstrncpy(self->data.host, host ? host : "", sizeof(self->data.host));
1009   sstrncpy(self->data.plugin, plugin ? plugin : "", sizeof(self->data.plugin));
1010   sstrncpy(self->data.plugin_instance, plugin_instance ? plugin_instance : "",
1011            sizeof(self->data.plugin_instance));
1012   sstrncpy(self->data.type, type ? type : "", sizeof(self->data.type));
1013   sstrncpy(self->data.type_instance, type_instance ? type_instance : "",
1014            sizeof(self->data.type_instance));
1015   sstrncpy(self->message, message ? message : "", sizeof(self->message));
1016   self->data.time = time;
1017   self->severity = severity;
1018
1019   FreeAll();
1020   PyMem_Free(message);
1021
1022   if (meta == NULL) {
1023     meta = PyDict_New();
1024     PyErr_Clear();
1025   } else {
1026     Py_INCREF(meta);
1027   }
1028
1029   PyObject *tmp = self->meta;
1030   self->meta = meta;
1031   Py_XDECREF(tmp);
1032
1033   return 0;
1034 }
1035
1036 static PyObject *Notification_dispatch(Notification *self, PyObject *args,
1037                                        PyObject *kwds) {
1038   int ret;
1039   const data_set_t *ds;
1040   notification_t notification;
1041   double t = self->data.time;
1042   PyObject *meta = self->meta;
1043   int severity = self->severity;
1044   char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL,
1045        *type_instance = NULL;
1046   char *message = NULL;
1047
1048   static char *kwlist[] = {
1049       "type", "message", "plugin_instance", "type_instance", "plugin",
1050       "host", "time",    "severity",        "meta",          NULL};
1051   if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdiO", kwlist, NULL,
1052                                    &type, NULL, &message, NULL,
1053                                    &plugin_instance, NULL, &type_instance, NULL,
1054                                    &plugin, NULL, &host, &t, &severity, &meta))
1055     return NULL;
1056
1057   notification.time = DOUBLE_TO_CDTIME_T(t);
1058   notification.severity = severity;
1059   sstrncpy(notification.message, message ? message : self->message,
1060            sizeof(notification.message));
1061   sstrncpy(notification.host, host ? host : self->data.host,
1062            sizeof(notification.host));
1063   sstrncpy(notification.plugin, plugin ? plugin : self->data.plugin,
1064            sizeof(notification.plugin));
1065   sstrncpy(notification.plugin_instance,
1066            plugin_instance ? plugin_instance : self->data.plugin_instance,
1067            sizeof(notification.plugin_instance));
1068   sstrncpy(notification.type, type ? type : self->data.type,
1069            sizeof(notification.type));
1070   sstrncpy(notification.type_instance,
1071            type_instance ? type_instance : self->data.type_instance,
1072            sizeof(notification.type_instance));
1073   notification.meta = NULL;
1074   FreeAll();
1075   PyMem_Free(message);
1076
1077   if (notification.type[0] == 0) {
1078     PyErr_SetString(PyExc_RuntimeError, "type not set");
1079     return NULL;
1080   }
1081   ds = plugin_get_ds(notification.type);
1082   if (ds == NULL) {
1083     PyErr_Format(PyExc_TypeError, "Dataset %s not found", notification.type);
1084     return NULL;
1085   }
1086   if (meta != NULL && meta != Py_None && !PyDict_Check(meta)) {
1087     PyErr_Format(PyExc_TypeError, "meta must be a dict");
1088     return NULL;
1089   }
1090   cpy_build_notification_meta(&notification, meta);
1091
1092   if (notification.time == 0)
1093     notification.time = cdtime();
1094   if (notification.host[0] == 0)
1095     sstrncpy(notification.host, hostname_g, sizeof(notification.host));
1096   if (notification.plugin[0] == 0)
1097     sstrncpy(notification.plugin, "python", sizeof(notification.plugin));
1098   Py_BEGIN_ALLOW_THREADS;
1099   ret = plugin_dispatch_notification(&notification);
1100   if (notification.meta)
1101     plugin_notification_meta_free(notification.meta);
1102   Py_END_ALLOW_THREADS;
1103   if (ret != 0) {
1104     PyErr_SetString(PyExc_RuntimeError,
1105                     "error dispatching notification, read the logs");
1106     return NULL;
1107   }
1108   Py_RETURN_NONE;
1109 }
1110
1111 static PyObject *Notification_new(PyTypeObject *type, PyObject *args,
1112                                   PyObject *kwds) {
1113   Notification *self;
1114
1115   self = (Notification *)PluginData_new(type, args, kwds);
1116   if (self == NULL)
1117     return NULL;
1118
1119   self->meta = PyDict_New();
1120   self->message[0] = 0;
1121   self->severity = 0;
1122   return (PyObject *)self;
1123 }
1124
1125 static int Notification_setstring(PyObject *self, PyObject *value, void *data) {
1126   char *old;
1127   const char *new;
1128
1129   if (value == NULL) {
1130     PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
1131     return -1;
1132   }
1133   Py_INCREF(value);
1134   new = cpy_unicode_or_bytes_to_string(&value);
1135   if (new == NULL) {
1136     Py_DECREF(value);
1137     return -1;
1138   }
1139   old = ((char *)self) + (intptr_t)data;
1140   sstrncpy(old, new, NOTIF_MAX_MSG_LEN);
1141   Py_DECREF(value);
1142   return 0;
1143 }
1144
1145 static PyObject *Notification_repr(PyObject *s) {
1146   PyObject *ret, *tmp;
1147   static PyObject *l_severity, *l_message, *l_meta, *l_closing;
1148   Notification *self = (Notification *)s;
1149
1150   if (l_severity == NULL)
1151     l_severity = cpy_string_to_unicode_or_bytes(",severity=");
1152   if (l_message == NULL)
1153     l_message = cpy_string_to_unicode_or_bytes(",message=");
1154   if (l_meta == NULL)
1155     l_meta = cpy_string_to_unicode_or_bytes(",meta=");
1156   if (l_closing == NULL)
1157     l_closing = cpy_string_to_unicode_or_bytes(")");
1158
1159   if (l_severity == NULL || l_message == NULL || l_meta == NULL ||
1160       l_closing == NULL)
1161     return NULL;
1162
1163   ret = cpy_common_repr(s);
1164   if (self->severity != 0) {
1165     CPY_STRCAT(&ret, l_severity);
1166     tmp = PyInt_FromLong(self->severity);
1167     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
1168     CPY_STRCAT_AND_DEL(&ret, tmp);
1169   }
1170   if (self->message[0] != 0) {
1171     CPY_STRCAT(&ret, l_message);
1172     tmp = cpy_string_to_unicode_or_bytes(self->message);
1173     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
1174     CPY_STRCAT_AND_DEL(&ret, tmp);
1175   }
1176   if (self->meta &&
1177       (!PyDict_Check(self->meta) || PyDict_Size(self->meta) > 0)) {
1178     CPY_STRCAT(&ret, l_meta);
1179     tmp = PyObject_Repr(self->meta);
1180     CPY_STRCAT_AND_DEL(&ret, tmp);
1181   }
1182   CPY_STRCAT(&ret, l_closing);
1183   return ret;
1184 }
1185
1186 static int Notification_traverse(PyObject *self, visitproc visit, void *arg) {
1187   Notification *n = (Notification *)self;
1188   Py_VISIT(n->meta);
1189   return 0;
1190 }
1191
1192 static int Notification_clear(PyObject *self) {
1193   Notification *n = (Notification *)self;
1194   Py_CLEAR(n->meta);
1195   return 0;
1196 }
1197
1198 static void Notification_dealloc(PyObject *self) {
1199   Notification_clear(self);
1200   self->ob_type->tp_free(self);
1201 }
1202
1203 static PyMethodDef Notification_methods[] = {
1204     {"dispatch", (PyCFunction)Notification_dispatch,
1205      METH_VARARGS | METH_KEYWORDS, dispatch_doc},
1206     {NULL}};
1207
1208 static PyMemberDef Notification_members[] = {
1209     {"severity", T_INT, offsetof(Notification, severity), 0, severity_doc},
1210     {"meta", T_OBJECT_EX, offsetof(Notification, meta), 0,
1211      notification_meta_doc},
1212     {NULL}};
1213
1214 static PyGetSetDef Notification_getseters[] = {
1215     {"message", PluginData_getstring, Notification_setstring, message_doc,
1216      (void *)offsetof(Notification, message)},
1217     {NULL}};
1218
1219 PyTypeObject NotificationType = {
1220     CPY_INIT_TYPE "collectd.Notification", /* tp_name */
1221     sizeof(Notification),                  /* tp_basicsize */
1222     0,                                     /* Will be filled in later */
1223     Notification_dealloc,                  /* tp_dealloc */
1224     0,                                     /* tp_print */
1225     0,                                     /* tp_getattr */
1226     0,                                     /* tp_setattr */
1227     0,                                     /* tp_compare */
1228     Notification_repr,                     /* tp_repr */
1229     0,                                     /* tp_as_number */
1230     0,                                     /* tp_as_sequence */
1231     0,                                     /* tp_as_mapping */
1232     0,                                     /* tp_hash */
1233     0,                                     /* tp_call */
1234     0,                                     /* tp_str */
1235     0,                                     /* tp_getattro */
1236     0,                                     /* tp_setattro */
1237     0,                                     /* tp_as_buffer */
1238     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
1239     Notification_doc,                                              /* tp_doc */
1240     Notification_traverse,  /* tp_traverse */
1241     Notification_clear,     /* tp_clear */
1242     0,                      /* tp_richcompare */
1243     0,                      /* tp_weaklistoffset */
1244     0,                      /* tp_iter */
1245     0,                      /* tp_iternext */
1246     Notification_methods,   /* tp_methods */
1247     Notification_members,   /* tp_members */
1248     Notification_getseters, /* tp_getset */
1249     0,                      /* tp_base */
1250     0,                      /* tp_dict */
1251     0,                      /* tp_descr_get */
1252     0,                      /* tp_descr_set */
1253     0,                      /* tp_dictoffset */
1254     Notification_init,      /* tp_init */
1255     0,                      /* tp_alloc */
1256     Notification_new        /* tp_new */
1257 };
1258
1259 static char Signed_doc[] =
1260     "This is a long by another name. Use it in meta data dicts\n"
1261     "to choose the way it is stored in the meta data.";
1262
1263 PyTypeObject SignedType = {
1264     CPY_INIT_TYPE "collectd.Signed",          /* tp_name */
1265     sizeof(Signed),                           /* tp_basicsize */
1266     0,                                        /* Will be filled in later */
1267     0,                                        /* tp_dealloc */
1268     0,                                        /* tp_print */
1269     0,                                        /* tp_getattr */
1270     0,                                        /* tp_setattr */
1271     0,                                        /* tp_compare */
1272     0,                                        /* tp_repr */
1273     0,                                        /* tp_as_number */
1274     0,                                        /* tp_as_sequence */
1275     0,                                        /* tp_as_mapping */
1276     0,                                        /* tp_hash */
1277     0,                                        /* tp_call */
1278     0,                                        /* tp_str */
1279     0,                                        /* tp_getattro */
1280     0,                                        /* tp_setattro */
1281     0,                                        /* tp_as_buffer */
1282     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
1283     Signed_doc                                /* tp_doc */
1284 };
1285
1286 static char Unsigned_doc[] =
1287     "This is a long by another name. Use it in meta data dicts\n"
1288     "to choose the way it is stored in the meta data.";
1289
1290 PyTypeObject UnsignedType = {
1291     CPY_INIT_TYPE "collectd.Unsigned",        /* tp_name */
1292     sizeof(Unsigned),                         /* tp_basicsize */
1293     0,                                        /* Will be filled in later */
1294     0,                                        /* tp_dealloc */
1295     0,                                        /* tp_print */
1296     0,                                        /* tp_getattr */
1297     0,                                        /* tp_setattr */
1298     0,                                        /* tp_compare */
1299     0,                                        /* tp_repr */
1300     0,                                        /* tp_as_number */
1301     0,                                        /* tp_as_sequence */
1302     0,                                        /* tp_as_mapping */
1303     0,                                        /* tp_hash */
1304     0,                                        /* tp_call */
1305     0,                                        /* tp_str */
1306     0,                                        /* tp_getattro */
1307     0,                                        /* tp_setattro */
1308     0,                                        /* tp_as_buffer */
1309     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
1310     Unsigned_doc                              /* tp_doc */
1311 };