d459ea93468a029e3fe70725c25037da5569100b
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 **/
27 #include <Python.h>
28 #include <structmember.h>
30 #include "collectd.h"
31 #include "common.h"
33 #include "cpython.h"
35 static char time_doc[] = "This is the Unix timestap of the time this value was read.\n"
36 "For dispatching values this can be set to 0 which means \"now\".\n"
37 "This means the time the value is actually dispatched, not the time\n"
38 "it was set to 0.";
40 static char host_doc[] = "The hostname of the host this value was read from.\n"
41 "For dispatching this can be set to an empty string which means\n"
42 "the local hostname as defined in the collectd.conf.";
44 static char type_doc[] = "The type of this value. This type has to be defined\n"
45 "in your types.db. Attempting to set it to any other value will\n"
46 "raise a TypeError exception.\n"
47 "Assigning a type is mandetory, calling dispatch without doing\n"
48 "so will raise a RuntimeError exception.";
50 static char type_instance_doc[] = "";
52 static char plugin_doc[] = "The name of the plugin that read the data. Setting this\n"
53 "member to an empty string will insert \"python\" upon dispatching.";
55 static char plugin_instance_doc[] = "";
57 static char PluginData_doc[] = "This is an internal class that is the base for Values\n"
58 "and Notification. It is pretty useless by itself and was therefore not\n"
59 "exported to the collectd module.";
61 static PyObject *PluginData_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
62 PluginData *self;
64 self = (PluginData *) type->tp_alloc(type, 0);
65 if (self == NULL)
66 return NULL;
68 self->time = 0;
69 self->host[0] = 0;
70 self->plugin[0] = 0;
71 self->plugin_instance[0] = 0;
72 self->type[0] = 0;
73 self->type_instance[0] = 0;
74 return (PyObject *) self;
75 }
77 static int PluginData_init(PyObject *s, PyObject *args, PyObject *kwds) {
78 PluginData *self = (PluginData *) s;
79 double time = 0;
80 const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
81 static char *kwlist[] = {"type", "plugin_instance", "type_instance",
82 "plugin", "host", "time", NULL};
84 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sssssd", kwlist, &type,
85 &plugin_instance, &type_instance, &plugin, &host, &time))
86 return -1;
88 if (type[0] != 0 && plugin_get_ds(type) == NULL) {
89 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
90 return -1;
91 }
93 sstrncpy(self->host, host, sizeof(self->host));
94 sstrncpy(self->plugin, plugin, sizeof(self->plugin));
95 sstrncpy(self->plugin_instance, plugin_instance, sizeof(self->plugin_instance));
96 sstrncpy(self->type, type, sizeof(self->type));
97 sstrncpy(self->type_instance, type_instance, sizeof(self->type_instance));
99 self->time = time;
100 return 0;
101 }
103 static PyObject *PluginData_repr(PyObject *s) {
104 PyObject *ret, *tmp;
105 static PyObject *l_type = NULL, *l_type_instance = NULL, *l_plugin = NULL, *l_plugin_instance = NULL;
106 static PyObject *l_host = NULL, *l_time = NULL, *l_closing = NULL;
107 PluginData *self = (PluginData *) s;
109 if (l_type == NULL)
110 l_type = cpy_string_to_unicode_or_bytes("(type=");
111 if (l_type_instance == NULL)
112 l_type_instance = cpy_string_to_unicode_or_bytes(",type_instance=");
113 if (l_plugin == NULL)
114 l_plugin = cpy_string_to_unicode_or_bytes(",plugin=");
115 if (l_plugin_instance == NULL)
116 l_plugin_instance = cpy_string_to_unicode_or_bytes(",plugin_instance=");
117 if (l_host == NULL)
118 l_host = cpy_string_to_unicode_or_bytes(",host=");
119 if (l_time == NULL)
120 l_time = cpy_string_to_unicode_or_bytes(",time=");
121 if (l_closing == NULL)
122 l_closing = cpy_string_to_unicode_or_bytes(")");
124 if (!l_type || !l_type_instance || !l_plugin || !l_plugin_instance || !l_host || !l_time)
125 return NULL;
127 ret = cpy_string_to_unicode_or_bytes(s->ob_type->tp_name);
129 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, l_type);
130 tmp = cpy_string_to_unicode_or_bytes(self->type);
131 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
132 if (tmp)
133 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, tmp);
134 Py_XDECREF(tmp);
136 if (self->type_instance[0] != 0) {
137 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, l_type_instance);
138 tmp = cpy_string_to_unicode_or_bytes(self->type_instance);
139 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
140 if (tmp)
141 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, tmp);
142 Py_XDECREF(tmp);
143 }
145 if (self->plugin[0] != 0) {
146 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, l_plugin);
147 tmp = cpy_string_to_unicode_or_bytes(self->plugin);
148 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
149 if (tmp)
150 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, tmp);
151 Py_XDECREF(tmp);
152 }
154 if (self->plugin_instance[0] != 0) {
155 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, l_plugin_instance);
156 tmp = cpy_string_to_unicode_or_bytes(self->plugin_instance);
157 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
158 if (tmp)
159 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, tmp);
160 Py_XDECREF(tmp);
161 }
163 if (self->host[0] != 0) {
164 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, l_host);
165 tmp = cpy_string_to_unicode_or_bytes(self->host);
166 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
167 if (tmp)
168 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, tmp);
169 Py_XDECREF(tmp);
170 }
172 if (self->time != 0) {
173 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, l_time);
174 tmp = PyInt_FromLong(self->time);
175 CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
176 if (tmp)
177 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, tmp);
178 Py_XDECREF(tmp);
179 }
180 CPY_SUBSTITUTE(CPY_STRCAT, ret, ret, l_closing);
181 return ret;
182 }
184 static PyMemberDef PluginData_members[] = {
185 {"time", T_DOUBLE, offsetof(PluginData, time), 0, time_doc},
186 {NULL}
187 };
189 static PyObject *PluginData_getstring(PyObject *self, void *data) {
190 const char *value = ((char *) self) + (intptr_t) data;
192 return cpy_string_to_unicode_or_bytes(value);
193 }
195 static int PluginData_setstring(PyObject *self, PyObject *value, void *data) {
196 char *old;
197 const char *new;
199 if (value == NULL) {
200 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
201 return -1;
202 }
203 Py_INCREF(value);
204 new = cpy_unicode_or_bytes_to_string(&value);
205 if (new == NULL) {
206 Py_DECREF(value);
207 return -1;
208 }
209 old = ((char *) self) + (intptr_t) data;
210 sstrncpy(old, new, DATA_MAX_NAME_LEN);
211 Py_DECREF(value);
212 return 0;
213 }
215 static int PluginData_settype(PyObject *self, PyObject *value, void *data) {
216 char *old;
217 const char *new;
219 if (value == NULL) {
220 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
221 return -1;
222 }
223 Py_INCREF(value);
224 new = cpy_unicode_or_bytes_to_string(&value);
225 if (new == NULL) {
226 Py_DECREF(value);
227 return -1;
228 }
230 if (plugin_get_ds(new) == NULL) {
231 PyErr_Format(PyExc_TypeError, "Dataset %s not found", new);
232 Py_DECREF(value);
233 return -1;
234 }
236 old = ((char *) self) + (intptr_t) data;
237 sstrncpy(old, new, DATA_MAX_NAME_LEN);
238 Py_DECREF(value);
239 return 0;
240 }
242 static PyGetSetDef PluginData_getseters[] = {
243 {"host", PluginData_getstring, PluginData_setstring, host_doc, (void *) offsetof(PluginData, host)},
244 {"plugin", PluginData_getstring, PluginData_setstring, plugin_doc, (void *) offsetof(PluginData, plugin)},
245 {"plugin_instance", PluginData_getstring, PluginData_setstring, plugin_instance_doc, (void *) offsetof(PluginData, plugin_instance)},
246 {"type_instance", PluginData_getstring, PluginData_setstring, type_instance_doc, (void *) offsetof(PluginData, type_instance)},
247 {"type", PluginData_getstring, PluginData_settype, type_doc, (void *) offsetof(PluginData, type)},
248 {NULL}
249 };
251 PyTypeObject PluginDataType = {
252 CPY_INIT_TYPE
253 "collectd.PluginData", /* tp_name */
254 sizeof(PluginData), /* tp_basicsize */
255 0, /* Will be filled in later */
256 0, /* tp_dealloc */
257 0, /* tp_print */
258 0, /* tp_getattr */
259 0, /* tp_setattr */
260 0, /* tp_compare */
261 PluginData_repr, /* tp_repr */
262 0, /* tp_as_number */
263 0, /* tp_as_sequence */
264 0, /* tp_as_mapping */
265 0, /* tp_hash */
266 0, /* tp_call */
267 0, /* tp_str */
268 0, /* tp_getattro */
269 0, /* tp_setattro */
270 0, /* tp_as_buffer */
271 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE /*| Py_TPFLAGS_HAVE_GC*/, /*tp_flags*/
272 PluginData_doc, /* tp_doc */
273 0, /* tp_traverse */
274 0, /* tp_clear */
275 0, /* tp_richcompare */
276 0, /* tp_weaklistoffset */
277 0, /* tp_iter */
278 0, /* tp_iternext */
279 0, /* tp_methods */
280 PluginData_members, /* tp_members */
281 PluginData_getseters, /* tp_getset */
282 0, /* tp_base */
283 0, /* tp_dict */
284 0, /* tp_descr_get */
285 0, /* tp_descr_set */
286 0, /* tp_dictoffset */
287 PluginData_init, /* tp_init */
288 0, /* tp_alloc */
289 PluginData_new /* tp_new */
290 };
292 static char interval_doc[] = "The interval is the timespan in seconds between two submits for\n"
293 "the same data source. This value has to be a positive integer, so you can't\n"
294 "submit more than one value per second. If this member is set to a\n"
295 "non-positive value, the default value as specified in the config file will\n"
296 "be used (default: 10).\n"
297 "\n"
298 "If you submit values more often than the specified interval, the average\n"
299 "will be used. If you submit less values, your graphs will have gaps.";
301 static char values_doc[] = "These are the actual values that get dispatched to collectd.\n"
302 "It has to be a sequence (a tuple or list) of numbers.\n"
303 "The size of the sequence and the type of its content depend on the type\n"
304 "member your types.db file. For more information on this read the types.db\n"
305 "man page.\n"
306 "\n"
307 "If the sequence does not have the correct size upon dispatch a RuntimeError\n"
308 "exception will be raised. If the content of the sequence is not a number,\n"
309 "a TypeError exception will be raised.";
311 static char dispatch_doc[] = "dispatch([type][, values][, plugin_instance][, type_instance]"
312 "[, plugin][, host][, time][, interval]) -> None. Dispatch a value list.\n"
313 "\n"
314 "Dispatch this instance to the collectd process. The object has members\n"
315 "for each of the possible arguments for this method. For a detailed explanation\n"
316 "of these parameters see the member of the same same.\n"
317 "\n"
318 "If you do not submit a parameter the value saved in its member will be submitted.\n"
319 "If you do provide a parameter it will be used instead, without altering the member.";
321 static char write_doc[] = "write([destination][, type][, values][, plugin_instance][, type_instance]"
322 "[, plugin][, host][, time][, interval]) -> None. Dispatch a value list.\n"
323 "\n"
324 "Write this instance to a single plugin or all plugins if 'destination' is obmitted.\n"
325 "This will bypass the main collectd process and all filtering and caching.\n"
326 "Other than that it works similar to 'dispatch'. In most cases 'dispatch' should be\n"
327 "used instead of 'write'.\n";
329 static char Values_doc[] = "A Values object used for dispatching values to collectd and receiving values from write callbacks.";
331 static PyObject *Values_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
332 Values *self;
334 self = (Values *) PluginData_new(type, args, kwds);
335 if (self == NULL)
336 return NULL;
338 self->values = PyList_New(0);
339 self->interval = 0;
340 return (PyObject *) self;
341 }
343 static int Values_init(PyObject *s, PyObject *args, PyObject *kwds) {
344 Values *self = (Values *) s;
345 int interval = 0, ret;
346 double time = 0;
347 PyObject *values = NULL, *tmp;
348 const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
349 static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
350 "plugin", "host", "time", "interval", NULL};
352 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sOssssdi", kwlist,
353 &type, &values, &plugin_instance, &type_instance,
354 &plugin, &host, &time, &interval))
355 return -1;
357 tmp = Py_BuildValue("sssssd", type, plugin_instance, type_instance, plugin, host, time);
358 if (tmp == NULL)
359 return -1;
360 ret = PluginDataType.tp_init(s, tmp, NULL);
361 Py_DECREF(tmp);
362 if (ret != 0)
363 return -1;
365 if (values == NULL) {
366 values = PyList_New(0);
367 PyErr_Clear();
368 } else {
369 Py_INCREF(values);
370 }
372 tmp = self->values;
373 self->values = values;
374 Py_XDECREF(tmp);
376 self->interval = interval;
377 return 0;
378 }
380 static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
381 int i, ret;
382 const data_set_t *ds;
383 int size;
384 value_t *value;
385 value_list_t value_list = VALUE_LIST_INIT;
386 PyObject *values = self->values;
387 double time = self->data.time;
388 int interval = self->interval;
389 const char *host = self->data.host;
390 const char *plugin = self->data.plugin;
391 const char *plugin_instance = self->data.plugin_instance;
392 const char *type = self->data.type;
393 const char *type_instance = self->data.type_instance;
395 static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
396 "plugin", "host", "time", "interval", NULL};
397 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sOzsssdi", kwlist,
398 &type, &values, &plugin_instance, &type_instance,
399 &plugin, &host, &time, &interval))
400 return NULL;
402 if (type[0] == 0) {
403 PyErr_SetString(PyExc_RuntimeError, "type not set");
404 return NULL;
405 }
406 ds = plugin_get_ds(type);
407 if (ds == NULL) {
408 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
409 return NULL;
410 }
411 if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
412 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
413 return NULL;
414 }
415 size = (int) PySequence_Length(values);
416 if (size != ds->ds_num) {
417 PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %i", type, ds->ds_num, size);
418 return NULL;
419 }
420 value = malloc(size * sizeof(*value));
421 for (i = 0; i < size; ++i) {
422 PyObject *item, *num;
423 item = PySequence_GetItem(values, i);
424 if (ds->ds->type == DS_TYPE_COUNTER) {
425 num = PyNumber_Long(item);
426 if (num != NULL)
427 value[i].counter = PyLong_AsUnsignedLongLong(num);
428 } else if (ds->ds->type == DS_TYPE_GAUGE) {
429 num = PyNumber_Float(item);
430 if (num != NULL)
431 value[i].gauge = PyFloat_AsDouble(num);
432 } else if (ds->ds->type == DS_TYPE_DERIVE) {
433 /* This might overflow without raising an exception.
434 * Not much we can do about it */
435 num = PyNumber_Long(item);
436 if (num != NULL)
437 value[i].derive = PyLong_AsLongLong(num);
438 } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
439 /* This might overflow without raising an exception.
440 * Not much we can do about it */
441 num = PyNumber_Long(item);
442 if (num != NULL)
443 value[i].absolute = PyLong_AsUnsignedLongLong(num);
444 } else {
445 free(value);
446 PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds->type, type);
447 return NULL;
448 }
449 if (PyErr_Occurred() != NULL) {
450 free(value);
451 return NULL;
452 }
453 }
454 value_list.values = value;
455 value_list.values_len = size;
456 value_list.time = time;
457 value_list.interval = interval;
458 sstrncpy(value_list.host, host, sizeof(value_list.host));
459 sstrncpy(value_list.plugin, plugin, sizeof(value_list.plugin));
460 sstrncpy(value_list.plugin_instance, plugin_instance, sizeof(value_list.plugin_instance));
461 sstrncpy(value_list.type, type, sizeof(value_list.type));
462 sstrncpy(value_list.type_instance, type_instance, sizeof(value_list.type_instance));
463 value_list.meta = NULL;
464 if (value_list.host[0] == 0)
465 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
466 if (value_list.plugin[0] == 0)
467 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
468 Py_BEGIN_ALLOW_THREADS;
469 ret = plugin_dispatch_values(&value_list);
470 Py_END_ALLOW_THREADS;
471 if (ret != 0) {
472 PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
473 return NULL;
474 }
475 free(value);
476 Py_RETURN_NONE;
477 }
479 static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
480 int i, ret;
481 const data_set_t *ds;
482 int size;
483 value_t *value;
484 value_list_t value_list = VALUE_LIST_INIT;
485 PyObject *values = self->values;
486 double time = self->data.time;
487 int interval = self->interval;
488 const char *host = self->data.host;
489 const char *plugin = self->data.plugin;
490 const char *plugin_instance = self->data.plugin_instance;
491 const char *type = self->data.type;
492 const char *type_instance = self->data.type_instance;
493 const char *dest = NULL;
495 static char *kwlist[] = {"destination", "type", "values", "plugin_instance", "type_instance",
496 "plugin", "host", "time", "interval", NULL};
497 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sOssssdi", kwlist,
498 &type, &values, &plugin_instance, &type_instance,
499 &plugin, &host, &time, &interval))
500 return NULL;
502 if (type[0] == 0) {
503 PyErr_SetString(PyExc_RuntimeError, "type not set");
504 return NULL;
505 }
506 ds = plugin_get_ds(type);
507 if (ds == NULL) {
508 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
509 return NULL;
510 }
511 if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
512 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
513 return NULL;
514 }
515 size = (int) PySequence_Length(values);
516 if (size != ds->ds_num) {
517 PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %i", type, ds->ds_num, size);
518 return NULL;
519 }
520 value = malloc(size * sizeof(*value));
521 for (i = 0; i < size; ++i) {
522 PyObject *item, *num;
523 item = PySequence_GetItem(values, i);
524 if (ds->ds->type == DS_TYPE_COUNTER) {
525 num = PyNumber_Long(item);
526 if (num != NULL)
527 value[i].counter = PyLong_AsUnsignedLongLong(num);
528 } else if (ds->ds->type == DS_TYPE_GAUGE) {
529 num = PyNumber_Float(item);
530 if (num != NULL)
531 value[i].gauge = PyFloat_AsDouble(num);
532 } else if (ds->ds->type == DS_TYPE_DERIVE) {
533 /* This might overflow without raising an exception.
534 * Not much we can do about it */
535 num = PyNumber_Long(item);
536 if (num != NULL)
537 value[i].derive = PyLong_AsLongLong(num);
538 } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
539 /* This might overflow without raising an exception.
540 * Not much we can do about it */
541 num = PyNumber_Long(item);
542 if (num != NULL)
543 value[i].absolute = PyLong_AsUnsignedLongLong(num);
544 } else {
545 free(value);
546 PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds->type, type);
547 return NULL;
548 }
549 if (PyErr_Occurred() != NULL) {
550 free(value);
551 return NULL;
552 }
553 }
554 value_list.values = value;
555 value_list.values_len = size;
556 value_list.time = time;
557 value_list.interval = interval;
558 sstrncpy(value_list.host, host, sizeof(value_list.host));
559 sstrncpy(value_list.plugin, plugin, sizeof(value_list.plugin));
560 sstrncpy(value_list.plugin_instance, plugin_instance, sizeof(value_list.plugin_instance));
561 sstrncpy(value_list.type, type, sizeof(value_list.type));
562 sstrncpy(value_list.type_instance, type_instance, sizeof(value_list.type_instance));
563 value_list.meta = NULL;
564 if (value_list.host[0] == 0)
565 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
566 if (value_list.plugin[0] == 0)
567 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
568 Py_BEGIN_ALLOW_THREADS;
569 ret = plugin_write(dest, NULL, &value_list);
570 Py_END_ALLOW_THREADS;
571 if (ret != 0) {
572 PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
573 return NULL;
574 }
575 free(value);
576 Py_RETURN_NONE;
577 }
579 /*static PyObject *Values_repr(PyObject *s) {
580 PyObject *ret, *valuestring = NULL;
581 Values *self = (Values *) s;
583 if (self->values != NULL)
584 valuestring = PyObject_Repr(self->values);
585 if (valuestring == NULL)
586 return NULL;
588 ret = PyString_FromFormat("collectd.Values(type='%s%s%s%s%s%s%s%s%s',time=%lu,interval=%i,values=%s)", self->data.type,
589 *self->data.type_instance ? "',type_instance='" : "", self->data.type_instance,
590 *self->data.plugin ? "',plugin='" : "", self->data.plugin,
591 *self->data.plugin_instance ? "',plugin_instance='" : "", self->data.plugin_instance,
592 *self->data.host ? "',host='" : "", self->data.host,
593 (long unsigned) self->data.time, self->interval,
594 valuestring ? cpy_unicode_or_bytes_to_string(valuestring) : "[]");
595 Py_XDECREF(valuestring);
596 return ret;
597 }*/
599 static int Values_traverse(PyObject *self, visitproc visit, void *arg) {
600 Values *v = (Values *) self;
601 Py_VISIT(v->values);
602 return 0;
603 }
605 static int Values_clear(PyObject *self) {
606 Values *v = (Values *) self;
607 Py_CLEAR(v->values);
608 return 0;
609 }
611 static void Values_dealloc(PyObject *self) {
612 Values_clear(self);
613 self->ob_type->tp_free(self);
614 }
616 static PyMemberDef Values_members[] = {
617 {"interval", T_INT, offsetof(Values, interval), 0, interval_doc},
618 {"values", T_OBJECT_EX, offsetof(Values, values), 0, values_doc},
619 {NULL}
620 };
622 static PyMethodDef Values_methods[] = {
623 {"dispatch", (PyCFunction) Values_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
624 {"write", (PyCFunction) Values_write, METH_VARARGS | METH_KEYWORDS, write_doc},
625 {NULL}
626 };
628 PyTypeObject ValuesType = {
629 CPY_INIT_TYPE
630 "collectd.Values", /* tp_name */
631 sizeof(Values), /* tp_basicsize */
632 0, /* Will be filled in later */
633 Values_dealloc, /* tp_dealloc */
634 0, /* tp_print */
635 0, /* tp_getattr */
636 0, /* tp_setattr */
637 0, /* tp_compare */
638 0/*Values_repr*/, /* tp_repr */
639 0, /* tp_as_number */
640 0, /* tp_as_sequence */
641 0, /* tp_as_mapping */
642 0, /* tp_hash */
643 0, /* tp_call */
644 0, /* tp_str */
645 0, /* tp_getattro */
646 0, /* tp_setattro */
647 0, /* tp_as_buffer */
648 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
649 Values_doc, /* tp_doc */
650 Values_traverse, /* tp_traverse */
651 Values_clear, /* tp_clear */
652 0, /* tp_richcompare */
653 0, /* tp_weaklistoffset */
654 0, /* tp_iter */
655 0, /* tp_iternext */
656 Values_methods, /* tp_methods */
657 Values_members, /* tp_members */
658 0, /* tp_getset */
659 0, /* tp_base */
660 0, /* tp_dict */
661 0, /* tp_descr_get */
662 0, /* tp_descr_set */
663 0, /* tp_dictoffset */
664 Values_init, /* tp_init */
665 0, /* tp_alloc */
666 Values_new /* tp_new */
667 };
669 static char severity_doc[] = "The severity of this notification. Assign or compare to\n"
670 "NOTIF_FAILURE, NOTIF_WARNING or NOTIF_OKAY.";
672 static char message_doc[] = "Some kind of description what's going on and why this Notification was generated.";
674 static char Notification_doc[] = "The Notification class is a wrapper around the collectd notification.\n"
675 "It can be used to notify other plugins about bad stuff happening. It works\n"
676 "similar to Values but has a severity and a message instead of interval\n"
677 "and time.\n"
678 "Notifications can be dispatched at any time and can be received with register_notification.";
680 static int Notification_init(PyObject *s, PyObject *args, PyObject *kwds) {
681 Notification *self = (Notification *) s;
682 PyObject *tmp;
683 int severity = 0, ret;
684 double time = 0;
685 const char *message = "";
686 const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
687 static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
688 "plugin", "host", "time", "severity", NULL};
690 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ssssssdi", kwlist,
691 &type, &message, &plugin_instance, &type_instance,
692 &plugin, &host, &time, &severity))
693 return -1;
695 tmp = Py_BuildValue("sssssd", type, plugin_instance, type_instance, plugin, host, time);
696 if (tmp == NULL)
697 return -1;
698 ret = PluginDataType.tp_init(s, tmp, NULL);
699 Py_DECREF(tmp);
700 if (ret != 0)
701 return -1;
703 sstrncpy(self->message, message, sizeof(self->message));
704 self->severity = severity;
705 return 0;
706 }
708 static PyObject *Notification_dispatch(Notification *self, PyObject *args, PyObject *kwds) {
709 int ret;
710 const data_set_t *ds;
711 notification_t notification;
712 double t = self->data.time;
713 int severity = self->severity;
714 const char *host = self->data.host;
715 const char *plugin = self->data.plugin;
716 const char *plugin_instance = self->data.plugin_instance;
717 const char *type = self->data.type;
718 const char *type_instance = self->data.type_instance;
719 const char *message = self->message;
721 static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
722 "plugin", "host", "time", "severity", NULL};
723 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ssssssdi", kwlist,
724 &type, &message, &plugin_instance, &type_instance,
725 &plugin, &host, &t, &severity))
726 return NULL;
728 if (type[0] == 0) {
729 PyErr_SetString(PyExc_RuntimeError, "type not set");
730 return NULL;
731 }
732 ds = plugin_get_ds(type);
733 if (ds == NULL) {
734 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
735 return NULL;
736 }
738 notification.time = t;
739 notification.severity = severity;
740 sstrncpy(notification.message, message, sizeof(notification.message));
741 sstrncpy(notification.host, host, sizeof(notification.host));
742 sstrncpy(notification.plugin, plugin, sizeof(notification.plugin));
743 sstrncpy(notification.plugin_instance, plugin_instance, sizeof(notification.plugin_instance));
744 sstrncpy(notification.type, type, sizeof(notification.type));
745 sstrncpy(notification.type_instance, type_instance, sizeof(notification.type_instance));
746 notification.meta = NULL;
747 if (notification.time < 1)
748 notification.time = time(0);
749 if (notification.host[0] == 0)
750 sstrncpy(notification.host, hostname_g, sizeof(notification.host));
751 if (notification.plugin[0] == 0)
752 sstrncpy(notification.plugin, "python", sizeof(notification.plugin));
753 Py_BEGIN_ALLOW_THREADS;
754 ret = plugin_dispatch_notification(¬ification);
755 Py_END_ALLOW_THREADS;
756 if (ret != 0) {
757 PyErr_SetString(PyExc_RuntimeError, "error dispatching notification, read the logs");
758 return NULL;
759 }
760 Py_RETURN_NONE;
761 }
763 static PyObject *Notification_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
764 Notification *self;
766 self = (Notification *) PluginData_new(type, args, kwds);
767 if (self == NULL)
768 return NULL;
770 self->message[0] = 0;
771 self->severity = 0;
772 return (PyObject *) self;
773 }
775 static int Notification_setstring(PyObject *self, PyObject *value, void *data) {
776 char *old;
777 const char *new;
779 if (value == NULL) {
780 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
781 return -1;
782 }
783 Py_INCREF(value);
784 new = cpy_unicode_or_bytes_to_string(&value);
785 if (new == NULL) {
786 Py_DECREF(value);
787 return -1;
788 }
789 old = ((char *) self) + (intptr_t) data;
790 sstrncpy(old, new, NOTIF_MAX_MSG_LEN);
791 Py_DECREF(value);
792 return 0;
793 }
795 /*static PyObject *Notification_repr(PyObject *s) {
796 PyObject *ret;
797 Notification *self = (Notification *) s;
799 ret = PyString_FromFormat("collectd.Values(type='%s%s%s%s%s%s%s%s%s%s%s',time=%lu,interval=%i)", self->data.type,
800 *self->data.type_instance ? "',type_instance='" : "", self->data.type_instance,
801 *self->data.plugin ? "',plugin='" : "", self->data.plugin,
802 *self->data.plugin_instance ? "',plugin_instance='" : "", self->data.plugin_instance,
803 *self->data.host ? "',host='" : "", self->data.host,
804 *self->message ? "',message='" : "", self->message,
805 (long unsigned) self->data.time, self->severity);
806 return ret;
807 }*/
809 static PyMethodDef Notification_methods[] = {
810 {"dispatch", (PyCFunction) Notification_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
811 {NULL}
812 };
814 static PyMemberDef Notification_members[] = {
815 {"severity", T_INT, offsetof(Notification, severity), 0, severity_doc},
816 {NULL}
817 };
819 static PyGetSetDef Notification_getseters[] = {
820 {"message", PluginData_getstring, Notification_setstring, message_doc, (void *) offsetof(Notification, message)},
821 {NULL}
822 };
824 PyTypeObject NotificationType = {
825 CPY_INIT_TYPE
826 "collectd.Notification", /* tp_name */
827 sizeof(Notification), /* tp_basicsize */
828 0, /* Will be filled in later */
829 0, /* tp_dealloc */
830 0, /* tp_print */
831 0, /* tp_getattr */
832 0, /* tp_setattr */
833 0, /* tp_compare */
834 0/*Notification_repr*/, /* tp_repr */
835 0, /* tp_as_number */
836 0, /* tp_as_sequence */
837 0, /* tp_as_mapping */
838 0, /* tp_hash */
839 0, /* tp_call */
840 0, /* tp_str */
841 0, /* tp_getattro */
842 0, /* tp_setattro */
843 0, /* tp_as_buffer */
844 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
845 Notification_doc, /* tp_doc */
846 0, /* tp_traverse */
847 0, /* tp_clear */
848 0, /* tp_richcompare */
849 0, /* tp_weaklistoffset */
850 0, /* tp_iter */
851 0, /* tp_iternext */
852 Notification_methods, /* tp_methods */
853 Notification_members, /* tp_members */
854 Notification_getseters, /* tp_getset */
855 0, /* tp_base */
856 0, /* tp_dict */
857 0, /* tp_descr_get */
858 0, /* tp_descr_set */
859 0, /* tp_dictoffset */
860 Notification_init, /* tp_init */
861 0, /* tp_alloc */
862 Notification_new /* tp_new */
863 };