From 61f3cabf159f51704575ffd9c4f7a2abafe4318c Mon Sep 17 00:00:00 2001 From: brettlangdon Date: Thu, 18 Feb 2016 20:49:11 -0500 Subject: [PATCH] Normalize metric points in dogapi.metric.send_all --- lib/api/metric.js | 57 ++++++++++-------- test/api/metric.js | 145 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 177 insertions(+), 25 deletions(-) diff --git a/lib/api/metric.js b/lib/api/metric.js index ed47e65..d1e96d3 100644 --- a/lib/api/metric.js +++ b/lib/api/metric.js @@ -1,14 +1,13 @@ var client = require("../client"); - /*section: metric *comment: | * submit a new metric *params: * metric: the metric name * points: | - * single datapoint or array of [timestamp, datapoint], if a single point - * is given "now" is used as the timestamp + * a single data point (e.g. `50`), an array of data points (e.g. `[50, 100]`) + * or an array of `[timestamp, value]` elements (e.g. `[[now, 50], [now, 100]]`) * extra: | * optional, object which can contain the following keys * * host: the host source of the metric @@ -27,8 +26,11 @@ var client = require("../client"); * dogapi.metric.send("my.metric", 1000, function(err, results){ * console.dir(results); * }); + * dogapi.metric.send("my.metric", [500, 1000], function(err, results){ + * console.dir(results); + * }); * var now = parseInt(new Date().getTime() / 1000); - * dogapi.metric.send("my.metric", [now, 1000], function(err, results){ + * dogapi.metric.send("my.metric", [[now, 1000]], function(err, results){ * console.dir(results); * }); * ``` @@ -38,23 +40,6 @@ function send(metric, points, extra, callback){ callback = extra; extra = {}; } - // Try to normalize `points` - // DEV: We need `points` to be an array of arrays regardless of what they give us - // Always wrap points in an array, this way we will get: - // 500 => [500] - // [, 500] => [[, 500]] - points = [points]; - points = points.map(function(point){ - // Make sure each point is an array, if not make array with current timestamp - // 500 => [, 500] - // [, 500] => unchanged - if(!Array.isArray(point)){ - var now = parseInt(new Date().getTime() / 1000); - point = [now, point]; - } - return point; - }); - extra = extra || {}; var series = [ { @@ -76,7 +61,7 @@ function send(metric, points, extra, callback){ * metrics: | * an array of metrics where each element is an object with the following keys * * metric: the name of the metric - * * points: a single datapoint or an array of [timestamp, datapoint] (same as `dogapi.metric.send`) + * * points: a single data point (e.g. `50`), an array of data points (e.g. `[50, 100]`) or an array of `[timestamp, value]` elements (e.g. `[[now, 50], [now, 100]]`) * * tags: an array of "tag:value"'s * * host: the source hostname to use for the metrics * * metric_type: the type of metric to use ("gauge" or "counter") [default: gauge] @@ -94,11 +79,15 @@ function send(metric, points, extra, callback){ * var metrics = [ * { * metric: "my.metric", - * points: [now, 1000], + * points: [[now, 1000]], * tags: ["tag:value"] * }, * { * metric: "another.metric", + * points: [50, 1000] + * }, + * { + * metric: "another.metric", * points: 1000 * } * ]; @@ -110,10 +99,30 @@ function send(metric, points, extra, callback){ function send_all(metrics, callback){ var now = parseInt(new Date().getTime() / 1000); for(var i = 0; i < metrics.length; ++i){ + // Try to normalize `points` + // DEV: We need `points` to be an array of arrays regardless of what they give us + // Always wrap points in an array, this way we will get: + // 500 => [500] + // [500, 100] => [[, 500], [, 1000]] + // [[, 500]] => [[, 500]] + points = metrics[i].points if(!Array.isArray(metrics[i].points)){ - metrics[i].points = [now, metrics[i].points]; + points = [points]; } + points = points.map(function(point){ + // Make sure each point is an array, if not make array with current timestamp + // 500 => [, 500] + // [, 500] => unchanged + if(!Array.isArray(point)){ + var now = parseInt(new Date().getTime() / 1000); + point = [now, point]; + } + return point; + }); + + metrics[i].points = points; } + var params = { body: { series: metrics diff --git a/test/api/metric.js b/test/api/metric.js index 7ec9bca..bf2f3e7 100644 --- a/test/api/metric.js +++ b/test/api/metric.js @@ -19,7 +19,7 @@ describe("api/metrics", function(){ it("should make a valid api call", function(){ // Make our api call var now = parseInt(new Date().getTime() / 1000); - metric.send("metric.send", [now, 500]); + metric.send("metric.send", [[now, 500]]); // Assert we properly called `client.request` assert(stub_request.calledOnce); @@ -79,5 +79,148 @@ describe("api/metrics", function(){ assert.equal(point.length, 2); assert.equal(point[1], 500); }); + + it("should properly normalize array of values to points", function(){ + // Make our api call + metric.send("metrics.send.normalize", [500, 1000]); + + // Assert we called `client.request` with the correct `points` + assert(stub_request.calledOnce); + var call_args = stub_request.getCall(0).args; + // { body: series: [ {points: [], }, ] } + var body = call_args[2].body; + assert.equal(body.series.length, 1); + + // points = [ [, 500], [, 1000] ] + var points = body.series[0].points; + assert(Array.isArray(points)); + assert.equal(points.length, 2); + + // point = [, 500] + var point = points[0]; + assert(Array.isArray(point)); + assert.equal(point.length, 2); + assert.equal(point[1], 500); + + // point = [, 1000] + point = points[1]; + assert(Array.isArray(point)); + assert.equal(point.length, 2); + assert.equal(point[1], 1000); + }); + + it("should not normalize correctly formatted points", function(){ + // Make our api call + var now = parseInt(new Date().getTime() / 1000); + metric.send("metrics.send.normalize", [[now, 1000]]); + + // Assert we called `client.request` with the correct `points` + assert(stub_request.calledOnce); + var call_args = stub_request.getCall(0).args; + // { body: series: [ {points: [], }, ] } + var body = call_args[2].body; + assert.equal(body.series.length, 1); + + // points = [ [, 1000], ] + var points = body.series[0].points; + assert(Array.isArray(points)); + assert.equal(points.length, 1); + + // point = [, 500] + var point = points[0]; + assert(Array.isArray(point)); + assert.deepEqual(point, [now, 1000]); + }); + }); + + describe("#send_all", function(){ + it("should make a valid api call", function(){ + // Make our api call + var now = parseInt(new Date().getTime() / 1000); + var metrics = [ + { + metric: "metric.send_all", + points: [[now, 500]] + } + ]; + metric.send_all(metrics); + + // Assert we properly called `client.request` + assert(stub_request.calledOnce); + var call_args = stub_request.getCall(0).args; + // Method and endpoint are correct + assert.equal(call_args[0], "POST"); + assert.equal(call_args[1], "/series"); + + // Properly formatted body + // { body: series: [ {metric: "metric.send_all", host: undefined, tags: undefined, metric_type: undefined} ] } + // DEV: host/tags/metric_type are optional and should be undefined for this case + var data = call_args[2]; + assert(data.hasOwnProperty("body")); + assert(data.body.hasOwnProperty("series")); + + // Assert we have only 1 series + // series = [ {metric: "", ...}, ... ] + var series = data.body.series; + assert(Array.isArray(series)); + assert.equal(series.length, 1); + + // Assert the first series is properly formatted + // first_series = {metric: "", points: [], ...} + var first_series = series[0] + assert.equal(first_series.metric, "metric.send_all"); + assert(Array.isArray(first_series.points)); + assert.deepEqual(first_series.points, [[now, 500]]); + }); + + it("should properly normalize metric points", function(){ + // Make our api call + var now = parseInt(new Date().getTime() / 1000); + var metrics = [ + { + metric: "metric.send_all.normalize", + points: [[now, 500]] + }, + { + metric: "metric.send_all.normalize", + points: [500, 1000] + }, + { + metric: "metric.send_all.normalize", + points: 1000 + } + ]; + metric.send_all(metrics); + + // Assert we called `client.request` with the correct `points` + assert(stub_request.calledOnce); + var call_args = stub_request.getCall(0).args; + // { body: series: [ {points: [], }, ] } + var body = call_args[2].body; + assert.equal(body.series.length, 3); + + // points = [ [, 500] ] + var points = body.series[0].points; + assert(Array.isArray(points)); + assert.equal(points.length, 1); + assert.equal(points[0].length, 2); + assert.equal(points[0][1], 500); + + // points = [ [, 500], [, 1000] ] + points = body.series[1].points; + assert(Array.isArray(points)); + assert.equal(points.length, 2); + assert.equal(points[0].length, 2); + assert.equal(points[0][1], 500); + assert.equal(points[1].length, 2); + assert.equal(points[1][1], 1000); + + // points = [ [, 1000] ] + points = body.series[2].points; + assert(Array.isArray(points)); + assert.equal(points.length, 1); + assert.equal(points[0].length, 2); + assert.equal(points[0][1], 1000); + }); }); });