diff --git a/LICENSE-3rdparty.csv b/LICENSE-3rdparty.csv index 8bc2127968a..9f4d306134e 100644 --- a/LICENSE-3rdparty.csv +++ b/LICENSE-3rdparty.csv @@ -3,6 +3,7 @@ require,@types/node,MIT,Copyright Authors require,bowser,MIT,Copyright 2015 Dustin Diaz require,container-info,MIT,Copyright 2018 Stephen Belanger require,core-js,MIT,Copyright 2014-2019 Denis Pushkarev +require,hdr-histogram-js,BSD-2-Clause,Copyright 2016 Alexandre Victoor require,int64-buffer,MIT,Copyright 2015-2016 Yusuke Kawasaki require,koalas,MIT,Copyright 2013-2017 Brian Woodward require,limiter,MIT,Copyright 2011 John Hurliman diff --git a/benchmark/core.js b/benchmark/core.js index 46c7cb7c5a1..e0caafb33ce 100644 --- a/benchmark/core.js +++ b/benchmark/core.js @@ -19,6 +19,8 @@ const format = require('../packages/dd-trace/src/format') const encode = require('../packages/dd-trace/src/encode') const config = new Config('benchmark', { service: 'benchmark' }) const id = require('../packages/dd-trace/src/id') +const Histogram = require('../packages/dd-trace/src/histogram') +const histogram = new Histogram() const suite = benchmark('core') @@ -99,5 +101,10 @@ suite id() } }) + .add('Histogram', { + fn () { + histogram.record(Math.round(Math.random() * 3e12)) + } + }) suite.run() diff --git a/package.json b/package.json index 4de182219e4..0c30f4a3100 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "bowser": "^2.5.3", "container-info": "^1.0.1", "core-js": "^3.3.4", + "hdr-histogram-js": "^1.1.4", "int64-buffer": "^0.1.9", "koalas": "^1.0.2", "limiter": "^1.1.4", diff --git a/packages/dd-trace/src/exporters/agent/writer.js b/packages/dd-trace/src/exporters/agent/writer.js index 45c01a7ee84..46a2a725400 100644 --- a/packages/dd-trace/src/exporters/agent/writer.js +++ b/packages/dd-trace/src/exporters/agent/writer.js @@ -26,6 +26,8 @@ class Writer { log.debug(() => `Adding encoded trace to buffer: ${buffer.toString('hex').match(/../g).join(' ')}`) + platform.metrics().histogram('datadog.tracer.node.exporter.agent.trace_size', buffer.length) + if (buffer.length + this._size > MAX_SIZE) { this.flush() } @@ -37,9 +39,12 @@ class Writer { flush () { if (this._queue.length > 0) { const data = platform.msgpack.prefix(this._queue) + const size = data.reduce((prev, next) => prev + next.length, 0) this._request(data, this._queue.length) + platform.metrics().histogram('datadog.tracer.node.exporter.agent.payload_size', size) + this._queue = [] this._size = 0 } @@ -70,7 +75,20 @@ class Writer { log.debug(() => `Request to the agent: ${JSON.stringify(options)}`) - platform.request(Object.assign({ data }, options), (err, res) => { + platform.metrics().increment('datadog.tracer.node.exporter.agent.requests') + + platform.request(Object.assign({ data }, options), (err, res, status) => { + if (status) { + platform.metrics().increment('datadog.tracer.node.exporter.agent.responses') + platform.metrics().increment('datadog.tracer.node.exporter.agent.responses.by.status', `status:${status}`) + } else { + platform.metrics().increment('datadog.tracer.node.exporter.agent.errors') + + if (err && err.code) { + platform.metrics().increment('datadog.tracer.node.exporter.agent.errors.by.code', `code:${err.code}`) + } + } + if (err) return log.error(err) log.debug(`Response from the agent: ${res}`) diff --git a/packages/dd-trace/src/histogram.js b/packages/dd-trace/src/histogram.js new file mode 100644 index 00000000000..95cfc0974fc --- /dev/null +++ b/packages/dd-trace/src/histogram.js @@ -0,0 +1,52 @@ +'use strict' + +const hdr = require('hdr-histogram-js') + +const highestTrackableValue = 3.6e12 // 1 hour + +class Histogram { + constructor () { + this._histogram = hdr.build({ + highestTrackableValue + }) + + this.reset() + } + + get min () { return this._min } + get max () { return this._max } + get avg () { return this._count === 0 ? 0 : this._sum / this._count } + get sum () { return this._sum } + get count () { return this._count } + get median () { return this.percentile(50) } + get p95 () { return this.percentile(95) } + + percentile (percentile) { + return this._histogram.getValueAtPercentile(percentile) + } + + record (value) { + if (this._count === 0) { + this._min = this._max = value + } else { + this._min = Math.min(this._min, value) + this._max = Math.max(this._max, value) + } + + this._count++ + this._sum += value + + this._histogram.recordValue(value) + } + + reset () { + this._min = 0 + this._max = 0 + this._sum = 0 + this._count = 0 + + this._histogram.reset() + } +} + +module.exports = Histogram diff --git a/packages/dd-trace/src/platform/browser/metrics.js b/packages/dd-trace/src/platform/browser/metrics.js index 518cdd21c3e..25836e66dda 100644 --- a/packages/dd-trace/src/platform/browser/metrics.js +++ b/packages/dd-trace/src/platform/browser/metrics.js @@ -16,6 +16,8 @@ module.exports = function () { } }, + histogram () {}, + count () {}, increment () {}, diff --git a/packages/dd-trace/src/platform/node/metrics.js b/packages/dd-trace/src/platform/node/metrics.js index b618d6ea63b..c56d22039e6 100644 --- a/packages/dd-trace/src/platform/node/metrics.js +++ b/packages/dd-trace/src/platform/node/metrics.js @@ -4,8 +4,10 @@ const v8 = require('v8') const path = require('path') +const os = require('os') const Client = require('./dogstatsd') const log = require('../../log') +const Histogram = require('../../histogram') const INTERVAL = 10 * 1000 @@ -16,7 +18,9 @@ let interval let client let time let cpuUsage +let gauges let counters +let histograms reset() @@ -99,21 +103,40 @@ module.exports = function () { return { finish: () => {} } }, - count (name, count, tag) { + histogram (name, value, tag) { if (!client) return - if (!counters[name]) { - counters[name] = tag ? Object.create(null) : 0 + + histograms[name] = histograms[name] || new Map() + + if (!histograms[name].has(tag)) { + histograms[name].set(tag, new Histogram()) + } + + histograms[name].get(tag).record(value) + }, + + count (name, count, tag, monotonic = false) { + if (!client) return + if (typeof tag === 'boolean') { + monotonic = tag + tag = undefined + } + + const map = monotonic ? counters : gauges + + if (!map[name]) { + map[name] = tag ? Object.create(null) : 0 } if (tag) { - counters[name][tag] = (counters[name][tag] || 0) + count + map[name][tag] = (map[name][tag] || 0) + count } else { - counters[name] = (counters[name] || 0) + count + map[name] = (map[name] || 0) + count } }, - increment (name, tag) { - this.count(name, 1, tag) + increment (name, tag, monotonic) { + this.count(name, 1, tag, monotonic) }, decrement (name, tag) { @@ -127,7 +150,9 @@ function reset () { client = null time = null cpuUsage = null + gauges = {} counters = {} + histograms = {} } function captureCpuUsage () { @@ -144,36 +169,38 @@ function captureCpuUsage () { const systemPercent = 100 * elapsedUsage.system / 1000 / elapsedMs const totalPercent = userPercent + systemPercent - client.gauge('cpu.system', systemPercent.toFixed(2)) - client.gauge('cpu.user', userPercent.toFixed(2)) - client.gauge('cpu.total', totalPercent.toFixed(2)) + client.gauge('runtime.node.cpu.system', systemPercent.toFixed(2)) + client.gauge('runtime.node.cpu.user', userPercent.toFixed(2)) + client.gauge('runtime.node.cpu.total', totalPercent.toFixed(2)) } function captureMemoryUsage () { const stats = process.memoryUsage() - client.gauge('mem.heap_total', stats.heapTotal) - client.gauge('mem.heap_used', stats.heapUsed) - client.gauge('mem.rss', stats.rss) + client.gauge('runtime.node.mem.heap_total', stats.heapTotal) + client.gauge('runtime.node.mem.heap_used', stats.heapUsed) + client.gauge('runtime.node.mem.rss', stats.rss) + client.gauge('runtime.node.mem.total', os.totalmem()) + client.gauge('runtime.node.mem.free', os.freemem()) - stats.external && client.gauge('mem.external', stats.external) + stats.external && client.gauge('runtime.node.mem.external', stats.external) } function captureProcess () { - client.gauge('process.uptime', Math.round(process.uptime())) + client.gauge('runtime.node.process.uptime', Math.round(process.uptime())) } function captureHeapStats () { const stats = v8.getHeapStatistics() - client.gauge('heap.total_heap_size', stats.total_heap_size) - client.gauge('heap.total_heap_size_executable', stats.total_heap_size_executable) - client.gauge('heap.total_physical_size', stats.total_physical_size) - client.gauge('heap.total_available_size', stats.total_available_size) - client.gauge('heap.heap_size_limit', stats.heap_size_limit) + client.gauge('runtime.node.heap.total_heap_size', stats.total_heap_size) + client.gauge('runtime.node.heap.total_heap_size_executable', stats.total_heap_size_executable) + client.gauge('runtime.node.heap.total_physical_size', stats.total_physical_size) + client.gauge('runtime.node.heap.total_available_size', stats.total_available_size) + client.gauge('runtime.node.heap.heap_size_limit', stats.heap_size_limit) - stats.malloced_memory && client.gauge('heap.malloced_memory', stats.malloced_memory) - stats.peak_malloced_memory && client.gauge('heap.peak_malloced_memory', stats.peak_malloced_memory) + stats.malloced_memory && client.gauge('runtime.node.heap.malloced_memory', stats.malloced_memory) + stats.peak_malloced_memory && client.gauge('runtime.node.heap.peak_malloced_memory', stats.peak_malloced_memory) } function captureHeapSpace () { @@ -184,30 +211,53 @@ function captureHeapSpace () { for (let i = 0, l = stats.length; i < l; i++) { const tags = [`space:${stats[i].space_name}`] - client.gauge('heap.size.by.space', stats[i].space_size, tags) - client.gauge('heap.used_size.by.space', stats[i].space_used_size, tags) - client.gauge('heap.available_size.by.space', stats[i].space_available_size, tags) - client.gauge('heap.physical_size.by.space', stats[i].physical_space_size, tags) + client.gauge('runtime.node.heap.size.by.space', stats[i].space_size, tags) + client.gauge('runtime.node.heap.used_size.by.space', stats[i].space_used_size, tags) + client.gauge('runtime.node.heap.available_size.by.space', stats[i].space_available_size, tags) + client.gauge('runtime.node.heap.physical_size.by.space', stats[i].physical_space_size, tags) } } +function captureGauges () { + Object.keys(gauges).forEach(name => { + if (typeof gauges[name] === 'object') { + Object.keys(gauges[name]).forEach(tag => { + client.gauge(name, gauges[name][tag], [tag]) + }) + } else { + client.gauge(name, gauges[name]) + } + }) +} + function captureCounters () { Object.keys(counters).forEach(name => { if (typeof counters[name] === 'object') { Object.keys(counters[name]).forEach(tag => { - client.gauge(name, counters[name][tag], [tag]) + client.increment(name, counters[name][tag], [tag]) }) } else { - client.gauge(name, counters[name]) + client.increment(name, counters[name]) } }) } +function captureHistograms () { + Object.keys(histograms).forEach(name => { + histograms[name].forEach((stats, tag) => { + histogram(name, stats, tag) + stats.reset() + }) + }) +} + function captureCommonMetrics () { captureMemoryUsage() captureProcess() captureHeapStats() + captureGauges() captureCounters() + captureHistograms() } function captureNativeMetrics () { @@ -222,49 +272,52 @@ function captureNativeMetrics () { const systemPercent = 100 * stats.cpu.system / elapsedUs const totalPercent = userPercent + systemPercent - client.gauge('cpu.system', systemPercent.toFixed(2)) - client.gauge('cpu.user', userPercent.toFixed(2)) - client.gauge('cpu.total', totalPercent.toFixed(2)) + client.gauge('runtime.node.cpu.system', systemPercent.toFixed(2)) + client.gauge('runtime.node.cpu.user', userPercent.toFixed(2)) + client.gauge('runtime.node.cpu.total', totalPercent.toFixed(2)) - histogram('event_loop.delay', stats.eventLoop) + histogram('runtime.node.event_loop.delay', stats.eventLoop) Object.keys(stats.gc).forEach(type => { if (type === 'all') { - histogram('gc.pause', stats.gc[type]) + histogram('runtime.node.gc.pause', stats.gc[type]) } else { - histogram('gc.pause.by.type', stats.gc[type], [`gc_type:${type}`]) + histogram('runtime.node.gc.pause.by.type', stats.gc[type], [`gc_type:${type}`]) } }) - client.gauge('spans.finished', stats.spans.total.finished) - client.gauge('spans.unfinished', stats.spans.total.unfinished) + client.gauge('runtime.node.spans.finished', stats.spans.total.finished) + client.gauge('runtime.node.spans.unfinished', stats.spans.total.unfinished) for (let i = 0, l = spaces.length; i < l; i++) { const tags = [`heap_space:${spaces[i].space_name}`] - client.gauge('heap.size.by.space', spaces[i].space_size, tags) - client.gauge('heap.used_size.by.space', spaces[i].space_used_size, tags) - client.gauge('heap.available_size.by.space', spaces[i].space_available_size, tags) - client.gauge('heap.physical_size.by.space', spaces[i].physical_space_size, tags) + client.gauge('runtime.node.heap.size.by.space', spaces[i].space_size, tags) + client.gauge('runtime.node.heap.used_size.by.space', spaces[i].space_used_size, tags) + client.gauge('runtime.node.heap.available_size.by.space', spaces[i].space_available_size, tags) + client.gauge('runtime.node.heap.physical_size.by.space', spaces[i].physical_space_size, tags) } if (stats.spans.operations) { const operations = stats.spans.operations Object.keys(operations.finished).forEach(name => { - client.gauge('spans.finished.by.name', operations.finished[name], [`span_name:${name}`]) + client.gauge('runtime.node.spans.finished.by.name', operations.finished[name], [`span_name:${name}`]) }) Object.keys(operations.unfinished).forEach(name => { - client.gauge('spans.unfinished.by.name', operations.unfinished[name], [`span_name:${name}`]) + client.gauge('runtime.node.spans.unfinished.by.name', operations.unfinished[name], [`span_name:${name}`]) }) } } function histogram (name, stats, tags) { + tags = [].concat(tags) + client.gauge(`${name}.min`, stats.min, tags) client.gauge(`${name}.max`, stats.max, tags) client.increment(`${name}.sum`, stats.sum, tags) + client.increment(`${name}.total`, stats.sum, tags) client.gauge(`${name}.avg`, stats.avg, tags) client.increment(`${name}.count`, stats.count, tags) client.gauge(`${name}.median`, stats.median, tags) diff --git a/packages/dd-trace/src/platform/node/request.js b/packages/dd-trace/src/platform/node/request.js index 7880bfde9c6..de7353bd1cd 100644 --- a/packages/dd-trace/src/platform/node/request.js +++ b/packages/dd-trace/src/platform/node/request.js @@ -30,12 +30,12 @@ function request (options, callback) { res.on('data', chunk => { data += chunk }) res.on('end', () => { if (res.statusCode >= 200 && res.statusCode <= 299) { - callback(null, data) + callback(null, data, res.statusCode) } else { - const error = new Error(http.STATUS_CODES[res.statusCode]) + const error = new Error(`Error from the agent: ${res.statusCode} ${http.STATUS_CODES[res.statusCode]}`) error.status = res.statusCode - callback(new Error(`Error from the agent: ${res.statusCode} ${http.STATUS_CODES[res.statusCode]}`)) + callback(error, null, res.statusCode) } }) }) diff --git a/packages/dd-trace/src/scope/async_hooks.js b/packages/dd-trace/src/scope/async_hooks.js index 9dadf40551e..5771da38863 100644 --- a/packages/dd-trace/src/scope/async_hooks.js +++ b/packages/dd-trace/src/scope/async_hooks.js @@ -108,8 +108,8 @@ class Scope extends Base { this._weaks.set(resource, asyncId) } - platform.metrics().increment('async.resources') - platform.metrics().increment('async.resources.by.type', `resource_type:${type}`) + platform.metrics().increment('runtime.node.async.resources') + platform.metrics().increment('runtime.node.async.resources.by.type', `resource_type:${type}`) if (this._trackAsyncScope && type === 'PROMISE') { this._initPromise() @@ -129,8 +129,8 @@ class Scope extends Base { const type = this._types[asyncId] if (type) { - platform.metrics().decrement('async.resources') - platform.metrics().decrement('async.resources.by.type', `resource_type:${type}`) + platform.metrics().decrement('runtime.node.async.resources') + platform.metrics().decrement('runtime.node.async.resources.by.type', `resource_type:${type}`) } delete this._spans[asyncId] diff --git a/packages/dd-trace/test/exporters/agent/writer.spec.js b/packages/dd-trace/test/exporters/agent/writer.spec.js index a7b18ea9d22..c1c549d8fba 100644 --- a/packages/dd-trace/test/exporters/agent/writer.spec.js +++ b/packages/dd-trace/test/exporters/agent/writer.spec.js @@ -53,7 +53,7 @@ describe('Writer', () => { engine: sinon.stub(), request: sinon.stub().yields(null, response), msgpack: { - prefix: sinon.stub() + prefix: sinon.stub().returns([]) } } @@ -125,7 +125,7 @@ describe('Writer', () => { }) it('should flush its traces to the agent', () => { - platform.msgpack.prefix.withArgs(['encoded', 'encoded']).returns('prefixed') + platform.msgpack.prefix.withArgs(['encoded', 'encoded']).returns(['prefixed']) platform.name.returns('lang') platform.version.returns('version') platform.engine.returns('interpreter') @@ -148,7 +148,7 @@ describe('Writer', () => { 'Datadog-Meta-Tracer-Version': 'tracerVersion', 'X-Datadog-Trace-Count': '2' }, - data: 'prefixed' + data: ['prefixed'] }) }) diff --git a/packages/dd-trace/test/histogram.spec.js b/packages/dd-trace/test/histogram.spec.js new file mode 100644 index 00000000000..ed4517e95d4 --- /dev/null +++ b/packages/dd-trace/test/histogram.spec.js @@ -0,0 +1,43 @@ +'use strict' + +const Histogram = require('../src/histogram') + +describe('Histogram', () => { + let histogram + + beforeEach(() => { + histogram = new Histogram() + }) + + it('should record values', () => { + histogram.record(1) + histogram.record(2) + histogram.record(3) + + expect(histogram).to.have.property('min', 1) + expect(histogram).to.have.property('max', 3) + expect(histogram).to.have.property('sum', 6) + expect(histogram).to.have.property('avg', 2) + expect(histogram).to.have.property('median', 2) + expect(histogram).to.have.property('count', 3) + expect(histogram).to.have.property('p95', 3) + expect(histogram.percentile(50)).to.equal(2) + }) + + it('should reset all stats', () => { + histogram.record(1) + histogram.record(2) + histogram.record(3) + + histogram.reset() + + expect(histogram).to.have.property('min', 0) + expect(histogram).to.have.property('max', 0) + expect(histogram).to.have.property('sum', 0) + expect(histogram).to.have.property('avg', 0) + expect(histogram).to.have.property('median', 0) + expect(histogram).to.have.property('count', 0) + expect(histogram).to.have.property('p95', 0) + expect(histogram.percentile(50)).to.equal(0) + }) +}) diff --git a/packages/dd-trace/test/platform/node/index.spec.js b/packages/dd-trace/test/platform/node/index.spec.js index 7b37a53130d..b5945000fce 100644 --- a/packages/dd-trace/test/platform/node/index.spec.js +++ b/packages/dd-trace/test/platform/node/index.spec.js @@ -378,6 +378,7 @@ describe('Platform', () => { client = { gauge: sinon.spy(), increment: sinon.spy(), + histogram: sinon.spy(), flush: sinon.spy() } @@ -436,59 +437,59 @@ describe('Platform', () => { clock.tick(10000) - expect(client.gauge).to.have.been.calledWith('cpu.user') - expect(client.gauge).to.have.been.calledWith('cpu.system') - expect(client.gauge).to.have.been.calledWith('cpu.total') - - expect(client.gauge).to.have.been.calledWith('mem.rss') - expect(client.gauge).to.have.been.calledWith('mem.heap_total') - expect(client.gauge).to.have.been.calledWith('mem.heap_used') - - expect(client.gauge).to.have.been.calledWith('process.uptime') - - expect(client.gauge).to.have.been.calledWith('heap.total_heap_size') - expect(client.gauge).to.have.been.calledWith('heap.total_heap_size_executable') - expect(client.gauge).to.have.been.calledWith('heap.total_physical_size') - expect(client.gauge).to.have.been.calledWith('heap.total_available_size') - expect(client.gauge).to.have.been.calledWith('heap.total_heap_size') - expect(client.gauge).to.have.been.calledWith('heap.heap_size_limit') - - expect(client.gauge).to.have.been.calledWith('heap.malloced_memory') - expect(client.gauge).to.have.been.calledWith('heap.peak_malloced_memory') - - expect(client.gauge).to.have.been.calledWith('event_loop.delay.max') - expect(client.gauge).to.have.been.calledWith('event_loop.delay.min') - expect(client.increment).to.have.been.calledWith('event_loop.delay.sum') - expect(client.gauge).to.have.been.calledWith('event_loop.delay.avg') - expect(client.gauge).to.have.been.calledWith('event_loop.delay.median') - expect(client.gauge).to.have.been.calledWith('event_loop.delay.95percentile') - expect(client.increment).to.have.been.calledWith('event_loop.delay.count') - - expect(client.gauge).to.have.been.calledWith('gc.pause.max') - expect(client.gauge).to.have.been.calledWith('gc.pause.min') - expect(client.increment).to.have.been.calledWith('gc.pause.sum') - expect(client.gauge).to.have.been.calledWith('gc.pause.avg') - expect(client.gauge).to.have.been.calledWith('gc.pause.median') - expect(client.gauge).to.have.been.calledWith('gc.pause.95percentile') - expect(client.increment).to.have.been.calledWith('gc.pause.count') - - expect(client.gauge).to.have.been.calledWith('gc.pause.by.type.max') - expect(client.gauge).to.have.been.calledWith('gc.pause.by.type.min') - expect(client.increment).to.have.been.calledWith('gc.pause.by.type.sum') - expect(client.gauge).to.have.been.calledWith('gc.pause.by.type.avg') - expect(client.gauge).to.have.been.calledWith('gc.pause.by.type.median') - expect(client.gauge).to.have.been.calledWith('gc.pause.by.type.95percentile') - expect(client.increment).to.have.been.calledWith('gc.pause.by.type.count') + expect(client.gauge).to.have.been.calledWith('runtime.node.cpu.user') + expect(client.gauge).to.have.been.calledWith('runtime.node.cpu.system') + expect(client.gauge).to.have.been.calledWith('runtime.node.cpu.total') + + expect(client.gauge).to.have.been.calledWith('runtime.node.mem.rss') + expect(client.gauge).to.have.been.calledWith('runtime.node.mem.heap_total') + expect(client.gauge).to.have.been.calledWith('runtime.node.mem.heap_used') + + expect(client.gauge).to.have.been.calledWith('runtime.node.process.uptime') + + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.total_heap_size') + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.total_heap_size_executable') + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.total_physical_size') + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.total_available_size') + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.total_heap_size') + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.heap_size_limit') + + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.malloced_memory') + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.peak_malloced_memory') + + expect(client.gauge).to.have.been.calledWith('runtime.node.event_loop.delay.max') + expect(client.gauge).to.have.been.calledWith('runtime.node.event_loop.delay.min') + expect(client.increment).to.have.been.calledWith('runtime.node.event_loop.delay.sum') + expect(client.gauge).to.have.been.calledWith('runtime.node.event_loop.delay.avg') + expect(client.gauge).to.have.been.calledWith('runtime.node.event_loop.delay.median') + expect(client.gauge).to.have.been.calledWith('runtime.node.event_loop.delay.95percentile') + expect(client.increment).to.have.been.calledWith('runtime.node.event_loop.delay.count') + + expect(client.gauge).to.have.been.calledWith('runtime.node.gc.pause.max') + expect(client.gauge).to.have.been.calledWith('runtime.node.gc.pause.min') + expect(client.increment).to.have.been.calledWith('runtime.node.gc.pause.sum') + expect(client.gauge).to.have.been.calledWith('runtime.node.gc.pause.avg') + expect(client.gauge).to.have.been.calledWith('runtime.node.gc.pause.median') + expect(client.gauge).to.have.been.calledWith('runtime.node.gc.pause.95percentile') + expect(client.increment).to.have.been.calledWith('runtime.node.gc.pause.count') + + expect(client.gauge).to.have.been.calledWith('runtime.node.gc.pause.by.type.max') + expect(client.gauge).to.have.been.calledWith('runtime.node.gc.pause.by.type.min') + expect(client.increment).to.have.been.calledWith('runtime.node.gc.pause.by.type.sum') + expect(client.gauge).to.have.been.calledWith('runtime.node.gc.pause.by.type.avg') + expect(client.gauge).to.have.been.calledWith('runtime.node.gc.pause.by.type.median') + expect(client.gauge).to.have.been.calledWith('runtime.node.gc.pause.by.type.95percentile') + expect(client.increment).to.have.been.calledWith('runtime.node.gc.pause.by.type.count') expect(client.increment).to.have.been.calledWith( - 'gc.pause.by.type.count', sinon.match.any, sinon.match(val => { + 'runtime.node.gc.pause.by.type.count', sinon.match.any, sinon.match(val => { return val && /^gc_type:[a-z_]+$/.test(val[0]) }) ) - expect(client.gauge).to.have.been.calledWith('heap.size.by.space') - expect(client.gauge).to.have.been.calledWith('heap.used_size.by.space') - expect(client.gauge).to.have.been.calledWith('heap.available_size.by.space') - expect(client.gauge).to.have.been.calledWith('heap.physical_size.by.space') + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.size.by.space') + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.used_size.by.space') + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.available_size.by.space') + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.physical_size.by.space') expect(client.flush).to.have.been.called }) @@ -505,8 +506,28 @@ describe('Platform', () => { }) }) + describe('histogram', () => { + it('should add a record to a histogram', () => { + metrics.apply(platform).start() + metrics.apply(platform).histogram('test', 1) + metrics.apply(platform).histogram('test', 2) + metrics.apply(platform).histogram('test', 3) + + clock.tick(10000) + + expect(client.gauge).to.have.been.calledWith('test.max', 3) + expect(client.gauge).to.have.been.calledWith('test.min', 1) + expect(client.increment).to.have.been.calledWith('test.sum', 6) + expect(client.increment).to.have.been.calledWith('test.total', 6) + expect(client.gauge).to.have.been.calledWith('test.avg', 2) + expect(client.gauge).to.have.been.calledWith('test.median', 2) + expect(client.gauge).to.have.been.calledWith('test.95percentile', 3) + expect(client.increment).to.have.been.calledWith('test.count', 3) + }) + }) + describe('increment', () => { - it('should increment a counter', () => { + it('should increment a gauge', () => { metrics.apply(platform).start() metrics.apply(platform).increment('test') @@ -515,7 +536,7 @@ describe('Platform', () => { expect(client.gauge).to.have.been.calledWith('test', 1) }) - it('should increment a counter with a tag', () => { + it('should increment a gauge with a tag', () => { metrics.apply(platform).start() metrics.apply(platform).increment('test', 'foo:bar') @@ -523,10 +544,28 @@ describe('Platform', () => { expect(client.gauge).to.have.been.calledWith('test', 1, ['foo:bar']) }) + + it('should increment a monotonic counter', () => { + metrics.apply(platform).start() + metrics.apply(platform).increment('test', true) + + clock.tick(10000) + + expect(client.increment).to.have.been.calledWith('test', 1) + }) + + it('should increment a monotonic counter with a tag', () => { + metrics.apply(platform).start() + metrics.apply(platform).increment('test', 'foo:bar', true) + + clock.tick(10000) + + expect(client.increment).to.have.been.calledWith('test', 1, ['foo:bar']) + }) }) describe('decrement', () => { - it('should increment a counter', () => { + it('should increment a gauge', () => { metrics.apply(platform).start() metrics.apply(platform).decrement('test') @@ -535,7 +574,7 @@ describe('Platform', () => { expect(client.gauge).to.have.been.calledWith('test', -1) }) - it('should decrement a counter with a tag', () => { + it('should decrement a gauge with a tag', () => { metrics.apply(platform).start() metrics.apply(platform).decrement('test', 'foo:bar') @@ -558,30 +597,30 @@ describe('Platform', () => { clock.tick(10000) - expect(client.gauge).to.have.been.calledWith('cpu.user') - expect(client.gauge).to.have.been.calledWith('cpu.system') - expect(client.gauge).to.have.been.calledWith('cpu.total') + expect(client.gauge).to.have.been.calledWith('runtime.node.cpu.user') + expect(client.gauge).to.have.been.calledWith('runtime.node.cpu.system') + expect(client.gauge).to.have.been.calledWith('runtime.node.cpu.total') - expect(client.gauge).to.have.been.calledWith('mem.rss') - expect(client.gauge).to.have.been.calledWith('mem.heap_total') - expect(client.gauge).to.have.been.calledWith('mem.heap_used') + expect(client.gauge).to.have.been.calledWith('runtime.node.mem.rss') + expect(client.gauge).to.have.been.calledWith('runtime.node.mem.heap_total') + expect(client.gauge).to.have.been.calledWith('runtime.node.mem.heap_used') - expect(client.gauge).to.have.been.calledWith('process.uptime') + expect(client.gauge).to.have.been.calledWith('runtime.node.process.uptime') - expect(client.gauge).to.have.been.calledWith('heap.total_heap_size') - expect(client.gauge).to.have.been.calledWith('heap.total_heap_size_executable') - expect(client.gauge).to.have.been.calledWith('heap.total_physical_size') - expect(client.gauge).to.have.been.calledWith('heap.total_available_size') - expect(client.gauge).to.have.been.calledWith('heap.total_heap_size') - expect(client.gauge).to.have.been.calledWith('heap.heap_size_limit') + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.total_heap_size') + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.total_heap_size_executable') + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.total_physical_size') + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.total_available_size') + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.total_heap_size') + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.heap_size_limit') - expect(client.gauge).to.have.been.calledWith('heap.malloced_memory') - expect(client.gauge).to.have.been.calledWith('heap.peak_malloced_memory') + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.malloced_memory') + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.peak_malloced_memory') - expect(client.gauge).to.have.been.calledWith('heap.size.by.space') - expect(client.gauge).to.have.been.calledWith('heap.used_size.by.space') - expect(client.gauge).to.have.been.calledWith('heap.available_size.by.space') - expect(client.gauge).to.have.been.calledWith('heap.physical_size.by.space') + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.size.by.space') + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.used_size.by.space') + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.available_size.by.space') + expect(client.gauge).to.have.been.calledWith('runtime.node.heap.physical_size.by.space') expect(client.flush).to.have.been.called }) diff --git a/packages/dd-trace/test/scope/async_hooks.spec.js b/packages/dd-trace/test/scope/async_hooks.spec.js index f5ebca9cc5b..aa49cae26c0 100644 --- a/packages/dd-trace/test/scope/async_hooks.spec.js +++ b/packages/dd-trace/test/scope/async_hooks.spec.js @@ -36,16 +36,16 @@ describe('Scope (async_hooks)', () => { scope._init(0, 'TEST') scope._destroy(0) - expect(metrics.increment).to.have.been.calledWith('async.resources') - expect(metrics.decrement).to.have.been.calledWith('async.resources') + expect(metrics.increment).to.have.been.calledWith('runtime.node.async.resources') + expect(metrics.decrement).to.have.been.calledWith('runtime.node.async.resources') }) it('should keep track of asynchronous resource count by type', () => { scope._init(0, 'TEST') scope._destroy(0) - expect(metrics.increment).to.have.been.calledWith('async.resources.by.type', 'resource_type:TEST') - expect(metrics.decrement).to.have.been.calledWith('async.resources.by.type', 'resource_type:TEST') + expect(metrics.increment).to.have.been.calledWith('runtime.node.async.resources.by.type', 'resource_type:TEST') + expect(metrics.decrement).to.have.been.calledWith('runtime.node.async.resources.by.type', 'resource_type:TEST') }) it('should only track destroys once', () => { @@ -54,8 +54,8 @@ describe('Scope (async_hooks)', () => { scope._destroy(0) expect(metrics.decrement).to.have.been.calledTwice - expect(metrics.decrement).to.have.been.calledWith('async.resources') - expect(metrics.decrement).to.have.been.calledWith('async.resources.by.type') + expect(metrics.decrement).to.have.been.calledWith('runtime.node.async.resources') + expect(metrics.decrement).to.have.been.calledWith('runtime.node.async.resources.by.type') }) it('should not break propagation for nested resources', done => {