Code

Add support for incr/decr counts
[collectd.git] / src / memcached.c
index 2df28877252a2d3d0ec95a4dbd7675ad38c159a8..535ea84704b3dac328a5af495f69bccdbdfedb9a 100644 (file)
@@ -53,8 +53,6 @@ typedef struct memcached_s memcached_t;
 
 static _Bool memcached_have_instances = 0;
 
-static int memcached_read (user_data_t *user_data);
-
 static void memcached_free (memcached_t *st)
 {
   if (st == NULL)
@@ -81,7 +79,7 @@ static int memcached_connect_unix (memcached_t *st)
   if (fd < 0)
   {
     char errbuf[1024];
-    ERROR ("memcached: memcached_connect_unix: socket(2) failed: %s",
+    ERROR ("memcached plugin: memcached_connect_unix: socket(2) failed: %s",
         sstrerror (errno, errbuf, sizeof (errbuf)));
     return (-1);
   }
@@ -116,7 +114,8 @@ static int memcached_connect_inet (memcached_t *st)
   if (status != 0)
   {
     char errbuf[1024];
-    ERROR ("memcached: memcached_connect_inet: getaddrinfo(%s,%s) failed: %s",
+    ERROR ("memcached plugin: memcached_connect_inet: "
+        "getaddrinfo(%s,%s) failed: %s",
         host, port,
         (status == EAI_SYSTEM)
         ? sstrerror (errno, errbuf, sizeof (errbuf))
@@ -131,7 +130,8 @@ static int memcached_connect_inet (memcached_t *st)
     if (fd < 0)
     {
       char errbuf[1024];
-      WARNING ("memcached: memcached_connect_inet: socket(2) failed: %s",
+      WARNING ("memcached plugin: memcached_connect_inet: "
+          "socket(2) failed: %s",
           sstrerror (errno, errbuf, sizeof (errbuf)));
       continue;
     }
@@ -170,7 +170,8 @@ static int memcached_query_daemon (char *buffer, size_t buffer_size, memcached_t
 
   fd = memcached_connect (st);
   if (fd < 0) {
-    ERROR ("memcached: Could not connect to daemon.");
+    ERROR ("memcached plugin: Instance \"%s\" could not connect to daemon.",
+        st->name);
     return -1;
   }
 
@@ -233,174 +234,36 @@ static int memcached_query_daemon (char *buffer, size_t buffer_size, memcached_t
   return (status);
 } /* int memcached_query_daemon */
 
-static int memcached_add_read_callback (memcached_t *st)
-{
-  user_data_t ud;
-  char callback_name[3*DATA_MAX_NAME_LEN];
-  int status;
-
-  memset (&ud, 0, sizeof (ud));
-  ud.data = st;
-  ud.free_func = (void *) memcached_free;
-
-  assert (st->name != NULL);
-  ssnprintf (callback_name, sizeof (callback_name), "memcached/%s", st->name);
-
-  status = plugin_register_complex_read (/* group = */ "memcached",
-      /* name      = */ callback_name,
-      /* callback  = */ memcached_read,
-      /* interval  = */ NULL,
-      /* user_data = */ &ud);
-  return (status);
-} /* int memcached_add_read_callback */
-
-/* Configuration handling functiions
- * <Plugin memcached>
- *   <Instance "instance_name">
- *     Host foo.zomg.com
- *     Port "1234"
- *   </Instance>
- * </Plugin>
- */
-static int config_add_instance(oconfig_item_t *ci)
+static void memcached_init_vl (value_list_t *vl, memcached_t const *st)
 {
-  memcached_t *st;
-  int i;
-  int status = 0;
-
-  /* Disable automatic generation of default instance in the init callback. */
-  memcached_have_instances = 1;
-
-  st = malloc (sizeof (*st));
-  if (st == NULL)
+  sstrncpy (vl->plugin, "memcached", sizeof (vl->plugin));
+  if (strcmp (st->name, "__legacy__") == 0) /* legacy mode */
   {
-    ERROR ("memcached plugin: malloc failed.");
-    return (-1);
-  }
-
-  memset (st, 0, sizeof (*st));
-  st->name = NULL;
-  st->socket = NULL;
-  st->host = NULL;
-  st->port = NULL;
-
-  if (strcasecmp (ci->key, "Plugin") == 0) /* default instance */
-    st->name = sstrdup ("default");
-  else /* <Instance /> block */
-    status = cf_util_get_string (ci, &st->name);
-  if (status != 0)
-  {
-    sfree (st);
-    return (status);
+    sstrncpy (vl->host, hostname_g, sizeof (vl->host));
   }
-  assert (st->name != NULL);
-
-  for (i = 0; i < ci->children_num; i++)
+  else
   {
-    oconfig_item_t *child = ci->children + i;
-
-    if (strcasecmp ("Socket", child->key) == 0)
-      status = cf_util_get_string (child, &st->socket);
-    else if (strcasecmp ("Host", child->key) == 0)
-      status = cf_util_get_string (child, &st->host);
-    else if (strcasecmp ("Port", child->key) == 0)
-      status = cf_util_get_service (child, &st->port);
+    if (st->socket != NULL)
+      sstrncpy (vl->host, hostname_g, sizeof (vl->host));
     else
-    {
-      WARNING ("memcached plugin: Option `%s' not allowed here.",
-          child->key);
-      status = -1;
-    }
-
-    if (status != 0)
-      break;
-  }
-
-  if (status == 0)
-    status = memcached_add_read_callback (st);
-
-  if (status != 0)
-  {
-    memcached_free(st);
-    return (-1);
+      sstrncpy (vl->host,
+          (st->host != NULL) ? st->host : MEMCACHED_DEF_HOST,
+          sizeof (vl->host));
+    sstrncpy (vl->plugin_instance, st->name, sizeof (vl->plugin_instance));
   }
-
-  return (0);
 }
 
-static int memcached_config (oconfig_item_t *ci)
-{
-  int status = 0;
-  _Bool have_instance_block = 0;
-  int i;
-
-  for (i = 0; i < ci->children_num; i++)
-  {
-    oconfig_item_t *child = ci->children + i;
-
-    if (strcasecmp ("Instance", child->key) == 0)
-    {
-      config_add_instance (child);
-      have_instance_block = 1;
-    }
-    else if (!have_instance_block)
-    {
-      /* Non-instance option: Assume legacy configuration (without <Instance />
-       * blocks) and call config_add_instance() with the <Plugin /> block. */
-      return (config_add_instance (ci));
-    }
-    else
-      WARNING ("memcached 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) */
-
-  return (status);
-}
-
-static int memcached_init (void)
-{
-  memcached_t *st;
-  int status;
-
-  if (memcached_have_instances)
-    return (0);
-
-  /* No instances were configured, lets start a default instance. */
-  st = malloc (sizeof (*st));
-  if (st == NULL)
-    return (ENOMEM);
-  memset (st, 0, sizeof (*st));
-  st->name = sstrdup ("default");
-  st->socket = NULL;
-  st->host = NULL;
-  st->port = NULL;
-
-  status = memcached_add_read_callback (st);
-  if (status == 0)
-    memcached_have_instances = 1;
-  else
-    memcached_free (st);
-
-  return (status);
-} /* int memcached_init */
-
 static void submit_derive (const char *type, const char *type_inst,
     derive_t value, memcached_t *st)
 {
   value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
+  memcached_init_vl (&vl, st);
 
   values[0].derive = value;
 
   vl.values = values;
   vl.values_len = 1;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
-  sstrncpy (vl.plugin, "memcached", 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_inst != NULL)
     sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
@@ -413,16 +276,13 @@ static void submit_derive2 (const char *type, const char *type_inst,
 {
   value_t values[2];
   value_list_t vl = VALUE_LIST_INIT;
+  memcached_init_vl (&vl, st);
 
   values[0].derive = value0;
   values[1].derive = value1;
 
   vl.values = values;
   vl.values_len = 2;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
-  sstrncpy (vl.plugin, "memcached", 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_inst != NULL)
     sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
@@ -435,15 +295,12 @@ static void submit_gauge (const char *type, const char *type_inst,
 {
   value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
+  memcached_init_vl (&vl, st);
 
   values[0].gauge = value;
 
   vl.values = values;
   vl.values_len = 1;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
-  sstrncpy (vl.plugin, "memcached", 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_inst != NULL)
     sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
@@ -456,16 +313,13 @@ static void submit_gauge2 (const char *type, const char *type_inst,
 {
   value_t values[2];
   value_list_t vl = VALUE_LIST_INIT;
+  memcached_init_vl (&vl, st);
 
   values[0].gauge = value0;
   values[1].gauge = value1;
 
   vl.values = values;
   vl.values_len = 2;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
-  sstrncpy (vl.plugin, "memcached", 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_inst != NULL)
     sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
@@ -486,6 +340,10 @@ static int memcached_read (user_data_t *user_data)
   gauge_t bytes_total = NAN;
   gauge_t hits = NAN;
   gauge_t gets = NAN;
+  gauge_t incr_hits = NAN;
+  derive_t incr = 0;
+  gauge_t decr_hits = NAN;
+  derive_t decr = 0;
   derive_t rusage_user = 0;
   derive_t rusage_syst = 0;
   derive_t octets_rx = 0;
@@ -582,6 +440,36 @@ static int memcached_read (user_data_t *user_data)
         gets = atof (fields[2]);
     }
 
+    /*
+     * Increment/Decrement
+     */
+    else if (FIELD_IS("incr_misses"))
+    {
+      derive_t incr_count = atoll (fields[2]);
+      submit_derive ("memcached_ops", "incr_misses", incr_count, st);
+      incr += incr_count;
+    }
+    else if (FIELD_IS ("incr_hits"))
+    {
+      derive_t incr_count = atoll (fields[2]);
+      submit_derive ("memcached_ops", "incr_hits", incr_count, st);
+      incr_hits = atof (fields[2]);
+      incr += incr_count;
+    }
+    else if (FIELD_IS ("decr_misses"))
+    {
+      derive_t decr_count = atoll (fields[2]);
+      submit_derive ("memcached_ops", "decr_misses", decr_count, st);
+      decr += decr_count;
+    }
+    else if (FIELD_IS ("decr_hits"))
+    {
+      derive_t decr_count = atoll (fields[2]);
+      submit_derive ("memcached_ops", "decr_hits", decr_count, st);
+      decr_hits = atof (fields[2]);
+      decr += decr_count;
+    }
+
     /*
      * Operations on the cache, i. e. cache hits, cache misses and evictions of items
      */
@@ -631,9 +519,177 @@ static int memcached_read (user_data_t *user_data)
     submit_gauge ("percent", "hitratio", rate, st);
   }
 
+  if (!isnan (incr_hits) && incr != 0)
+  {
+    gauge_t incr_rate = 100.0 * incr_hits / incr;
+    submit_gauge ("percent", "incr_hitratio", incr_rate, st);
+    submit_derive ("memcached_ops", "incr", incr, st);
+  }
+
+  if (!isnan (decr_hits) && decr != 0)
+  {
+    gauge_t decr_rate = 100.0 * decr_hits / decr;
+    submit_gauge ("percent", "decr_hitratio", decr_rate, st);
+    submit_derive ("memcached_ops", "decr", decr, st);
+  }
+
   return 0;
 } /* int memcached_read */
 
+static int memcached_add_read_callback (memcached_t *st)
+{
+  user_data_t ud;
+  char callback_name[3*DATA_MAX_NAME_LEN];
+  int status;
+
+  memset (&ud, 0, sizeof (ud));
+  ud.data = st;
+  ud.free_func = (void *) memcached_free;
+
+  assert (st->name != NULL);
+  ssnprintf (callback_name, sizeof (callback_name), "memcached/%s", st->name);
+
+  status = plugin_register_complex_read (/* group = */ "memcached",
+      /* name      = */ callback_name,
+      /* callback  = */ memcached_read,
+      /* interval  = */ NULL,
+      /* user_data = */ &ud);
+  return (status);
+} /* int memcached_add_read_callback */
+
+/* Configuration handling functiions
+ * <Plugin memcached>
+ *   <Instance "instance_name">
+ *     Host foo.zomg.com
+ *     Port "1234"
+ *   </Instance>
+ * </Plugin>
+ */
+static int config_add_instance(oconfig_item_t *ci)
+{
+  memcached_t *st;
+  int i;
+  int status = 0;
+
+  /* Disable automatic generation of default instance in the init callback. */
+  memcached_have_instances = 1;
+
+  st = malloc (sizeof (*st));
+  if (st == NULL)
+  {
+    ERROR ("memcached plugin: malloc failed.");
+    return (-1);
+  }
+
+  memset (st, 0, sizeof (*st));
+  st->name = NULL;
+  st->socket = NULL;
+  st->host = NULL;
+  st->port = NULL;
+
+  if (strcasecmp (ci->key, "Plugin") == 0) /* default instance */
+    st->name = sstrdup ("__legacy__");
+  else /* <Instance /> block */
+    status = cf_util_get_string (ci, &st->name);
+  if (status != 0)
+  {
+    sfree (st);
+    return (status);
+  }
+  assert (st->name != NULL);
+
+  for (i = 0; i < ci->children_num; i++)
+  {
+    oconfig_item_t *child = ci->children + i;
+
+    if (strcasecmp ("Socket", child->key) == 0)
+      status = cf_util_get_string (child, &st->socket);
+    else if (strcasecmp ("Host", child->key) == 0)
+      status = cf_util_get_string (child, &st->host);
+    else if (strcasecmp ("Port", child->key) == 0)
+      status = cf_util_get_service (child, &st->port);
+    else
+    {
+      WARNING ("memcached plugin: Option `%s' not allowed here.",
+          child->key);
+      status = -1;
+    }
+
+    if (status != 0)
+      break;
+  }
+
+  if (status == 0)
+    status = memcached_add_read_callback (st);
+
+  if (status != 0)
+  {
+    memcached_free(st);
+    return (-1);
+  }
+
+  return (0);
+}
+
+static int memcached_config (oconfig_item_t *ci)
+{
+  int status = 0;
+  _Bool have_instance_block = 0;
+  int i;
+
+  for (i = 0; i < ci->children_num; i++)
+  {
+    oconfig_item_t *child = ci->children + i;
+
+    if (strcasecmp ("Instance", child->key) == 0)
+    {
+      config_add_instance (child);
+      have_instance_block = 1;
+    }
+    else if (!have_instance_block)
+    {
+      /* Non-instance option: Assume legacy configuration (without <Instance />
+       * blocks) and call config_add_instance() with the <Plugin /> block. */
+      return (config_add_instance (ci));
+    }
+    else
+      WARNING ("memcached 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) */
+
+  return (status);
+}
+
+static int memcached_init (void)
+{
+  memcached_t *st;
+  int status;
+
+  if (memcached_have_instances)
+    return (0);
+
+  /* No instances were configured, lets start a default instance. */
+  st = malloc (sizeof (*st));
+  if (st == NULL)
+    return (ENOMEM);
+  memset (st, 0, sizeof (*st));
+  st->name = sstrdup ("__legacy__");
+  st->socket = NULL;
+  st->host = NULL;
+  st->port = NULL;
+
+  status = memcached_add_read_callback (st);
+  if (status == 0)
+    memcached_have_instances = 1;
+  else
+    memcached_free (st);
+
+  return (status);
+} /* int memcached_init */
+
 void module_register (void)
 {
   plugin_register_complex_config ("memcached", memcached_config);