native private static void log (int severity, String message);
/**
+ * Yield contents of collectd/src/collectd.h:hostname_g
+ *
+ * @return The hostname as set in the collectd configuration.
+ */
+ native public static java.lang.String getHostname ();
+
+ /**
* Prints an error message.
*/
public static void logError (String message)
return (this._host);
}
- try
- {
- InetAddress localHost = InetAddress.getLocalHost();
- return (localHost.getHostName ());
- }
- catch (UnknownHostException e)
- {
- return ("localhost");
- }
+ return Collectd.getHostname();
} /* }}} String getHost */
private void connect () /* {{{ */
or B<type_instance> without B<type> doesn't make much sense and should be
avoided.
+=item B<type:key=>I<value>
+
+Sets user defined meta information. The B<type> key is a single character
+defining the type of the meta information.
+
+The current supported types are:
+
+=over 8
+
+=item B<s> A string passed as-is.
+
+=back
+
=back
=back
or B<type_instance> without B<type> doesn't make much sense and should be
avoided.
-Please note that this is the same format as used in the B<exec plugin>, see
-L<collectd-exec(5)>.
+=item B<type:key=>I<value>
+
+Sets user defined meta information. The B<type> key is a single character
+defining the type of the meta information.
+
+The current supported types are:
+
+=over 8
+
+=item B<s> A string passed as-is.
=back
+=back
+
+Please note that this is the same format as used in the B<exec plugin>, see
+L<collectd-exec(5)>.
+
Example:
-> | PUTNOTIF type=temperature severity=warning time=1201094702 message=The roof is on fire!
<- | 0 Success
*/
char hostname_g[DATA_MAX_NAME_LEN];
cdtime_t interval_g;
+int pidfile_from_cli = 0;
int timeout_g;
#if HAVE_LIBKSTAT
kstat_ctl_t *kc;
#if COLLECT_DAEMON
case 'P':
global_option_set ("PIDFile", optarg);
+ pidfile_from_cli = 1;
break;
case 'f':
daemonize = 0;
# IgnoreSelected false
# HostnameFormat name
# InterfaceFormat name
+# PluginInstanceFormat name
#</Plugin>
#<Plugin load>
# VerifyPeer true
# VerifyHost true
# CACert "/etc/ssl/ca.crt"
+# CAPath "/etc/ssl/certs/"
+# ClientKey "/etc/ssl/client.pem"
+# ClientCert "/etc/ssl/client.crt"
+# ClientKeyPass "secret"
+# SSLVersion "TLSv1"
# Format "Command"
# StoreRates false
# </URL>
=back
+=head2 Plugin C<conntrack>
+
+This plugin collects IP conntrack statistics.
+
+=over 4
+
+=item B<OldFiles>
+
+Assume the B<conntrack_count> and B<conntrack_max> files to be found in
+F</proc/sys/net/ipv4/netfilter> instead of F</proc/sys/net/netfilter/>.
+
+=back
+
=head2 Plugin C<cpu>
The I<CPU plugin> collects CPU usage metrics.
=item B<ReportByCpu> B<false>|B<true>
When true reports usage for all cores. When false, reports cpu usage
-aggregated over all cores. Implies ValuesPercentage when false.
+aggregated over all cores.
Defaults to true.
=item B<ValuesPercentage> B<false>|B<true>
There must be at least one B<ValuesFrom> option inside each B<Result> block.
+=item B<MetadataFrom> [I<column0> I<column1> ...]
+
+Names the columns whose content is used as metadata for the data sets
+that are dispatched to the daemon.
+
+The actual data type in the columns is not that important. The plugin will
+automatically cast the values to the right type if it know how to do that. So
+it should be able to handle integer an floating point types, as well as strings
+(if they include a number at the beginning).
+
=back
=head3 B<Database> blocks
B<address> means use the interface's mac address. This is useful since the
interface path might change between reboots of a guest or across migrations.
+=item B<PluginInstanceFormat> B<name|uuid>
+
+When the libvirt plugin logs data, it sets the plugin_instance of the collected
+data according to this setting. The default is to use the guest name as provided
+by the hypervisor, which is equal to setting B<name>.
+
+B<uuid> means use the guest's UUID.
+
=back
+=head2 Plugin C<load>
possibly need this option. What CA certificates come bundled with C<libcurl>
and are checked by default depends on the distribution you use.
+=item B<CAPath> I<Directory>
+
+Directory holding one or more CA certificate files. You can use this if for
+some reason all the needed CA certificates aren't in the same file and can't be
+pointed to using the B<CACert> option. Requires C<libcurl> to be built against
+OpenSSL.
+
+=item B<ClientKey> I<File>
+
+File that holds the private key in PEM format to be used for certificate-based
+authentication.
+
+=item B<ClientCert> I<File>
+
+File that holds the SSL certificate to be used for certificate-based
+authentication.
+
+=item B<ClientKeyPass> I<Password>
+
+Password required to load the private key in B<ClientKey>.
+
+=item B<SSLVersion> B<SSLv2>|B<SSLv3>|B<TLSv1>|B<TLSv1_0>|B<TLSv1_1>|B<TLSv1_2>
+
+Define which SSL protocol version must be used. By default C<libcurl> will
+attempt to figure out the remote SSL protocol version. See
+L<curl_easy_setopt(3)> for more details.
+
=item B<Format> B<Command>|B<JSON>
Format of the output to generate. If set to B<Command>, will create output that
extern char hostname_g[];
extern cdtime_t interval_g;
+extern int pidfile_from_cli;
extern int timeout_g;
#endif /* COLLECTD_H */
if (i >= cf_global_options_num)
return (-1);
+ if (strcasecmp (option, "PIDFile") == 0 && pidfile_from_cli == 1)
+ {
+ DEBUG ("Configfile: Ignoring `PIDFILE' option because "
+ "command-line option `-P' take precedence.");
+ return (0);
+ }
+
sfree (cf_global_options[i].value);
if (value != NULL)
#define CONNTRACK_FILE "/proc/sys/net/netfilter/nf_conntrack_count"
#define CONNTRACK_MAX_FILE "/proc/sys/net/netfilter/nf_conntrack_max"
+#define CONNTRACK_FILE_OLD "/proc/sys/net/ipv4/netfilter/ip_conntrack_count"
+#define CONNTRACK_MAX_FILE_OLD "/proc/sys/net/ipv4/netfilter/ip_conntrack_max"
+
+static const char *config_keys[] =
+{
+ "OldFiles"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+/*
+ Each table/chain combo that will be queried goes into this list
+*/
+
+static int old_files = 0;
+
+static int conntrack_config(const char *key, const char *value)
+{
+ if (strcmp(key, "OldFiles") == 0)
+ old_files = 1;
+
+ return 0;
+}
static void conntrack_submit (const char *type, const char *type_instance,
value_t conntrack)
char buffer[64];
size_t buffer_len;
- fh = fopen (CONNTRACK_FILE, "r");
+ fh = fopen (old_files?CONNTRACK_FILE_OLD:CONNTRACK_FILE, "r");
if (fh == NULL)
return (-1);
conntrack_submit ("conntrack", NULL, conntrack);
- fh = fopen (CONNTRACK_MAX_FILE, "r");
+ fh = fopen (old_files?CONNTRACK_MAX_FILE_OLD:CONNTRACK_MAX_FILE, "r");
if (fh == NULL)
return (-1);
void module_register (void)
{
+ plugin_register_config ("conntrack", conntrack_config,
+ config_keys, config_keys_num);
plugin_register_read ("conntrack", conntrack_read);
} /* void module_register */
static int pnumcpu;
#endif /* HAVE_PERFSTAT */
-static value_to_rate_state_t *percents = NULL;
-static gauge_t agg_percents[CPU_SUBMIT_MAX] = {
+static value_to_rate_state_t *values = NULL;
+static gauge_t agg_values[CPU_SUBMIT_MAX] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
-static int percents_cells = 0;
+static int cpu_cells = 0;
static int cpu_count = 0;
{
if (strcasecmp (key, "ReportByCpu") == 0) {
report_by_cpu = IS_TRUE (value) ? 1 : 0;
- if (!report_by_cpu)
- report_percent = 1;
}
if (strcasecmp (key, "ValuesPercentage") == 0) {
report_percent = IS_TRUE (value) ? 1 : 0;
- if (!report_percent)
- report_by_cpu = 1;
}
if (strcasecmp (key, "ReportActive") == 0)
report_active = IS_TRUE (value) ? 1 : 0;
if (size <= 0)
return 0;
- if (percents_cells >= size)
+ if (cpu_cells >= size)
return 0;
- if (percents == NULL) {
- percents = malloc(size * sizeof(*percents));
- if (percents == NULL)
+ if (values == NULL) {
+ values = malloc(size * sizeof(*values));
+ if (values == NULL)
return -1;
for (i = 0; i < size; i++)
- memset(&percents[i], 0, sizeof(*percents));
- percents_cells = size;
+ memset(&values[i], 0, sizeof(*values));
+ cpu_cells = size;
return 0;
}
- tmp = realloc(percents, size * sizeof(*percents));
+ tmp = realloc(values, size * sizeof(*values));
if (tmp == NULL) {
ERROR ("cpu plugin: could not reserve enough space to hold states");
- percents = NULL;
+ values = NULL;
return -1;
}
- percents = tmp;
+ values = tmp;
- for (i = percents_cells ; i < size; i++)
- memset(&percents[i], 0, sizeof(*percents));
+ for (i = cpu_cells ; i < size; i++)
+ memset(&values[i], 0, sizeof(*values));
- percents_cells = size;
+ cpu_cells = size;
return 0;
} /* cpu_states_grow */
static void submit_flush (void)
{
int i = 0;
+ int cpu_submit_max = CPU_SUBMIT_MAX;
if (report_by_cpu) {
cpu_count = 0;
return;
}
- for (i = 0; i < CPU_SUBMIT_MAX; i++) {
- if (agg_percents[i] == -1)
+ if (report_active)
+ cpu_submit_max = CPU_SUBMIT_MAX;
+ else
+ cpu_submit_max = CPU_SUBMIT_ACTIVE;
+ for (i = 0; i < cpu_submit_max; i++) {
+ if (agg_values[i] == -1)
continue;
- submit_percent(-1, i, agg_percents[i] / cpu_count);
- agg_percents[i] = -1;
+ if (report_percent)
+ submit_percent(-1, i, agg_values[i] / cpu_count);
+ else
+ submit_derive(-1, i, agg_values[i]);
+ agg_values[i] = -1;
}
cpu_count = 0;
}
{
int i = 0;
+ int cpu_submit_max = CPU_SUBMIT_MAX;
+
+ if (report_active)
+ cpu_submit_max = CPU_SUBMIT_MAX;
+ else
+ cpu_submit_max = CPU_SUBMIT_ACTIVE;
if (!report_percent && report_by_cpu) {
derive_t cpu_active = 0;
if (report_active)
submit_derive(cpu_num, CPU_SUBMIT_ACTIVE, cpu_active);
}
- else /* we are reporting percents */
- {
+ else {
cdtime_t cdt;
- gauge_t percent;
+ gauge_t value;
gauge_t cpu_total = 0;
gauge_t cpu_active = 0;
gauge_t local_rates[CPU_SUBMIT_MAX];
cdt = cdtime();
for (i = 0; i < CPU_SUBMIT_ACTIVE; i++) {
- value_t rate;
- int index;
-
- if (derives[i] == -1)
- continue;
-
- index = (cpu_num * CPU_SUBMIT_MAX) + i;
- if (value_to_rate(&rate, derives[i], &percents[index],
- DS_TYPE_DERIVE, cdt) != 0) {
- local_rates[i] = -1;
- continue;
+ if (report_percent) {
+ value_t rate;
+ int index;
+
+ if (derives[i] == -1)
+ continue;
+
+ index = (cpu_num * CPU_SUBMIT_MAX) + i;
+ if (value_to_rate(&rate, derives[i], &values[index],
+ DS_TYPE_DERIVE, cdt) != 0) {
+ local_rates[i] = -1;
+ continue;
+ }
+
+ local_rates[i] = rate.gauge;
+ cpu_total += rate.gauge;
+ if (i != CPU_SUBMIT_IDLE)
+ cpu_active += rate.gauge;
+ }
+ else {
+ cpu_total += derives[i];
+ if (i != CPU_SUBMIT_IDLE)
+ cpu_active += derives[i];
}
-
- local_rates[i] = rate.gauge;
- cpu_total += rate.gauge;
- if (i != CPU_SUBMIT_IDLE)
- cpu_active += rate.gauge;
}
if (cpu_total == 0.0)
return;
if (report_active)
local_rates[CPU_SUBMIT_ACTIVE] = cpu_active;
- for (i = 0; i < CPU_SUBMIT_MAX; i++) {
+ for (i = 0; i < cpu_submit_max; i++) {
if (local_rates[i] == -1)
continue;
- percent = (local_rates[i] / cpu_total) * 100;
- if (report_by_cpu)
- submit_percent (cpu_num, i, percent);
+ if (report_percent)
+ value = (local_rates[i] / cpu_total) * 100;
+ else
+ value = derives[i];
+ if (report_by_cpu) {
+ if (report_percent) {
+ submit_percent (cpu_num, i, value);
+ } else {
+ submit_derive(cpu_num, i, value);
+ }
+ }
else {
- if (agg_percents[i] == -1)
- agg_percents[i] = percent;
+ if (agg_values[i] == -1)
+ agg_values[i] = value;
else
- agg_percents[i] += percent;
+ agg_values[i] += value;
}
-
}
}
}
if (key->instance == NULL)
{
- if ((db->depth == 0) || (strcmp ("", db->state[db->depth-1].name) == 0))
- sstrncpy (vl.type_instance, db->state[db->depth].name, sizeof (vl.type_instance));
- else
- ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%s-%s",
- db->state[db->depth-1].name, db->state[db->depth].name);
+ int i, len = 0;
+ for (i = 0; i < db->depth; i++)
+ len += ssnprintf(vl.type_instance+len, sizeof(vl.type_instance)-len,
+ i ? "-%s" : "%s", db->state[i+1].name);
}
else
sstrncpy (vl.type_instance, key->instance, sizeof (vl.type_instance));
static int cjni_match_target_invoke (const data_set_t *ds, value_list_t *vl,
notification_meta_t **meta, void **user_data);
-/*
+/*
* C to Java conversion functions
*/
static int ctoj_string (JNIEnv *jvm_env, /* {{{ */
return (0);
} /* }}} int ctoj_string */
+static jstring ctoj_output_string (JNIEnv *jvm_env, /* {{{ */
+ const char *string)
+{
+ jstring o_string;
+
+ /* Create a java.lang.String */
+ o_string = (*jvm_env)->NewStringUTF (jvm_env,
+ (string != NULL) ? string : "");
+ if (o_string == NULL)
+ {
+ ERROR ("java plugin: ctoj_output_string: NewStringUTF failed.");
+ return NULL;
+ }
+
+ return (o_string);
+} /* }}} int ctoj_output_string */
+
static int ctoj_int (JNIEnv *jvm_env, /* {{{ */
jint value,
jclass class_ptr, jobject object_ptr, const char *method_name)
return (0);
} /* }}} int jtoc_notification */
-/*
+/*
* Functions accessible from Java
*/
static jint JNICALL cjni_api_dispatch_values (JNIEnv *jvm_env, /* {{{ */
(*jvm_env)->ReleaseStringUTFChars (jvm_env, o_message, c_str);
} /* }}} void cjni_api_log */
+static jstring JNICALL cjni_api_get_hostname (JNIEnv *jvm_env, jobject this)
+{
+ return ctoj_output_string(jvm_env, hostname_g);
+}
+
/* List of ``native'' functions, i. e. C-functions that can be called from
* Java. */
static JNINativeMethod jni_api_functions[] = /* {{{ */
{ "log",
"(ILjava/lang/String;)V",
cjni_api_log },
+
+ { "getHostname",
+ "()Ljava/lang/String;",
+ cjni_api_get_hostname },
+
};
static size_t jni_api_functions_num = sizeof (jni_api_functions)
/ sizeof (jni_api_functions[0]);
#include <libxml/tree.h>
#include <libxml/xpath.h>
+/* Plugin name */
+#define PLUGIN_NAME "libvirt"
+
static const char *config_keys[] = {
"Connection",
"HostnameFormat",
"InterfaceFormat",
+ "PluginInstanceFormat",
+
NULL
};
#define NR_CONFIG_KEYS ((sizeof config_keys / sizeof config_keys[0]) - 1)
static enum hf_field hostname_format[HF_MAX_FIELDS] =
{ hf_name };
+/* PluginInstanceFormat */
+#define PLGINST_MAX_FIELDS 2
+
+enum plginst_field {
+ plginst_none = 0,
+ plginst_name,
+ plginst_uuid
+};
+
+static enum plginst_field plugin_instance_format[PLGINST_MAX_FIELDS] =
+ { plginst_name };
+
/* InterfaceFormat. */
enum if_field {
if_address,
const char *name;
char uuid[VIR_UUID_STRING_BUFLEN];
- sstrncpy (vl->plugin, "libvirt", sizeof (vl->plugin));
+ sstrncpy (vl->plugin, PLUGIN_NAME, sizeof (vl->plugin));
vl->host[0] = '\0';
}
vl->host[sizeof (vl->host) - 1] = '\0';
+
+ /* Construct the plugin instance field according to PluginInstanceFormat. */
+ for (i = 0; i < PLGINST_MAX_FIELDS; ++i) {
+ if (plugin_instance_format[i] == plginst_none)
+ continue;
+
+ n = sizeof(vl->plugin_instance) - strlen (vl->plugin_instance) - 2;
+
+ if (i > 0 && n >= 1) {
+ strncat (vl->plugin_instance, ":", 1);
+ n--;
+ }
+
+ switch (plugin_instance_format[i]) {
+ case plginst_none: break;
+ case plginst_name:
+ name = virDomainGetName (dom);
+ if (name)
+ strncat (vl->plugin_instance, name, n);
+ break;
+ case plginst_uuid:
+ if (virDomainGetUUIDString (dom, uuid) == 0)
+ strncat (vl->plugin_instance, uuid, n);
+ break;
+ }
+ }
+
+ vl->plugin_instance[sizeof (vl->plugin_instance) - 1] = '\0';
+
} /* void init_value_list */
static void
if (strcasecmp (key, "Connection") == 0) {
char *tmp = strdup (value);
if (tmp == NULL) {
- ERROR ("libvirt plugin: Connection strdup failed.");
+ ERROR (PLUGIN_NAME " plugin: Connection strdup failed.");
return 1;
}
sfree (conn_string);
value_copy = strdup (value);
if (value_copy == NULL) {
- ERROR ("libvirt plugin: strdup failed.");
+ ERROR (PLUGIN_NAME " plugin: strdup failed.");
return -1;
}
n = strsplit (value_copy, fields, HF_MAX_FIELDS);
if (n < 1) {
sfree (value_copy);
- ERROR ("HostnameFormat: no fields");
+ ERROR (PLUGIN_NAME " plugin: HostnameFormat: no fields");
return -1;
}
hostname_format[i] = hf_uuid;
else {
sfree (value_copy);
- ERROR ("unknown HostnameFormat field: %s", fields[i]);
+ ERROR (PLUGIN_NAME " plugin: unknown HostnameFormat field: %s", fields[i]);
return -1;
}
}
return 0;
}
+ if (strcasecmp (key, "PluginInstanceFormat") == 0) {
+ char *value_copy;
+ char *fields[PLGINST_MAX_FIELDS];
+ int i, n;
+
+ value_copy = strdup (value);
+ if (value_copy == NULL) {
+ ERROR (PLUGIN_NAME " plugin: strdup failed.");
+ return -1;
+ }
+
+ n = strsplit (value_copy, fields, PLGINST_MAX_FIELDS);
+ if (n < 1) {
+ sfree (value_copy);
+ ERROR (PLUGIN_NAME " plugin: PluginInstanceFormat: no fields");
+ return -1;
+ }
+
+ for (i = 0; i < n; ++i) {
+ if (strcasecmp (fields[i], "name") == 0)
+ plugin_instance_format[i] = plginst_name;
+ else if (strcasecmp (fields[i], "uuid") == 0)
+ plugin_instance_format[i] = plginst_uuid;
+ else {
+ sfree (value_copy);
+ ERROR (PLUGIN_NAME " plugin: unknown HostnameFormat field: %s", fields[i]);
+ return -1;
+ }
+ }
+ sfree (value_copy);
+
+ for (i = n; i < PLGINST_MAX_FIELDS; ++i)
+ plugin_instance_format[i] = plginst_none;
+
+ return 0;
+ }
+
if (strcasecmp (key, "InterfaceFormat") == 0) {
if (strcasecmp (value, "name") == 0)
interface_format = if_name;
else if (strcasecmp (value, "number") == 0)
interface_format = if_number;
else {
- ERROR ("unknown InterfaceFormat: %s", value);
+ ERROR (PLUGIN_NAME " plugin: unknown InterfaceFormat: %s", value);
return -1;
}
return 0;
conn = virConnectOpenReadOnly (conn_string);
if (conn == NULL) {
c_complain (LOG_ERR, &conn_complain,
- "libvirt plugin: Unable to connect: "
+ PLUGIN_NAME " plugin: Unable to connect: "
"virConnectOpenReadOnly failed.");
return -1;
}
}
c_release (LOG_NOTICE, &conn_complain,
- "libvirt plugin: Connection established.");
+ PLUGIN_NAME " plugin: Connection established.");
time (&t);
status = virDomainGetInfo (domains[i], &info);
if (status != 0)
{
- ERROR ("libvirt plugin: virDomainGetInfo failed with status %i.",
+ ERROR (PLUGIN_NAME " plugin: virDomainGetInfo failed with status %i.",
status);
continue;
}
vinfo = malloc (info.nrVirtCpu * sizeof (vinfo[0]));
if (vinfo == NULL) {
- ERROR ("libvirt plugin: malloc failed.");
+ ERROR (PLUGIN_NAME " plugin: malloc failed.");
continue;
}
/* cpu map = */ NULL, /* cpu map length = */ 0);
if (status < 0)
{
- ERROR ("libvirt plugin: virDomainGetVcpus failed with status %i.",
+ ERROR (PLUGIN_NAME " plugin: virDomainGetVcpus failed with status %i.",
status);
free (vinfo);
continue;
/* Get list of domains. */
domids = malloc (sizeof (int) * n);
if (domids == 0) {
- ERROR ("libvirt plugin: malloc failed.");
+ ERROR (PLUGIN_NAME " plugin: malloc failed.");
return -1;
}
goto cont;
if (add_domain (dom) < 0) {
- ERROR ("libvirt plugin: malloc failed.");
+ ERROR (PLUGIN_NAME " plugin: malloc failed.");
goto cont;
}
n = sizeof (char) * (strlen (domname) + strlen (devpath) + 2);
name = malloc (n);
if (name == NULL) {
- ERROR ("libvirt plugin: malloc failed.");
+ ERROR (PLUGIN_NAME " plugin: malloc failed.");
return 0;
}
ssnprintf (name, n, "%s:%s", domname, devpath);
void
module_register (void)
{
- plugin_register_config ("libvirt",
+ plugin_register_config (PLUGIN_NAME,
lv_config,
config_keys, NR_CONFIG_KEYS);
- plugin_register_init ("libvirt", lv_init);
- plugin_register_read ("libvirt", lv_read);
- plugin_register_shutdown ("libvirt", lv_shutdown);
+ plugin_register_init (PLUGIN_NAME, lv_init);
+ plugin_register_read (PLUGIN_NAME, lv_read);
+ plugin_register_shutdown (PLUGIN_NAME, lv_shutdown);
}
/*
/* see http://owfs.sourceforge.net/ow_table.html for a list of families */
static ow_family_features_t ow_family_features[] =
{
- {
+ { /* DS18S20 Precision Thermometer and DS1920 ibutton */
/* family = */ "10.",
{
{
}
},
/* features_num = */ 1
+ },
+ { /* DS1822 Econo Thermometer */
+ /* family = */ "22.",
+ {
+ {
+ /* filename = */ "temperature",
+ /* type = */ "temperature",
+ /* type_instance = */ ""
+ }
+ },
+ /* features_num = */ 1
+ },
+ { /* DS18B20 Programmable Resolution Thermometer */
+ /* family = */ "28.",
+ {
+ {
+ /* filename = */ "temperature",
+ /* type = */ "temperature",
+ /* type_instance = */ ""
+ }
+ },
+ /* features_num = */ 1
+ },
+ { /* DS2436 Volts/Temp */
+ /* family = */ "1B.",
+ {
+ {
+ /* filename = */ "temperature",
+ /* type = */ "temperature",
+ /* type_instance = */ ""
+ }
+ },
+ /* features_num = */ 1
+ },
+ { /* DS2438 Volts/Temp */
+ /* family = */ "26.",
+ {
+ {
+ /* filename = */ "temperature",
+ /* type = */ "temperature",
+ /* type_instance = */ ""
+ }
+ },
+ /* features_num = */ 1
}
};
static int ow_family_features_num = STATIC_ARRAY_SIZE (ow_family_features);
#define V1STRING "Common Name,Real Address,Bytes Received,Bytes Sent,Connected Since\n"
#define V2STRING "HEADER,CLIENT_LIST,Common Name,Real Address,Virtual Address,Bytes Received,Bytes Sent,Connected Since,Connected Since (time_t)\n"
#define V3STRING "HEADER CLIENT_LIST Common Name Real Address Virtual Address Bytes Received Bytes Sent Connected Since Connected Since (time_t)\n"
+#define V4STRING "HEADER,CLIENT_LIST,Common Name,Real Address,Virtual Address,Bytes Received,Bytes Sent,Connected Since,Connected Since (time_t),Username\n"
#define VSSTRING "OpenVPN STATISTICS\n"
MULTI1 = 1, /* status-version 1 */
MULTI2, /* status-version 2 */
MULTI3, /* status-version 3 */
+ MULTI4, /* status-version 4 */
SINGLE = 10 /* currently no versions for single mode, maybe in the future */
} version;
char *name;
return (read);
} /* int multi3_read */
+/* for reading status version 4 */
+static int multi4_read (char *name, FILE *fh)
+{
+ char buffer[1024];
+ char *fields[11];
+ const int max_fields = STATIC_ARRAY_SIZE (fields);
+ int fields_num, read = 0;
+ long long sum_users = 0;
+
+ while (fgets (buffer, sizeof (buffer), fh) != NULL)
+ {
+ fields_num = openvpn_strsplit (buffer, fields, max_fields);
+
+ /* status file is generated by openvpn/multi.c:multi_print_status()
+ * http://svn.openvpn.net/projects/openvpn/trunk/openvpn/multi.c
+ *
+ * The line we're expecting has 9 fields. We ignore all lines
+ * with more or less fields.
+ */
+ if (fields_num != 9)
+ continue;
+
+
+ if (strcmp (fields[0], "CLIENT_LIST") != 0)
+ continue;
+
+
+ if (collect_user_count)
+ /* If so, sum all users, ignore the individuals*/
+ {
+ sum_users += 1;
+ }
+ if (collect_individual_users)
+ {
+ if (new_naming_schema)
+ {
+ /* plugin inst = file name, type inst = fields[1] */
+ iostats_submit (name, /* vpn instance */
+ fields[1], /* "Common Name" */
+ atoll (fields[4]), /* "Bytes Received" */
+ atoll (fields[5])); /* "Bytes Sent" */
+ }
+ else
+ {
+ /* plugin inst = fields[1], type inst = "" */
+ iostats_submit (fields[1], /* "Common Name" */
+ NULL, /* unused when in multimode */
+ atoll (fields[4]), /* "Bytes Received" */
+ atoll (fields[5])); /* "Bytes Sent" */
+ }
+ }
+
+ read = 1;
+ }
+
+ if (collect_user_count)
+ {
+ numusers_submit(name, name, sum_users);
+ read = 1;
+ }
+
+ return (read);
+} /* int multi4_read */
+
/* read callback */
static int openvpn_read (void)
{
FILE *fh;
- int i, read;
+ int i, vpn_read, read;
- read = 0;
+ vpn_read = read = 0;
/* call the right read function for every status entry in the list */
for (i = 0; i < vpn_num; i++)
switch (vpn_list[i]->version)
{
case SINGLE:
- read = single_read(vpn_list[i]->name, fh);
+ vpn_read = single_read(vpn_list[i]->name, fh);
break;
case MULTI1:
- read = multi1_read(vpn_list[i]->name, fh);
+ vpn_read = multi1_read(vpn_list[i]->name, fh);
break;
case MULTI2:
- read = multi2_read(vpn_list[i]->name, fh);
+ vpn_read = multi2_read(vpn_list[i]->name, fh);
break;
case MULTI3:
- read = multi3_read(vpn_list[i]->name, fh);
+ vpn_read = multi3_read(vpn_list[i]->name, fh);
+ break;
+
+ case MULTI4:
+ vpn_read = multi4_read(vpn_list[i]->name, fh);
break;
}
fclose (fh);
+ read += vpn_read;
}
return (read ? 0 : -1);
version = MULTI3;
break;
}
+ /* searching for multi version 4 */
+ else if (strcmp (buffer, V4STRING) == 0)
+ {
+ DEBUG ("openvpn plugin: found status file version MULTI4");
+ version = MULTI4;
+ break;
+ }
}
if (version == 0)
": Value is no longer missing.");
else
status = ssnprintf (buf, bufsize,
- ": All data sources are within range again.");
+ ": All data sources are within range again. "
+ "Current value of \"%s\" is %f.",
+ ds->ds[ds_index].name, values[ds_index]);
buf += status;
bufsize -= status;
}
/* XXX: This is an experimental code, not optimized, not fast, not reliable,
* and probably, do not work as you expect. Enjoy! :D */
- if ( (th->hysteresis > 0) && ((prev_state = uc_get_state(ds,vl)) != STATE_OKAY) )
- {
- switch(prev_state)
+ if (th->hysteresis > 0)
+ {
+ prev_state = uc_get_state(ds,vl);
+ /* The purpose of hysteresis is elliminating flapping state when the value
+ * oscilates around the thresholds. In other words, what is important is
+ * the previous state; if the new value would trigger a transition, make
+ * sure that we artificially widen the range which is considered to apply
+ * for the previous state, and only trigger the notification if the value
+ * is outside of this expanded range.
+ *
+ * There is no hysteresis for the OKAY state.
+ * */
+ gauge_t hysteresis_for_warning = 0, hysteresis_for_failure = 0;
+ switch (prev_state)
{
case STATE_ERROR:
- if ( (!isnan (th->failure_min) && ((th->failure_min + th->hysteresis) < values[ds_index])) ||
- (!isnan (th->failure_max) && ((th->failure_max - th->hysteresis) > values[ds_index])) )
- return (STATE_OKAY);
- else
- is_failure++;
+ hysteresis_for_failure = th->hysteresis;
+ break;
case STATE_WARNING:
- if ( (!isnan (th->warning_min) && ((th->warning_min + th->hysteresis) < values[ds_index])) ||
- (!isnan (th->warning_max) && ((th->warning_max - th->hysteresis) > values[ds_index])) )
- return (STATE_OKAY);
- else
- is_warning++;
- }
+ hysteresis_for_warning = th->hysteresis;
+ break;
+ case STATE_OKAY:
+ /* do nothing -- the hysteresis only applies to the non-normal states */
+ break;
+ }
+
+ if ((!isnan (th->failure_min) && (th->failure_min + hysteresis_for_failure > values[ds_index]))
+ || (!isnan (th->failure_max) && (th->failure_max - hysteresis_for_failure < values[ds_index])))
+ is_failure++;
+
+ if ((!isnan (th->warning_min) && (th->warning_min + hysteresis_for_warning > values[ds_index]))
+ || (!isnan (th->warning_max) && (th->warning_max - hysteresis_for_warning < values[ds_index])))
+ is_warning++;
+
}
else { /* no hysteresis */
if ((!isnan (th->failure_min) && (th->failure_min > values[ds_index]))
if ((!isnan (th->warning_min) && (th->warning_min > values[ds_index]))
|| (!isnan (th->warning_max) && (th->warning_max < values[ds_index])))
is_warning++;
- }
+ }
if (is_failure != 0)
return (STATE_ERROR);
DEBUG ("utils_cmd_putnotif: set_option (option = %s, value = %s);",
option, value);
+ /* Add a meta option in the form: <type>:<key> */
+ if (option[0] != '\0' && option[1] == ':') {
+ /* Refuse empty key */
+ if (option[2] == '\0')
+ return (1);
+
+ if (option[0] == 's')
+ return plugin_notification_meta_add_string (n, option + 2, value);
+ else
+ return (1);
+ }
+
if (strcasecmp ("severity", option) == 0)
return (set_option_severity (n, value));
else if (strcasecmp ("time", option) == 0)
size_t instances_num;
char **values;
size_t values_num;
+ char **metadata;
+ size_t metadata_num;
udb_result_t *next;
}; /* }}} */
const data_set_t *ds;
size_t *instances_pos;
size_t *values_pos;
+ size_t *metadata_pos;
char **instances_buffer;
char **values_buffer;
+ char **metadata_buffer;
struct udb_result_preparation_area_s *next;
}; /* }}} */
{
value_list_t vl = VALUE_LIST_INIT;
size_t i;
+ int status;
assert (r != NULL);
assert (r_area->ds != NULL);
vl.type_instance[sizeof (vl.type_instance) - 1] = 0;
/* }}} */
+ /* Annotate meta data. {{{ */
+ if (r->metadata_num > 0)
+ {
+ vl.meta = meta_data_create ();
+ if (vl.meta == NULL)
+ {
+ ERROR ("db query utils:: meta_data_create failed.");
+ return (-ENOMEM);
+ }
+
+ for (i = 0; i < r->metadata_num; i++)
+ {
+ status = meta_data_add_string (vl.meta, r->metadata[i],
+ r_area->metadata_buffer[i]);
+ if (status != 0)
+ {
+ ERROR ("db query utils:: meta_data_add_string failed.");
+ meta_data_destroy (vl.meta);
+ vl.meta = NULL;
+ return (status);
+ }
+ }
+ }
+ /* }}} */
+
plugin_dispatch_values (&vl);
+ if (r->metadata_num > 0)
+ {
+ meta_data_destroy (vl.meta);
+ vl.meta = NULL;
+ }
sfree (vl.values);
return (0);
} /* }}} void udb_result_submit */
prep_area->ds = NULL;
sfree (prep_area->instances_pos);
sfree (prep_area->values_pos);
+ sfree (prep_area->metadata_pos);
sfree (prep_area->instances_buffer);
sfree (prep_area->values_buffer);
+ sfree (prep_area->metadata_buffer);
} /* }}} void udb_result_finish_result */
static int udb_result_handle_result (udb_result_t *r, /* {{{ */
for (i = 0; i < r->values_num; i++)
r_area->values_buffer[i] = column_values[r_area->values_pos[i]];
+ for (i = 0; i < r->metadata_num; i++)
+ r_area->metadata_buffer[i] = column_values[r_area->metadata_pos[i]];
+
return udb_result_submit (r, r_area, q, q_area);
} /* }}} int udb_result_handle_result */
prep_area->ds = NULL; \
sfree (prep_area->instances_pos); \
sfree (prep_area->values_pos); \
+ sfree (prep_area->metadata_pos); \
sfree (prep_area->instances_buffer); \
sfree (prep_area->values_buffer); \
+ sfree (prep_area->metadata_buffer); \
return (status)
/* Make sure previous preparations are cleaned up. */
udb_result_finish_result (r, prep_area);
prep_area->instances_pos = NULL;
prep_area->values_pos = NULL;
+ prep_area->metadata_pos = NULL;
/* Read `ds' and check number of values {{{ */
prep_area->ds = plugin_get_ds (r->type);
}
/* }}} */
- /* Allocate r->instances_pos, r->values_pos, r->instances_buffer, and
- * r->values_buffer {{{ */
+ /* Allocate r->instances_pos, r->values_pos, r->metadata_post,
+ * r->instances_buffer, r->values_buffer, and r->metadata_buffer {{{ */
if (r->instances_num > 0)
{
prep_area->instances_pos
ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
BAIL_OUT (-ENOMEM);
}
+
+ prep_area->metadata_pos
+ = (size_t *) calloc (r->metadata_num, sizeof (size_t));
+ if (prep_area->metadata_pos == NULL)
+ {
+ ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
+ BAIL_OUT (-ENOMEM);
+ }
+
+ prep_area->metadata_buffer
+ = (char **) calloc (r->metadata_num, sizeof (char *));
+ if (prep_area->metadata_buffer == NULL)
+ {
+ ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
+ BAIL_OUT (-ENOMEM);
+ }
+
/* }}} */
/* Determine the position of the instance columns {{{ */
}
} /* }}} for (i = 0; i < r->values_num; i++) */
+ /* Determine the position of the metadata columns {{{ */
+ for (i = 0; i < r->metadata_num; i++)
+ {
+ size_t j;
+
+ for (j = 0; j < column_num; j++)
+ {
+ if (strcasecmp (r->metadata[i], column_names[j]) == 0)
+ {
+ prep_area->metadata_pos[i] = j;
+ break;
+ }
+ }
+
+ if (j >= column_num)
+ {
+ ERROR ("db query utils: udb_result_prepare_result: "
+ "Metadata column `%s' could not be found.",
+ r->values[i]);
+ BAIL_OUT (-ENOENT);
+ }
+ } /* }}} for (i = 0; i < r->metadata_num; i++) */
+
#undef BAIL_OUT
return (0);
} /* }}} int udb_result_prepare_result */
sfree (r->values[i]);
sfree (r->values);
+ for (i = 0; i < r->metadata_num; i++)
+ sfree (r->metadata[i]);
+ sfree (r->metadata);
+
udb_result_free (r->next);
sfree (r);
r->instance_prefix = NULL;
r->instances = NULL;
r->values = NULL;
+ r->metadata = NULL;
r->next = NULL;
/* Fill the `udb_result_t' structure.. */
status = udb_config_add_string (&r->instances, &r->instances_num, child);
else if (strcasecmp ("ValuesFrom", child->key) == 0)
status = udb_config_add_string (&r->values, &r->values_num, child);
+ else if (strcasecmp ("MetadataFrom", child->key) == 0)
+ status = udb_config_add_string (&r->metadata, &r->metadata_num, child);
else
{
WARNING ("db query utils: Query `%s': Option `%s' not allowed here.",
{
double average;
- if (lc == NULL)
+ if ((lc == NULL) || (lc->num == 0))
return (0);
average = CDTIME_T_TO_DOUBLE (lc->sum) / ((double) lc->num);
int sum;
size_t i;
- if ((lc == NULL) || !((percent > 0.0) && (percent < 100.0)))
+ if ((lc == NULL) || (lc->num == 0) || !((percent > 0.0) && (percent < 100.0)))
return (0);
/* Find index i so that at least "percent" events are within i+1 ms. */
/* Look for the equal sign */
buffer = key;
- while (isalnum ((int) *buffer) || *buffer == '_')
+ while (isalnum ((int) *buffer) || *buffer == '_' || *buffer == ':')
buffer++;
if ((*buffer != '=') || (buffer == key))
return (1);
DEFAULT_VERSION="5.4.0.git"
-VERSION="`git describe 2> /dev/null | sed -e 's/^collectd-//'`"
+VERSION="`git describe 2> /dev/null | grep collectd | sed -e 's/^collectd-//'`"
if test -z "$VERSION"; then
VERSION="$DEFAULT_VERSION"