cloudwatch-metrics
Advanced tools
Comparing version 1.2.0 to 1.3.0
106
index.js
@@ -82,3 +82,3 @@ /** | ||
var AWS = require('aws-sdk'); | ||
var CloudWatch = require('aws-sdk/clients/cloudwatch'); | ||
const SummarySet = require('./src/summarySet'); | ||
@@ -100,3 +100,2 @@ | ||
const DEFAULT_METRIC_OPTIONS = { | ||
@@ -107,3 +106,5 @@ enabled: true, | ||
sendCallback: () => {}, | ||
maxCapacity: 20 | ||
maxCapacity: 20, | ||
withTimestamp: false, | ||
storageResolution: undefined | ||
}; | ||
@@ -129,3 +130,3 @@ | ||
var self = this; | ||
self.cloudwatch = new AWS.CloudWatch(_awsConfig); | ||
self.cloudwatch = new CloudWatch(_awsConfig); | ||
self.namespace = namespace; | ||
@@ -153,17 +154,38 @@ self.units = units; | ||
* @param {String} namespace Name of the metric | ||
* @param {Array} additionalDimensions Array of additional CloudWatch metric dimensions. See | ||
* @param {String} units CloudWatch units | ||
* @param {Array} [additionalDimensions] Array of additional CloudWatch metric dimensions. See | ||
* http://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_Dimension.html for details. | ||
*/ | ||
Metric.prototype.put = function(value, metricName, additionalDimensions) { | ||
Metric.prototype.put = function(...args) { | ||
if (args.length === 3) { | ||
const [value, metricName] = args; | ||
const shouldInheritUnits = Array.isArray(args[2]); | ||
const units = shouldInheritUnits ? this.units : args[2]; | ||
const additionalDimensions = shouldInheritUnits ? args[2] : []; | ||
return this._put(value, metricName, units, additionalDimensions); | ||
} else if (args.length === 2) { | ||
return this._put(...args, this.units); | ||
} | ||
return this._put(...args); | ||
}; | ||
Metric.prototype._put = function(value, metricName, units, additionalDimensions) { | ||
var self = this; | ||
// Only publish if we are enabled | ||
if (self.options.enabled) { | ||
additionalDimensions = additionalDimensions || []; | ||
self._storedMetrics.push({ | ||
var payload = { | ||
MetricName: metricName, | ||
Dimensions: self.defaultDimensions.concat(additionalDimensions), | ||
Unit: self.units, | ||
Unit: units, | ||
Value: value | ||
}); | ||
}; | ||
if (this.options.withTimestamp) { | ||
payload.Timestamp = new Date().toISOString(); | ||
} | ||
if (this.options.storageResolution) { | ||
payload.StorageResolution = this.options.storageResolution; | ||
} | ||
self._storedMetrics.push(payload); | ||
// We need to see if we're at our maxCapacity, if we are - then send the | ||
@@ -188,6 +210,20 @@ // metrics now. | ||
* @param {String} metricName The name of the metric we're summarizing. | ||
* @param {String} units CloudWatch units | ||
* @param {Object[]} additionalDimensions The extra dimensions we're tracking. | ||
*/ | ||
Metric.prototype.summaryPut = function(value, metricName, additionalDimensions = []) { | ||
const key = makeKey(metricName, additionalDimensions); | ||
Metric.prototype.summaryPut = function(...args) { | ||
if (args.length === 3) { | ||
const [value, metricName] = args; | ||
const shouldInheritUnits = Array.isArray(args[2]); | ||
const units = shouldInheritUnits ? this.units : args[2]; | ||
const additionalDimensions = shouldInheritUnits ? args[2] : []; | ||
return this._summaryPut(value, metricName, units, additionalDimensions); | ||
} else if (args.length === 2) { | ||
return this._summaryPut(...args, this.units, []); | ||
} | ||
return this._summaryPut(...args); | ||
}; | ||
Metric.prototype._summaryPut = function(value, metricName, units, additionalDimensions = []) { | ||
const key = makeKey(metricName, units, additionalDimensions); | ||
const entry = this._summaryData.get(key); | ||
@@ -197,7 +233,7 @@ | ||
if (entry) { | ||
set = entry[2]; | ||
set = entry[3]; | ||
} else { | ||
set = new SummarySet(); | ||
const allDimensions = [...this.defaultDimensions, ...additionalDimensions]; | ||
this._summaryData.set(key, [metricName, allDimensions, set]); | ||
this._summaryData.set(key, [metricName, units, allDimensions, set]); | ||
} | ||
@@ -212,2 +248,3 @@ set.put(value); | ||
* @param {String} namespace Name of the metric | ||
* @param {String} units CloudWatch units | ||
* @param {Array} additionalDimensions Array of additional CloudWatch metric dimensions. See | ||
@@ -220,6 +257,17 @@ * http://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_Dimension.html for details. | ||
*/ | ||
Metric.prototype.sample = function(value, metricName, additionalDimensions, sampleRate) { | ||
if (Math.random() < sampleRate) this.put(value, metricName, additionalDimensions); | ||
Metric.prototype.sample = function(...args) { | ||
if (args.length === 4) { | ||
const [value, metricName, additionalDimensions, sampleRate] = args; | ||
const units = this.units; | ||
return this._sample(value, metricName, units, additionalDimensions, sampleRate); | ||
} | ||
return this.prototype._sample(...args); | ||
}; | ||
Metric.prototype._sample = function(value, metricName, units, additionalDimensions, sampleRate) { | ||
sampleRate = Array.isArray(additionalDimensions) ? sampleRate : additionalDimensions; | ||
if (Math.random() < sampleRate) this.put(value, metricName, units, additionalDimensions); | ||
}; | ||
/** | ||
@@ -247,2 +295,19 @@ * _sendMetrics is called on a specified interval (defaults to 5 seconds but | ||
/** | ||
* Shuts down metric service by clearing any outstanding timer and sending any existing metrics | ||
*/ | ||
Metric.prototype.shutdown = function() { | ||
clearInterval(this._interval); | ||
this._sendMetrics(); | ||
}; | ||
/** | ||
* Gets whether outstanding metrics exist or not. | ||
* | ||
* @return {boolean} | ||
*/ | ||
Metric.prototype.hasMetrics = function() { | ||
return !!this._storedMetrics.length; | ||
}; | ||
/** | ||
* _summarizeMetrics is called on a specified interval (default, 10 seconds). It | ||
@@ -254,3 +319,3 @@ * sends summarized statistics to Cloudwatch. | ||
const dataPoints = []; | ||
for (const [MetricName, Dimensions, set] of summaryEntries) { | ||
for (const [MetricName, Unit, Dimensions, set] of summaryEntries) { | ||
if (!set.size) continue; | ||
@@ -262,3 +327,3 @@ | ||
StatisticValues: set.get(), | ||
Unit: this.units, | ||
Unit, | ||
}); | ||
@@ -296,7 +361,8 @@ | ||
* @param {String} metricName | ||
* @param {String} units | ||
* @param {Object[]} dimensions | ||
* @returns {String} Something we can actually use as a Map key. | ||
*/ | ||
function makeKey(metricName, dimensions) { | ||
let key = metricName; | ||
function makeKey(metricName, units, dimensions) { | ||
let key = `${metricName}\0${units}`; | ||
for (const {Name, Value} of dimensions) { | ||
@@ -303,0 +369,0 @@ key += `\0${Name}\0${Value}`; |
{ | ||
"name": "cloudwatch-metrics", | ||
"version": "1.2.0", | ||
"version": "1.3.0", | ||
"description": "A simple wrapper for simplifying using Cloudwatch metrics", | ||
"main": "index.js", | ||
"scripts": { | ||
"ci": "npm run lint && npm test", | ||
"test": "jasmine", | ||
@@ -26,3 +27,3 @@ "lint": "eslint ." | ||
"dependencies": { | ||
"aws-sdk": "^2.4.14" | ||
"aws-sdk": "^2.412.0" | ||
}, | ||
@@ -29,0 +30,0 @@ "devDependencies": { |
@@ -32,3 +32,3 @@ ## cloudwatch-metrics | ||
For creating a metric, we simply need to provide the | ||
namespace and the type of metric: | ||
namespace and the default type of metric: | ||
```js | ||
@@ -71,2 +71,4 @@ var myMetric = new cloudwatchMetrics.Metric('namespace', 'Count'); | ||
maxCapacity | A maximum number of events to buffer before we send immediately (before the sendInterval is reached). | ||
withTimestamp | Include the timestamp with the metric value. | ||
storageResolution | The metric storage resolution to use in seconds. Set to 1 for high resolution metrics. See (https://aws.amazon.com/blogs/aws/new-high-resolution-custom-metrics-and-alarms-for-amazon-cloudwatch/) | ||
@@ -76,3 +78,3 @@ ### Publishing metric data | ||
```js | ||
myMetric.put(value, metric, additionalDimensions); | ||
myMetric.put(value, metric, units, additionalDimensions); | ||
``` | ||
@@ -141,7 +143,1 @@ | ||
``` | ||
## Release History | ||
* 1.2.0 Add the ability to use summary metrics. | ||
* 1.1.0 Add `metric.sample()` | ||
* 1.0.0 Initial release. |
@@ -1,2 +0,2 @@ | ||
/* globals describe, afterEach, it, expect, spyOn */ | ||
/* globals describe, afterEach, it, expect, spyOn, jasmine */ | ||
@@ -12,6 +12,4 @@ var _ = require('underscore'); | ||
function attachHook(hook) { | ||
restoreAWS = cloudwatchMetric.__set__('AWS', { | ||
CloudWatch: function() { | ||
this.putMetricData = hook; | ||
} | ||
restoreAWS = cloudwatchMetric.__set__('CloudWatch', function() { | ||
this.putMetricData = hook; | ||
}); | ||
@@ -140,2 +138,104 @@ } | ||
}); | ||
it('should set a Timestamp if specified in the options', function(done) { | ||
attachHook(function(data, cb) { | ||
expect(data).toEqual({ | ||
MetricData: [{ | ||
Dimensions: [{ | ||
Name: 'environment', | ||
Value: 'PROD' | ||
}, { | ||
Name: 'ExtraDimension', | ||
Value: 'Value' | ||
}], | ||
MetricName: 'metricName', | ||
Unit: 'Count', | ||
Timestamp: jasmine.any(String), | ||
Value: 1 | ||
}], | ||
Namespace: 'namespace' | ||
}); | ||
expect(Date.parse(data.MetricData[0].Timestamp)).toBeLessThanOrEqual(Date.now()); | ||
cb(); | ||
}); | ||
var metric = new cloudwatchMetric.Metric('namespace', 'Count', [{ | ||
Name: 'environment', | ||
Value: 'PROD' | ||
}], { | ||
withTimestamp: true, | ||
sendInterval: 1000, // mocha defaults to a 2 second timeout so setting | ||
// larger than that will cause the test to fail if we | ||
// hit the timeout | ||
sendCallback: done, | ||
}); | ||
metric.put(1, 'metricName', [{Name: 'ExtraDimension', Value: 'Value'}]); | ||
}); | ||
it('should set a StorageResolution if specified in the options', function(done) { | ||
attachHook(function(data, cb) { | ||
expect(data).toEqual({ | ||
MetricData: [{ | ||
Dimensions: [{ | ||
Name: 'environment', | ||
Value: 'PROD' | ||
}, { | ||
Name: 'ExtraDimension', | ||
Value: 'Value' | ||
}], | ||
MetricName: 'metricName', | ||
Unit: 'Count', | ||
StorageResolution: 1, | ||
Value: 1 | ||
}], | ||
Namespace: 'namespace' | ||
}); | ||
cb(); | ||
}); | ||
var metric = new cloudwatchMetric.Metric('namespace', 'Count', [{ | ||
Name: 'environment', | ||
Value: 'PROD' | ||
}], { | ||
storageResolution: 1, | ||
sendInterval: 1000, // mocha defaults to a 2 second timeout so setting | ||
// larger than that will cause the test to fail if we | ||
// hit the timeout | ||
sendCallback: done, | ||
}); | ||
metric.put(1, 'metricName', [{Name: 'ExtraDimension', Value: 'Value'}]); | ||
}); | ||
it('should override the Unit from the namespace if specified in the put call', function (done) { | ||
attachHook(function (data, cb) { | ||
expect(data).toEqual({ | ||
MetricData: [{ | ||
Dimensions: [{ | ||
Name: 'environment', | ||
Value: 'PROD' | ||
}, { | ||
Name: 'ExtraDimension', | ||
Value: 'Value' | ||
}], | ||
MetricName: 'metricName', | ||
Unit: 'Percent', | ||
Value: 1 | ||
}], | ||
Namespace: 'namespace' | ||
}); | ||
cb(); | ||
}); | ||
const metric = new cloudwatchMetric.Metric('namespace', 'Count', [{ | ||
Name: 'environment', | ||
Value: 'PROD' | ||
}], { | ||
sendInterval: 1000, | ||
sendCallback: done, | ||
}); | ||
metric.put(1, 'metricName', 'Percent', [{ Name: 'ExtraDimension', Value: 'Value' }]); | ||
}); | ||
}); | ||
@@ -233,2 +333,18 @@ | ||
}, | ||
}, { | ||
Dimensions: [{ | ||
Name: 'environment', | ||
Value: 'PROD' | ||
}, { | ||
Name: 'ExtraDimension', | ||
Value: 'Value' | ||
}], | ||
MetricName: 'a-metric-with-different-unit', | ||
Unit: 'Percent', | ||
StatisticValues: { | ||
Minimum: 5, | ||
Maximum: 5, | ||
Sum: 5, | ||
SampleCount: 1, | ||
}, | ||
}], | ||
@@ -251,4 +367,5 @@ Namespace: 'namespace' | ||
metric.summaryPut(12, 'some-metric', [{Name: 'ExtraDimension', Value: 'Value'}]); | ||
metric.summaryPut(2, 'some-other-metric', [{Name: 'ExtraDimension', Value: 'Value'}]); | ||
metric.summaryPut(12, 'some-metric', [{ Name: 'ExtraDimension', Value: 'Value' }]); | ||
metric.summaryPut(2, 'some-other-metric', [{ Name: 'ExtraDimension', Value: 'Value' }]); | ||
metric.summaryPut(5, 'a-metric-with-different-unit', 'Percent', [{ Name: 'ExtraDimension', Value: 'Value' }]); | ||
setTimeout(() => { | ||
@@ -255,0 +372,0 @@ metric.summaryPut(13, 'some-metric', [{Name: 'ExtraDimension', Value: 'Value'}]); |
34006
12
799
140
+ Addedavailable-typed-arrays@1.0.7(transitive)
+ Addedaws-sdk@2.1624.0(transitive)
+ Addedbase64-js@1.5.1(transitive)
+ Addedbuffer@4.9.2(transitive)
+ Addedcall-bind@1.0.7(transitive)
+ Addeddefine-data-property@1.1.4(transitive)
+ Addedes-define-property@1.0.0(transitive)
+ Addedes-errors@1.3.0(transitive)
+ Addedevents@1.1.1(transitive)
+ Addedfor-each@0.3.3(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedget-intrinsic@1.2.4(transitive)
+ Addedgopd@1.0.1(transitive)
+ Addedhas-property-descriptors@1.0.2(transitive)
+ Addedhas-proto@1.0.3(transitive)
+ Addedhas-symbols@1.0.3(transitive)
+ Addedhas-tostringtag@1.0.2(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedieee754@1.1.13(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedis-arguments@1.1.1(transitive)
+ Addedis-callable@1.2.7(transitive)
+ Addedis-generator-function@1.0.10(transitive)
+ Addedis-typed-array@1.1.13(transitive)
+ Addedisarray@1.0.0(transitive)
+ Addedjmespath@0.16.0(transitive)
+ Addedpossible-typed-array-names@1.0.0(transitive)
+ Addedpunycode@1.3.2(transitive)
+ Addedquerystring@0.2.0(transitive)
+ Addedsax@1.2.1(transitive)
+ Addedset-function-length@1.2.2(transitive)
+ Addedurl@0.10.3(transitive)
+ Addedutil@0.12.5(transitive)
+ Addeduuid@8.0.0(transitive)
+ Addedwhich-typed-array@1.1.15(transitive)
+ Addedxml2js@0.6.2(transitive)
+ Addedxmlbuilder@11.0.1(transitive)
Updatedaws-sdk@^2.412.0