close ($fh);
# Save the exit status of the check in $state
- $state = $?;
+ $state = $? >> 8;
if ($state == 0)
{
COLLECTDMONPIDDIR="/var/run"
COLLECTDMONPID="$COLLECTDMONPIDDIR/collectdmon.pid"
+MAXWAIT=30
+
if [ -r /etc/sysconfig/$service ]; then
. /etc/sysconfig/$service
fi
}
stop () {
echo -n $"Stopping collectd: "
- killproc -p $COLLECTDMONPID $prog
+ killproc -p $COLLECTDMONPID -d $MAXWAIT $prog
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$service
#</Plugin>
#<Plugin curl_json>
+# <URL "http://localhost:80/test.json">
+# Instance "test_http_json"
+# <Key "testArray/0">
+# Type "gauge"
+# # Expect: 1
+# </Key>
+# <Key "testArray/1">
+# Type "gauge"
+# # Expect: 2
+# </Key>
+# <Key "testArrayInbetween/0/blarg">
+# Type "gauge"
+# # Expect: 3
+# </Key>
+# <Key "testArrayInbetween/1/blub">
+# Type "gauge"
+# # Expect: 4
+# </Key>
+# <Key "testDirectHit">
+# Type "gauge"
+# # Expect: 5
+# </Key>
+# <Key "testSubLevelHit/oneMoreLevel">
+# Type "gauge"
+# # Expect: 6
+# </Key>
+# </URL>
+# put this as test.json on your webserver, the above config demonstraces
+# how to match them.
+# {
+# "testArray":[1,2],
+# "testArrayInbetween":[{"blarg":3},{"blub":4}],
+# "testDirectHit":5,
+# "testSubLevelHit":{"oneMoreLevel":6}
+# }
## See: http://wiki.apache.org/couchdb/Runtime_Statistics
# <URL "http://localhost:5984/_stats">
# Instance "httpd"
# DeleteGauges false
# DeleteSets false
# TimerPercentile 90.0
+# TimerPercentile 95.0
+# TimerPercentile 99.0
+# TimerLower false
+# TimerUpper false
+# TimerSum false
+# TimerCount false
#</Plugin>
#<Plugin swap>
computed latency. This is useful for cutting off the long tail latency, as it's
often done in I<Service Level Agreements> (SLAs).
-If not specified, no percentile is calculated / dispatched.
+Different percentiles can be calculated by setting this option several times.
+If none are specified, no percentiles are calculated / dispatched.
+
+=item B<TimerLower> B<false>|B<true>
+
+=item B<TimerUpper> B<false>|B<true>
+
+=item B<TimerSum> B<false>|B<true>
+
+=item B<TimerCount> B<false>|B<true>
+
+Calculate and dispatch various values out of I<Timer> metrics received during
+an interval. If set to B<False>, the default, these values aren't calculated /
+dispatched.
=back
=back
+=head2 Plugin C<write_redis>
+
+The I<write_redis plugin> submits values to I<Redis>, a data structure server.
+
+Synopsis:
+
+ <Plugin "write_redis">
+ <Node "example">
+ Host "localhost"
+ Port "6379"
+ Timeout 1000
+ </Node>
+ </Plugin>
+
+Values are submitted to I<Sorted Sets>, using the metric name as the key, and
+the timestamp as the score. Retrieving a date range can then be done using the
+C<ZRANGEBYSCORE> I<Redis> command. Additionnally, all the identifiers of these
+I<Sorted Sets> are kept in a I<Set> called C<collectd/values> and can be
+retrieved using the C<SMEMBERS> I<Redis> command. See
+L<http://redis.io/commands#sorted_set> and L<http://redis.io/commands#set> for
+details.
+
+The information shown in the synopsis above is the I<default configuration>
+which is used by the plugin if no configuration is present.
+
+The plugin can send values to multiple instances of I<Redis> by specifying
+one B<Node> block for each instance. Within the B<Node> blocks, the following
+options are available:
+
+=over 4
+
+=item B<Node> I<Nodename>
+
+The B<Node> block identifies a new I<Redis> node, that is a new I<Redis>
+instance running in an specified host and port. The name for node is a
+canonical identifier which is used as I<plugin instance>. It is limited to
+64E<nbsp>characters in length.
+
+=item B<Host> I<Hostname>
+
+The B<Host> option is the hostname or IP-address where the I<Redis> instance is
+running on.
+
+=item B<Port> I<Port>
+
+The B<Port> option is the TCP port on which the Redis instance accepts
+connections. Either a service name of a port number may be given. Please note
+that numerical port numbers must be given as a string, too.
+
+=item B<Timeout> I<Timeout in miliseconds>
+
+The B<Timeout> option sets the socket connection timeout, in milliseconds.
+
+=back
+
=head2 Plugin C<write_riemann>
The I<write_riemann plugin> will send values to I<Riemann>, a powerful stream
static mach_port_t port_host;
static processor_port_array_t cpu_list;
static mach_msg_type_number_t cpu_list_len;
-
-#if PROCESSOR_TEMPERATURE
-static int cpu_temp_retry_counter = 0;
-static int cpu_temp_retry_step = 1;
-static int cpu_temp_retry_max = 1;
-#endif /* PROCESSOR_TEMPERATURE */
/* #endif PROCESSOR_CPU_LOAD_INFO */
#elif defined(KERNEL_LINUX)
static int init (void)
{
-#if PROCESSOR_CPU_LOAD_INFO || PROCESSOR_TEMPERATURE
+#if PROCESSOR_CPU_LOAD_INFO
kern_return_t status;
port_host = mach_host_self ();
{
cdtime_t now = cdtime ();
-#if PROCESSOR_CPU_LOAD_INFO || PROCESSOR_TEMPERATURE /* {{{ */
+#if PROCESSOR_CPU_LOAD_INFO /* {{{ */
int cpu;
kern_return_t status;
-#if PROCESSOR_CPU_LOAD_INFO
processor_cpu_load_info_data_t cpu_info;
mach_msg_type_number_t cpu_info_len;
-#endif
-#if PROCESSOR_TEMPERATURE
- processor_info_data_t cpu_temp;
- mach_msg_type_number_t cpu_temp_len;
-#endif
host_t cpu_host;
for (cpu = 0; cpu < cpu_list_len; cpu++)
{
-#if PROCESSOR_CPU_LOAD_INFO
cpu_host = 0;
cpu_info_len = PROCESSOR_BASIC_INFO_COUNT;
- if ((status = processor_info (cpu_list[cpu],
- PROCESSOR_CPU_LOAD_INFO, &cpu_host,
- (processor_info_t) &cpu_info, &cpu_info_len)) != KERN_SUCCESS)
+ status = processor_info (cpu_list[cpu], PROCESSOR_CPU_LOAD_INFO, &cpu_host,
+ (processor_info_t) &cpu_info, &cpu_info_len);
+ if (status != KERN_SUCCESS)
{
- ERROR ("cpu plugin: processor_info failed with status %i", (int) status);
+ ERROR ("cpu plugin: processor_info (PROCESSOR_CPU_LOAD_INFO) failed: %s",
+ mach_error_string (status));
continue;
}
cpu_stage (cpu, CPU_STATE_NICE, (derive_t) cpu_info.cpu_ticks[CPU_STATE_NICE], now);
cpu_stage (cpu, CPU_STATE_SYSTEM, (derive_t) cpu_info.cpu_ticks[CPU_STATE_SYSTEM], now);
cpu_stage (cpu, CPU_STATE_IDLE, (derive_t) cpu_info.cpu_ticks[CPU_STATE_IDLE], now);
-#endif /* PROCESSOR_CPU_LOAD_INFO */
-
-#if PROCESSOR_TEMPERATURE
- /*
- * Not all Apple computers do have this ability. To minimize
- * the messages sent to the syslog we do an exponential
- * stepback if `processor_info' fails. We still try ~once a day
- * though..
- */
- if (cpu_temp_retry_counter > 0)
- {
- cpu_temp_retry_counter--;
- continue;
- }
-
- cpu_temp_len = PROCESSOR_INFO_MAX;
-
- status = processor_info (cpu_list[cpu],
- PROCESSOR_TEMPERATURE,
- &cpu_host,
- cpu_temp, &cpu_temp_len);
- if (status != KERN_SUCCESS)
- {
- ERROR ("cpu plugin: processor_info failed: %s",
- mach_error_string (status));
-
- cpu_temp_retry_counter = cpu_temp_retry_step;
- cpu_temp_retry_step *= 2;
- if (cpu_temp_retry_step > cpu_temp_retry_max)
- cpu_temp_retry_step = cpu_temp_retry_max;
-
- continue;
- }
-
- if (cpu_temp_len != 1)
- {
- DEBUG ("processor_info (PROCESSOR_TEMPERATURE) returned %i elements..?",
- (int) cpu_temp_len);
- continue;
- }
-
- cpu_temp_retry_counter = 0;
- cpu_temp_retry_step = 1;
-#endif /* PROCESSOR_TEMPERATURE */
}
/* }}} #endif PROCESSOR_CPU_LOAD_INFO */
if (key != NULL)
NOTICE ("curl_json plugin: Found \"%s\", but the configuration expects"
" a map.", buffer);
- cj_cb_inc_array_index (ctx, /* update_key = */ 0);
- return (CJ_CB_CONTINUE);
- } else {
+ cj_cb_inc_array_index (ctx, /* update_key = */ 1);
+ key = db->state[db->depth].key;
+ if (key == NULL) {
+ return (CJ_CB_CONTINUE);
+ }
+ }
+ else
+ {
cj_cb_inc_array_index (ctx, /* update_key = */ 1);
}
memcpy (name, in_name, name_len);
name[name_len] = 0;
- if (c_avl_get (tree, name, (void *) &value) == 0)
- db->state[db->depth].key = value;
+ if (c_avl_get (tree, name, (void *) &value) == 0) {
+ if (CJ_IS_KEY((cj_key_t*)value)) {
+ db->state[db->depth].key = value;
+ }
+ else {
+ db->state[db->depth].tree = (c_avl_tree_t*) value;
+ }
+ }
else if (c_avl_get (tree, CJ_ANY, (void *) &value) == 0)
- db->state[db->depth].key = value;
+ if (CJ_IS_KEY((cj_key_t*)value)) {
+ db->state[db->depth].key = value;
+ }
+ else {
+ db->state[db->depth].tree = (c_avl_tree_t*) value;
+ }
else
db->state[db->depth].key = NULL;
}
if ((buffer[buffer_len - 1] != '\n')
&& (buffer[buffer_len - 1] != '\r'))
break;
- buffer[buffer_len] = 0;
buffer_len--;
+ buffer[buffer_len] = 0;
}
return (buffer_len);
fc_chain_t *next;
}; /* }}} */
+/* Writer configuration. */
+struct fc_writer_s;
+typedef struct fc_writer_s fc_writer_t; /* {{{ */
+struct fc_writer_s
+{
+ char *plugin;
+ c_complain_t complaint;
+}; /* }}} */
+
/*
* Global variables
*/
{
int i;
- char **plugin_list;
- size_t plugin_list_len;
-
- plugin_list = NULL;
- plugin_list_len = 0;
+ fc_writer_t *plugin_list = NULL;
+ size_t plugin_list_len = 0;
for (i = 0; i < ci->children_num; i++)
{
oconfig_item_t *child = ci->children + i;
- char **temp;
+ fc_writer_t *temp;
int j;
if (strcasecmp ("Plugin", child->key) != 0)
for (j = 0; j < child->values_num; j++)
{
+ char *plugin;
+
if (child->values[j].type != OCONFIG_TYPE_STRING)
{
ERROR ("Filter subsystem: Built-in target `write': "
"The `Plugin' option accepts only string arguments.");
continue;
}
+ plugin = child->values[j].value.string;
- temp = (char **) realloc (plugin_list, (plugin_list_len + 2)
+ temp = (fc_writer_t *) realloc (plugin_list, (plugin_list_len + 2)
* (sizeof (*plugin_list)));
if (temp == NULL)
{
}
plugin_list = temp;
- plugin_list[plugin_list_len] = fc_strdup (child->values[j].value.string);
- if (plugin_list[plugin_list_len] == NULL)
+ plugin_list[plugin_list_len].plugin = fc_strdup (plugin);
+ if (plugin_list[plugin_list_len].plugin == NULL)
{
ERROR ("fc_bit_write_create: fc_strdup failed.");
continue;
}
+ C_COMPLAIN_INIT (&plugin_list[plugin_list_len].complaint);
plugin_list_len++;
- plugin_list[plugin_list_len] = NULL;
+ plugin_list[plugin_list_len].plugin = NULL;
} /* for (j = 0; j < child->values_num; j++) */
} /* for (i = 0; i < ci->children_num; i++) */
static int fc_bit_write_destroy (void **user_data) /* {{{ */
{
- char **plugin_list;
+ fc_writer_t *plugin_list;
size_t i;
if ((user_data == NULL) || (*user_data == NULL))
plugin_list = *user_data;
- for (i = 0; plugin_list[i] != NULL; i++)
- free (plugin_list[i]);
+ for (i = 0; plugin_list[i].plugin != NULL; i++)
+ free (plugin_list[i].plugin);
free (plugin_list);
return (0);
value_list_t *vl, notification_meta_t __attribute__((unused)) **meta,
void **user_data)
{
- char **plugin_list;
+ fc_writer_t *plugin_list;
int status;
plugin_list = NULL;
if (user_data != NULL)
plugin_list = *user_data;
- if ((plugin_list == NULL) || (plugin_list[0] == NULL))
+ if ((plugin_list == NULL) || (plugin_list[0].plugin == NULL))
{
- static c_complain_t enoent_complaint = C_COMPLAIN_INIT_STATIC;
+ static c_complain_t write_complaint = C_COMPLAIN_INIT_STATIC;
status = plugin_write (/* plugin = */ NULL, ds, vl);
if (status == ENOENT)
{
/* in most cases this is a permanent error, so use the complain
* mechanism rather than spamming the logs */
- c_complain (LOG_INFO, &enoent_complaint,
+ c_complain (LOG_INFO, &write_complaint,
"Filter subsystem: Built-in target `write': Dispatching value to "
"all write plugins failed with status %i (ENOENT). "
"Most likely this means you didn't load any write plugins.",
}
else if (status != 0)
{
- INFO ("Filter subsystem: Built-in target `write': Dispatching value to "
+ /* often, this is a permanent error (e.g. target system unavailable),
+ * so use the complain mechanism rather than spamming the logs */
+ c_complain (LOG_INFO, &write_complaint,
+ "Filter subsystem: Built-in target `write': Dispatching value to "
"all write plugins failed with status %i.", status);
}
else
{
assert (status == 0);
- c_release (LOG_INFO, &enoent_complaint, "Filter subsystem: "
+ c_release (LOG_INFO, &write_complaint, "Filter subsystem: "
"Built-in target `write': Some write plugin is back to normal "
"operation. `write' succeeded.");
}
{
size_t i;
- for (i = 0; plugin_list[i] != NULL; i++)
+ for (i = 0; plugin_list[i].plugin != NULL; i++)
{
- status = plugin_write (plugin_list[i], ds, vl);
+ status = plugin_write (plugin_list[i].plugin, ds, vl);
if (status != 0)
{
- INFO ("Filter subsystem: Built-in target `write': Dispatching value to "
- "the `%s' plugin failed with status %i.", plugin_list[i], status);
+ c_complain (LOG_INFO, &plugin_list[i].complaint,
+ "Filter subsystem: Built-in target `write': Dispatching value to "
+ "the `%s' plugin failed with status %i.",
+ plugin_list[i].plugin, status);
+ }
+ else
+ {
+ c_release (LOG_INFO, &plugin_list[i].complaint,
+ "Filter subsystem: Built-in target `write': Plugin `%s' is back "
+ "to normal operation. `write' succeeded.", plugin_list[i].plugin);
}
} /* for (i = 0; plugin_list[i] != NULL; i++) */
}
ssnprintf (errbuf, sizeof (errbuf),
"lt_dlopen (\"%s\") failed: %s. "
- "The most common cause for this problem are "
+ "The most common cause for this problem is "
"missing dependencies. Use ldd(1) to check "
"the dependencies of the plugin "
"/ shared object.",
const char *service = cb->service ? cb->service : WG_DEFAULT_SERVICE;
const char *protocol = cb->protocol ? cb->protocol : WG_DEFAULT_PROTOCOL;
+ char connerr[1024] = "";
+
if (cb->sock_fd > 0)
return (0);
{
cb->sock_fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype,
ai_ptr->ai_protocol);
- if (cb->sock_fd < 0)
+ if (cb->sock_fd < 0) {
+ char errbuf[1024];
+ snprintf (connerr, sizeof (connerr), "failed to open socket: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
continue;
+ }
status = connect (cb->sock_fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
if (status != 0)
{
+ char errbuf[1024];
+ snprintf (connerr, sizeof (connerr), "failed to connect to remote "
+ "host: %s", sstrerror (errno, errbuf, sizeof (errbuf)));
close (cb->sock_fd);
cb->sock_fd = -1;
continue;
if (cb->sock_fd < 0)
{
- char errbuf[1024];
+ if (connerr[0] == '\0')
+ /* this should not happen but try to get a message anyway */
+ sstrerror (errno, connerr, sizeof (connerr));
c_complain (LOG_ERR, &cb->init_complaint,
- "write_graphite plugin: Connecting to %s:%s via %s failed. "
- "The last error was: %s", node, service, protocol,
- sstrerror (errno, errbuf, sizeof (errbuf)));
+ "write_graphite plugin: Connecting to %s:%s via %s failed. "
+ "The last error was: %s", node, service, protocol, connerr);
return (-1);
}
else