Dear all,
I have modified nginx.c using code from apache.c to enable multi-instance for
nginx instance similar to apache plugin.
The config syntax, therefore, is the same as apache plugin
<Instance "name">nginx config ....</Instance>
Please kindly review the patch. Thank you very much.
Regards,msongd
diff -pur collectd-5.6.1/src/nginx.c collectd-5.6.1-p1/src/nginx.c
--- collectd-5.6.1/src/nginx.c 2016-10-07 21:01:01.054990030 +0700
+++ collectd-5.6.1-p1/src/nginx.c 2016-10-20 13:45:27.564051653 +0700
@@ -33,278 +33,415 @@
#include <curl/curl.h>
-static char *url = NULL;
-static char *user = NULL;
-static char *pass = NULL;
-static char *verify_peer = NULL;
-static char *verify_host = NULL;
-static char *cacert = NULL;
-static char *timeout = NULL;
-
-static CURL *curl = NULL;
-
-static char nginx_buffer[16384];
-static size_t nginx_buffer_len = 0;
-static char nginx_curl_error[CURL_ERROR_SIZE];
-
-static const char *config_keys[] =
-{
- "URL",
- "User",
- "Password",
- "VerifyPeer",
- "VerifyHost",
- "CACert",
- "Timeout"
-};
-static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
-
-static size_t nginx_curl_callback (void *buf, size_t size, size_t nmemb,
- void __attribute__((unused)) *stream)
+struct nginx_s
{
- size_t len = size * nmemb;
+ char *name;
+ char *host;
+ char *url;
+ char *user;
+ char *pass;
+ _Bool verify_peer;
+ _Bool verify_host;
+ char *cacert;
+ char *nginx_buffer;
+ char nginx_curl_error[CURL_ERROR_SIZE];
+ size_t nginx_buffer_size ;
+ size_t nginx_buffer_fill ;
+ int timeout ;
+ CURL *curl;
+}; /* nginx_s */
- /* Check if the data fits into the memory. If not, truncate it. */
- if ((nginx_buffer_len + len) >= sizeof (nginx_buffer))
- {
- assert (sizeof (nginx_buffer) > nginx_buffer_len);
- len = (sizeof (nginx_buffer) - 1) - nginx_buffer_len;
- }
+typedef struct nginx_s nginx_t;
- if (len == 0)
- return (len);
+static void nginx_free (void *arg)
+{
+ nginx_t *st = arg;
- memcpy (&nginx_buffer[nginx_buffer_len], buf, len);
- nginx_buffer_len += len;
- nginx_buffer[nginx_buffer_len] = 0;
+ if (st == NULL)
+ return;
- return (len);
-}
+ sfree (st->name);
+ sfree (st->host);
+ sfree (st->url);
+ sfree (st->user);
+ sfree (st->pass);
+ sfree (st->cacert);
+ sfree (st->nginx_buffer);
+ if (st->curl) {
+ curl_easy_cleanup(st->curl);
+ st->curl = NULL;
+ }
+ sfree (st);
+} /* nginx_free */
-static int config_set (char **var, const char *value)
+static size_t nginx_curl_callback (void *buf, size_t size, size_t nmemb,
+ void *user_data)
{
- if (*var != NULL)
- {
- free (*var);
- *var = NULL;
- }
-
- if ((*var = strdup (value)) == NULL)
- return (1);
- else
- return (0);
+ size_t len = size * nmemb;
+ nginx_t *st;
+
+ st = user_data;
+ if (st == NULL)
+ {
+ ERROR ("nginx plugin: nginx_curl_callback: "
+ "user_data pointer is NULL.");
+ return (0);
+ }
+
+ if (len == 0)
+ return (len);
+
+ if ((st->nginx_buffer_fill + len) >= st->nginx_buffer_size)
+ {
+ char *temp;
+
+ temp = realloc (st->nginx_buffer,
+ st->nginx_buffer_fill + len + 1);
+ if (temp == NULL)
+ {
+ ERROR ("nginx plugin: realloc failed.");
+ return (0);
+ }
+ st->nginx_buffer = temp;
+ st->nginx_buffer_size = st->nginx_buffer_fill + len + 1;
+ }
+
+ memcpy (st->nginx_buffer + st->nginx_buffer_fill, (char *) buf, len);
+ st->nginx_buffer_fill += len;
+ st->nginx_buffer[st->nginx_buffer_fill] = 0;
+
+ return (len);
}
-static int config (const char *key, const char *value)
+/* initialize curl for each host */
+static int init_host (nginx_t *st) /* {{{ */
{
- if (strcasecmp (key, "url") == 0)
- return (config_set (&url, value));
- else if (strcasecmp (key, "user") == 0)
- return (config_set (&user, value));
- else if (strcasecmp (key, "password") == 0)
- return (config_set (&pass, value));
- else if (strcasecmp (key, "verifypeer") == 0)
- return (config_set (&verify_peer, value));
- else if (strcasecmp (key, "verifyhost") == 0)
- return (config_set (&verify_host, value));
- else if (strcasecmp (key, "cacert") == 0)
- return (config_set (&cacert, value));
- else if (strcasecmp (key, "timeout") == 0)
- return (config_set (&timeout, value));
- else
- return (-1);
-} /* int config */
+ assert (st->url != NULL);
+ /* (Assured by `config_add') */
-static int init (void)
-{
- if (curl != NULL)
- curl_easy_cleanup (curl);
+ if (st->curl != NULL)
+ {
+ curl_easy_cleanup (st->curl);
+ st->curl = NULL;
+ }
+
+ if ((st->curl = curl_easy_init ()) == NULL)
+ {
+ ERROR ("nginx plugin: init_host: `curl_easy_init' failed.");
+ return (-1);
+ }
+
+ curl_easy_setopt (st->curl, CURLOPT_NOSIGNAL, 1L);
+ curl_easy_setopt (st->curl, CURLOPT_WRITEFUNCTION, nginx_curl_callback);
+ curl_easy_setopt (st->curl, CURLOPT_WRITEDATA, st);
- if ((curl = curl_easy_init ()) == NULL)
- {
- ERROR ("nginx plugin: curl_easy_init failed.");
- return (-1);
- }
-
- curl_easy_setopt (curl, CURLOPT_NOSIGNAL, 1L);
- curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, nginx_curl_callback);
- curl_easy_setopt (curl, CURLOPT_USERAGENT, COLLECTD_USERAGENT);
- curl_easy_setopt (curl, CURLOPT_ERRORBUFFER, nginx_curl_error);
+ curl_easy_setopt (st->curl, CURLOPT_USERAGENT, COLLECTD_USERAGENT);
+ curl_easy_setopt (st->curl, CURLOPT_ERRORBUFFER, st->nginx_curl_error);
- if (user != NULL)
- {
+ if (st->user != NULL)
+ {
#ifdef HAVE_CURLOPT_USERNAME
- curl_easy_setopt (curl, CURLOPT_USERNAME, user);
- curl_easy_setopt (curl, CURLOPT_PASSWORD, (pass == NULL) ? "" : pass);
+ curl_easy_setopt (st->curl, CURLOPT_USERNAME, st->user);
+ curl_easy_setopt (st->curl, CURLOPT_PASSWORD,
+ (st->pass == NULL) ? "" : st->pass);
#else
- static char credentials[1024];
- int status = ssnprintf (credentials, sizeof (credentials),
- "%s:%s", user, pass == NULL ? "" : pass);
- if ((status < 0) || ((size_t) status >= sizeof (credentials)))
- {
- ERROR ("nginx plugin: Credentials would have been truncated.");
- return (-1);
- }
+ static char credentials[1024];
+ int status;
+
+ status = ssnprintf (credentials, sizeof (credentials), "%s:%s",
+ st->user, (st->pass == NULL) ? "" : st->pass);
+ if ((status < 0) || ((size_t) status >= sizeof (credentials)))
+ {
+ ERROR ("nginx plugin: init_host: Returning an error "
+ "because the credentials have been "
+ "truncated.");
+ curl_easy_cleanup (st->curl);
+ st->curl = NULL;
+ return (-1);
+ }
- curl_easy_setopt (curl, CURLOPT_USERPWD, credentials);
+ curl_easy_setopt (st->curl, CURLOPT_USERPWD, credentials);
#endif
- }
+ }
- if (url != NULL)
- {
- curl_easy_setopt (curl, CURLOPT_URL, url);
- }
-
- curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1L);
- curl_easy_setopt (curl, CURLOPT_MAXREDIRS, 50L);
-
- if ((verify_peer == NULL) || IS_TRUE (verify_peer))
- {
- curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 1L);
- }
- else
- {
- curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0L);
- }
-
- if ((verify_host == NULL) || IS_TRUE (verify_host))
- {
- curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 2L);
- }
- else
- {
- curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0L);
- }
-
- if (cacert != NULL)
- {
- curl_easy_setopt (curl, CURLOPT_CAINFO, cacert);
- }
+ curl_easy_setopt (st->curl, CURLOPT_URL, st->url);
+ curl_easy_setopt (st->curl, CURLOPT_FOLLOWLOCATION, 1L);
+ curl_easy_setopt (st->curl, CURLOPT_MAXREDIRS, 50L);
+
+ curl_easy_setopt (st->curl, CURLOPT_SSL_VERIFYPEER,
+ (long) st->verify_peer);
+ curl_easy_setopt (st->curl, CURLOPT_SSL_VERIFYHOST,
+ st->verify_host ? 2L : 0L);
+ if (st->cacert != NULL)
+ curl_easy_setopt (st->curl, CURLOPT_CAINFO, st->cacert);
#ifdef HAVE_CURLOPT_TIMEOUT_MS
- if (timeout != NULL)
- {
- curl_easy_setopt (curl, CURLOPT_TIMEOUT_MS, atol(timeout));
- }
- else
- {
- curl_easy_setopt (curl, CURLOPT_TIMEOUT_MS, (long) CDTIME_T_TO_MS(plugin_get_interval()));
- }
+ if (st->timeout >= 0)
+ curl_easy_setopt (st->curl, CURLOPT_TIMEOUT_MS, (long) st->timeout);
+ else
+ curl_easy_setopt (st->curl, CURLOPT_TIMEOUT_MS, (long) CDTIME_T_TO_MS(plugin_get_interval()));
#endif
- return (0);
-} /* void init */
+ return (0);
+} /* }}} int init_host */
+
+static void submit_value (const char *type, const char *type_instance,
+ value_t value, nginx_t *st)
+{
+ value_list_t vl = VALUE_LIST_INIT;
+
+ vl.values = &value;
+ vl.values_len = 1;
+
+ sstrncpy (vl.host, (st->host != NULL) ? st->host : hostname_g,
+ sizeof (vl.host));
+
+ sstrncpy (vl.plugin, "nginx", sizeof (vl.plugin));
+ if (st->name != NULL)
+ sstrncpy (vl.plugin_instance, st->name,
+ sizeof (vl.plugin_instance));
+
+ sstrncpy (vl.type, type, sizeof (vl.type));
+ if (type_instance != NULL)
+ sstrncpy (vl.type_instance, type_instance,
+ sizeof (vl.type_instance));
-static void submit (const char *type, const char *inst, long long value)
+ plugin_dispatch_values (&vl);
+} /* void submit_value */
+
+static void submit_derive (const char *type, const char *type_instance,
+ derive_t c, nginx_t *st)
+{
+ value_t v;
+ v.derive = c;
+ submit_value (type, type_instance, v, st);
+} /* void submit_derive */
+
+static void submit_gauge (const char *type, const char *type_instance,
+ gauge_t g, nginx_t *st)
+{
+ value_t v;
+ v.gauge = g;
+ submit_value (type, type_instance, v, st);
+} /* void submit_gauge */
+
+static int nginx_read_host (user_data_t *user_data) /* {{{ */
+{
+ char *ptr;
+ char *saveptr;
+ char *lines[16];
+ int lines_num = 0;
+
+ char *fields[16];
+ int fields_num;
+
+ nginx_t *st;
+
+ st = user_data->data;
+
+ int status;
+
+ assert (st->url != NULL);
+ /* (Assured by `config_add') */
+
+ if (st->curl == NULL)
+ {
+ status = init_host (st);
+ if (status != 0)
+ return (-1);
+ }
+ assert (st->curl != NULL);
+
+ st->nginx_buffer_fill = 0;
+ if (curl_easy_perform (st->curl) != CURLE_OK)
+ {
+ ERROR ("nginx: curl_easy_perform failed: %s",
+ st->nginx_curl_error);
+ return (-1);
+ }
+
+ ptr = st->nginx_buffer;
+ saveptr = NULL;
+ while ((lines[lines_num] = strtok_r (ptr, "\n\r", &saveptr)) != NULL)
+ {
+ ptr = NULL;
+ lines_num++;
+
+ if (lines_num >= 16)
+ break;
+ }
+
+ /*
+ * Active connections: 291
+ * server accepts handled requests
+ * 16630948 16630948 31070465
+ * Reading: 6 Writing: 179 Waiting: 106
+ */
+ for (int i = 0; i < lines_num; i++)
+ {
+ fields_num = strsplit (lines[i], fields,
+ (sizeof (fields) / sizeof (fields[0])));
+
+ if (fields_num == 3)
+ {
+ if ((strcmp (fields[0], "Active") == 0)
+ && (strcmp (fields[1], "connections:") == 0))
+ {
+ submit_gauge("nginx_connections", "active", atoll (fields[2]), st);
+ }
+ else if ((atoll (fields[0]) != 0)
+ && (atoll (fields[1]) != 0)
+ && (atoll (fields[2]) != 0))
+ {
+ submit_derive("connections", "accepted", atoll(fields[0]), st);
+ submit_derive("connections", "handled", atoll(fields[1]), st);
+ submit_derive("nginx_requests", NULL, atoll(fields[2]), st);
+ }
+ }
+ else if (fields_num == 6)
+ {
+ if ((strcmp (fields[0], "Reading:") == 0)
+ && (strcmp (fields[2], "Writing:") == 0)
+ && (strcmp (fields[4], "Waiting:") == 0))
+ {
+ submit_gauge("nginx_connections", "reading", atoll (fields[1]), st);
+ submit_gauge("nginx_connections", "writing", atoll (fields[3]), st);
+ submit_gauge("nginx_connections", "waiting", atoll (fields[5]), st);
+ }
+ }
+ }
+
+ st->nginx_buffer_fill = 0;
+
+ return (0);
+} /* }}} int nginx_read_host */
+
+static int config_add (oconfig_item_t *ci)
+{
+ nginx_t *st;
+ int status;
+
+ st = calloc (1, sizeof (*st));
+ if (st == NULL)
+ {
+ ERROR ("nginx plugin: calloc failed.");
+ return (-1);
+ }
+
+ st->timeout = -1;
+
+ status = cf_util_get_string (ci, &st->name);
+ if (status != 0)
+ {
+ sfree (st);
+ return (status);
+ }
+ assert (st->name != NULL);
+
+ for (int i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("URL", child->key) == 0)
+ status = cf_util_get_string (child, &st->url);
+ else if (strcasecmp ("Host", child->key) == 0)
+ status = cf_util_get_string (child, &st->host);
+ else if (strcasecmp ("User", child->key) == 0)
+ status = cf_util_get_string (child, &st->user);
+ else if (strcasecmp ("Password", child->key) == 0)
+ status = cf_util_get_string (child, &st->pass);
+ else if (strcasecmp ("VerifyPeer", child->key) == 0)
+ status = cf_util_get_boolean (child, &st->verify_peer);
+ else if (strcasecmp ("VerifyHost", child->key) == 0)
+ status = cf_util_get_boolean (child, &st->verify_host);
+ else if (strcasecmp ("CACert", child->key) == 0)
+ status = cf_util_get_string (child, &st->cacert);
+ else if (strcasecmp ("Timeout", child->key) == 0)
+ status = cf_util_get_int (child, &st->timeout);
+ else
+ {
+ WARNING ("nginx plugin: Option `%s' not allowed here.",
+ child->key);
+ status = -1;
+ }
+
+ if (status != 0)
+ break;
+ }
+
+ /* Check if struct is complete.. */
+ if ((status == 0) && (st->url == NULL))
+ {
+ ERROR ("nginx plugin: Instance `%s': "
+ "No URL has been configured.",
+ st->name);
+ status = -1;
+ }
+
+ if (status == 0)
+ {
+ user_data_t ud = {
+ .data = st,
+ .free_func = nginx_free
+ };
+
+ char callback_name[3*DATA_MAX_NAME_LEN];
+
+ ssnprintf (callback_name, sizeof (callback_name),
+ "nginx/%s/%s",
+ (st->host != NULL) ? st->host : hostname_g,
+ (st->name != NULL) ? st->name : "default");
+
+ status = plugin_register_complex_read (/* group = */ NULL,
+ /* name = */ callback_name,
+ /* callback = */ nginx_read_host,
+ /* interval = */ 0,
+ /* user_data = */ &ud);
+ }
+
+ if (status != 0)
+ {
+ nginx_free (st);
+ return (-1);
+ }
+
+ return (0);
+} /* int config_add */
+
+static int config (oconfig_item_t *ci)
{
- value_t values[1];
- value_list_t vl = VALUE_LIST_INIT;
+ int status = 0;
+
+ for (int i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("Instance", child->key) == 0)
+ config_add (child);
+ else
+ WARNING ("nginx plugin: The configuration option "
+ "\"%s\" is not allowed here. Did you "
+ "forget to add an <Instance /> block "
+ "around the configuration?",
+ child->key);
+ } /* for (ci->children) */
- if (strcmp (type, "nginx_connections") == 0)
- values[0].gauge = value;
- else if (strcmp (type, "nginx_requests") == 0)
- values[0].derive = value;
- else if (strcmp (type, "connections") == 0)
- values[0].derive = value;
- else
- return;
-
- vl.values = values;
- vl.values_len = 1;
- sstrncpy (vl.host, hostname_g, sizeof (vl.host));
- sstrncpy (vl.plugin, "nginx", sizeof (vl.plugin));
- sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
- sstrncpy (vl.type, type, sizeof (vl.type));
-
- if (inst != NULL)
- sstrncpy (vl.type_instance, inst, sizeof (vl.type_instance));
-
- plugin_dispatch_values (&vl);
-} /* void submit */
-
-static int nginx_read (void)
-{
- char *ptr;
- char *lines[16];
- int lines_num = 0;
- char *saveptr;
-
- char *fields[16];
- int fields_num;
-
- if (curl == NULL)
- return (-1);
- if (url == NULL)
- return (-1);
-
- nginx_buffer_len = 0;
- if (curl_easy_perform (curl) != CURLE_OK)
- {
- WARNING ("nginx plugin: curl_easy_perform failed: %s", nginx_curl_error);
- return (-1);
- }
-
- ptr = nginx_buffer;
- saveptr = NULL;
- while ((lines[lines_num] = strtok_r (ptr, "\n\r", &saveptr)) != NULL)
- {
- ptr = NULL;
- lines_num++;
-
- if (lines_num >= 16)
- break;
- }
-
- /*
- * Active connections: 291
- * server accepts handled requests
- * 16630948 16630948 31070465
- * Reading: 6 Writing: 179 Waiting: 106
- */
- for (int i = 0; i < lines_num; i++)
- {
- fields_num = strsplit (lines[i], fields,
- (sizeof (fields) / sizeof (fields[0])));
-
- if (fields_num == 3)
- {
- if ((strcmp (fields[0], "Active") == 0)
- && (strcmp (fields[1], "connections:") == 0))
- {
- submit ("nginx_connections", "active", atoll (fields[2]));
- }
- else if ((atoll (fields[0]) != 0)
- && (atoll (fields[1]) != 0)
- && (atoll (fields[2]) != 0))
- {
- submit ("connections", "accepted", atoll (fields[0]));
- submit ("connections", "handled", atoll (fields[1]));
- submit ("nginx_requests", NULL, atoll (fields[2]));
- }
- }
- else if (fields_num == 6)
- {
- if ((strcmp (fields[0], "Reading:") == 0)
- && (strcmp (fields[2], "Writing:") == 0)
- && (strcmp (fields[4], "Waiting:") == 0))
- {
- submit ("nginx_connections", "reading", atoll (fields[1]));
- submit ("nginx_connections", "writing", atoll (fields[3]));
- submit ("nginx_connections", "waiting", atoll (fields[5]));
- }
- }
- }
+ return (status);
+} /* int config */
- nginx_buffer_len = 0;
- return (0);
-} /* int nginx_read */
+static int nginx_init (void) /* {{{ */
+{
+ /* Call this while collectd is still single-threaded to avoid
+ * initialization issues in libgcrypt. */
+ curl_global_init (CURL_GLOBAL_SSL);
+ return (0);
+} /* }}} int nginx_init */
void module_register (void)
{
- plugin_register_config ("nginx", config, config_keys, config_keys_num);
- plugin_register_init ("nginx", init);
- plugin_register_read ("nginx", nginx_read);
+ plugin_register_complex_config ("nginx", config);
+ plugin_register_init ("nginx", nginx_init);
} /* void module_register */
/*
_______________________________________________
collectd mailing list
[email protected]
https://mailman.verplant.org/listinfo/collectd