--- /dev/null
+# Example configuration for PHP-FPM
+<Plugin "curl_json">
+ <URL "http://nginx-status/php-fpm-status?json">
+ Plugin "phpfpm"
+ Instance "main"
+ <Key "accepted conn">
+ Type "total_requests"
+ Instance "accepted"
+ </Key>
+ <Key "slow requests">
+ Type "total_requests"
+ Instance "slow"
+ </Key>
+ <Key "listen queue">
+ Type "queue_length"
+ Instance "listen"
+ </Key>
+ <Key "active processes">
+ Type "vs_processes"
+ Instance "active"
+ </Key>
+ <Key "total processes">
+ Type "vs_processes"
+ Instance "total"
+ </Key>
+ </URL>
+</Plugin>
#
# - fetch the desired collectd release file from https://collectd.org/files/
# and save it in your ~/rpmbuild/SOURCES/ directory (or build your own out of
-# the git repository: ./build.sh && ./configure && make-dist-bz2)
+# the git repository: ./build.sh && ./configure && make dist-bzip2)
#
# - copy this file in your ~/rpmbuild/SPECS/ directory. Make sure the
# "Version:" tag matches the version from the tarball.
# </Result>
# </Query>
# <Database "customers_db">
+# #Plugin "mycompany"
# Driver "mysql"
# DriverOption "host" "localhost"
# DriverOption "username" "collectd"
# </Result>
# </Query>
# <Database "product_information">
+# #Plugin "warehouse"
# ConnectID "db01"
# Username "oracle"
# Password "secret"
# StoreRates true
# </Writer>
# <Database foo>
+# #Plugin "kingdom"
# Host "hostname"
# Port "5432"
# User "username"
<Plugin curl>
<Page "stock_quotes">
+ Plugin "quotes"
URL "http://finance.google.com/finance?q=NYSE%3AAMD"
User "foo"
Password "bar"
=over 4
+=item B<Plugin> I<Plugin>
+
+Use I<Plugin> as the plugin name when submitting values.
+Defaults to C<curl>.
+
=item B<URL> I<URL>
URL of the web site to retrieve. Since a regular expression will be used to
Use I<Name> as the host name when submitting values. Defaults to the global
host name setting.
+=item B<Plugin> I<Plugin>
+
+Use I<Plugin> as the plugin name when submitting values.
+Defaults to C<curl_json>.
+
=item B<Instance> I<Instance>
Sets the plugin instance to I<Instance>.
</Result>
</Query>
<Database "product_information">
+ #Plugin "warehouse"
Driver "mysql"
Interval 120
DriverOption "host" "localhost"
=over 4
+=item B<Plugin> I<Plugin>
+
+Use I<Plugin> as the plugin name when submitting query results from
+this B<Database>. Defaults to C<dbi>.
+
=item B<Interval> I<Interval>
Sets the interval (in seconds) in which the values will be collected from this
<Page "plugin_instance">
Server "localhost"
Key "page_key"
+ Plugin "plugin_name"
<Match>
Regex "(\\d+) bytes sent"
DSType CounterAdd
When connected to the memcached server, asks for the page I<Key>.
+=item B<Plugin> I<Plugin>
+
+Use I<Plugin> as the plugin name when submitting values.
+Defaults to C<memcachec>.
+
=item E<lt>B<Match>E<gt>
Match blocks define which strings to look for and how matches substrings are
</Result>
</Query>
<Database "product_information">
+ #Plugin "warehouse"
ConnectID "db01"
Username "oracle"
Password "secret"
=over 4
+=item B<Plugin> I<Plugin>
+
+Use I<Plugin> as the plugin name when submitting query results from
+this B<Database>. Defaults to C<oracle>.
+
=item B<ConnectID> I<ID>
Defines the "database alias" or "service name" to connect to. Usually, these
enable the interface, OVS DB daemon should be running with C<--remote=ptcp:>
option. See L<ovsdb-server(1)> for more details. The option may be either
network hostname, IPv4 numbers-and-dots notation or IPv6 hexadecimal string
-format. Defaults to B<'localhost'>.
+format. Defaults to C<localhost>.
=item B<Port> I<service>
enable the interface, OVS DB daemon should be running with C<--remote=ptcp:>
option. See L<ovsdb-server(1)> for more details. The option may be either
network hostname, IPv4 numbers-and-dots notation or IPv6 hexadecimal string
-format. Defaults to B<'localhost'>.
+format. Defaults to C<localhost>.
=item B<Port> I<service>
</Writer>
<Database foo>
+ Plugin "kingdom"
Host "hostname"
Port "5432"
User "username"
amount of time will be lost, for example, if a single statement within the
transaction fails or if the database server crashes.
+=item B<Plugin> I<Plugin>
+
+Use I<Plugin> as the plugin name when submitting query results from
+this B<Database>. Defaults to C<postgresql>.
+
=item B<Instance> I<name>
Specify the plugin instance name that should be used instead of the database
<Plugin "tail">
<File "/var/log/exim4/mainlog">
+ Plugin "mail"
Instance "exim"
Interval 60
<Match>
logfile to parse. Within each B<File> block, there are one or more B<Match>
blocks, which configure a regular expression to search for.
-The B<Instance> option in the B<File> block may be used to set the plugin
-instance. So in the above example the plugin name C<tail-foo> would be used.
-This plugin instance is for all B<Match> blocks that B<follow> it, until the
-next B<Instance> option. This way you can extract several plugin instances from
-one logfile, handy when parsing syslog and the like.
+The B<Plugin> and B<Instance> options in the B<File> block may be used to set
+the plugin name and instance respectively. So in the above example the plugin name
+C<mail-exim> would be used.
+
+These options are applied for all B<Match> blocks that B<follow> it, until the
+next B<Plugin> or B<Instance> option. This way you can extract several plugin
+instances from one logfile, handy when parsing syslog and the like.
The B<Interval> option allows you to define the length of time between reads. If
this is not set, the default Interval will be used.
Index 1
</Metric>
<File "/var/log/snort/snort.stats">
- Instance "snort-eth0"
+ Plugin "snortstats"
+ Instance "eth0"
Interval 600
Collect "snort-dropped"
</File>
=over 4
+=item B<Plugin> I<Plugin>
+
+Use I<Plugin> as the plugin name when submitting values.
+Defaults to C<tail_csv>.
+
=item B<Instance> I<PluginInstance>
Sets the I<plugin instance> used when dispatching the values.
Prefix "collectd/"
Database 1
MaxSetSize -1
+ MaxSetDuration -1
StoreRates true
</Node>
</Plugin>
The B<MaxSetSize> option limits the number of items that the I<Sorted Sets> can
hold. Negative values for I<Items> sets no limit, which is the default behavior.
+=item B<MaxSetDuration> I<Seconds>
+
+The B<MaxSetDuration> option limits the duration of items that the
+I<Sorted Sets> can hold. Negative values for I<Items> sets no duration, which
+is the default behavior.
+
=item B<StoreRates> B<true>|B<false>
If set to B<true> (the default), convert counter values to rates. If set to
typedef struct web_page_s web_page_t;
struct web_page_s /* {{{ */
{
+ char *plugin_name;
char *instance;
char *url;
curl_easy_cleanup(wp->curl);
wp->curl = NULL;
+ sfree(wp->plugin_name);
sfree(wp->instance);
sfree(wp->url);
ERROR("curl plugin: calloc failed.");
return -1;
}
+ page->plugin_name = NULL;
page->url = NULL;
page->user = NULL;
page->pass = NULL;
for (int i = 0; i < ci->children_num; i++) {
oconfig_item_t *child = ci->children + i;
- if (strcasecmp("URL", child->key) == 0)
+ if (strcasecmp("Plugin", child->key) == 0)
+ status = cf_util_get_string(child, &page->plugin_name);
+ else if (strcasecmp("URL", child->key) == 0)
status = cf_util_get_string(child, &page->url);
else if (strcasecmp("User", child->key) == 0)
status = cf_util_get_string(child, &page->user);
vl.values = &value;
vl.values_len = 1;
- sstrncpy(vl.plugin, "curl", sizeof(vl.plugin));
+ sstrncpy(vl.plugin, (wp->plugin_name != NULL) ? wp->plugin_name : "curl",
+ sizeof(vl.plugin));
sstrncpy(vl.plugin_instance, wp->instance, sizeof(vl.plugin_instance));
sstrncpy(vl.type, wm->type, sizeof(vl.type));
if (wm->instance != NULL)
vl.values = &(value_t){.gauge = (gauge_t)code};
vl.values_len = 1;
- sstrncpy(vl.plugin, "curl", sizeof(vl.plugin));
+ sstrncpy(vl.plugin, (wp->plugin_name != NULL) ? wp->plugin_name : "curl",
+ sizeof(vl.plugin));
sstrncpy(vl.plugin_instance, wp->instance, sizeof(vl.plugin_instance));
sstrncpy(vl.type, "response_code", sizeof(vl.type));
vl.values = &(value_t){.gauge = response_time};
vl.values_len = 1;
- sstrncpy(vl.plugin, "curl", sizeof(vl.plugin));
+ sstrncpy(vl.plugin, (wp->plugin_name != NULL) ? wp->plugin_name : "curl",
+ sizeof(vl.plugin));
sstrncpy(vl.plugin_instance, wp->instance, sizeof(vl.plugin_instance));
sstrncpy(vl.type, "response_time", sizeof(vl.type));
struct cj_s /* {{{ */
{
char *instance;
+ char *plugin_name;
char *host;
char *sock;
db->tree = NULL;
sfree(db->instance);
+ sfree(db->plugin_name);
sfree(db->host);
sfree(db->sock);
if (strcasecmp("Instance", child->key) == 0)
status = cf_util_get_string(child, &db->instance);
+ else if (strcasecmp("Plugin", child->key) == 0)
+ status = cf_util_get_string(child, &db->plugin_name);
else if (strcasecmp("Host", child->key) == 0)
status = cf_util_get_string(child, &db->host);
else if (db->url && strcasecmp("User", child->key) == 0)
sstrncpy(vl.type_instance, key->instance, sizeof(vl.type_instance));
sstrncpy(vl.host, cj_host(db), sizeof(vl.host));
- sstrncpy(vl.plugin, "curl_json", sizeof(vl.plugin));
+ sstrncpy(vl.plugin, (db->plugin_name != NULL) ? db->plugin_name : "curl_json",
+ sizeof(vl.plugin));
sstrncpy(vl.plugin_instance, db->instance, sizeof(vl.plugin_instance));
sstrncpy(vl.type, key->type, sizeof(vl.type));
{
char *name;
char *select_db;
+ char *plugin_name;
cdtime_t interval;
return;
sfree(db->name);
+ sfree(db->select_db);
+ sfree(db->plugin_name);
sfree(db->driver);
+ sfree(db->host);
for (size_t i = 0; i < db->driver_options_num; i++) {
sfree(db->driver_options[i].key);
if (db->q_prep_areas)
for (size_t i = 0; i < db->queries_num; ++i)
udb_query_delete_preparation_area(db->q_prep_areas[i]);
- free(db->q_prep_areas);
+ sfree(db->q_prep_areas);
+ /* N.B.: db->queries references objects "owned" by the global queries
+ * variable. Free the array here, but not the content. */
+ sfree(db->queries);
sfree(db);
} /* }}} void cdbi_database_free */
status = cf_util_get_string(child, &db->host);
else if (strcasecmp("Interval", child->key) == 0)
status = cf_util_get_cdtime(child, &db->interval);
+ else if (strcasecmp("Plugin", child->key) == 0)
+ status = cf_util_get_string(child, &db->plugin_name);
else {
WARNING("dbi plugin: Option `%s' not allowed here.", child->key);
status = -1;
udb_query_prepare_result(
q, prep_area, (db->host ? db->host : hostname_g),
- /* plugin = */ "dbi", db->name, column_names, column_num,
+ /* plugin = */ (db->plugin_name != NULL) ? db->plugin_name : "dbi",
+ db->name, column_names, column_num,
/* interval = */ (db->interval > 0) ? db->interval : 0);
/* 0 = error; 1 = success; */
{
struct group sg;
struct group *grp;
- char grbuf[4096];
int status;
+ long int grbuf_size = sysconf(_SC_GETGR_R_SIZE_MAX);
+ if (grbuf_size <= 0)
+ grbuf_size = sysconf(_SC_PAGESIZE);
+ if (grbuf_size <= 0)
+ grbuf_size = 4096;
+ char grbuf[grbuf_size];
+
grp = NULL;
status = getgrnam_r(group, &sg, grbuf, sizeof(grbuf), &grp);
if (status != 0) {
struct passwd *sp_ptr;
struct passwd sp;
- char nambuf[4096];
if (pl->pid != 0)
return -1;
+ long int nambuf_size = sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (nambuf_size <= 0)
+ nambuf_size = sysconf(_SC_PAGESIZE);
+ if (nambuf_size <= 0)
+ nambuf_size = 4096;
+ char nambuf[nambuf_size];
+
if ((create_pipe(fd_pipe_in) == -1) || (create_pipe(fd_pipe_out) == -1) ||
(create_pipe(fd_pipe_err) == -1))
goto failed;
struct group *gr_ptr = NULL;
struct group gr;
- status = getgrnam_r(pl->group, &gr, nambuf, sizeof(nambuf), &gr_ptr);
+ long int grbuf_size = sysconf(_SC_GETGR_R_SIZE_MAX);
+ if (grbuf_size <= 0)
+ grbuf_size = sysconf(_SC_PAGESIZE);
+ if (grbuf_size <= 0)
+ grbuf_size = 4096;
+ char grbuf[grbuf_size];
+
+ status = getgrnam_r(pl->group, &gr, grbuf, sizeof(grbuf), &gr_ptr);
if (status != 0) {
ERROR("exec plugin: Failed to get group information "
"for group ``%s'': %s",
typedef struct web_page_s web_page_t;
struct web_page_s /* {{{ */
{
+ char *plugin_name;
char *instance;
char *server;
memcached_free(wp->memc);
wp->memc = NULL;
+ sfree(wp->plugin_name);
sfree(wp->instance);
sfree(wp->server);
sfree(wp->key);
status = cmc_config_add_string("Server", &page->server, child);
else if (strcasecmp("Key", child->key) == 0)
status = cmc_config_add_string("Key", &page->key, child);
+ else if (strcasecmp("Plugin", child->key) == 0)
+ status = cmc_config_add_string("Plugin", &page->plugin_name, child);
else if (strcasecmp("Match", child->key) == 0)
/* Be liberal with failing matches => don't set `status'. */
cmc_config_add_match(page, child);
vl.values = &value;
vl.values_len = 1;
- sstrncpy(vl.plugin, "memcachec", sizeof(vl.plugin));
+ sstrncpy(vl.plugin, (wp->plugin_name != NULL) ? wp->plugin_name : "memcachec",
+ sizeof (vl.plugin));
sstrncpy(vl.plugin_instance, wp->instance, sizeof(vl.plugin_instance));
sstrncpy(vl.type, wm->type, sizeof(vl.type));
sstrncpy(vl.type_instance, wm->instance, sizeof(vl.type_instance));
char *connect_id;
char *username;
char *password;
+ char *plugin_name;
udb_query_preparation_area_t **q_prep_areas;
udb_query_t **queries;
sfree(db->username);
sfree(db->password);
sfree(db->queries);
+ sfree(db->plugin_name);
if (db->q_prep_areas != NULL)
for (size_t i = 0; i < db->queries_num; ++i)
db->connect_id = NULL;
db->username = NULL;
db->password = NULL;
+ db->plugin_name = NULL;
status = cf_util_get_string(ci, &db->name);
if (status != 0) {
status = cf_util_get_string(child, &db->username);
else if (strcasecmp("Password", child->key) == 0)
status = cf_util_get_string(child, &db->password);
+ else if (strcasecmp("Plugin", child->key) == 0)
+ status = cf_util_get_string(child, &db->plugin_name);
else if (strcasecmp("Query", child->key) == 0)
status = udb_query_pick_from_list(child, queries, queries_num,
&db->queries, &db->queries_num);
status = udb_query_prepare_result(
q, prep_area, (db->host != NULL) ? db->host : hostname_g,
- /* plugin = */ "oracle", db->name, column_names, column_num,
+ /* plugin = */ (db->plugin_name != NULL) ? db->plugin_name : "oracle",
+ db->name, column_names, column_num,
/* interval = */ 0);
if (status != 0) {
ERROR("oracle plugin: o_read_database_query (%s, %s): "
char *password;
char *instance;
+ char *plugin_name;
char *sslmode;
db->instance = sstrdup(name);
+ db->plugin_name = NULL;
+
db->sslmode = NULL;
db->krbsrvname = NULL;
sfree(db->instance);
+ sfree(db->plugin_name);
+
sfree(db->sslmode);
sfree(db->krbsrvname);
else
host = db->host;
- status =
- udb_query_prepare_result(q, prep_area, host, "postgresql", db->instance,
- column_names, (size_t)column_num, db->interval);
+ status = udb_query_prepare_result(
+ q, prep_area, host,
+ (db->plugin_name != NULL) ? db->plugin_name : "postgresql",
+ db->instance, column_names, (size_t)column_num, db->interval);
+
if (0 != status) {
log_err("udb_query_prepare_result failed with status %i.", status);
BAIL_OUT(-1);
cf_util_get_string(c, &db->password);
else if (0 == strcasecmp(c->key, "Instance"))
cf_util_get_string(c, &db->instance);
+ else if (0 == strcasecmp (c->key, "Plugin"))
+ cf_util_get_string (c, &db->plugin_name);
else if (0 == strcasecmp(c->key, "SSLMode"))
cf_util_get_string(c, &db->sslmode);
else if (0 == strcasecmp(c->key, "KRBSrvName"))
status = 0;
while (status == 0) {
- int oid_list_todo_num;
-
req = snmp_pdu_create(SNMP_MSG_GETNEXT);
if (req == NULL) {
ERROR("snmp plugin: snmp_pdu_create failed.");
break;
}
- oid_list_todo_num = 0;
+ size_t oid_list_todo_num = 0;
+ size_t var_idx[oid_list_len];
+ memset(var_idx, 0, sizeof(var_idx));
+
for (i = 0; i < oid_list_len; i++) {
/* Do not rerequest already finished OIDs */
if (!oid_list_todo[i])
continue;
- oid_list_todo_num++;
snmp_add_null_var(req, oid_list[i].oid, oid_list[i].oid_len);
+ var_idx[oid_list_todo_num] = i;
+ oid_list_todo_num++;
}
if (oid_list_todo_num == 0) {
/* The request is still empty - so we are finished */
DEBUG("snmp plugin: all variables have left their subtree");
+ snmp_free_pdu(req);
status = 0;
break;
}
res = NULL;
status = snmp_sess_synch_response(host->sess_handle, req, &res);
+
+ /* snmp_sess_synch_response always frees our req PDU */
+ req = NULL;
+
if ((status != STAT_SUCCESS) || (res == NULL)) {
char *errstr = NULL;
snmp_free_pdu(res);
res = NULL;
- /* snmp_synch_response already freed our PDU */
- req = NULL;
sfree(errstr);
csnmp_host_close_session(host);
break;
}
+ if (res->errstat != SNMP_ERR_NOERROR) {
+ if (res->errindex != 0) {
+ /* Find the OID which caused error */
+ for (i = 1, vb = res->variables; vb != NULL && i != res->errindex;
+ vb = vb->next_variable, i++)
+ /* do nothing */;
+ }
+
+ if ((res->errindex == 0) || (vb == NULL)) {
+ ERROR("snmp plugin: host %s; data %s: response error: %s (%li) ",
+ host->name, data->name, snmp_errstring(res->errstat),
+ res->errstat);
+ status = -1;
+ break;
+ }
+
+ char oid_buffer[1024] = {0};
+ snprint_objid(oid_buffer, sizeof(oid_buffer) - 1, vb->name,
+ vb->name_length);
+ NOTICE("snmp plugin: host %s; data %s: OID `%s` failed: %s", host->name,
+ data->name, oid_buffer, snmp_errstring(res->errstat));
+
+ /* Get value index from todo list and skip OID found */
+ assert(res->errindex <= oid_list_todo_num);
+ i = var_idx[res->errindex - 1];
+ assert(i < oid_list_len);
+ oid_list_todo[i] = 0;
+
+ snmp_free_pdu(res);
+ res = NULL;
+ continue;
+ }
+
for (vb = res->variables, i = 0; (vb != NULL);
vb = vb->next_variable, i++) {
/* Calculate value index from todo list */
snmp_free_pdu(res);
res = NULL;
- if (req != NULL)
- snmp_free_pdu(req);
- req = NULL;
if (status == 0)
csnmp_dispatch_table(host, data, instance_list_head, value_list_head);
/*
* <Plugin tail>
* <File "/var/log/exim4/mainlog">
- * Instance "exim"
+ * Plugin "mail"
+ * Instance "exim"
* Interval 60
* <Match>
* Regex "S=([1-9][0-9]*)"
} /* int ctail_config_add_match_dstype */
static int ctail_config_add_match(cu_tail_match_t *tm,
+ const char *plugin_name,
const char *plugin_instance,
oconfig_item_t *ci, cdtime_t interval) {
ctail_config_match_t cm = {0};
if (status == 0) {
// TODO(octo): there's nothing "simple" about the latency stuff …
status = tail_match_add_match_simple(
- tm, cm.regex, cm.excluderegex, cm.flags, "tail", plugin_instance,
+ tm, cm.regex, cm.excluderegex, cm.flags,
+ (plugin_name != NULL) ? plugin_name : "tail", plugin_instance,
cm.type, cm.type_instance, cm.latency, interval);
if (status != 0)
static int ctail_config_add_file(oconfig_item_t *ci) {
cu_tail_match_t *tm;
cdtime_t interval = 0;
+ char *plugin_name = NULL;
char *plugin_instance = NULL;
int num_matches = 0;
oconfig_item_t *option = ci->children + i;
int status = 0;
- if (strcasecmp("Instance", option->key) == 0)
+ if (strcasecmp("Plugin", option->key) == 0)
+ status = cf_util_get_string (option, &plugin_name);
+ else if (strcasecmp("Instance", option->key) == 0)
status = cf_util_get_string(option, &plugin_instance);
else if (strcasecmp("Interval", option->key) == 0)
cf_util_get_cdtime(option, &interval);
else if (strcasecmp("Match", option->key) == 0) {
- status = ctail_config_add_match(tm, plugin_instance, option, interval);
+ status = ctail_config_add_match(tm, plugin_name, plugin_instance, option,
+ interval);
if (status == 0)
num_matches++;
/* Be mild with failed matches.. */
break;
} /* for (i = 0; i < ci->children_num; i++) */
+ sfree(plugin_name);
sfree(plugin_instance);
if (num_matches == 0) {
typedef struct metric_definition_s metric_definition_t;
struct instance_definition_s {
+ char *plugin_name;
char *instance;
char *path;
cu_tail_t *tail;
vl.values_len = 1;
vl.values = &v;
- sstrncpy(vl.plugin, "tail_csv", sizeof(vl.plugin));
+ sstrncpy(vl.plugin, (id->plugin_name != NULL) ? id->plugin_name : "tail_csv",
+ sizeof(vl.plugin));
if (id->instance != NULL)
sstrncpy(vl.plugin_instance, id->instance, sizeof(vl.plugin_instance));
sstrncpy(vl.type, md->type, sizeof(vl.type));
cu_tail_destroy(id->tail);
id->tail = NULL;
+ sfree(id->plugin_name);
sfree(id->instance);
sfree(id->path);
sfree(id->metric_list);
id = calloc(1, sizeof(*id));
if (id == NULL)
return -1;
+ id->plugin_name = NULL;
id->instance = NULL;
id->path = NULL;
id->metric_list = NULL;
cf_util_get_cdtime(option, &id->interval);
else if (strcasecmp("TimeFrom", option->key) == 0)
status = tcsv_config_get_index(option, &id->time_from);
+ else if (strcasecmp("Plugin", option->key) == 0)
+ status = cf_util_get_string(option, &id->plugin_name);
else {
WARNING("tail_csv plugin: Option `%s' not allowed here.", option->key);
status = -1;
const char *grpname;
struct group *g;
struct group sg;
- char grbuf[4096];
+
+ long int grbuf_size = sysconf(_SC_GETGR_R_SIZE_MAX);
+ if (grbuf_size <= 0)
+ grbuf_size = sysconf(_SC_PAGESIZE);
+ if (grbuf_size <= 0)
+ grbuf_size = 4096;
+ char grbuf[grbuf_size];
grpname = (sock_group != NULL) ? sock_group : COLLECTD_GRP_NAME;
g = NULL;