"The callback function will be called with no parameters except for\n"
" data if it was supplied.";
+static char CollectdError_doc[] =
+ "Basic exception for collectd Python scripts.\n"
+ "\n"
+ "Throwing this exception will not cause a stacktrace to be logged, \n"
+ "even if LogTraces is enabled in the config.";
+
static pthread_t main_thread;
static PyOS_sighandler_t python_sigint_handler;
-static _Bool do_interactive = 0;
+static bool do_interactive;
/* This is our global thread state. Python saves some stuff in thread-local
* storage. So if we allow the interpreter to run in the background
static PyThreadState *state;
-static PyObject *sys_path, *cpy_format_exception;
+static PyObject *sys_path, *cpy_format_exception, *CollectdError;
static cpy_callback_t *cpy_config_callbacks;
static cpy_callback_t *cpy_init_callbacks;
static cpy_callback_t *cpy_shutdown_callbacks;
/* Make sure to hold the GIL while modifying these. */
-static int cpy_shutdown_triggered = 0;
-static int cpy_num_callbacks = 0;
+static int cpy_shutdown_triggered;
+static int cpy_num_callbacks;
static void cpy_destroy_user_data(void *data) {
cpy_callback_t *c = data;
}
void cpy_log_exception(const char *context) {
- int l = 0;
+ int l = 0, collectd_error;
const char *typename = NULL, *message = NULL;
PyObject *type, *value, *traceback, *tn, *m, *list;
PyErr_NormalizeException(&type, &value, &traceback);
if (type == NULL)
return;
+ collectd_error = PyErr_GivenExceptionMatches(value, CollectdError);
tn = PyObject_GetAttrString(type, "__name__"); /* New reference. */
m = PyObject_Str(value); /* New reference. */
if (tn != NULL)
typename = "NamelessException";
if (message == NULL)
message = "N/A";
- Py_BEGIN_ALLOW_THREADS ERROR("Unhandled python exception in %s: %s: %s",
- context, typename, message);
- Py_END_ALLOW_THREADS Py_XDECREF(tn);
+ Py_BEGIN_ALLOW_THREADS;
+ if (collectd_error) {
+ WARNING("%s in %s: %s", typename, context, message);
+ } else {
+ ERROR("Unhandled python exception in %s: %s: %s", context, typename,
+ message);
+ }
+ Py_END_ALLOW_THREADS;
+ Py_XDECREF(tn);
Py_XDECREF(m);
- if (!cpy_format_exception || !traceback) {
+ if (!cpy_format_exception || !traceback || collectd_error) {
PyErr_Clear();
Py_DECREF(type);
Py_XDECREF(value);
if (cpy[strlen(cpy) - 1] == '\n')
cpy[strlen(cpy) - 1] = 0;
- Py_BEGIN_ALLOW_THREADS ERROR("%s", cpy);
- Py_END_ALLOW_THREADS
+ Py_BEGIN_ALLOW_THREADS;
+ ERROR("%s", cpy);
+ Py_END_ALLOW_THREADS;
- free(cpy);
+ free(cpy);
}
Py_XDECREF(list);
PyList_SetItem(
list, i, PyLong_FromUnsignedLongLong(value_list->values[i].absolute));
} else {
- Py_BEGIN_ALLOW_THREADS ERROR("cpy_write_callback: Unknown value type %d.",
- ds->ds[i].type);
- Py_END_ALLOW_THREADS Py_DECREF(list);
+ Py_BEGIN_ALLOW_THREADS;
+ ERROR("cpy_write_callback: Unknown value type %d.", ds->ds[i].type);
+ Py_END_ALLOW_THREADS;
+ Py_DECREF(list);
CPY_RETURN_FROM_THREADS 0;
}
if (PyErr_Occurred() != NULL) {
}
dict = PyDict_New(); /* New reference. */
if (value_list->meta) {
- char **table;
+ char **table = NULL;
meta_data_t *meta = value_list->meta;
int num = meta_data_toc(meta, &table);
int64_t si;
uint64_t ui;
double d;
- _Bool b;
+ bool b;
type = meta_data_type(meta, table[i]);
if (type == MD_TYPE_STRING) {
} else if (type == MD_TYPE_SIGNED_INT) {
if (meta_data_get_signed_int(meta, table[i], &si))
continue;
- temp = PyObject_CallFunctionObjArgs((void *)&SignedType,
- PyLong_FromLongLong(si),
+ PyObject *sival = PyLong_FromLongLong(si); /* New reference */
+ temp = PyObject_CallFunctionObjArgs((void *)&SignedType, sival,
(void *)0); /* New reference. */
PyDict_SetItemString(dict, table[i], temp);
Py_XDECREF(temp);
+ Py_XDECREF(sival);
} else if (type == MD_TYPE_UNSIGNED_INT) {
if (meta_data_get_unsigned_int(meta, table[i], &ui))
continue;
- temp = PyObject_CallFunctionObjArgs((void *)&UnsignedType,
- PyLong_FromUnsignedLongLong(ui),
+ PyObject *uval = PyLong_FromUnsignedLongLong(ui); /* New reference */
+ temp = PyObject_CallFunctionObjArgs((void *)&UnsignedType, uval,
(void *)0); /* New reference. */
PyDict_SetItemString(dict, table[i], temp);
Py_XDECREF(temp);
+ Py_XDECREF(uval);
} else if (type == MD_TYPE_DOUBLE) {
if (meta_data_get_double(meta, table[i], &d))
continue;
Notification *n;
CPY_LOCK_THREADS
+ PyObject *dict = PyDict_New(); /* New reference. */
+ for (notification_meta_t *meta = notification->meta; meta != NULL;
+ meta = meta->next) {
+ PyObject *temp = NULL;
+ if (meta->type == NM_TYPE_STRING) {
+ temp = cpy_string_to_unicode_or_bytes(
+ meta->nm_value.nm_string); /* New reference. */
+ PyDict_SetItemString(dict, meta->name, temp);
+ Py_XDECREF(temp);
+ } else if (meta->type == NM_TYPE_SIGNED_INT) {
+ PyObject *sival = PyLong_FromLongLong(meta->nm_value.nm_signed_int);
+ temp = PyObject_CallFunctionObjArgs((void *)&SignedType, sival,
+ (void *)0); /* New reference. */
+ PyDict_SetItemString(dict, meta->name, temp);
+ Py_XDECREF(temp);
+ Py_XDECREF(sival);
+ } else if (meta->type == NM_TYPE_UNSIGNED_INT) {
+ PyObject *uval =
+ PyLong_FromUnsignedLongLong(meta->nm_value.nm_unsigned_int);
+ temp = PyObject_CallFunctionObjArgs((void *)&UnsignedType, uval,
+ (void *)0); /* New reference. */
+ PyDict_SetItemString(dict, meta->name, temp);
+ Py_XDECREF(temp);
+ Py_XDECREF(uval);
+ } else if (meta->type == NM_TYPE_DOUBLE) {
+ temp = PyFloat_FromDouble(meta->nm_value.nm_double); /* New reference. */
+ PyDict_SetItemString(dict, meta->name, temp);
+ Py_XDECREF(temp);
+ } else if (meta->type == NM_TYPE_BOOLEAN) {
+ PyDict_SetItemString(dict, meta->name,
+ meta->nm_value.nm_boolean ? Py_True : Py_False);
+ }
+ }
notify = Notification_New(); /* New reference. */
n = (Notification *)notify;
sstrncpy(n->data.host, notification->host, sizeof(n->data.host));
n->data.time = CDTIME_T_TO_DOUBLE(notification->time);
sstrncpy(n->message, notification->message, sizeof(n->message));
n->severity = notification->severity;
+ Py_CLEAR(n->meta);
+ n->meta = dict; /* Steals a reference. */
ret = PyObject_CallFunctionObjArgs(c->callback, n, c->data,
(void *)0); /* New reference. */
Py_XDECREF(notify);
if (PyArg_ParseTupleAndKeywords(args, kwds, "|etiet", kwlist, NULL, &plugin,
&timeout, NULL, &identifier) == 0)
return NULL;
- Py_BEGIN_ALLOW_THREADS plugin_flush(plugin, timeout, identifier);
- Py_END_ALLOW_THREADS PyMem_Free(plugin);
+ Py_BEGIN_ALLOW_THREADS;
+ plugin_flush(plugin, timeout, identifier);
+ Py_END_ALLOW_THREADS;
+ PyMem_Free(plugin);
PyMem_Free(identifier);
Py_RETURN_NONE;
}
char *text;
if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
return NULL;
- Py_BEGIN_ALLOW_THREADS plugin_log(LOG_ERR, "%s", text);
- Py_END_ALLOW_THREADS PyMem_Free(text);
+ Py_BEGIN_ALLOW_THREADS;
+ plugin_log(LOG_ERR, "%s", text);
+ Py_END_ALLOW_THREADS;
+ PyMem_Free(text);
Py_RETURN_NONE;
}
char *text;
if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
return NULL;
- Py_BEGIN_ALLOW_THREADS plugin_log(LOG_WARNING, "%s", text);
- Py_END_ALLOW_THREADS PyMem_Free(text);
+ Py_BEGIN_ALLOW_THREADS;
+ plugin_log(LOG_WARNING, "%s", text);
+ Py_END_ALLOW_THREADS;
+ PyMem_Free(text);
Py_RETURN_NONE;
}
char *text;
if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
return NULL;
- Py_BEGIN_ALLOW_THREADS plugin_log(LOG_NOTICE, "%s", text);
- Py_END_ALLOW_THREADS PyMem_Free(text);
+ Py_BEGIN_ALLOW_THREADS;
+ plugin_log(LOG_NOTICE, "%s", text);
+ Py_END_ALLOW_THREADS;
+ PyMem_Free(text);
Py_RETURN_NONE;
}
char *text;
if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
return NULL;
- Py_BEGIN_ALLOW_THREADS plugin_log(LOG_INFO, "%s", text);
- Py_END_ALLOW_THREADS PyMem_Free(text);
+ Py_BEGIN_ALLOW_THREADS;
+ plugin_log(LOG_INFO, "%s", text);
+ Py_END_ALLOW_THREADS;
+ PyMem_Free(text);
Py_RETURN_NONE;
}
char *text;
if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
return NULL;
- Py_BEGIN_ALLOW_THREADS plugin_log(LOG_DEBUG, "%s", text);
- Py_END_ALLOW_THREADS PyMem_Free(text);
+ Py_BEGIN_ALLOW_THREADS;
+ plugin_log(LOG_DEBUG, "%s", text);
+ Py_END_ALLOW_THREADS;
+ PyMem_Free(text);
#endif
Py_RETURN_NONE;
}
}
PyErr_Print();
- Py_BEGIN_ALLOW_THREADS cpy_unregister_list(&cpy_config_callbacks);
+ Py_BEGIN_ALLOW_THREADS;
+ cpy_unregister_list(&cpy_config_callbacks);
cpy_unregister_list(&cpy_init_callbacks);
cpy_unregister_list(&cpy_shutdown_callbacks);
cpy_shutdown_triggered = 1;
- Py_END_ALLOW_THREADS
+ Py_END_ALLOW_THREADS;
- if (!cpy_num_callbacks) {
+ if (!cpy_num_callbacks) {
Py_Finalize();
return 0;
}
static int cpy_init_python(void) {
PyOS_sighandler_t cur_sig;
- PyObject *sys;
+ PyObject *sys, *errordict;
PyObject *module;
#ifdef IS_PY3K
PyType_Ready(&SignedType);
UnsignedType.tp_base = &PyLong_Type;
PyType_Ready(&UnsignedType);
+ errordict = PyDict_New();
+ PyDict_SetItemString(
+ errordict, "__doc__",
+ cpy_string_to_unicode_or_bytes(CollectdError_doc)); /* New reference. */
+ CollectdError = PyErr_NewException("collectd.CollectdError", NULL, errordict);
sys = PyImport_ImportModule("sys"); /* New reference. */
if (sys == NULL) {
cpy_log_exception("python initialization");
(void *)&SignedType); /* Steals a reference. */
PyModule_AddObject(module, "Unsigned",
(void *)&UnsignedType); /* Steals a reference. */
+ Py_XINCREF(CollectdError);
+ PyModule_AddObject(module, "CollectdError",
+ CollectdError); /* Steals a reference. */
PyModule_AddIntConstant(module, "LOG_DEBUG", LOG_DEBUG);
PyModule_AddIntConstant(module, "LOG_INFO", LOG_INFO);
PyModule_AddIntConstant(module, "LOG_NOTICE", LOG_NOTICE);
#endif
sfree(encoding);
} else if (strcasecmp(item->key, "LogTraces") == 0) {
- _Bool log_traces;
+ bool log_traces;
if (cf_util_get_boolean(item, &log_traces) != 0) {
status = 1;
continue;
status = 1;
}
}
- return (status);
+ return status;
}
void module_register(void) {