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