RFE: Add plugin name field into plugin context use it to improve error reporting
struct cb_view_s {
char *name;
- int qtypes;
- int resolver_stats;
- int cacherrsets;
+ _Bool qtypes;
+ _Bool resolver_stats;
+ _Bool cacherrsets;
char **zones;
size_t zones_num;
static bool config_parse_time = true;
static char *url;
-static int global_opcodes = 1;
-static int global_qtypes = 1;
-static int global_server_stats = 1;
-static int global_zone_maint_stats = 1;
-static int global_resolver_stats;
-static int global_memory_stats = 1;
+static _Bool global_opcodes = 1;
+static _Bool global_qtypes = 1;
+static _Bool global_server_stats = 1;
+static _Bool global_zone_maint_stats = 1;
+static _Bool global_resolver_stats;
+static _Bool global_memory_stats = 1;
static int timeout = -1;
static cb_view_t *views;
return ret;
} /* }}} int bind_xml */
-static int bind_config_set_bool(const char *name, int *var, /* {{{ */
- oconfig_item_t *ci) {
- if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN)) {
- WARNING("bind plugin: The `%s' option needs "
- "exactly one boolean argument.",
- name);
- return -1;
- }
-
- if (ci->values[0].value.boolean)
- *var = 1;
- else
- *var = 0;
- return 0;
-} /* }}} int bind_config_set_bool */
-
static int bind_config_add_view_zone(cb_view_t *view, /* {{{ */
oconfig_item_t *ci) {
if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
oconfig_item_t *child = ci->children + i;
if (strcasecmp("QTypes", child->key) == 0)
- bind_config_set_bool("QTypes", &tmp->qtypes, child);
+ cf_util_get_boolean(child, &tmp->qtypes);
else if (strcasecmp("ResolverStats", child->key) == 0)
- bind_config_set_bool("ResolverStats", &tmp->resolver_stats, child);
+ cf_util_get_boolean(child, &tmp->resolver_stats);
else if (strcasecmp("CacheRRSets", child->key) == 0)
- bind_config_set_bool("CacheRRSets", &tmp->cacherrsets, child);
+ cf_util_get_boolean(child, &tmp->cacherrsets);
else if (strcasecmp("Zone", child->key) == 0)
bind_config_add_view_zone(tmp, child);
else {
oconfig_item_t *child = ci->children + i;
if (strcasecmp("Url", child->key) == 0) {
- if ((child->values_num != 1) ||
- (child->values[0].type != OCONFIG_TYPE_STRING)) {
- WARNING("bind plugin: The `Url' option needs "
- "exactly one string argument.");
- return -1;
- }
-
- sfree(url);
- url = strdup(child->values[0].value.string);
+ cf_util_get_string(child, &url);
} else if (strcasecmp("OpCodes", child->key) == 0)
- bind_config_set_bool("OpCodes", &global_opcodes, child);
+ cf_util_get_boolean(child, &global_opcodes);
else if (strcasecmp("QTypes", child->key) == 0)
- bind_config_set_bool("QTypes", &global_qtypes, child);
+ cf_util_get_boolean(child, &global_qtypes);
else if (strcasecmp("ServerStats", child->key) == 0)
- bind_config_set_bool("ServerStats", &global_server_stats, child);
+ cf_util_get_boolean(child, &global_server_stats);
else if (strcasecmp("ZoneMaintStats", child->key) == 0)
- bind_config_set_bool("ZoneMaintStats", &global_zone_maint_stats, child);
+ cf_util_get_boolean(child, &global_zone_maint_stats);
else if (strcasecmp("ResolverStats", child->key) == 0)
- bind_config_set_bool("ResolverStats", &global_resolver_stats, child);
+ cf_util_get_boolean(child, &global_resolver_stats);
else if (strcasecmp("MemoryStats", child->key) == 0)
- bind_config_set_bool("MemoryStats", &global_memory_stats, child);
+ cf_util_get_boolean(child, &global_memory_stats);
else if (strcasecmp("View", child->key) == 0)
bind_config_add_view(child);
else if (strcasecmp("ParseTime", child->key) == 0)
continue;
if (((i + 1) >= buf_len) || (buf[i + 1] == 0)) {
- ERROR("string unescape: backslash found at end of string.");
+ P_ERROR("string unescape: backslash found at end of string.");
/* Ensure null-byte at the end of the buffer. */
buf[i] = 0;
return -1;
* behavior.
*/
if (fields[i][0] == '.') {
- ERROR("Cowardly refusing to create a directory that "
- "begins with a `.' (dot): `%s'",
- file_orig);
+ P_ERROR("Cowardly refusing to create a directory that "
+ "begins with a `.' (dot): `%s'",
+ file_orig);
return -2;
}
if (strjoin(dir + path_is_absolute,
(size_t)(sizeof(dir) - path_is_absolute), fields,
(size_t)(i + 1), "/") < 0) {
- ERROR("strjoin failed: `%s', component #%i", file_orig, i);
+ P_ERROR("strjoin failed: `%s', component #%i", file_orig, i);
return -1;
}
if (EEXIST == errno)
continue;
- ERROR("check_create_dir: mkdir (%s): %s", dir, STRERRNO);
+ P_ERROR("check_create_dir: mkdir (%s): %s", dir, STRERRNO);
return -1;
} else {
- ERROR("check_create_dir: stat (%s): %s", dir, STRERRNO);
+ P_ERROR("check_create_dir: stat (%s): %s", dir, STRERRNO);
return -1;
}
} else if (!S_ISDIR(statbuf.st_mode)) {
- ERROR("check_create_dir: `%s' exists but is not "
- "a directory!",
- dir);
+ P_ERROR("check_create_dir: `%s' exists but is not "
+ "a directory!",
+ dir);
return -1;
}
break;
*ksp_ptr = kstat_lookup(kc, module, instance, name);
if (*ksp_ptr == NULL) {
- ERROR("get_kstat: Cound not find kstat %s", ident);
+ P_ERROR("get_kstat: Cound not find kstat %s", ident);
return -1;
}
if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED) {
- ERROR("get_kstat: kstat %s has wrong type", ident);
+ P_ERROR("get_kstat: kstat %s has wrong type", ident);
*ksp_ptr = NULL;
return -1;
}
#endif
if (kstat_read(kc, *ksp_ptr, NULL) == -1) {
- ERROR("get_kstat: kstat %s could not be read", ident);
+ P_ERROR("get_kstat: kstat %s could not be read", ident);
return -1;
}
if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED) {
- ERROR("get_kstat: kstat %s has wrong type", ident);
+ P_ERROR("get_kstat: kstat %s has wrong type", ident);
return -1;
}
long long retval = -1LL;
if (ksp == NULL) {
- ERROR("get_kstat_value (\"%s\"): ksp is NULL.", name);
+ P_ERROR("get_kstat_value (\"%s\"): ksp is NULL.", name);
return -1LL;
} else if (ksp->ks_type != KSTAT_TYPE_NAMED) {
- ERROR("get_kstat_value (\"%s\"): ksp->ks_type (%#x) "
- "is not KSTAT_TYPE_NAMED (%#x).",
- name, (unsigned int)ksp->ks_type, (unsigned int)KSTAT_TYPE_NAMED);
+ P_ERROR("get_kstat_value (\"%s\"): ksp->ks_type (%#x) "
+ "is not KSTAT_TYPE_NAMED (%#x).",
+ name, (unsigned int)ksp->ks_type, (unsigned int)KSTAT_TYPE_NAMED);
return -1LL;
}
else if (kn->data_type == KSTAT_DATA_UINT64)
retval = (long long)kn->value.ui64; /* XXX: Might overflow! */
else
- WARNING("get_kstat_value: Not a numeric value: %s", name);
+ P_WARNING("get_kstat_value: Not a numeric value: %s", name);
return retval;
}
default:
sfree(value);
- ERROR("parse_value: Invalid data source type: %i.", ds_type);
+ P_ERROR("parse_value: Invalid data source type: %i.", ds_type);
return -1;
}
if (value == endptr) {
- ERROR("parse_value: Failed to parse string as %s: \"%s\".",
- DS_TYPE_TO_STRING(ds_type), value);
+ P_ERROR("parse_value: Failed to parse string as %s: \"%s\".",
+ DS_TYPE_TO_STRING(ds_type), value);
sfree(value);
return -1;
} else if ((NULL != endptr) && ('\0' != *endptr))
- INFO("parse_value: Ignoring trailing garbage \"%s\" after %s value. "
- "Input string was \"%s\".",
- endptr, DS_TYPE_TO_STRING(ds_type), value_orig);
+ P_INFO("parse_value: Ignoring trailing garbage \"%s\" after %s value. "
+ "Input string was \"%s\".",
+ endptr, DS_TYPE_TO_STRING(ds_type), value_orig);
sfree(value);
return 0;
failure = 0;
if ((dh = opendir(dir)) == NULL) {
- ERROR("walk_directory: Cannot open '%s': %s", dir, STRERRNO);
+ P_ERROR("walk_directory: Cannot open '%s': %s", dir, STRERRNO);
return -1;
}
ret = (ssize_t)fread(buf, 1, bufsize, fh);
if ((ret == 0) && (ferror(fh) != 0)) {
- ERROR("read_file_contents: Reading file \"%s\" failed.", filename);
+ P_ERROR("read_file_contents: Reading file \"%s\" failed.", filename);
ret = -1;
}
status = getaddrinfo(/* node = */ NULL, service_name, &ai_hints, &ai_list);
if (status != 0) {
- ERROR("service_name_to_port_number: getaddrinfo failed: %s",
- gai_strerror(status));
+ P_ERROR("service_name_to_port_number: getaddrinfo failed: %s",
+ gai_strerror(status));
return -1;
}
status = getsockopt(sockfd, SOL_SOCKET, SO_TYPE, &socktype,
&(socklen_t){sizeof(socktype)});
if (status != 0) {
- WARNING("set_sock_opts: failed to determine socket type");
+ P_WARNING("set_sock_opts: failed to determine socket type");
return;
}
status =
setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &(int){1}, sizeof(int));
if (status != 0)
- WARNING("set_sock_opts: failed to set socket keepalive flag");
+ P_WARNING("set_sock_opts: failed to set socket keepalive flag");
#ifdef TCP_KEEPIDLE
int tcp_keepidle = ((CDTIME_T_TO_MS(plugin_get_interval()) - 1) / 100 + 1);
status = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, &tcp_keepidle,
sizeof(tcp_keepidle));
if (status != 0)
- WARNING("set_sock_opts: failed to set socket tcp keepalive time");
+ P_WARNING("set_sock_opts: failed to set socket tcp keepalive time");
#endif
#ifdef TCP_KEEPINTVL
status = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL, &tcp_keepintvl,
sizeof(tcp_keepintvl));
if (status != 0)
- WARNING("set_sock_opts: failed to set socket tcp keepalive interval");
+ P_WARNING("set_sock_opts: failed to set socket tcp keepalive interval");
#endif
}
} /* }}} void set_sock_opts */
return -1;
if (!(cap = cap_get_proc())) {
- ERROR("check_capability: cap_get_proc failed.");
+ P_ERROR("check_capability: cap_get_proc failed.");
return -1;
}
if (cap_get_flag(cap, cap_value, CAP_EFFECTIVE, &cap_flag_value) < 0) {
- ERROR("check_capability: cap_get_flag failed.");
+ P_ERROR("check_capability: cap_get_flag failed.");
cap_free(cap);
return -1;
}
#else
int check_capability(__attribute__((unused)) int arg) /* {{{ */
{
- WARNING("check_capability: unsupported capability implementation. "
- "Some plugin(s) may require elevated privileges to work properly.");
+ P_WARNING("check_capability: unsupported capability implementation. "
+ "Some plugin(s) may require elevated privileges to work properly.");
return 0;
} /* }}} int check_capability */
#endif /* HAVE_CAPABILITY */
}
static int dispatch_loadplugin(oconfig_item_t *ci) {
- const char *name;
bool global = false;
- plugin_ctx_t ctx = {0};
- plugin_ctx_t old_ctx;
- int ret_val;
assert(strcasecmp(ci->key, "LoadPlugin") == 0);
return -1;
}
- name = ci->values[0].value.string;
+ const char *name = ci->values[0].value.string;
if (strcmp("libvirt", name) == 0)
name = "virt";
/* default to the global interval set before loading this plugin */
- ctx.interval = cf_get_default_interval();
- ctx.flush_interval = 0;
- ctx.flush_timeout = 0;
+ plugin_ctx_t ctx = {
+ .interval = cf_get_default_interval(), .name = strdup(name),
+ };
+ if (ctx.name == NULL)
+ return ENOMEM;
for (int i = 0; i < ci->children_num; ++i) {
oconfig_item_t *child = ci->children + i;
else {
WARNING("Ignoring unknown LoadPlugin option \"%s\" "
"for plugin \"%s\"",
- child->key, ci->values[0].value.string);
+ child->key, name);
}
}
- old_ctx = plugin_set_ctx(ctx);
- ret_val = plugin_load(name, global);
+ plugin_ctx_t old_ctx = plugin_set_ctx(ctx);
+ int ret_val = plugin_load(name, global);
/* reset to the "global" context */
plugin_set_ctx(old_ctx);
* success. */
int cf_util_get_string(const oconfig_item_t *ci, char **ret_string) /* {{{ */
{
- char *string;
-
if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
- ERROR("cf_util_get_string: The %s option requires "
- "exactly one string argument.",
- ci->key);
+ P_ERROR("The `%s' option requires exactly one string argument.", ci->key);
return -1;
}
- string = strdup(ci->values[0].value.string);
+ char *string = strdup(ci->values[0].value.string);
if (string == NULL)
return -1;
return EINVAL;
if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
- ERROR("cf_util_get_string_buffer: The %s option requires "
- "exactly one string argument.",
- ci->key);
+ P_ERROR("The `%s' option requires exactly one string argument.", ci->key);
return -1;
}
return EINVAL;
if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER)) {
- ERROR("cf_util_get_int: The %s option requires "
- "exactly one numeric argument.",
- ci->key);
+ P_ERROR("The `%s' option requires exactly one numeric argument.", ci->key);
return -1;
}
return EINVAL;
if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER)) {
- ERROR("cf_util_get_double: The %s option requires "
- "exactly one numeric argument.",
- ci->key);
+ P_ERROR("The `%s' option requires exactly one numeric argument.", ci->key);
return -1;
}
if ((ci->values_num != 1) || ((ci->values[0].type != OCONFIG_TYPE_BOOLEAN) &&
(ci->values[0].type != OCONFIG_TYPE_STRING))) {
- ERROR("cf_util_get_boolean: The %s option requires "
- "exactly one boolean argument.",
- ci->key);
+ P_ERROR("The `%s' option requires exactly one boolean argument.", ci->key);
return -1;
}
*ret_bool = ci->values[0].value.boolean ? true : false;
break;
case OCONFIG_TYPE_STRING:
- WARNING("cf_util_get_boolean: Using string value `%s' for boolean option "
- "`%s' is deprecated and will be removed in future releases. "
- "Use unquoted true or false instead.",
- ci->values[0].value.string, ci->key);
+ P_WARNING("Using string value `%s' for boolean option `%s' is deprecated "
+ "and will be removed in future releases. Use unquoted true or "
+ "false instead.",
+ ci->values[0].value.string, ci->key);
if (IS_TRUE(ci->values[0].value.string))
*ret_bool = true;
else if (IS_FALSE(ci->values[0].value.string))
*ret_bool = false;
else {
- ERROR("cf_util_get_boolean: Cannot parse string value `%s' of the `%s' "
- "option as a boolean value.",
- ci->values[0].value.string, ci->key);
+ P_ERROR("Cannot parse string value `%s' of the `%s' option as a boolean "
+ "value.",
+ ci->values[0].value.string, ci->key);
return -1;
}
break;
if ((ci->values_num != 1) || ((ci->values[0].type != OCONFIG_TYPE_STRING) &&
(ci->values[0].type != OCONFIG_TYPE_NUMBER))) {
- ERROR("cf_util_get_port_number: The \"%s\" option requires "
- "exactly one string argument.",
- ci->key);
+ P_ERROR("The `%s' option requires exactly one string argument.", ci->key);
return -1;
}
assert(ci->values[0].type == OCONFIG_TYPE_NUMBER);
tmp = (int)(ci->values[0].value.number + 0.5);
if ((tmp < 1) || (tmp > 65535)) {
- ERROR("cf_util_get_port_number: The \"%s\" option requires "
- "a service name or a port number. The number "
- "you specified, %i, is not in the valid "
- "range of 1-65535.",
- ci->key, tmp);
+ P_ERROR("The `%s' option requires a service name or a port number. The "
+ "number you specified, %i, is not in the valid range of 1-65535.",
+ ci->key, tmp);
return -1;
}
int status;
if (ci->values_num != 1) {
- ERROR("cf_util_get_service: The %s option requires exactly "
- "one argument.",
- ci->key);
+ P_ERROR("The `%s` option requires exactly one argument.", ci->key);
return -1;
}
if (ci->values[0].type == OCONFIG_TYPE_STRING)
return cf_util_get_string(ci, ret_string);
if (ci->values[0].type != OCONFIG_TYPE_NUMBER) {
- ERROR("cf_util_get_service: The %s option requires "
- "exactly one string or numeric argument.",
- ci->key);
+ P_ERROR("The `%s` option requires exactly one string or numeric argument.",
+ ci->key);
}
port = 0;
if (status != 0)
return status;
else if ((port < 1) || (port > 65535)) {
- ERROR("cf_util_get_service: The port number given "
- "for the %s option is out of "
- "range (%i).",
- ci->key, port);
+ P_ERROR("The port number given for the `%s` option is out of range (%i).",
+ ci->key, port);
return -1;
}
service = malloc(6);
if (service == NULL) {
- ERROR("cf_util_get_service: Out of memory.");
+ P_ERROR("cf_util_get_service: Out of memory.");
return -1;
}
snprintf(service, 6, "%i", port);
return EINVAL;
if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER)) {
- ERROR("cf_util_get_cdtime: The %s option requires "
- "exactly one numeric argument.",
- ci->key);
+ P_ERROR("The `%s' option requires exactly one numeric argument.", ci->key);
return -1;
}
if (ci->values[0].value.number < 0.0) {
- ERROR("cf_util_get_cdtime: The numeric argument of the %s "
- "option must not be negative.",
- ci->key);
+ P_ERROR("The numeric argument of the `%s' option must not be negative.",
+ ci->key);
return -1;
}
static int create_register_callback(llist_t **list, /* {{{ */
const char *name, void *callback,
user_data_t const *ud) {
- callback_func_t *cf;
- cf = calloc(1, sizeof(*cf));
+ if (name == NULL || callback == NULL)
+ return EINVAL;
+
+ callback_func_t *cf = calloc(1, sizeof(*cf));
if (cf == NULL) {
free_userdata(ud);
ERROR("plugin: create_register_callback: calloc failed.");
- return -1;
+ return ENOMEM;
}
cf->cf_callback = callback;
if (ud == NULL) {
- cf->cf_udata.data = NULL;
- cf->cf_udata.free_func = NULL;
+ cf->cf_udata = (user_data_t){
+ .data = NULL, .free_func = NULL,
+ };
} else {
cf->cf_udata = *ud;
}
callback_func_t *cf = le->value;
plugin_write_cb callback;
- /* do not switch plugin context; rather keep the context (interval)
- * information of the calling read plugin */
+ /* Keep the read plugin's interval and flush information but update the
+ * plugin name. */
+ plugin_ctx_t old_ctx = plugin_get_ctx();
+ plugin_ctx_t ctx = old_ctx;
+ ctx.name = cf->cf_ctx.name;
+ plugin_set_ctx(ctx);
DEBUG("plugin: plugin_write: Writing values via %s.", le->key);
callback = cf->cf_callback;
else
success++;
+ plugin_set_ctx(old_ctx);
le = le->next;
}
}
} /* void plugin_log */
+void daemon_log(int level, const char *format, ...) {
+ char msg[1024] = ""; // Size inherits from plugin_log()
+
+ char const *name = plugin_get_ctx().name;
+ if (name == NULL)
+ name = "UNKNOWN";
+
+ va_list ap;
+ va_start(ap, format);
+ vsnprintf(msg, sizeof(msg), format, ap);
+ va_end(ap);
+
+ plugin_log(level, "%s plugin: %s", name, msg);
+} /* void daemon_log */
+
int parse_log_severity(const char *severity) {
int log_level = -1;
typedef struct user_data_s user_data_t;
struct plugin_ctx_s {
+ char *name;
cdtime_t interval;
cdtime_t flush_interval;
cdtime_t flush_timeout;
#define DEBUG(...) /* noop */
#endif /* ! COLLECT_DEBUG */
+/* This will log messages, prefixed by plugin name */
+void daemon_log(int level, const char *format, ...)
+ __attribute__((format(printf, 2, 3)));
+
+#define P_ERROR(...) daemon_log(LOG_ERR, __VA_ARGS__)
+#define P_WARNING(...) daemon_log(LOG_WARNING, __VA_ARGS__)
+#define P_NOTICE(...) daemon_log(LOG_NOTICE, __VA_ARGS__)
+#define P_INFO(...) daemon_log(LOG_INFO, __VA_ARGS__)
+
const data_set_t *plugin_get_ds(const char *name);
int plugin_notification_meta_add_string(notification_t *n, const char *name,
printf("plugin_log (%i, \"%s\");\n", level, buffer);
}
+void daemon_log(int level, char const *format, ...) {
+ char buffer[1024];
+ va_list ap;
+
+ va_start(ap, format);
+ vsnprintf(buffer, sizeof(buffer), format, ap);
+ va_end(ap);
+
+ printf("daemon_log (%i, \"%s\");\n", level, buffer);
+}
+
void plugin_init_ctx(void) { /* nop */
}