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
collectd@verplant.org
https://mailman.verplant.org/listinfo/collectd

Reply via email to