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
cpy_common_repr(PyObject * s)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
PluginData_new(PyTypeObject * type,PyObject * args,PyObject * kwds)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
PluginData_init(PyObject * s,PyObject * args,PyObject * kwds)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
PluginData_repr(PyObject * s)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
PluginData_getstring(PyObject * self,void * data)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
PluginData_setstring(PyObject * self,PyObject * value,void * data)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
PluginData_settype(PyObject * self,PyObject * value,void * data)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
Values_new(PyTypeObject * type,PyObject * args,PyObject * kwds)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
Values_init(PyObject * s,PyObject * args,PyObject * kwds)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
cpy_build_meta_generic(PyObject * meta,cpy_build_meta_handler_t * meta_func,void * m)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
cpy_build_meta(PyObject * meta)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
cpy_build_notification_meta(notification_t * n,PyObject * meta)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
Values_dispatch(Values * self,PyObject * args,PyObject * kwds)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
Values_write(Values * self,PyObject * args,PyObject * kwds)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
Values_repr(PyObject * s)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
Values_traverse(PyObject * self,visitproc visit,void * arg)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
Values_clear(PyObject * self)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
Values_dealloc(PyObject * self)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
Notification_init(PyObject * s,PyObject * args,PyObject * kwds)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
Notification_dispatch(Notification * self,PyObject * args,PyObject * kwds)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(¬ification, 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(¬ification);
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
Notification_new(PyTypeObject * type,PyObject * args,PyObject * kwds)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
Notification_setstring(PyObject * self,PyObject * value,void * data)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
Notification_repr(PyObject * s)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
Notification_traverse(PyObject * self,visitproc visit,void * arg)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
Notification_clear(PyObject * self)1192 static int Notification_clear(PyObject *self) {
1193 Notification *n = (Notification *)self;
1194 Py_CLEAR(n->meta);
1195 return 0;
1196 }
1197
Notification_dealloc(PyObject * self)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 };
1312