[collectd] [RFC 1/2] Add DDERIVE type

David Gibson david at gibson.dropbear.id.au
Sat Aug 13 13:10:23 CEST 2016


This adds a new DDERIVE ds-type to collectd.  This is modelled on the
DDERIVE type in recent rrdtool versions - the semantics are the same as
DERIVE, but it has floating point (double) values, instead of integers.

Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
---
 contrib/collectd_network.py |  4 ++++
 src/collectd-perl.pod       |  4 +++-
 src/csv.c                   |  9 ++++++++-
 src/curl.c                  | 11 +++++++++++
 src/curl_xml.c              |  5 +++++
 src/daemon/collectd.h       |  4 ++++
 src/daemon/common.c         | 25 +++++++++++++++++++++++++
 src/daemon/common_test.c    |  3 +++
 src/daemon/plugin.c         |  3 +++
 src/daemon/plugin.h         |  4 ++++
 src/daemon/types_list.c     |  2 ++
 src/daemon/utils_cache.c    | 15 +++++++++++++++
 src/daemon/utils_match.c    | 24 ++++++++++++++++++++++++
 src/daemon/utils_match.h    | 12 ++++++++----
 src/java.c                  | 10 ++++++++--
 src/perl.c                  |  8 +++++++-
 src/python.c                |  6 +++++-
 src/pyvalues.c              | 14 ++++++++++++++
 src/redis.c                 |  3 +++
 src/rrdcached.c             |  9 +++++++--
 src/tail.c                  | 10 ++++++++++
 src/target_scale.c          | 13 +++++++++++++
 src/utils_format_graphite.c |  2 ++
 src/utils_format_json.c     |  7 +++++++
 src/utils_format_json.h     |  4 ++++
 src/utils_format_kairosdb.c | 20 ++++++++++++++++++++
 src/utils_format_kairosdb.h |  4 ++++
 src/utils_rrdcreate.c       |  2 ++
 src/write_mongodb.c         |  2 ++
 src/write_riemann.c         |  7 +++++++
 src/write_sensu.c           | 10 +++++++++-
 src/write_tsdb.c            |  2 ++
 32 files changed, 245 insertions(+), 13 deletions(-)

diff --git a/contrib/collectd_network.py b/contrib/collectd_network.py
index 809f19d..fa7f5e9 100644
--- a/contrib/collectd_network.py
+++ b/contrib/collectd_network.py
@@ -63,6 +63,7 @@ DS_TYPE_COUNTER      = 0
 DS_TYPE_GAUGE        = 1
 DS_TYPE_DERIVE       = 2
 DS_TYPE_ABSOLUTE     = 3
+DS_TYPE_DDERIVE      = 4
 
 header = struct.Struct("!2H")
 number = struct.Struct("!Q")
@@ -94,6 +95,9 @@ def decode_network_values(ptype, plen, buf):
         elif dstype == DS_TYPE_ABSOLUTE:
             result.append((dstype, number.unpack_from(buf, off)[0]))
             off += valskip
+        elif dstype == DS_TYPE_DDERIVE:
+            result.append((dstype, number.unpack_from(buf, off)[0]))
+            off += valskip
         else:
             raise ValueError("DS type %i unsupported" % dstype)
 
diff --git a/src/collectd-perl.pod b/src/collectd-perl.pod
index 0102e92..491f28b 100644
--- a/src/collectd-perl.pod
+++ b/src/collectd-perl.pod
@@ -186,7 +186,7 @@ structure. The general layout looks like this:
 
   [{
     name => 'data_source_name',
-    type => DS_TYPE_COUNTER || DS_TYPE_GAUGE || DS_TYPE_DERIVE || DS_TYPE_ABSOLUTE,
+    type => DS_TYPE_COUNTER || DS_TYPE_GAUGE || DS_TYPE_DERIVE || DS_TYPE_ABSOLUTE || DS_TYPE_DDERIVE,
     min  => value || undef,
     max  => value || undef
   }, ...]
@@ -567,6 +567,8 @@ available (B<:all> will export all of them):
 
 =item B<DS_TYPE_ABSOLUTE>
 
+=item B<DS_TYPE_DDERIVE>
+
 =back
 
 =item B<:log>
diff --git a/src/csv.c b/src/csv.c
index e008ecf..8c26d47 100644
--- a/src/csv.c
+++ b/src/csv.c
@@ -63,7 +63,8 @@ static int value_list_to_string (char *buffer, int buffer_len,
 		if ((ds->ds[i].type != DS_TYPE_COUNTER)
 				&& (ds->ds[i].type != DS_TYPE_GAUGE)
 				&& (ds->ds[i].type != DS_TYPE_DERIVE)
-				&& (ds->ds[i].type != DS_TYPE_ABSOLUTE))
+				&& (ds->ds[i].type != DS_TYPE_ABSOLUTE)
+				&& (ds->ds[i].type != DS_TYPE_DDERIVE))
 		{
 			sfree (rates);
 			return (-1);
@@ -109,6 +110,12 @@ static int value_list_to_string (char *buffer, int buffer_len,
 					",%"PRIu64,
 					vl->values[i].absolute);
 		}
+		else if (ds->ds[i].type == DS_TYPE_DDERIVE)
+		{
+			status = ssnprintf (buffer + offset,
+					buffer_len - offset,
+					",%lf", vl->values[i].dderive);
+		}
 
 		if ((status < 1) || (status >= (buffer_len - offset)))
 		{
diff --git a/src/curl.c b/src/curl.c
index 8d7baa5..70ce32f 100644
--- a/src/curl.c
+++ b/src/curl.c
@@ -248,6 +248,17 @@ else if (strncasecmp ("Absolute", ci->values[0].value.string,
     else
       dstype = 0;
   }
+else if (strncasecmp ("DDerive", ci->values[0].value.string,
+        strlen ("DDerive")) == 0)
+  {
+    dstype = UTILS_MATCH_DS_TYPE_DDERIVE;
+    if (strcasecmp ("DDeriveSet", ci->values[0].value.string) == 0)
+      dstype |= UTILS_MATCH_CF_DDERIVE_SET;
+    else if (strcasecmp ("DDeriveAdd", ci->values[0].value.string) == 0)
+      dstype |= UTILS_MATCH_CF_DDERIVE_ADD;
+    else
+      dstype = 0;
+  }
 
   else
   {
diff --git a/src/curl_xml.c b/src/curl_xml.c
index f3aa2d9..1894c93 100644
--- a/src/curl_xml.c
+++ b/src/curl_xml.c
@@ -351,6 +351,11 @@ static int cx_handle_single_value_xpath (xmlXPathContextPtr xpath_ctx, /* {{{ */
     case DS_TYPE_GAUGE:
       vl->values[index].gauge = (gauge_t) strtod (node_value,
           /* endptr = */ NULL);
+      break;
+    case DS_TYPE_DDERIVE:
+      vl->values[index].dderive = (dderive_t) strtod (node_value,
+          /* endptr = */ NULL);
+      break;
   }
 
   /* free up object */
diff --git a/src/daemon/collectd.h b/src/daemon/collectd.h
index 3cb0c1b..df1a623 100644
--- a/src/daemon/collectd.h
+++ b/src/daemon/collectd.h
@@ -305,6 +305,10 @@ typedef int _Bool;
 # define GAUGE_FORMAT "%.15g"
 #endif
 
+#ifndef DDERIVE_FORMAT
+# define DDERIVE_FORMAT "%.15g"
+#endif
+
 /* Type for time as used by "utils_time.h" */
 typedef uint64_t cdtime_t;
 
diff --git a/src/daemon/common.c b/src/daemon/common.c
index 05b1199..220201b 100644
--- a/src/daemon/common.c
+++ b/src/daemon/common.c
@@ -984,6 +984,8 @@ int format_values (char *ret, size_t ret_len, /* {{{ */
                         BUFFER_ADD (":%"PRIi64, vl->values[i].derive);
                 else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
                         BUFFER_ADD (":%"PRIu64, vl->values[i].absolute);
+                else if (ds->ds[i].type == DS_TYPE_DDERIVE)
+                        BUFFER_ADD (":"DDERIVE_FORMAT, vl->values[i].dderive);
                 else
                 {
                         ERROR ("format_values: Unknown data source type: %i",
@@ -1117,6 +1119,10 @@ int parse_value (const char *value_orig, value_t *ret_value, int ds_type)
       ret_value->absolute = (absolute_t) strtoull (value, &endptr, 0);
       break;
 
+    case DS_TYPE_DDERIVE:
+      ret_value->dderive = (dderive_t) strtod (value, &endptr);
+      break;
+
     default:
       sfree (value);
       ERROR ("parse_value: Invalid data source type: %i.", ds_type);
@@ -1188,6 +1194,8 @@ int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds)
 
 		if ((strcmp ("U", ptr) == 0) && (ds->ds[i].type == DS_TYPE_GAUGE))
 			vl->values[i].gauge = NAN;
+		else if ((strcmp ("U", ptr) == 0) && (ds->ds[i].type == DS_TYPE_DDERIVE))
+			vl->values[i].dderive = NAN;
 		else if (0 != parse_value (ptr, &vl->values[i], ds->ds[i].type))
 			return -1;
 
@@ -1423,6 +1431,11 @@ int rate_to_value (value_t *ret_value, gauge_t rate, /* {{{ */
 			state->last_value.absolute = (absolute_t) rate;
 			state->residual = rate - ((gauge_t) state->last_value.absolute);
 		}
+		else if (ds_type == DS_TYPE_DDERIVE)
+		{
+			state->last_value.dderive = (dderive_t) rate;
+			state->residual = 0.0;
+		}
 		else
 		{
 			assert (23 == 42);
@@ -1453,6 +1466,13 @@ int rate_to_value (value_t *ret_value, gauge_t rate, /* {{{ */
 		state->last_value.absolute = delta_absolute;
 		state->residual = delta_gauge - ((gauge_t) delta_absolute);
 	}
+	else if (ds_type == DS_TYPE_DDERIVE)
+	{
+		dderive_t delta_dderive = (dderive_t) delta_gauge;
+
+		state->last_value.dderive += delta_dderive;
+		state->residual = 0.0;
+	}
 	else
 	{
 		assert (23 == 42);
@@ -1505,6 +1525,11 @@ int value_to_rate (gauge_t *ret_rate, /* {{{ */
 		*ret_rate = ((gauge_t) diff) / ((gauge_t) interval);
 		break;
 	}
+	case DS_TYPE_DDERIVE: {
+		dderive_t diff = value.dderive - state->last_value.dderive;
+		*ret_rate = ((gauge_t) diff) / ((gauge_t) interval);
+		break;
+	}
 	default:
 		return EINVAL;
 	}
diff --git a/src/daemon/common_test.c b/src/daemon/common_test.c
index 202ddf6..f520f5e 100644
--- a/src/daemon/common_test.c
+++ b/src/daemon/common_test.c
@@ -357,6 +357,9 @@ DEF_TEST(value_to_rate)
     {20, 30, DS_TYPE_COUNTER, {.counter = 4294967238ULL}, {.counter =   42}, 10.0},
     /* 64bit wrap-around. */
     {30, 40, DS_TYPE_COUNTER, {.counter = 18446744073709551558ULL}, {.counter =   42}, 10.0},
+    { 0, 10, DS_TYPE_DDERIVE, {.dderive = 0.0}, {.dderive = 100.0}, NAN},
+    {10, 20, DS_TYPE_DDERIVE, {.dderive = 100.0}, {.dderive = 200.0}, 10.0},
+    {20, 30, DS_TYPE_DDERIVE, {.dderive = 200.0}, {.dderive = 195.0}, -0.5},
   };
 
   for (size_t i = 0; i < STATIC_ARRAY_SIZE (cases); i++) {
diff --git a/src/daemon/plugin.c b/src/daemon/plugin.c
index 1bee8cd..5b35fe4 100644
--- a/src/daemon/plugin.c
+++ b/src/daemon/plugin.c
@@ -2412,6 +2412,9 @@ int plugin_dispatch_multivalue (value_list_t const *template, /* {{{ */
 		case DS_TYPE_DERIVE:
 			vl->values[0].derive   = va_arg (ap, derive_t);
 			break;
+		case DS_TYPE_DDERIVE:
+			vl->values[0].dderive  = va_arg (ap, dderive_t);
+			break;
 		default:
 			ERROR ("plugin_dispatch_multivalue: given store_type is incorrect.");
 			failed++;
diff --git a/src/daemon/plugin.h b/src/daemon/plugin.h
index 49edba2..96bd2f5 100644
--- a/src/daemon/plugin.h
+++ b/src/daemon/plugin.h
@@ -46,11 +46,13 @@
 #define DS_TYPE_GAUGE    1
 #define DS_TYPE_DERIVE   2
 #define DS_TYPE_ABSOLUTE 3
+#define DS_TYPE_DDERIVE  4
 
 #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" : \
+				(t == DS_TYPE_DDERIVE)  ? "dderive"  : \
 				"unknown"
 
 
@@ -85,6 +87,7 @@ typedef unsigned long long counter_t;
 typedef double gauge_t;
 typedef int64_t derive_t;
 typedef uint64_t absolute_t;
+typedef double dderive_t;
 
 union value_u
 {
@@ -92,6 +95,7 @@ union value_u
 	gauge_t    gauge;
 	derive_t   derive;
 	absolute_t absolute;
+	dderive_t  dderive;
 };
 typedef union value_u value_t;
 
diff --git a/src/daemon/types_list.c b/src/daemon/types_list.c
index 34c222c..ed0726a 100644
--- a/src/daemon/types_list.c
+++ b/src/daemon/types_list.c
@@ -79,6 +79,8 @@ static int parse_ds (data_source_t *dsrc, char *buf, size_t buf_len)
     dsrc->type = DS_TYPE_DERIVE;
   else if (strcasecmp (fields[1], "ABSOLUTE") == 0)
     dsrc->type = DS_TYPE_ABSOLUTE;
+  else if (strcasecmp (fields[1], "DDERIVE") == 0)
+    dsrc->type = DS_TYPE_DDERIVE;
   else
   {
     ERROR ("(fields[1] = %s) != (GAUGE || COUNTER || DERIVE || ABSOLUTE)", fields[1]);
diff --git a/src/daemon/utils_cache.c b/src/daemon/utils_cache.c
index 7c1fa41..3ab1b23 100644
--- a/src/daemon/utils_cache.c
+++ b/src/daemon/utils_cache.c
@@ -199,6 +199,11 @@ static int uc_insert (const data_set_t *ds, const value_list_t *vl,
 	ce->values_raw[i].absolute = vl->values[i].absolute;
 	break;
 
+      case DS_TYPE_DDERIVE:
+	ce->values_gauge[i] = NAN;
+	ce->values_raw[i].dderive = vl->values[i].dderive;
+	break;
+
       default:
 	/* This shouldn't happen. */
 	ERROR ("uc_insert: Don't know how to handle data source type %i.",
@@ -444,6 +449,16 @@ int uc_update (const data_set_t *ds, const value_list_t *vl)
 	ce->values_raw[i].absolute = vl->values[i].absolute;
 	break;
 
+      case DS_TYPE_DDERIVE:
+	{
+	  dderive_t diff = vl->values[i].dderive - ce->values_raw[i].dderive;
+
+	  ce->values_gauge[i] = ((double) diff)
+	    / (CDTIME_T_TO_DOUBLE (vl->time - ce->last_time));
+	  ce->values_raw[i].dderive = vl->values[i].dderive;
+	}
+	break;
+
       default:
 	/* This shouldn't happen. */
 	pthread_mutex_unlock (&cache_lock);
diff --git a/src/daemon/utils_match.c b/src/daemon/utils_match.c
index 914b6e2..1dc5f79 100644
--- a/src/daemon/utils_match.c
+++ b/src/daemon/utils_match.c
@@ -216,6 +216,30 @@ static int default_callback (const char __attribute__((unused)) *str,
 
     data->values_num++;
   }
+  else if (data->ds_type & UTILS_MATCH_DS_TYPE_DDERIVE)
+  {
+    dderive_t value;
+    char *endptr = NULL;
+
+    if (matches_num < 2)
+      return (-1);
+
+    value = (dderive_t) strtod (matches[1], &endptr);
+    if (matches[1] == endptr)
+      return (-1);
+
+    if (data->ds_type & UTILS_MATCH_CF_DDERIVE_SET)
+      data->value.dderive = value;
+    else if (data->ds_type & UTILS_MATCH_CF_DDERIVE_ADD)
+      data->value.dderive += value;
+    else
+    {
+      ERROR ("utils_match: default_callback: obj->ds_type is invalid!");
+      return (-1);
+    }
+
+    data->values_num++;
+  }
   else
   {
     ERROR ("utils_match: default_callback: obj->ds_type is invalid!");
diff --git a/src/daemon/utils_match.h b/src/daemon/utils_match.h
index a1d1002..68dbe41 100644
--- a/src/daemon/utils_match.h
+++ b/src/daemon/utils_match.h
@@ -35,10 +35,11 @@
  *          ^             <- Type bit
  *           ^^^^^^^^^^^^ <- Subtype bits
  */
-#define UTILS_MATCH_DS_TYPE_GAUGE    0x1000
-#define UTILS_MATCH_DS_TYPE_COUNTER  0x2000
-#define UTILS_MATCH_DS_TYPE_DERIVE   0x4000
-#define UTILS_MATCH_DS_TYPE_ABSOLUTE 0x8000
+#define UTILS_MATCH_DS_TYPE_GAUGE    0x01000
+#define UTILS_MATCH_DS_TYPE_COUNTER  0x02000
+#define UTILS_MATCH_DS_TYPE_DERIVE   0x04000
+#define UTILS_MATCH_DS_TYPE_ABSOLUTE 0x08000
+#define UTILS_MATCH_DS_TYPE_DDERIVE  0x10000
 
 #define UTILS_MATCH_CF_GAUGE_AVERAGE 0x01
 #define UTILS_MATCH_CF_GAUGE_MIN     0x02
@@ -59,6 +60,9 @@
 #define UTILS_MATCH_CF_ABSOLUTE_ADD   0x02
 #define UTILS_MATCH_CF_ABSOLUTE_INC   0x04
 
+#define UTILS_MATCH_CF_DDERIVE_SET   0x01
+#define UTILS_MATCH_CF_DDERIVE_ADD   0x02
+
 /*
  * Data types
  */
diff --git a/src/java.c b/src/java.c
index 47f4cd3..04d7dd2 100644
--- a/src/java.c
+++ b/src/java.c
@@ -307,6 +307,8 @@ static jobject ctoj_value_to_number (JNIEnv *jvm_env, /* {{{ */
     return (ctoj_jlong_to_number (jvm_env, (jlong) value.derive));
   if (ds_type == DS_TYPE_ABSOLUTE)
     return (ctoj_jlong_to_number (jvm_env, (jlong) value.absolute));
+  else if (ds_type == DS_TYPE_DDERIVE)
+    return (ctoj_jlong_to_number (jvm_env, (jdouble) value.dderive));
   else
     return (NULL);
 } /* }}} jobject ctoj_value_to_number */
@@ -1063,7 +1065,8 @@ static int jtoc_value (JNIEnv *jvm_env, /* {{{ */
 
   class_ptr = (*jvm_env)->GetObjectClass (jvm_env, object_ptr);
 
-  if (ds_type == DS_TYPE_GAUGE)
+  if ((ds_type == DS_TYPE_GAUGE)
+      || (ds_type == DS_TYPE_DDERIVE))
   {
     jdouble tmp_double;
 
@@ -1075,7 +1078,10 @@ static int jtoc_value (JNIEnv *jvm_env, /* {{{ */
           "jtoc_double failed.");
       return (-1);
     }
-    (*ret_value).gauge = (gauge_t) tmp_double;
+    if (ds_type == DS_TYPE_GAUGE)
+      (*ret_value).gauge = (gauge_t) tmp_double;
+    else if (ds_type == DS_TYPE_DDERIVE)
+      (*ret_value).dderive = (gauge_t) tmp_double;
   }
   else
   {
diff --git a/src/perl.c b/src/perl.c
index 48374b6..6673e2e 100644
--- a/src/perl.c
+++ b/src/perl.c
@@ -216,6 +216,7 @@ struct {
 	{ "Collectd::DS_TYPE_GAUGE",      DS_TYPE_GAUGE },
 	{ "Collectd::DS_TYPE_DERIVE",     DS_TYPE_DERIVE },
 	{ "Collectd::DS_TYPE_ABSOLUTE",   DS_TYPE_ABSOLUTE },
+	{ "Collectd::DS_TYPE_DDERIVE",    DS_TYPE_DDERIVE },
 	{ "Collectd::LOG_ERR",            LOG_ERR },
 	{ "Collectd::LOG_WARNING",        LOG_WARNING },
 	{ "Collectd::LOG_NOTICE",         LOG_NOTICE },
@@ -283,7 +284,8 @@ static int hv2data_source (pTHX_ HV *hash, data_source_t *ds)
 		if ((DS_TYPE_COUNTER != ds->type)
 				&& (DS_TYPE_GAUGE != ds->type)
 				&& (DS_TYPE_DERIVE != ds->type)
-				&& (DS_TYPE_ABSOLUTE != ds->type)) {
+				&& (DS_TYPE_ABSOLUTE != ds->type)
+				&& (DS_TYPE_DDERIVE != ds->type)) {
 			log_err ("hv2data_source: Invalid DS type.");
 			return -1;
 		}
@@ -340,6 +342,8 @@ static size_t av2value (pTHX_ char *name, AV *array, value_t *value, size_t arra
 				value[i].derive = SvIV (*tmp);
 			else if (DS_TYPE_ABSOLUTE == ds->ds[i].type)
 				value[i].absolute = SvIV (*tmp);
+			else if (DS_TYPE_DDERIVE == ds->ds[i].type)
+				value[i].dderive = SvNV (*tmp);
 		}
 		else {
 			return 0;
@@ -658,6 +662,8 @@ static int value_list2hv (pTHX_ value_list_t *vl, data_set_t *ds, HV *hash)
 			val = newSViv (vl->values[i].derive);
 		else if (DS_TYPE_ABSOLUTE == ds->ds[i].type)
 			val = newSViv (vl->values[i].absolute);
+		else if (DS_TYPE_DDERIVE == ds->ds[i].type)
+			val = newSVnv (vl->values[i].dderive);
 
 		if (NULL == av_store (values, i, val)) {
 			av_undef (values);
diff --git a/src/python.c b/src/python.c
index 24046de..fe71162 100644
--- a/src/python.c
+++ b/src/python.c
@@ -54,7 +54,8 @@ static char get_ds_doc[] = "get_dataset(name) -> definition\n"
 		"    name, type, min and max value.\n"
 		"    'name' is a string.\n"
 		"    'type' is a string that is equal to either DS_TYPE_COUNTER,\n"
-		"        DS_TYPE_GAUGE, DS_TYPE_DERIVE or DS_TYPE_ABSOLUTE.\n"
+		"        DS_TYPE_GAUGE, DS_TYPE_DERIVE, DS_TYPE_ABSOLUTE,\n"
+		"        or DS_TYPE_DDERIVE.\n"
 		"    'min' and 'max' are either a float or None.";
 
 static char flush_doc[] = "flush([plugin][, timeout][, identifier]) -> None\n"
@@ -374,6 +375,8 @@ static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_li
 				PyList_SetItem(list, i, PyLong_FromLongLong(value_list->values[i].derive));
 			} else if (ds->ds[i].type == DS_TYPE_ABSOLUTE) {
 				PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].absolute));
+			} else if (ds->ds[i].type == DS_TYPE_DDERIVE) {
+				PyList_SetItem(list, i, PyFloat_FromDouble(value_list->values[i].dderive));
 			} else {
 				Py_BEGIN_ALLOW_THREADS
 				ERROR("cpy_write_callback: Unknown value type %d.", ds->ds[i].type);
@@ -1092,6 +1095,7 @@ static int cpy_init_python(void) {
 	PyModule_AddStringConstant(module, "DS_TYPE_GAUGE", DS_TYPE_TO_STRING(DS_TYPE_GAUGE));
 	PyModule_AddStringConstant(module, "DS_TYPE_DERIVE", DS_TYPE_TO_STRING(DS_TYPE_DERIVE));
 	PyModule_AddStringConstant(module, "DS_TYPE_ABSOLUTE", DS_TYPE_TO_STRING(DS_TYPE_ABSOLUTE));
+	PyModule_AddStringConstant(module, "DS_TYPE_DDERIVE", DS_TYPE_TO_STRING(DS_TYPE_DDERIVE));
 	return 0;
 }
 
diff --git a/src/pyvalues.c b/src/pyvalues.c
index a7cb792..f634fd9 100644
--- a/src/pyvalues.c
+++ b/src/pyvalues.c
@@ -585,6 +585,13 @@ static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
 				Py_XDECREF(num);
 			}
 			break;
+		case DS_TYPE_DDERIVE:
+			num = PyNumber_Float(item); /* New reference. */
+			if (num != NULL) {
+				value[i].dderive = PyFloat_AsDouble(num);
+				Py_XDECREF(num);
+			}
+			break;
 		default:
 			free(value);
 			PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds[i].type, value_list.type);
@@ -694,6 +701,13 @@ static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
 				Py_XDECREF(num);
 			}
 			break;
+		case DS_TYPE_DDERIVE:
+			num = PyNumber_Float(item); /* New reference. */
+			if (num != NULL) {
+				value[i].dderive = PyFloat_AsDouble(num);
+				Py_XDECREF(num);
+			}
+			break;
 		default:
 			free(value);
 			PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s", ds->ds[i].type, value_list.type);
diff --git a/src/redis.c b/src/redis.c
index 7395ba0..f1b9c8d 100644
--- a/src/redis.c
+++ b/src/redis.c
@@ -354,6 +354,9 @@ static int redis_handle_query (redisContext *rh, redis_node_t *rn, redis_query_t
         case DS_TYPE_ABSOLUTE:
             val.gauge = (absolute_t)rr->integer;
             break;
+        case DS_TYPE_DDERIVE:
+            val.dderive = (dderive_t)rr->integer;
+            break;
         }
         break;
     case REDIS_REPLY_STRING:
diff --git a/src/rrdcached.c b/src/rrdcached.c
index 0425419..156f24b 100644
--- a/src/rrdcached.c
+++ b/src/rrdcached.c
@@ -87,7 +87,8 @@ static int value_list_to_string (char *buffer, int buffer_len,
     if ((ds->ds[i].type != DS_TYPE_COUNTER)
         && (ds->ds[i].type != DS_TYPE_GAUGE)
 	&& (ds->ds[i].type != DS_TYPE_DERIVE)
-	&& (ds->ds[i].type != DS_TYPE_ABSOLUTE))
+	&& (ds->ds[i].type != DS_TYPE_ABSOLUTE)
+	&& (ds->ds[i].type != DS_TYPE_DDERIVE))
       return (-1);
 
     if (ds->ds[i].type == DS_TYPE_COUNTER)
@@ -104,11 +105,15 @@ static int value_list_to_string (char *buffer, int buffer_len,
       status = ssnprintf (buffer + offset, buffer_len - offset,
 	  ":%"PRIi64, vl->values[i].derive);
     }
-    else /* if (ds->ds[i].type == DS_TYPE_ABSOLUTE) */ {
+    else if (ds->ds[i].type == DS_TYPE_ABSOLUTE) {
       status = ssnprintf (buffer + offset, buffer_len - offset,
 	  ":%"PRIu64, vl->values[i].absolute);
 
     }
+    else /* if (ds->ds[i].type == DS_TYPE_DDERIVE) */ {
+      status = ssnprintf (buffer + offset, buffer_len - offset,
+          ":%f", vl->values[i].dderive);
+    }
 
     if ((status < 1) || (status >= (buffer_len - offset)))
       return (-1);
diff --git a/src/tail.c b/src/tail.c
index b8922ec..dbbed8e 100644
--- a/src/tail.c
+++ b/src/tail.c
@@ -120,6 +120,16 @@ static int ctail_config_add_match_dstype (ctail_config_match_t *cm,
     else
       cm->flags = 0;
   }
+  else if (strncasecmp ("DDerive", ci->values[0].value.string, strlen ("DDerive")) == 0)
+  {
+    cm->flags = UTILS_MATCH_DS_TYPE_DDERIVE;
+    if (strcasecmp ("DDeriveSet", ci->values[0].value.string) == 0)
+      cm->flags |= UTILS_MATCH_CF_DDERIVE_SET;
+    else if (strcasecmp ("DDeriveAdd", ci->values[0].value.string) == 0)
+      cm->flags |= UTILS_MATCH_CF_DDERIVE_ADD;
+    else
+      cm->flags = 0;
+  }
   else
   {
     cm->flags = 0;
diff --git a/src/target_scale.c b/src/target_scale.c
index 22af4e3..818635e 100644
--- a/src/target_scale.c
+++ b/src/target_scale.c
@@ -298,6 +298,17 @@ static int ts_config_set_double (double *ret, oconfig_item_t *ci) /* {{{ */
 	return (0);
 } /* }}} int ts_config_set_double */
 
+static int ts_invoke_dderive (const data_set_t *ds, value_list_t *vl, /* {{{ */
+		ts_data_t *data, int dsrc_index)
+{
+	if (!isnan (data->factor))
+		vl->values[dsrc_index].dderive *= data->factor;
+	if (!isnan (data->offset))
+		vl->values[dsrc_index].dderive += data->offset;
+
+	return (0);
+} /* }}} int ts_invoke_dderive */
+
 static int ts_config_add_data_source(ts_data_t *data, /* {{{ */
 		oconfig_item_t *ci)
 {
@@ -477,6 +488,8 @@ static int ts_invoke (const data_set_t *ds, value_list_t *vl, /* {{{ */
 			ts_invoke_derive (ds, vl, data, i);
 		else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
 			ts_invoke_absolute (ds, vl, data, i);
+		else if (ds->ds[i].type == DS_TYPE_DDERIVE)
+			ts_invoke_dderive (ds, vl, data, i);
 		else
 			ERROR ("Target `scale': Ignoring unknown data source type %i",
 					ds->ds[i].type);
diff --git a/src/utils_format_graphite.c b/src/utils_format_graphite.c
index e523420..a212356 100644
--- a/src/utils_format_graphite.c
+++ b/src/utils_format_graphite.c
@@ -70,6 +70,8 @@ static int gr_format_values (char *ret, size_t ret_len,
         BUFFER_ADD ("%"PRIi64, vl->values[ds_num].derive);
     else if (ds->ds[ds_num].type == DS_TYPE_ABSOLUTE)
         BUFFER_ADD ("%"PRIu64, vl->values[ds_num].absolute);
+    else if (ds->ds[ds_num].type == DS_TYPE_DDERIVE)
+        BUFFER_ADD (DDERIVE_FORMAT, vl->values[ds_num].dderive);
     else
     {
         ERROR ("gr_format_values plugin: Unknown data source type: %i",
diff --git a/src/utils_format_json.c b/src/utils_format_json.c
index 5b5fcdf..e45f6df 100644
--- a/src/utils_format_json.c
+++ b/src/utils_format_json.c
@@ -149,6 +149,13 @@ static int values_to_json (char *buffer, size_t buffer_size, /* {{{ */
       BUFFER_ADD ("%"PRIi64, vl->values[i].derive);
     else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
       BUFFER_ADD ("%"PRIu64, vl->values[i].absolute);
+    else if (ds->ds[i].type == DS_TYPE_DDERIVE)
+    {
+      if(isfinite (vl->values[i].dderive))
+        BUFFER_ADD (JSON_DDERIVE_FORMAT, vl->values[i].dderive);
+      else
+        BUFFER_ADD ("null");
+    }
     else
     {
       ERROR ("format_json: Unknown data source type: %i",
diff --git a/src/utils_format_json.h b/src/utils_format_json.h
index a3eda30..2091c7e 100644
--- a/src/utils_format_json.h
+++ b/src/utils_format_json.h
@@ -35,6 +35,10 @@
 # define JSON_GAUGE_FORMAT GAUGE_FORMAT
 #endif
 
+#ifndef JSON_DDERIVE_FORMAT
+# define JSON_DDERIVE_FORMAT DDERIVE_FORMAT
+#endif
+
 int format_json_initialize (char *buffer,
     size_t *ret_buffer_fill, size_t *ret_buffer_free);
 int format_json_value_list (char *buffer,
diff --git a/src/utils_format_kairosdb.c b/src/utils_format_kairosdb.c
index 41055c7..f073d8c 100644
--- a/src/utils_format_kairosdb.c
+++ b/src/utils_format_kairosdb.c
@@ -200,6 +200,26 @@ static int values_to_kairosdb (char *buffer, size_t buffer_size, /* {{{ */
     BUFFER_ADD (",");
     BUFFER_ADD ("%"PRIu64, vl->values[ds_idx].absolute);
   }
+  else if (ds->ds[ds_idx].type == DS_TYPE_DDERIVE)
+  {
+    if (isfinite (vl->values[ds_idx].dderive))
+    {
+      BUFFER_ADD ("[[");
+      BUFFER_ADD ("%"PRIu64, CDTIME_T_TO_MS (vl->time));
+      BUFFER_ADD (",");
+      BUFFER_ADD (JSON_DDERIVE_FORMAT, vl->values[ds_idx].dderive);
+    }
+    else
+    {
+      DEBUG ("utils_format_kairosdb: invalid vl->values[ds_idx].dderive for %s|%s|%s|%s|%s",
+                vl->plugin,
+                vl->plugin_instance,
+                vl->type,
+                vl->type_instance,
+                ds->ds[ds_idx].name);
+      return (-1);
+    }
+  }
   else
   {
     ERROR ("format_kairosdb: Unknown data source type: %i",
diff --git a/src/utils_format_kairosdb.h b/src/utils_format_kairosdb.h
index 764b0b1..dc8ffab 100644
--- a/src/utils_format_kairosdb.h
+++ b/src/utils_format_kairosdb.h
@@ -35,6 +35,10 @@
 # define JSON_GAUGE_FORMAT GAUGE_FORMAT
 #endif
 
+#ifndef JSON_DDERIVE_FORMAT
+# define JSON_DDERIVE_FORMAT DDERIVE_FORMAT
+#endif
+
 int format_kairosdb_initialize (char *buffer,
     size_t *ret_buffer_fill, size_t *ret_buffer_free);
 int format_kairosdb_value_list (char *buffer,
diff --git a/src/utils_rrdcreate.c b/src/utils_rrdcreate.c
index 884de8f..2f23d97 100644
--- a/src/utils_rrdcreate.c
+++ b/src/utils_rrdcreate.c
@@ -310,6 +310,8 @@ static int ds_get (char ***ret, /* {{{ */
       type = "DERIVE";
     else if (d->type == DS_TYPE_ABSOLUTE)
       type = "ABSOLUTE";
+    else if (d->type == DS_TYPE_DDERIVE)
+      type = "DDERIVE";
     else
     {
       ERROR ("rrdtool plugin: Unknown DS type: %i",
diff --git a/src/write_mongodb.c b/src/write_mongodb.c
index 8fb13c3..7b6e2e9 100644
--- a/src/write_mongodb.c
+++ b/src/write_mongodb.c
@@ -123,6 +123,8 @@ static bson *wm_create_bson (const data_set_t *ds, /* {{{ */
       bson_append_long(ret, key, vl->values[i].derive);
     else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
       bson_append_long(ret, key, vl->values[i].absolute);
+    else if (ds->ds[i].type == DS_TYPE_DDERIVE)
+      bson_append_double(ret, key, vl->values[i].dderive);
     else
       assert (23 == 42);
   }
diff --git a/src/write_riemann.c b/src/write_riemann.c
index f143723..4dbb259 100644
--- a/src/write_riemann.c
+++ b/src/write_riemann.c
@@ -371,6 +371,13 @@ wrr_value_to_event(struct riemann_host const *host, /* {{{ */
   } else if (rates != NULL) {
     riemann_event_set(event, RIEMANN_EVENT_FIELD_METRIC_D, (double)rates[index],
                       RIEMANN_EVENT_FIELD_NONE);
+  } else if (ds->ds[index].type == DS_TYPE_DDERIVE) {
+    double metric;
+
+    metric = vl->values[index].dderive;
+
+    riemann_event_set(event, RIEMANN_EVENT_FIELD_METRIC_D,
+		      metric, RIEMANN_EVENT_FIELD_NONE);
   } else {
     int64_t metric;
 
diff --git a/src/write_sensu.c b/src/write_sensu.c
index 6cb4994..0c3a881 100644
--- a/src/write_sensu.c
+++ b/src/write_sensu.c
@@ -499,7 +499,7 @@ static char *sensu_value_to_json(struct sensu_host const *host, /* {{{ */
 				return NULL;
 			}
 		}
-		else {
+		else if (ds->ds[index].type == DS_TYPE_COUNTER) {
 			res = my_asprintf(&value_str, "%llu", vl->values[index].counter);
 			if (res == -1) {
 				free(ret_str);
@@ -507,6 +507,14 @@ static char *sensu_value_to_json(struct sensu_host const *host, /* {{{ */
 				return NULL;
 			}
 		}
+		else /* if (ds->ds[index].type == DS_TYPE_DDERIVE) */ {
+			res = my_asprintf(&value_str, DDERIVE_FORMAT, vl->values[index].dderive);
+			if (res == -1) {
+				free(ret_str);
+				ERROR("write_sensu plugin: Unable to alloc memory");
+				return NULL;
+			}
+		}
 	}
 
 	// Generate the full service name
diff --git a/src/write_tsdb.c b/src/write_tsdb.c
index bf49ba5..8db0551 100644
--- a/src/write_tsdb.c
+++ b/src/write_tsdb.c
@@ -322,6 +322,8 @@ static int wt_format_values(char *ret, size_t ret_len,
         BUFFER_ADD("%" PRIi64, vl->values[ds_num].derive);
     else if (ds->ds[ds_num].type == DS_TYPE_ABSOLUTE)
         BUFFER_ADD("%" PRIu64, vl->values[ds_num].absolute);
+    else if (ds->ds[ds_num].type == DS_TYPE_DDERIVE)
+        BUFFER_ADD(DDERIVE_FORMAT, vl->values[ds_num].dderive);
     else
     {
         ERROR("format_values plugin: Unknown data source type: %i",
-- 
2.7.4




More information about the collectd mailing list