From: Pavel Rochnyak Date: Fri, 20 Oct 2017 06:34:43 +0000 (+0700) Subject: Merge pull request #2071 from maryamtahhan/feat_ipmi_analog X-Git-Tag: collectd-5.8.0~34 X-Git-Url: https://git.octo.it/?a=commitdiff_plain;h=7e860946c5cf09d9ddc5428bc8efc06fb15e320e;hp=3d5a504a44fe11fbd5141f3987b097d69983db1e;p=collectd.git Merge pull request #2071 from maryamtahhan/feat_ipmi_analog ipmi plugin: add more analog sensors support --- diff --git a/AUTHORS b/AUTHORS index b99c156a..4df743c5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -116,6 +116,9 @@ Dan Ryder David Bacher - serial plugin. +Denis Pompilio + - Improvements to the write_http plugin. + Doug MacEachern - The `-T' option (config testing mode). - OpenVPN plugin. diff --git a/Makefile.am b/Makefile.am index 04636b3f..ae027a36 100644 --- a/Makefile.am +++ b/Makefile.am @@ -199,6 +199,8 @@ collectd_SOURCES = \ src/daemon/configfile.h \ src/daemon/filter_chain.c \ src/daemon/filter_chain.h \ + src/daemon/globals.c \ + src/daemon/globals.h \ src/daemon/meta_data.c \ src/daemon/meta_data.h \ src/daemon/plugin.c \ diff --git a/src/collectd-snmp.pod b/src/collectd-snmp.pod index edb95060..d615088e 100644 --- a/src/collectd-snmp.pod +++ b/src/collectd-snmp.pod @@ -36,6 +36,8 @@ collectd-snmp - Documentation of collectd's C Community "community_string" Collect "std_traffic" Interval 120 + Timeout 10 + Retries 1 Address "192.168.0.42" @@ -60,6 +62,8 @@ collectd-snmp - Documentation of collectd's C Community "more_communities" Collect "powerplus_voltge_input" Interval 300 + Timeout 5 + Retries 5 @@ -78,7 +82,7 @@ and ten threads are used. =head1 CONFIGURATION Since the aim of the C is to provide a generic interface to SNMP, -it's configuration is not trivial and may take some time. +its configuration is not trivial and may take some time. Since the C library is used you can use all the environment variables that are interpreted by that package. See L for more details. @@ -281,6 +285,15 @@ switches, embedded devices, rack monitoring systems and so on. Since the B of generated RRD files depends on this setting it's wise to select a reasonable value once and never change it. +=item B I + +How long to wait for a response. The C library default is 1 second. + +=item B I + +The number of times that a query should be retried after the Timeout expires. +The C library default is 5. + =back =head1 SEE ALSO diff --git a/src/collectd.conf.in b/src/collectd.conf.in index 5f58a6e9..261abdfd 100644 --- a/src/collectd.conf.in +++ b/src/collectd.conf.in @@ -601,6 +601,7 @@ # Size "+10k" # Recursive true # IncludeHidden false +# RegularOnly true # #FilesSizeType "bytes" # #FilesCountType "files" # #TypeInstance "instance" @@ -1316,6 +1317,8 @@ # Community "community_string" # Collect "std_traffic" # Interval 120 +# Timeout 10 +# Retries 1 # # # Address "192.168.0.42" @@ -1329,6 +1332,8 @@ # Community "more_communities" # Collect "powerplus_voltge_input" # Interval 300 +# Timeout 5 +# Retries 5 # # @@ -1636,6 +1641,7 @@ # Header "X-Custom-Header: custom_value" # SSLVersion "TLSv1" # Format "Command" +# Prefix "collectd" # metric prefix, only available for KAIROSDB format # Attribute "key" "value" # only available for KAIROSDB format # TTL 0 # data ttl, only available for KAIROSDB format # Metrics true diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod index 9548fd63..4c4c261e 100644 --- a/src/collectd.conf.pod +++ b/src/collectd.conf.pod @@ -2834,6 +2834,11 @@ Controls whether or not to include "hidden" files and directories in the count. "Hidden" files and directories are those, whose name begins with a dot. Defaults to I, i.e. by default hidden files and directories are ignored. +=item B I|I + +Controls whether or not to include only regular files in the count. +Defaults to I, i.e. by default non regular files are ignored. + =item B I Sets the type used to dispatch files combined size. Empty value ("") disables @@ -6804,12 +6809,15 @@ C/var/run/collectd-powerdns>. =head2 Plugin C -=over 4 +Collects information about processes of local system. -=item B I +By default, with no process matches configured, only general statistics is +collected: the number of processes in each state and fork rate. + +Process matches can be configured by B and B options. +These may also be a block in which further options may be specified. -Select more detailed statistics of processes matching this name. The statistics -collected for these selected processes are: +The statistics collected for matched processes are: - size of the resident segment size (RSS) - user- and system-time used - number of processes @@ -6820,21 +6828,49 @@ collected for these selected processes are: - context switches (under Linux) - minor and major pagefaults. -Some platforms have a limit on the length of process names. I must stay -below this limit. +B + + + CollectFileDescriptor true + CollectContextSwitch true + Process "name" + ProcessMatch "name" "regex" + + CollectFileDescriptor false + CollectContextSwitch false + + + CollectFileDescriptor false + CollectContextSwitch true + + + +=over 4 + +=item B I + +Select more detailed statistics of processes matching this name. + +Some platforms have a limit on the length of process names. +I must stay below this limit. =item B I I -Similar to the B option this allows one to select more detailed -statistics of processes matching the specified I (see L for -details). The statistics of all matching processes are summed up and -dispatched to the daemon using the specified I as an identifier. This -allows one to "group" several processes together. I must not contain -slashes. +Select more detailed statistics of processes matching the specified I +(see L for details). The statistics of all matching processes are +summed up and dispatched to the daemon using the specified I as an +identifier. This allows one to "group" several processes together. +I must not contain slashes. =item B I -Collect context switch of the process. +Collect the number of context switches for matched processes. +Disabled by default. + +=item B I + +Collect number of file descriptors of matched processes. +Disabled by default. =item B I @@ -6844,6 +6880,10 @@ the Linux kernel. =back +Options B and B may be used inside +B and B blocks - then they affect corresponding match +only. Otherwise they set the default value for subsequent matches. + =head2 Plugin C Collects a lot of information about various network protocols, such as I, @@ -9270,6 +9310,12 @@ Sets the Cassandra ttl for the data points. Please refer to L +=item B I + +Only available for the KAIROSDB output format. + +Sets the metrics prefix I. Defaults to I. + =item B B|B Controls whether I are POSTed to this location. Defaults to B. diff --git a/src/daemon/collectd.c b/src/daemon/collectd.c index af8fb568..dd9b12f8 100644 --- a/src/daemon/collectd.c +++ b/src/daemon/collectd.c @@ -47,16 +47,6 @@ #define COLLECTD_LOCALE "C" #endif -/* - * Global variables - */ -char hostname_g[DATA_MAX_NAME_LEN]; -cdtime_t interval_g; -int timeout_g; -#if HAVE_LIBKSTAT -kstat_ctl_t *kc; -#endif /* HAVE_LIBKSTAT */ - static int loop = 0; static void *do_flush(void __attribute__((unused)) * arg) { @@ -91,13 +81,19 @@ static int init_hostname(void) { struct addrinfo *ai_list; int status; + long hostname_len = sysconf(_SC_HOST_NAME_MAX); + if (hostname_len == -1) { + hostname_len = NI_MAXHOST; + } + char hostname[hostname_len]; + str = global_option_get("Hostname"); if ((str != NULL) && (str[0] != 0)) { - sstrncpy(hostname_g, str, sizeof(hostname_g)); + hostname_set(str); return 0; } - if (gethostname(hostname_g, sizeof(hostname_g)) != 0) { + if (gethostname(hostname, hostname_len) != 0) { fprintf(stderr, "`gethostname' failed and no " "hostname was configured.\n"); return -1; @@ -109,14 +105,14 @@ static int init_hostname(void) { struct addrinfo ai_hints = {.ai_flags = AI_CANONNAME}; - status = getaddrinfo(hostname_g, NULL, &ai_hints, &ai_list); + status = getaddrinfo(hostname, NULL, &ai_hints, &ai_list); if (status != 0) { ERROR("Looking up \"%s\" failed. You have set the " "\"FQDNLookup\" option, but I cannot resolve " "my hostname to a fully qualified domain " "name. Please fix the network " "configuration.", - hostname_g); + hostname); return -1; } @@ -125,7 +121,7 @@ static int init_hostname(void) { if (ai_ptr->ai_canonname == NULL) continue; - sstrncpy(hostname_g, ai_ptr->ai_canonname, sizeof(hostname_g)); + hostname_set(ai_ptr->ai_canonname); break; } @@ -455,23 +451,19 @@ static int notify_systemd(void) { } #endif /* KERNEL_LINUX */ -int main(int argc, char **argv) { - const char *configfile = CONFIGFILE; - int test_config = 0; - int test_readall = 0; - const char *basedir; - _Bool opt_create_basedir = 1; -#if COLLECT_DAEMON - pid_t pid; - int daemonize = 1; -#endif - int exit_status = 0; +struct cmdline_config { + _Bool test_config; + _Bool test_readall; + _Bool create_basedir; + const char *configfile; + _Bool daemonize; +}; +void read_cmdline(int argc, char **argv, struct cmdline_config *config) { /* read options */ while (1) { int c; - - c = getopt(argc, argv, "BhtTC:" + c = getopt(argc, argv, "htTC:" #if COLLECT_DAEMON "fP:" #endif @@ -482,19 +474,19 @@ int main(int argc, char **argv) { switch (c) { case 'B': - opt_create_basedir = 0; + config->create_basedir = 0; break; case 'C': - configfile = optarg; + config->configfile = optarg; break; case 't': - test_config = 1; + config->test_config = 1; break; case 'T': - test_readall = 1; + config->test_readall = 1; global_option_set("ReadThreads", "-1", 1); #if COLLECT_DAEMON - daemonize = 0; + config->daemonize = 0; #endif /* COLLECT_DAEMON */ break; #if COLLECT_DAEMON @@ -502,7 +494,7 @@ int main(int argc, char **argv) { global_option_set("PIDFile", optarg, 1); break; case 'f': - daemonize = 0; + config->daemonize = 0; break; #endif /* COLLECT_DAEMON */ case 'h': @@ -512,19 +504,17 @@ int main(int argc, char **argv) { exit_usage(1); } /* switch (c) */ } /* while (1) */ +} - if (optind < argc) - exit_usage(1); - - plugin_init_ctx(); - +int configure_collectd(struct cmdline_config *config) { + const char *basedir; /* * Read options from the config file, the environment and the command * line (in that order, with later options overwriting previous ones in * general). * Also, this will automatically load modules. */ - if (cf_read(configfile)) { + if (cf_read(config->configfile)) { fprintf(stderr, "Error: Reading the config file failed!\n" "Read the logs for details.\n"); return 1; @@ -538,23 +528,47 @@ int main(int argc, char **argv) { fprintf(stderr, "Don't have a basedir to use. This should not happen. Ever."); return 1; - } else if (change_basedir(basedir, opt_create_basedir)) { + } else if (change_basedir(basedir, config->create_basedir)) { fprintf(stderr, "Error: Unable to change to directory `%s'.\n", basedir); return 1; } /* - * Set global variables or, if that failes, exit. We cannot run with + * Set global variables or, if that fails, exit. We cannot run with * them being uninitialized. If nothing is configured, then defaults * are being used. So this means that the user has actually done * something wrong. */ if (init_global_variables() != 0) - exit(EXIT_FAILURE); + return 1; + + return 0; +} + +int main(int argc, char **argv) { +#if COLLECT_DAEMON + pid_t pid; +#endif + int exit_status = 0; - if (test_config) + struct cmdline_config config = { + .daemonize = 1, .create_basedir = 1, .configfile = CONFIGFILE, + }; + + read_cmdline(argc, argv, &config); + + if (config.test_config) return 0; + if (optind < argc) + exit_usage(1); + + plugin_init_ctx(); + + int status; + if ((status = configure_collectd(&config)) != 0) + exit(EXIT_FAILURE); + #if COLLECT_DAEMON /* * fork off child @@ -567,7 +581,7 @@ int main(int argc, char **argv) { * Only daemonize if we're not being supervised * by upstart or systemd (when using Linux). */ - if (daemonize + if (config.daemonize #ifdef KERNEL_LINUX && notify_upstart() == 0 && notify_systemd() == 0 #endif @@ -617,7 +631,7 @@ int main(int argc, char **argv) { status); return 1; } - } /* if (daemonize) */ + } /* if (config.daemonize) */ #endif /* COLLECT_DAEMON */ struct sigaction sig_pipe_action = {.sa_handler = SIG_IGN}; @@ -662,7 +676,7 @@ int main(int argc, char **argv) { exit_status = 1; } - if (test_readall) { + if (config.test_readall) { if (plugin_read_all_once() != 0) { ERROR("Error: one or more plugin read callbacks failed."); exit_status = 1; @@ -681,7 +695,7 @@ int main(int argc, char **argv) { } #if COLLECT_DAEMON - if (daemonize) + if (config.daemonize) pidfile_remove(); #endif /* COLLECT_DAEMON */ diff --git a/src/daemon/collectd.h b/src/daemon/collectd.h index 01d484ee..0558aa40 100644 --- a/src/daemon/collectd.h +++ b/src/daemon/collectd.h @@ -186,10 +186,6 @@ #include #endif -#if HAVE_KSTAT_H -#include -#endif - #ifndef PACKAGE_NAME #define PACKAGE_NAME "collectd" #endif @@ -267,11 +263,6 @@ #define GAUGE_FORMAT "%.15g" #endif -/* Type for time as used by "utils_time.h" */ -typedef uint64_t cdtime_t; - -extern char hostname_g[]; -extern cdtime_t interval_g; -extern int timeout_g; +#include "globals.h" #endif /* COLLECTD_H */ diff --git a/src/daemon/common.c b/src/daemon/common.c index 6c856a6b..cf981dc0 100644 --- a/src/daemon/common.c +++ b/src/daemon/common.c @@ -212,7 +212,7 @@ void sfree (void **ptr) } #endif -ssize_t sread(int fd, void *buf, size_t count) { +int sread(int fd, void *buf, size_t count) { char *ptr; size_t nleft; ssize_t status; @@ -230,10 +230,7 @@ ssize_t sread(int fd, void *buf, size_t count) { return status; if (status == 0) { - DEBUG("Received EOF from fd %i. " - "Closing fd and returning error.", - fd); - close(fd); + DEBUG("Received EOF from fd %i. ", fd); return -1; } @@ -246,7 +243,7 @@ ssize_t sread(int fd, void *buf, size_t count) { return 0; } -ssize_t swrite(int fd, const void *buf, size_t count) { +int swrite(int fd, const void *buf, size_t count) { const char *ptr; size_t nleft; ssize_t status; diff --git a/src/daemon/common.h b/src/daemon/common.h index afd292a3..7f860521 100644 --- a/src/daemon/common.h +++ b/src/daemon/common.h @@ -79,8 +79,7 @@ char *sstrerror(int errnum, char *buf, size_t buflen); * * DESCRIPTION * Reads exactly `n' bytes or fails. Syntax and other behavior is analogous - * to `read(2)'. If EOF is received the file descriptor is closed and an - * error is returned. + * to `read(2)'. * * PARAMETERS * `fd' File descriptor to write to. @@ -91,7 +90,7 @@ char *sstrerror(int errnum, char *buf, size_t buflen); * Zero upon success or non-zero if an error occurred. `errno' is set in this * case. */ -ssize_t sread(int fd, void *buf, size_t count); +int sread(int fd, void *buf, size_t count); /* * NAME @@ -110,7 +109,7 @@ ssize_t sread(int fd, void *buf, size_t count); * Zero upon success or non-zero if an error occurred. `errno' is set in this * case. */ -ssize_t swrite(int fd, const void *buf, size_t count); +int swrite(int fd, const void *buf, size_t count); /* * NAME diff --git a/src/daemon/configfile.c b/src/daemon/configfile.c index 0d295c1c..f5086ae6 100644 --- a/src/daemon/configfile.c +++ b/src/daemon/configfile.c @@ -461,9 +461,9 @@ static int cf_ci_replace_child(oconfig_item_t *dst, oconfig_item_t *src, return 0; } - temp = - realloc(dst->children, sizeof(oconfig_item_t) * - (dst->children_num + src->children_num - 1)); + temp = realloc(dst->children, + sizeof(oconfig_item_t) * + (dst->children_num + src->children_num - 1)); if (temp == NULL) { ERROR("configfile: realloc failed."); return -1; @@ -502,8 +502,9 @@ static int cf_ci_append_children(oconfig_item_t *dst, oconfig_item_t *src) { if ((src == NULL) || (src->children_num == 0)) return 0; - temp = realloc(dst->children, sizeof(oconfig_item_t) * - (dst->children_num + src->children_num)); + temp = + realloc(dst->children, + sizeof(oconfig_item_t) * (dst->children_num + src->children_num)); if (temp == NULL) { ERROR("configfile: realloc failed."); return -1; @@ -874,7 +875,8 @@ const char *global_option_get(const char *option) { return NULL; } - return (cf_global_options[i].value != NULL) ? cf_global_options[i].value : cf_global_options[i].def; + return (cf_global_options[i].value != NULL) ? cf_global_options[i].value + : cf_global_options[i].def; } /* char *global_option_get */ long global_option_get_long(const char *option, long default_value) { @@ -1031,6 +1033,7 @@ int cf_read(const char *filename) { } return ret; + } /* int cf_read */ /* Assures the config option is a string, duplicates it and returns the copy in diff --git a/src/daemon/globals.c b/src/daemon/globals.c new file mode 100644 index 00000000..5c6749ff --- /dev/null +++ b/src/daemon/globals.c @@ -0,0 +1,48 @@ +/** + * collectd - src/globals.c + * Copyright (C) 2017 Google LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + **/ + +#include "common.h" +#include "globals.h" + +#if HAVE_KSTAT_H +#include +#endif + +/* + * Global variables + */ +char *hostname_g; +cdtime_t interval_g; +int timeout_g; +#if HAVE_KSTAT_H +kstat_ctl_t *kc; +#endif + +void hostname_set(char const *hostname) { + char *h = strdup(hostname); + if (h == NULL) + return; + + sfree(hostname_g); + hostname_g = h; +} diff --git a/src/daemon/globals.h b/src/daemon/globals.h new file mode 100644 index 00000000..bc11d6bf --- /dev/null +++ b/src/daemon/globals.h @@ -0,0 +1,43 @@ +/** + * collectd - src/globals.h + * Copyright (C) 2017 Google LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + **/ + +#ifndef GLOBALS_H +#define GLOBALS_H + +#include + +#ifndef DATA_MAX_NAME_LEN +#define DATA_MAX_NAME_LEN 128 +#endif + +/* Type for time as used by "utils_time.h" */ +typedef uint64_t cdtime_t; + +/* hostname_set updates hostname_g */ +void hostname_set(char const *hostname); + +extern char *hostname_g; +extern cdtime_t interval_g; +extern int pidfile_from_cli; +extern int timeout_g; +#endif /* GLOBALS_H */ diff --git a/src/daemon/plugin.h b/src/daemon/plugin.h index 4f877e0e..a9ee72d4 100644 --- a/src/daemon/plugin.h +++ b/src/daemon/plugin.h @@ -36,23 +36,19 @@ #include -#ifndef DATA_MAX_NAME_LEN -#define DATA_MAX_NAME_LEN 128 -#endif - #define DS_TYPE_COUNTER 0 #define DS_TYPE_GAUGE 1 #define DS_TYPE_DERIVE 2 #define DS_TYPE_ABSOLUTE 3 #define DS_TYPE_TO_STRING(t) \ - (t == DS_TYPE_COUNTER) ? "counter" : (t == DS_TYPE_GAUGE) \ - ? "gauge" \ - : (t == DS_TYPE_DERIVE) \ - ? "derive" \ - : (t == DS_TYPE_ABSOLUTE) \ - ? "absolute" \ - : "unknown" + (t == DS_TYPE_COUNTER) \ + ? "counter" \ + : (t == DS_TYPE_GAUGE) \ + ? "gauge" \ + : (t == DS_TYPE_DERIVE) \ + ? "derive" \ + : (t == DS_TYPE_ABSOLUTE) ? "absolute" : "unknown" #ifndef LOG_ERR #define LOG_ERR 3 diff --git a/src/daemon/plugin_mock.c b/src/daemon/plugin_mock.c index ca985398..6df4c15d 100644 --- a/src/daemon/plugin_mock.c +++ b/src/daemon/plugin_mock.c @@ -30,7 +30,7 @@ kstat_ctl_t *kc = NULL; #endif /* HAVE_LIBKSTAT */ -char hostname_g[] = "example.com"; +char *hostname_g = "example.com"; void plugin_set_dir(const char *dir) { /* nop */ } diff --git a/src/filecount.c b/src/filecount.c index 5b812b88..7842aa61 100644 --- a/src/filecount.c +++ b/src/filecount.c @@ -34,6 +34,7 @@ #define FC_RECURSIVE 1 #define FC_HIDDEN 2 +#define FC_REGULAR 4 struct fc_directory_conf_s { char *path; @@ -340,7 +341,7 @@ static int fc_config_add_dir(oconfig_item_t *ci) { return -1; } - dir->options = FC_RECURSIVE; + dir->options = FC_RECURSIVE | FC_REGULAR; dir->name = NULL; dir->plugin_name = strdup("filecount"); @@ -377,6 +378,8 @@ static int fc_config_add_dir(oconfig_item_t *ci) { status = fc_config_add_dir_option(dir, option, FC_RECURSIVE); else if (strcasecmp("IncludeHidden", option->key) == 0) status = fc_config_add_dir_option(dir, option, FC_HIDDEN); + else if (strcasecmp("RegularOnly", option->key) == 0) + status = fc_config_add_dir_option(dir, option, FC_REGULAR); else if (strcasecmp("FilesSizeType", option->key) == 0) status = cf_util_get_string(option, &dir->files_size_type); else if (strcasecmp("FilesCountType", option->key) == 0) @@ -488,7 +491,7 @@ static int fc_read_dir_callback(const char *dirname, const char *filename, abs_path, fc_read_dir_callback, dir, /* include hidden = */ (dir->options & FC_HIDDEN) ? 1 : 0); return status; - } else if (!S_ISREG(statbuf.st_mode)) { + } else if ((dir->options & FC_REGULAR) && !S_ISREG(statbuf.st_mode)) { return 0; } @@ -498,6 +501,11 @@ static int fc_read_dir_callback(const char *dirname, const char *filename, return 0; } + if (!S_ISREG(statbuf.st_mode)) { + dir->files_num++; + return 0; + } + if (dir->mtime != 0) { time_t mtime = dir->now; diff --git a/src/mcelog.c b/src/mcelog.c index 6b10b04c..ae5a7f54 100644 --- a/src/mcelog.c +++ b/src/mcelog.c @@ -257,7 +257,7 @@ static int socket_write(socket_adapter_t *self, const char *msg, const size_t len) { int ret = 0; pthread_rwlock_rdlock(&self->lock); - if (swrite(self->sock_fd, msg, len) < 0) + if (swrite(self->sock_fd, msg, len) != 0) ret = -1; pthread_rwlock_unlock(&self->lock); return ret; diff --git a/src/multimeter.c b/src/multimeter.c index 72b0fed9..fc69e02d 100644 --- a/src/multimeter.c +++ b/src/multimeter.c @@ -62,7 +62,7 @@ static int multimeter_read_value(double *value) { struct timeval time_now; status = swrite(fd, "D", 1); - if (status < 0) { + if (status != 0) { ERROR("multimeter plugin: swrite failed."); return -1; } diff --git a/src/ntpd.c b/src/ntpd.c index 48d7aa72..0faf2a2a 100644 --- a/src/ntpd.c +++ b/src/ntpd.c @@ -669,7 +669,7 @@ static int ntpd_send_request(int req_code, int req_items, int req_size, (void *)req_data); status = swrite(sd, (const char *)&req, REQ_LEN_NOMAC); - if (status < 0) { + if (status != 0) { DEBUG("`swrite' failed. Closing socket #%i", sd); close(sd); sock_descr = sd = -1; diff --git a/src/perl.c b/src/perl.c index d2a00bfd..671d1f3f 100644 --- a/src/perl.c +++ b/src/perl.c @@ -261,12 +261,6 @@ struct { {"Collectd::NOTIF_WARNING", NOTIF_WARNING}, {"Collectd::NOTIF_OKAY", NOTIF_OKAY}, {"", 0}}; - -struct { - char name[64]; - char *var; -} g_strings[] = {{"Collectd::hostname_g", hostname_g}, {"", NULL}}; - /* * Helper functions for data type conversion. */ @@ -2099,7 +2093,7 @@ static int perl_init(void) { /* Lock the base thread to avoid race conditions with c_ithread_create(). * See https://github.com/collectd/collectd/issues/9 and * https://github.com/collectd/collectd/issues/1706 for details. - */ + */ assert(aTHX == perl_threads->head->interp); pthread_mutex_lock(&perl_threads->mutex); @@ -2190,7 +2184,7 @@ static void perl_log(int level, const char *msg, user_data_t *user_data) { /* Lock the base thread if this is not called from one of the read threads * to avoid race conditions with c_ithread_create(). See * https://github.com/collectd/collectd/issues/9 for details. - */ + */ if (aTHX == perl_threads->head->interp) pthread_mutex_lock(&perl_threads->mutex); @@ -2349,14 +2343,25 @@ static int g_interval_set(pTHX_ SV *var, MAGIC *mg) { return 0; } /* static int g_interval_set (pTHX_ SV *, MAGIC *) */ -static MGVTBL g_pv_vtbl = {g_pv_get, g_pv_set, NULL, NULL, NULL, NULL, NULL +static MGVTBL g_pv_vtbl = {g_pv_get, + g_pv_set, + NULL, + NULL, + NULL, + NULL, + NULL #if HAVE_PERL_STRUCT_MGVTBL_SVT_LOCAL , NULL #endif }; -static MGVTBL g_interval_vtbl = {g_interval_get, g_interval_set, NULL, NULL, - NULL, NULL, NULL +static MGVTBL g_interval_vtbl = {g_interval_get, + g_interval_set, + NULL, + NULL, + NULL, + NULL, + NULL #if HAVE_PERL_STRUCT_MGVTBL_SVT_LOCAL , NULL @@ -2390,6 +2395,11 @@ static void xs_init(pTHX) { * accessing any such variable (this is basically the same as using * tie() in Perl) */ /* global strings */ + struct { + char name[64]; + char *var; + } g_strings[] = {{"Collectd::hostname_g", hostname_g}, {"", NULL}}; + for (int i = 0; '\0' != g_strings[i].name[0]; ++i) { tmp = get_sv(g_strings[i].name, 1); sv_magicext(tmp, NULL, PERL_MAGIC_ext, &g_pv_vtbl, g_strings[i].var, 0); diff --git a/src/rrdtool.c b/src/rrdtool.c index 2dfa87a0..5f42561a 100644 --- a/src/rrdtool.c +++ b/src/rrdtool.c @@ -36,15 +36,14 @@ /* * Private types */ -struct rrd_cache_s { +typedef struct rrd_cache_s { int values_num; char **values; cdtime_t first_value; cdtime_t last_value; int64_t random_variation; enum { FLAG_NONE = 0x00, FLAG_QUEUED = 0x01, FLAG_FLUSHQ = 0x02 } flags; -}; -typedef struct rrd_cache_s rrd_cache_t; +} rrd_cache_t; enum rrd_queue_dir_e { QUEUE_INSERT_FRONT, QUEUE_INSERT_BACK }; typedef enum rrd_queue_dir_e rrd_queue_dir_t; @@ -110,13 +109,10 @@ static int do_shutdown = 0; #if HAVE_THREADSAFE_LIBRRD static int srrd_update(char *filename, char *template, int argc, const char **argv) { - int status; - optind = 0; /* bug in librrd? */ rrd_clear_error(); - status = rrd_update_r(filename, template, argc, (void *)argv); - + int status = rrd_update_r(filename, template, argc, (void *)argv); if (status != 0) { WARNING("rrdtool plugin: rrd_update_r (%s) failed: %s", filename, rrd_get_error()); @@ -794,10 +790,6 @@ static int rrd_compare_numeric(const void *a_ptr, const void *b_ptr) { static int rrd_write(const data_set_t *ds, const value_list_t *vl, user_data_t __attribute__((unused)) * user_data) { - struct stat statbuf; - char filename[512]; - char values[512]; - int status; if (do_shutdown) return 0; @@ -807,33 +799,34 @@ static int rrd_write(const data_set_t *ds, const value_list_t *vl, return -1; } + char filename[PATH_MAX]; if (value_list_to_filename(filename, sizeof(filename), vl) != 0) return -1; + char values[32 * ds->ds_num]; if (value_list_to_string(values, sizeof(values), ds, vl) != 0) return -1; + struct stat statbuf = {0}; if (stat(filename, &statbuf) == -1) { if (errno == ENOENT) { - status = cu_rrd_create_file(filename, ds, vl, &rrdcreate_config); - if (status != 0) + if (cu_rrd_create_file(filename, ds, vl, &rrdcreate_config) != 0) { return -1; - else if (rrdcreate_config.async) + } else if (rrdcreate_config.async) { return 0; + } } else { char errbuf[1024]; - ERROR("stat(%s) failed: %s", filename, + ERROR("rrdtool plugin: stat(%s) failed: %s", filename, sstrerror(errno, errbuf, sizeof(errbuf))); return -1; } } else if (!S_ISREG(statbuf.st_mode)) { - ERROR("stat(%s): Not a regular file!", filename); + ERROR("rrdtool plugin: stat(%s): Not a regular file!", filename); return -1; } - status = rrd_cache_insert(filename, values, vl->time); - - return status; + return rrd_cache_insert(filename, values, vl->time); } /* int rrd_write */ static int rrd_flush(cdtime_t timeout, const char *identifier, @@ -1030,7 +1023,6 @@ static int rrd_shutdown(void) { static int rrd_init(void) { static int init_once = 0; - int status; if (init_once != 0) return 0; @@ -1054,7 +1046,8 @@ static int rrd_init(void) { random_timeout = 0; cache_flush_timeout = 0; } else if (cache_flush_timeout < cache_timeout) { - INFO("rrdtool plugin: \"CacheFlush %.3f\" is less than \"CacheTimeout %.3f\". " + INFO("rrdtool plugin: \"CacheFlush %.3f\" is less than \"CacheTimeout " + "%.3f\". " "Ajusting \"CacheFlush\" to %.3f seconds.", CDTIME_T_TO_DOUBLE(cache_flush_timeout), CDTIME_T_TO_DOUBLE(cache_timeout), @@ -1071,7 +1064,7 @@ static int rrd_init(void) { pthread_mutex_unlock(&cache_lock); - status = + int status = plugin_thread_create(&queue_thread, /* attr = */ NULL, rrd_queue_thread, /* args = */ NULL, "rrdtool queue"); if (status != 0) { diff --git a/src/snmp.c b/src/snmp.c index 1ac65c8e..0a20e34b 100644 --- a/src/snmp.c +++ b/src/snmp.c @@ -63,7 +63,7 @@ struct data_definition_s { struct data_definition_s *next; char **ignores; size_t ignores_len; - int invert_match; + _Bool invert_match; }; typedef struct data_definition_s data_definition_t; @@ -71,6 +71,8 @@ struct host_definition_s { char *name; char *address; int version; + cdtime_t timeout; + int retries; /* snmpv1/2 options */ char *community; @@ -327,29 +329,14 @@ static int csnmp_config_add_data_blacklist(data_definition_t *dd, return 0; } /* int csnmp_config_add_data_blacklist */ -static int csnmp_config_add_data_blacklist_match_inverted(data_definition_t *dd, - oconfig_item_t *ci) { - if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN)) { - WARNING("snmp plugin: `InvertMatch' needs exactly one boolean argument."); - return -1; - } - - dd->invert_match = ci->values[0].value.boolean ? 1 : 0; - - return 0; -} /* int csnmp_config_add_data_blacklist_match_inverted */ - static int csnmp_config_add_data(oconfig_item_t *ci) { - data_definition_t *dd; - int status = 0; - - dd = calloc(1, sizeof(*dd)); + data_definition_t *dd = calloc(1, sizeof(*dd)); if (dd == NULL) return -1; - status = cf_util_get_string(ci, &dd->name); + int status = cf_util_get_string(ci, &dd->name); if (status != 0) { - free(dd); + sfree(dd); return -1; } @@ -376,7 +363,7 @@ static int csnmp_config_add_data(oconfig_item_t *ci) { else if (strcasecmp("Ignore", option->key) == 0) status = csnmp_config_add_data_blacklist(dd, option); else if (strcasecmp("InvertMatch", option->key) == 0) - status = csnmp_config_add_data_blacklist_match_inverted(dd, option); + status = cf_util_get_boolean(option, &dd->invert_match); else { WARNING("snmp plugin: Option `%s' not allowed here.", option->key); status = -1; @@ -597,6 +584,10 @@ static int csnmp_config_add_host(oconfig_item_t *ci) { hd->sess_handle = NULL; hd->interval = 0; + /* These mean that we have not set a timeout or retry value */ + hd->timeout = 0; + hd->retries = -1; + for (int i = 0; i < ci->children_num; i++) { oconfig_item_t *option = ci->children + i; status = 0; @@ -607,6 +598,10 @@ static int csnmp_config_add_host(oconfig_item_t *ci) { status = cf_util_get_string(option, &hd->community); else if (strcasecmp("Version", option->key) == 0) status = csnmp_config_add_host_version(hd, option); + else if (strcasecmp("Timeout", option->key) == 0) + cf_util_get_cdtime(option, &hd->timeout); + else if (strcasecmp("Retries", option->key) == 0) + cf_util_get_int(option, &hd->retries); else if (strcasecmp("Collect", option->key) == 0) csnmp_config_add_host_collect(hd, option); else if (strcasecmp("Interval", option->key) == 0) @@ -803,6 +798,15 @@ static void csnmp_host_open_session(host_definition_t *host) { sess.community_len = strlen(host->community); } + /* Set timeout & retries, if they have been changed from the default */ + if (host->timeout != 0) { + /* net-snmp expects microseconds */ + sess.timeout = CDTIME_T_TO_US(host->timeout); + } + if (host->retries >= 0) { + sess.retries = host->retries; + } + /* snmp_sess_open will copy the `struct snmp_session *'. */ host->sess_handle = snmp_sess_open(&sess); @@ -1032,7 +1036,6 @@ static int csnmp_instance_list_add(csnmp_list_instances_t **head, struct variable_list *vb; oid_t vb_name; int status; - uint32_t is_matched; /* Set vb on the last variable */ for (vb = res->variables; (vb != NULL) && (vb->next_variable != NULL); @@ -1062,11 +1065,11 @@ static int csnmp_instance_list_add(csnmp_list_instances_t **head, char *ptr; csnmp_strvbcopy(il->instance, vb, sizeof(il->instance)); - is_matched = 0; + _Bool is_matched = 0; for (uint32_t i = 0; i < dd->ignores_len; i++) { status = fnmatch(dd->ignores[i], il->instance, 0); if (status == 0) { - if (dd->invert_match == 0) { + if (!dd->invert_match) { sfree(il); return 0; } else { @@ -1075,7 +1078,7 @@ static int csnmp_instance_list_add(csnmp_list_instances_t **head, } } } - if (dd->invert_match != 0 && is_matched == 0) { + if (dd->invert_match && !is_matched) { sfree(il); return 0; } @@ -1521,7 +1524,6 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) { snmp_free_pdu(res); res = NULL; - if (status == 0) csnmp_dispatch_table(host, data, instance_list_head, value_list_head); diff --git a/src/ted.c b/src/ted.c index 94b4e3ab..3b64b75f 100644 --- a/src/ted.c +++ b/src/ted.c @@ -88,7 +88,7 @@ static int ted_read_value(double *ret_power, double *ret_voltage) { status = write(fd, pkt_request, sizeof(pkt_request)); if (status <= 0) { - ERROR("ted plugin: swrite failed."); + ERROR("ted plugin: write failed."); return -1; } diff --git a/src/utils_format_kairosdb.c b/src/utils_format_kairosdb.c index 0128c575..460f807a 100644 --- a/src/utils_format_kairosdb.c +++ b/src/utils_format_kairosdb.c @@ -183,7 +183,8 @@ static int value_list_to_kairosdb(char *buffer, size_t buffer_size, /* {{{ */ const data_set_t *ds, const value_list_t *vl, int store_rates, char const *const *http_attrs, - size_t http_attrs_num, int data_ttl) { + size_t http_attrs_num, int data_ttl, + char const *metrics_prefix) { char temp[512]; size_t offset = 0; int status; @@ -212,11 +213,13 @@ static int value_list_to_kairosdb(char *buffer, size_t buffer_size, /* {{{ */ for (size_t i = 0; i < ds->ds_num; i++) { /* All value lists have a leading comma. The first one will be replaced with * a square bracket in `format_kairosdb_finalize'. */ - BUFFER_ADD(",{"); + BUFFER_ADD(",{\"name\":\""); - BUFFER_ADD("\"name\":\"collectd"); + if (metrics_prefix != NULL) { + BUFFER_ADD("%s.", metrics_prefix); + } - BUFFER_ADD(".%s", vl->plugin); + BUFFER_ADD("%s", vl->plugin); status = values_to_kairosdb(temp, sizeof(temp), ds, vl, store_rates, i); if (status != 0) @@ -263,12 +266,14 @@ static int format_kairosdb_value_list_nocheck( char *buffer, /* {{{ */ size_t *ret_buffer_fill, size_t *ret_buffer_free, const data_set_t *ds, const value_list_t *vl, int store_rates, size_t temp_size, - char const *const *http_attrs, size_t http_attrs_num, int data_ttl) { + char const *const *http_attrs, size_t http_attrs_num, int data_ttl, + char const *metrics_prefix) { char temp[temp_size]; int status; status = value_list_to_kairosdb(temp, sizeof(temp), ds, vl, store_rates, - http_attrs, http_attrs_num, data_ttl); + http_attrs, http_attrs_num, data_ttl, + metrics_prefix); if (status != 0) return status; temp_size = strlen(temp); @@ -337,7 +342,8 @@ int format_kairosdb_value_list(char *buffer, /* {{{ */ size_t *ret_buffer_fill, size_t *ret_buffer_free, const data_set_t *ds, const value_list_t *vl, int store_rates, char const *const *http_attrs, - size_t http_attrs_num, int data_ttl) { + size_t http_attrs_num, int data_ttl, + char const *metrics_prefix) { if ((buffer == NULL) || (ret_buffer_fill == NULL) || (ret_buffer_free == NULL) || (ds == NULL) || (vl == NULL)) return -EINVAL; @@ -347,7 +353,8 @@ int format_kairosdb_value_list(char *buffer, /* {{{ */ return format_kairosdb_value_list_nocheck( buffer, ret_buffer_fill, ret_buffer_free, ds, vl, store_rates, - (*ret_buffer_free) - 2, http_attrs, http_attrs_num, data_ttl); + (*ret_buffer_free) - 2, http_attrs, http_attrs_num, data_ttl, + metrics_prefix); } /* }}} int format_kairosdb_value_list */ /* vim: set sw=2 sts=2 et fdm=marker : */ diff --git a/src/utils_format_kairosdb.h b/src/utils_format_kairosdb.h index 3a4c7c77..7b9e0e7a 100644 --- a/src/utils_format_kairosdb.h +++ b/src/utils_format_kairosdb.h @@ -41,7 +41,8 @@ int format_kairosdb_value_list(char *buffer, size_t *ret_buffer_fill, size_t *ret_buffer_free, const data_set_t *ds, const value_list_t *vl, int store_rates, char const *const *http_attrs, - size_t http_attrs_num, int data_ttl); + size_t http_attrs_num, int data_ttl, + char const *metrics_prefix); int format_kairosdb_finalize(char *buffer, size_t *ret_buffer_fill, size_t *ret_buffer_free); diff --git a/src/write_http.c b/src/write_http.c index 06327edb..87e518b6 100644 --- a/src/write_http.c +++ b/src/write_http.c @@ -36,6 +36,10 @@ #define WRITE_HTTP_DEFAULT_BUFFER_SIZE 4096 #endif +#ifndef WRITE_HTTP_DEFAULT_PREFIX +#define WRITE_HTTP_DEFAULT_PREFIX "collectd" +#endif + /* * Private variables */ @@ -80,6 +84,7 @@ struct wh_callback_s { pthread_mutex_t send_lock; int data_ttl; + char *metrics_prefix; }; typedef struct wh_callback_s wh_callback_t; @@ -328,6 +333,7 @@ static void wh_callback_free(void *data) /* {{{ */ sfree(cb->clientcert); sfree(cb->clientkeypass); sfree(cb->send_buffer); + sfree(cb->metrics_prefix); sfree(cb); } /* }}} void wh_callback_free */ @@ -476,7 +482,7 @@ static int wh_write_kairosdb(const data_set_t *ds, status = format_kairosdb_value_list( cb->send_buffer, &cb->send_buffer_fill, &cb->send_buffer_free, ds, vl, cb->store_rates, (char const *const *)http_attrs, http_attrs_num, - cb->data_ttl); + cb->data_ttl, cb->metrics_prefix); if (status == -ENOMEM) { status = wh_flush_nolock(/* timeout = */ 0, cb); if (status != 0) { @@ -488,7 +494,7 @@ static int wh_write_kairosdb(const data_set_t *ds, status = format_kairosdb_value_list( cb->send_buffer, &cb->send_buffer_fill, &cb->send_buffer_free, ds, vl, cb->store_rates, (char const *const *)http_attrs, http_attrs_num, - cb->data_ttl); + cb->data_ttl, cb->metrics_prefix); } if (status != 0) { pthread_mutex_unlock(&cb->send_lock); @@ -629,6 +635,13 @@ static int wh_config_node(oconfig_item_t *ci) /* {{{ */ cb->send_metrics = 1; cb->send_notifications = 0; cb->data_ttl = 0; + cb->metrics_prefix = strdup(WRITE_HTTP_DEFAULT_PREFIX); + + if (cb->metrics_prefix == NULL) { + ERROR("write_http plugin: strdup failed."); + sfree(cb); + return -1; + } pthread_mutex_init(&cb->send_lock, /* attr = */ NULL); @@ -740,6 +753,8 @@ static int wh_config_node(oconfig_item_t *ci) /* {{{ */ sfree(val); } else if (strcasecmp("TTL", child->key) == 0) { status = cf_util_get_int(child, &cb->data_ttl); + } else if (strcasecmp("Prefix", child->key) == 0) { + status = cf_util_get_string(child, &cb->metrics_prefix); } else { ERROR("write_http plugin: Invalid configuration " "option: %s.", @@ -770,6 +785,9 @@ static int wh_config_node(oconfig_item_t *ci) /* {{{ */ return -1; } + if (strlen(cb->metrics_prefix) == 0) + sfree(cb->metrics_prefix); + if (cb->low_speed_limit > 0) cb->low_speed_time = CDTIME_T_TO_TIME_T(plugin_get_interval()); diff --git a/src/write_tsdb.c b/src/write_tsdb.c index 10f636c5..eb6ceb3f 100644 --- a/src/write_tsdb.c +++ b/src/write_tsdb.c @@ -111,7 +111,7 @@ static int wt_send_buffer(struct wt_callback *cb) { ssize_t status = 0; status = swrite(cb->sock_fd, cb->send_buf, strlen(cb->send_buf)); - if (status < 0) { + if (status != 0) { char errbuf[1024]; ERROR("write_tsdb plugin: send failed with status %zi (%s)", status, sstrerror(errno, errbuf, sizeof(errbuf)));