9542a40b07e6feae448747296e52309bcdc4c53c
1 #include <Python.h>
2 #include <structmember.h>
4 #include "collectd.h"
5 #include "common.h"
7 #include "cpython.h"
9 static char time_doc[] = "This is the Unix timestap of the time this value was read.\n"
10 "For dispatching values this can be set to 0 which means \"now\".\n"
11 "This means the time the value is actually dispatched, not the time\n"
12 "it was set to 0.";
14 static char host_doc[] = "The hostname of the host this value was read from.\n"
15 "For dispatching this can be set to an empty string which means\n"
16 "the local hostname as defined in the collectd.conf.";
18 static char type_doc[] = "The type of this value. This type has to be defined\n"
19 "in your types.db. Attempting to set it to any other value will\n"
20 "raise a TypeError exception.\n"
21 "Assigning a type is mandetory, calling dispatch without doing\n"
22 "so will raise a RuntimeError exception.";
24 static char type_instance_doc[] = "";
26 static char plugin_doc[] = "The name of the plugin that read the data. Setting this\n"
27 "member to an empty string will insert \"python\" upon dispatching.";
29 static char plugin_instance_doc[] = "";
31 static char PluginData_doc[] = "This is an internal class that is the base for Values\n"
32 "and Notification. It is pretty useless by itself and was therefore not\n"
33 "exported to the collectd module.";
35 static PyObject *PluginData_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
36 PluginData *self;
38 self = (PluginData *) type->tp_alloc(type, 0);
39 if (self == NULL)
40 return NULL;
42 self->time = 0;
43 self->host[0] = 0;
44 self->plugin[0] = 0;
45 self->plugin_instance[0] = 0;
46 self->type[0] = 0;
47 self->type_instance[0] = 0;
48 return (PyObject *) self;
49 }
51 static int PluginData_init(PyObject *s, PyObject *args, PyObject *kwds) {
52 PluginData *self = (PluginData *) s;
53 double time = 0;
54 const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
55 static char *kwlist[] = {"type", "plugin_instance", "type_instance",
56 "plugin", "host", "time", NULL};
58 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sssssd", kwlist, &type,
59 &plugin_instance, &type_instance, &plugin, &host, &time))
60 return -1;
62 if (type[0] != 0 && plugin_get_ds(type) == NULL) {
63 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
64 return -1;
65 }
67 sstrncpy(self->host, host, sizeof(self->host));
68 sstrncpy(self->plugin, plugin, sizeof(self->plugin));
69 sstrncpy(self->plugin_instance, plugin_instance, sizeof(self->plugin_instance));
70 sstrncpy(self->type, type, sizeof(self->type));
71 sstrncpy(self->type_instance, type_instance, sizeof(self->type_instance));
73 self->time = time;
74 return 0;
75 }
77 static PyObject *PluginData_repr(PyObject *s) {
78 PluginData *self = (PluginData *) s;
80 return PyString_FromFormat("collectd.Values(type='%s%s%s%s%s%s%s%s%s',time=%lu)", self->type,
81 *self->type_instance ? "',type_instance='" : "", self->type_instance,
82 *self->plugin ? "',plugin='" : "", self->plugin,
83 *self->plugin_instance ? "',plugin_instance='" : "", self->plugin_instance,
84 *self->host ? "',host='" : "", self->host,
85 (long unsigned) self->time);
86 }
88 static PyMemberDef PluginData_members[] = {
89 {"time", T_DOUBLE, offsetof(PluginData, time), 0, time_doc},
90 {NULL}
91 };
93 static PyObject *PluginData_getstring(PyObject *self, void *data) {
94 const char *value = ((char *) self) + (int) data;
96 return PyString_FromString(value);
97 }
99 static int PluginData_setstring(PyObject *self, PyObject *value, void *data) {
100 char *old;
101 const char *new;
103 if (value == NULL) {
104 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
105 return -1;
106 }
107 new = PyString_AsString(value);
108 if (new == NULL) return -1;
109 old = ((char *) self) + (int) data;
110 sstrncpy(old, new, DATA_MAX_NAME_LEN);
111 return 0;
112 }
114 static int PluginData_settype(PyObject *self, PyObject *value, void *data) {
115 char *old;
116 const char *new;
118 if (value == NULL) {
119 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
120 return -1;
121 }
122 new = PyString_AsString(value);
123 if (new == NULL) return -1;
125 if (plugin_get_ds(new) == NULL) {
126 PyErr_Format(PyExc_TypeError, "Dataset %s not found", new);
127 return -1;
128 }
130 old = ((char *) self) + (int) data;
131 sstrncpy(old, new, DATA_MAX_NAME_LEN);
132 return 0;
133 }
135 static PyGetSetDef PluginData_getseters[] = {
136 {"host", PluginData_getstring, PluginData_setstring, host_doc, (void *) offsetof(PluginData, host)},
137 {"plugin", PluginData_getstring, PluginData_setstring, plugin_doc, (void *) offsetof(PluginData, plugin)},
138 {"plugin_instance", PluginData_getstring, PluginData_setstring, plugin_instance_doc, (void *) offsetof(PluginData, plugin_instance)},
139 {"type_instance", PluginData_getstring, PluginData_setstring, type_instance_doc, (void *) offsetof(PluginData, type_instance)},
140 {"type", PluginData_getstring, PluginData_settype, type_doc, (void *) offsetof(PluginData, type)},
141 {NULL}
142 };
144 PyTypeObject PluginDataType = {
145 PyObject_HEAD_INIT(NULL)
146 0, /* Always 0 */
147 "collectd.PluginData", /* tp_name */
148 sizeof(PluginData), /* tp_basicsize */
149 0, /* Will be filled in later */
150 0, /* tp_dealloc */
151 0, /* tp_print */
152 0, /* tp_getattr */
153 0, /* tp_setattr */
154 0, /* tp_compare */
155 PluginData_repr, /* tp_repr */
156 0, /* tp_as_number */
157 0, /* tp_as_sequence */
158 0, /* tp_as_mapping */
159 0, /* tp_hash */
160 0, /* tp_call */
161 0, /* tp_str */
162 0, /* tp_getattro */
163 0, /* tp_setattro */
164 0, /* tp_as_buffer */
165 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE /*| Py_TPFLAGS_HAVE_GC*/, /*tp_flags*/
166 PluginData_doc, /* tp_doc */
167 0, /* tp_traverse */
168 0, /* tp_clear */
169 0, /* tp_richcompare */
170 0, /* tp_weaklistoffset */
171 0, /* tp_iter */
172 0, /* tp_iternext */
173 0, /* tp_methods */
174 PluginData_members, /* tp_members */
175 PluginData_getseters, /* tp_getset */
176 0, /* tp_base */
177 0, /* tp_dict */
178 0, /* tp_descr_get */
179 0, /* tp_descr_set */
180 0, /* tp_dictoffset */
181 PluginData_init, /* tp_init */
182 0, /* tp_alloc */
183 PluginData_new /* tp_new */
184 };
186 static char interval_doc[] = "The interval is the timespan in seconds between two submits for\n"
187 "the same data source. This value has to be a positive integer, so you can't\n"
188 "submit more than one value per second. If this member is set to a\n"
189 "non-positive value, the default value as specified in the config file will\n"
190 "be used (default: 10).\n"
191 "\n"
192 "If you submit values more often than the specified interval, the average\n"
193 "will be used. If you submit less values, your graphs will have gaps.";
195 static char values_doc[] = "These are the actual values that get dispatched to collectd.\n"
196 "It has to be a sequence (a tuple or list) of numbers.\n"
197 "The size of the sequence and the type of its content depend on the type\n"
198 "member your types.db file. For more information on this read the types.db\n"
199 "man page.\n"
200 "\n"
201 "If the sequence does not have the correct size upon dispatch a RuntimeError\n"
202 "exception will be raised. If the content of the sequence is not a number,\n"
203 "a TypeError exception will be raised.";
205 static char dispatch_doc[] = "dispatch([type][, values][, plugin_instance][, type_instance]"
206 "[, plugin][, host][, time][, interval]) -> None. Dispatch a value list.\n"
207 "\n"
208 "Dispatch this instance to the collectd process. The object has members\n"
209 "for each of the possible arguments for this method. For a detailed explanation\n"
210 "of these parameters see the member of the same same.\n"
211 "\n"
212 "If you do not submit a parameter the value saved in its member will be submitted.\n"
213 "If you do provide a parameter it will be used instead, without altering the member.";
215 static char write_doc[] = "write([destination][, type][, values][, plugin_instance][, type_instance]"
216 "[, plugin][, host][, time][, interval]) -> None. Dispatch a value list.\n"
217 "\n"
218 "Write this instance to a single plugin or all plugins if 'destination' is obmitted.\n"
219 "This will bypass the main collectd process and all filtering and caching.\n"
220 "Other than that it works similar to 'dispatch'. In most cases 'dispatch' should be\n"
221 "used instead of 'write'.\n";
223 static char Values_doc[] = "A Values object used for dispatching values to collectd and receiving values from write callbacks.";
225 static PyObject *Values_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
226 Values *self;
228 self = (Values *) PluginData_new(type, args, kwds);
229 if (self == NULL)
230 return NULL;
232 self->values = PyList_New(0);
233 self->interval = 0;
234 return (PyObject *) self;
235 }
237 static int Values_init(PyObject *s, PyObject *args, PyObject *kwds) {
238 Values *self = (Values *) s;
239 int interval = 0, ret;
240 double time = 0;
241 PyObject *values = NULL, *tmp;
242 const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
243 static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
244 "plugin", "host", "time", "interval", NULL};
246 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sOssssdi", kwlist,
247 &type, &values, &plugin_instance, &type_instance,
248 &plugin, &host, &time, &interval))
249 return -1;
251 tmp = Py_BuildValue("sssssd", type, plugin_instance, type_instance, plugin, host, time);
252 if (tmp == NULL)
253 return -1;
254 ret = PluginDataType.tp_init(s, tmp, NULL);
255 Py_DECREF(tmp);
256 if (ret != 0)
257 return -1;
259 if (values == NULL) {
260 values = PyList_New(0);
261 PyErr_Clear();
262 } else {
263 Py_INCREF(values);
264 }
266 tmp = self->values;
267 self->values = values;
268 Py_XDECREF(tmp);
270 self->interval = interval;
271 return 0;
272 }
274 static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
275 int i, ret;
276 const data_set_t *ds;
277 Py_ssize_t size;
278 value_t *value;
279 value_list_t value_list = VALUE_LIST_INIT;
280 PyObject *values = self->values;
281 double time = self->data.time;
282 int interval = self->interval;
283 const char *host = self->data.host;
284 const char *plugin = self->data.plugin;
285 const char *plugin_instance = self->data.plugin_instance;
286 const char *type = self->data.type;
287 const char *type_instance = self->data.type_instance;
289 static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
290 "plugin", "host", "time", "interval", NULL};
291 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sOssssdi", kwlist,
292 &type, &values, &plugin_instance, &type_instance,
293 &plugin, &host, &time, &interval))
294 return NULL;
296 if (type[0] == 0) {
297 PyErr_SetString(PyExc_RuntimeError, "type not set");
298 return NULL;
299 }
300 ds = plugin_get_ds(type);
301 if (ds == NULL) {
302 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
303 return NULL;
304 }
305 if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
306 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
307 return NULL;
308 }
309 size = PySequence_Length(values);
310 if (size != ds->ds_num) {
311 PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %zd", type, ds->ds_num, size);
312 return NULL;
313 }
314 value = malloc(size * sizeof(*value));
315 for (i = 0; i < size; ++i) {
316 PyObject *item, *num;
317 item = PySequence_GetItem(values, i);
318 if (ds->ds->type == DS_TYPE_COUNTER) {
319 num = PyNumber_Long(item);
320 if (num != NULL)
321 value[i].counter = PyLong_AsUnsignedLongLong(num);
322 } else if (ds->ds->type == DS_TYPE_GAUGE) {
323 num = PyNumber_Float(item);
324 if (num != NULL)
325 value[i].gauge = PyFloat_AsDouble(num);
326 } else if (ds->ds->type == DS_TYPE_DERIVE) {
327 /* This might overflow without raising an exception.
328 * Not much we can do about it */
329 num = PyNumber_Long(item);
330 if (num != NULL)
331 value[i].derive = PyLong_AsLongLong(num);
332 } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
333 /* This might overflow without raising an exception.
334 * Not much we can do about it */
335 num = PyNumber_Long(item);
336 if (num != NULL)
337 value[i].absolute = PyLong_AsUnsignedLongLong(num);
338 } else {
339 free(value);
340 PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds->type, type);
341 return NULL;
342 }
343 if (PyErr_Occurred() != NULL) {
344 free(value);
345 return NULL;
346 }
347 }
348 value_list.values = value;
349 value_list.values_len = size;
350 value_list.time = time;
351 value_list.interval = interval;
352 sstrncpy(value_list.host, host, sizeof(value_list.host));
353 sstrncpy(value_list.plugin, plugin, sizeof(value_list.plugin));
354 sstrncpy(value_list.plugin_instance, plugin_instance, sizeof(value_list.plugin_instance));
355 sstrncpy(value_list.type, type, sizeof(value_list.type));
356 sstrncpy(value_list.type_instance, type_instance, sizeof(value_list.type_instance));
357 value_list.meta = NULL;
358 if (value_list.host[0] == 0)
359 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
360 if (value_list.plugin[0] == 0)
361 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
362 Py_BEGIN_ALLOW_THREADS;
363 ret = plugin_dispatch_values(&value_list);
364 Py_END_ALLOW_THREADS;
365 if (ret != 0) {
366 PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
367 return NULL;
368 }
369 free(value);
370 Py_RETURN_NONE;
371 }
373 static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
374 int i, ret;
375 const data_set_t *ds;
376 Py_ssize_t size;
377 value_t *value;
378 value_list_t value_list = VALUE_LIST_INIT;
379 PyObject *values = self->values;
380 double time = self->data.time;
381 int interval = self->interval;
382 const char *host = self->data.host;
383 const char *plugin = self->data.plugin;
384 const char *plugin_instance = self->data.plugin_instance;
385 const char *type = self->data.type;
386 const char *type_instance = self->data.type_instance;
387 const char *dest = NULL;
389 static char *kwlist[] = {"destination", "type", "values", "plugin_instance", "type_instance",
390 "plugin", "host", "time", "interval", NULL};
391 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sOssssdi", kwlist,
392 &type, &values, &plugin_instance, &type_instance,
393 &plugin, &host, &time, &interval))
394 return NULL;
396 if (type[0] == 0) {
397 PyErr_SetString(PyExc_RuntimeError, "type not set");
398 return NULL;
399 }
400 ds = plugin_get_ds(type);
401 if (ds == NULL) {
402 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
403 return NULL;
404 }
405 if (values == NULL || (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
406 PyErr_Format(PyExc_TypeError, "values must be list or tuple");
407 return NULL;
408 }
409 size = PySequence_Length(values);
410 if (size != ds->ds_num) {
411 PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %zd", type, ds->ds_num, size);
412 return NULL;
413 }
414 value = malloc(size * sizeof(*value));
415 for (i = 0; i < size; ++i) {
416 PyObject *item, *num;
417 item = PySequence_GetItem(values, i);
418 if (ds->ds->type == DS_TYPE_COUNTER) {
419 num = PyNumber_Long(item);
420 if (num != NULL)
421 value[i].counter = PyLong_AsUnsignedLongLong(num);
422 } else if (ds->ds->type == DS_TYPE_GAUGE) {
423 num = PyNumber_Float(item);
424 if (num != NULL)
425 value[i].gauge = PyFloat_AsDouble(num);
426 } else if (ds->ds->type == DS_TYPE_DERIVE) {
427 /* This might overflow without raising an exception.
428 * Not much we can do about it */
429 num = PyNumber_Long(item);
430 if (num != NULL)
431 value[i].derive = PyLong_AsLongLong(num);
432 } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
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].absolute = PyLong_AsUnsignedLongLong(num);
438 } else {
439 free(value);
440 PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds->type, type);
441 return NULL;
442 }
443 if (PyErr_Occurred() != NULL) {
444 free(value);
445 return NULL;
446 }
447 }
448 value_list.values = value;
449 value_list.values_len = size;
450 value_list.time = time;
451 value_list.interval = interval;
452 sstrncpy(value_list.host, host, sizeof(value_list.host));
453 sstrncpy(value_list.plugin, plugin, sizeof(value_list.plugin));
454 sstrncpy(value_list.plugin_instance, plugin_instance, sizeof(value_list.plugin_instance));
455 sstrncpy(value_list.type, type, sizeof(value_list.type));
456 sstrncpy(value_list.type_instance, type_instance, sizeof(value_list.type_instance));
457 value_list.meta = NULL;
458 if (value_list.host[0] == 0)
459 sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
460 if (value_list.plugin[0] == 0)
461 sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
462 Py_BEGIN_ALLOW_THREADS;
463 ret = plugin_write(dest, NULL, &value_list);
464 Py_END_ALLOW_THREADS;
465 if (ret != 0) {
466 PyErr_SetString(PyExc_RuntimeError, "error dispatching values, read the logs");
467 return NULL;
468 }
469 free(value);
470 Py_RETURN_NONE;
471 }
473 static PyObject *Values_repr(PyObject *s) {
474 PyObject *ret, *valuestring = NULL;
475 Values *self = (Values *) s;
477 if (self->values != NULL)
478 valuestring = PyObject_Repr(self->values);
479 if (valuestring == NULL)
480 return NULL;
482 ret = PyString_FromFormat("collectd.Values(type='%s%s%s%s%s%s%s%s%s',time=%lu,interval=%i,values=%s)", self->data.type,
483 *self->data.type_instance ? "',type_instance='" : "", self->data.type_instance,
484 *self->data.plugin ? "',plugin='" : "", self->data.plugin,
485 *self->data.plugin_instance ? "',plugin_instance='" : "", self->data.plugin_instance,
486 *self->data.host ? "',host='" : "", self->data.host,
487 (long unsigned) self->data.time, self->interval,
488 valuestring ? PyString_AsString(valuestring) : "[]");
489 Py_XDECREF(valuestring);
490 return ret;
491 }
493 static int Values_traverse(PyObject *self, visitproc visit, void *arg) {
494 Values *v = (Values *) self;
495 Py_VISIT(v->values);
496 return 0;
497 }
499 static int Values_clear(PyObject *self) {
500 Values *v = (Values *) self;
501 Py_CLEAR(v->values);
502 return 0;
503 }
505 static void Values_dealloc(PyObject *self) {
506 Values_clear(self);
507 self->ob_type->tp_free(self);
508 }
510 static PyMemberDef Values_members[] = {
511 {"interval", T_INT, offsetof(Values, interval), 0, interval_doc},
512 {"values", T_OBJECT_EX, offsetof(Values, values), 0, values_doc},
513 {NULL}
514 };
516 static PyMethodDef Values_methods[] = {
517 {"dispatch", (PyCFunction) Values_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
518 {"write", (PyCFunction) Values_write, METH_VARARGS | METH_KEYWORDS, write_doc},
519 {NULL}
520 };
522 PyTypeObject ValuesType = {
523 PyObject_HEAD_INIT(NULL)
524 0, /* Always 0 */
525 "collectd.Values", /* tp_name */
526 sizeof(Values), /* tp_basicsize */
527 0, /* Will be filled in later */
528 Values_dealloc, /* tp_dealloc */
529 0, /* tp_print */
530 0, /* tp_getattr */
531 0, /* tp_setattr */
532 0, /* tp_compare */
533 Values_repr, /* tp_repr */
534 0, /* tp_as_number */
535 0, /* tp_as_sequence */
536 0, /* tp_as_mapping */
537 0, /* tp_hash */
538 0, /* tp_call */
539 0, /* tp_str */
540 0, /* tp_getattro */
541 0, /* tp_setattro */
542 0, /* tp_as_buffer */
543 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
544 Values_doc, /* tp_doc */
545 Values_traverse, /* tp_traverse */
546 Values_clear, /* tp_clear */
547 0, /* tp_richcompare */
548 0, /* tp_weaklistoffset */
549 0, /* tp_iter */
550 0, /* tp_iternext */
551 Values_methods, /* tp_methods */
552 Values_members, /* tp_members */
553 0, /* tp_getset */
554 0, /* tp_base */
555 0, /* tp_dict */
556 0, /* tp_descr_get */
557 0, /* tp_descr_set */
558 0, /* tp_dictoffset */
559 Values_init, /* tp_init */
560 0, /* tp_alloc */
561 Values_new /* tp_new */
562 };
564 static char severity_doc[] = "The severity of this notification. Assign or compare to\n"
565 "NOTIF_FAILURE, NOTIF_WARNING or NOTIF_OKAY.";
567 static char message_doc[] = "Some kind of description what's going on and why this Notification was generated.";
569 static char Notification_doc[] = "The Notification class is a wrapper around the collectd notification.\n"
570 "It can be used to notify other plugins about bad stuff happening. It works\n"
571 "similar to Values but has a severity and a message instead of interval\n"
572 "and time.\n"
573 "Notifications can be dispatched at any time and can be received with register_notification.";
575 static int Notification_init(PyObject *s, PyObject *args, PyObject *kwds) {
576 Notification *self = (Notification *) s;
577 PyObject *tmp;
578 int severity = 0, ret;
579 double time = 0;
580 const char *message = "";
581 const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
582 static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
583 "plugin", "host", "time", "severity", NULL};
585 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ssssssdi", kwlist,
586 &type, &message, &plugin_instance, &type_instance,
587 &plugin, &host, &time, &severity))
588 return -1;
590 tmp = Py_BuildValue("sssssd", type, plugin_instance, type_instance, plugin, host, time);
591 if (tmp == NULL)
592 return -1;
593 ret = PluginDataType.tp_init(s, tmp, NULL);
594 Py_DECREF(tmp);
595 if (ret != 0)
596 return -1;
598 sstrncpy(self->message, message, sizeof(self->message));
599 self->severity = severity;
600 return 0;
601 }
603 static PyObject *Notification_dispatch(Notification *self, PyObject *args, PyObject *kwds) {
604 int ret;
605 const data_set_t *ds;
606 notification_t notification;
607 double t = self->data.time;
608 int severity = self->severity;
609 const char *host = self->data.host;
610 const char *plugin = self->data.plugin;
611 const char *plugin_instance = self->data.plugin_instance;
612 const char *type = self->data.type;
613 const char *type_instance = self->data.type_instance;
614 const char *message = self->message;
616 static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance",
617 "plugin", "host", "time", "severity", NULL};
618 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ssssssdi", kwlist,
619 &type, &message, &plugin_instance, &type_instance,
620 &plugin, &host, &t, &severity))
621 return NULL;
623 if (type[0] == 0) {
624 PyErr_SetString(PyExc_RuntimeError, "type not set");
625 return NULL;
626 }
627 ds = plugin_get_ds(type);
628 if (ds == NULL) {
629 PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
630 return NULL;
631 }
633 notification.time = t;
634 notification.severity = severity;
635 sstrncpy(notification.message, message, sizeof(notification.message));
636 sstrncpy(notification.host, host, sizeof(notification.host));
637 sstrncpy(notification.plugin, plugin, sizeof(notification.plugin));
638 sstrncpy(notification.plugin_instance, plugin_instance, sizeof(notification.plugin_instance));
639 sstrncpy(notification.type, type, sizeof(notification.type));
640 sstrncpy(notification.type_instance, type_instance, sizeof(notification.type_instance));
641 notification.meta = NULL;
642 if (notification.time < 1)
643 notification.time = time(0);
644 if (notification.host[0] == 0)
645 sstrncpy(notification.host, hostname_g, sizeof(notification.host));
646 if (notification.plugin[0] == 0)
647 sstrncpy(notification.plugin, "python", sizeof(notification.plugin));
648 Py_BEGIN_ALLOW_THREADS;
649 ret = plugin_dispatch_notification(¬ification);
650 Py_END_ALLOW_THREADS;
651 if (ret != 0) {
652 PyErr_SetString(PyExc_RuntimeError, "error dispatching notification, read the logs");
653 return NULL;
654 }
655 Py_RETURN_NONE;
656 }
658 static PyObject *Notification_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
659 Notification *self;
661 self = (Notification *) PluginData_new(type, args, kwds);
662 if (self == NULL)
663 return NULL;
665 self->message[0] = 0;
666 self->severity = 0;
667 return (PyObject *) self;
668 }
670 static int Notification_setstring(PyObject *self, PyObject *value, void *data) {
671 char *old;
672 const char *new;
674 if (value == NULL) {
675 PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
676 return -1;
677 }
678 new = PyString_AsString(value);
679 if (new == NULL) return -1;
680 old = ((char *) self) + (int) data;
681 sstrncpy(old, new, NOTIF_MAX_MSG_LEN);
682 return 0;
683 }
685 static PyObject *Notification_repr(PyObject *s) {
686 PyObject *ret;
687 Notification *self = (Notification *) s;
689 ret = PyString_FromFormat("collectd.Values(type='%s%s%s%s%s%s%s%s%s%s%s',time=%lu,interval=%i)", self->data.type,
690 *self->data.type_instance ? "',type_instance='" : "", self->data.type_instance,
691 *self->data.plugin ? "',plugin='" : "", self->data.plugin,
692 *self->data.plugin_instance ? "',plugin_instance='" : "", self->data.plugin_instance,
693 *self->data.host ? "',host='" : "", self->data.host,
694 *self->message ? "',message='" : "", self->message,
695 (long unsigned) self->data.time, self->severity);
696 return ret;
697 }
699 static PyMethodDef Notification_methods[] = {
700 {"dispatch", (PyCFunction) Notification_dispatch, METH_VARARGS | METH_KEYWORDS, dispatch_doc},
701 {NULL}
702 };
704 static PyMemberDef Notification_members[] = {
705 {"severity", T_INT, offsetof(Notification, severity), 0, severity_doc},
706 {NULL}
707 };
709 static PyGetSetDef Notification_getseters[] = {
710 {"message", PluginData_getstring, Notification_setstring, message_doc, (void *) offsetof(Notification, message)},
711 {NULL}
712 };
714 PyTypeObject NotificationType = {
715 PyObject_HEAD_INIT(NULL)
716 0, /* Always 0 */
717 "collectd.Notification", /* tp_name */
718 sizeof(Notification), /* tp_basicsize */
719 0, /* Will be filled in later */
720 0, /* tp_dealloc */
721 0, /* tp_print */
722 0, /* tp_getattr */
723 0, /* tp_setattr */
724 0, /* tp_compare */
725 Notification_repr, /* tp_repr */
726 0, /* tp_as_number */
727 0, /* tp_as_sequence */
728 0, /* tp_as_mapping */
729 0, /* tp_hash */
730 0, /* tp_call */
731 0, /* tp_str */
732 0, /* tp_getattro */
733 0, /* tp_setattro */
734 0, /* tp_as_buffer */
735 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
736 Notification_doc, /* tp_doc */
737 0, /* tp_traverse */
738 0, /* tp_clear */
739 0, /* tp_richcompare */
740 0, /* tp_weaklistoffset */
741 0, /* tp_iter */
742 0, /* tp_iternext */
743 Notification_methods, /* tp_methods */
744 Notification_members, /* tp_members */
745 Notification_getseters, /* tp_getset */
746 0, /* tp_base */
747 0, /* tp_dict */
748 0, /* tp_descr_get */
749 0, /* tp_descr_set */
750 0, /* tp_dictoffset */
751 Notification_init, /* tp_init */
752 0, /* tp_alloc */
753 Notification_new /* tp_new */
754 };