Skip to content

Commit

Permalink
chore: Simplify the labels and prefix usage
Browse files Browse the repository at this point in the history
  • Loading branch information
marcbachmann committed Dec 25, 2020
1 parent 3efd636 commit b354ecc
Show file tree
Hide file tree
Showing 16 changed files with 77 additions and 117 deletions.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
# opentelemetry-node-metrics

This module is an adoption of the metric set of [`prom-client`](https://www.npmjs.com/package/prom-client) for [`@opentelemetry/metrics`](https://www.npmjs.com/package/@opentelemetry/metrics).

```
There's no node cluster support as `@opentelemetry/metrics` doesn't support it.

### Usage

```js
const {MeterProvider} = require('@opentelemetry/metrics');
const {PrometheusExporter} = require('@opentelemetry/exporter-prometheus');

Expand All @@ -16,7 +21,7 @@ const meterProvider = new MeterProvider({
interval: 2000,
})

require('./index')({meterProvider})
require('./index')(meterProvider)
```


Expand Down
4 changes: 4 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
module.exports = function setupNodeMetrics (meterProvider, config) {
config = config || {}
config.prefix = config.prefix ? config.prefix : ''
config.labels = config.labels ? config.labels : {}

const meter = meterProvider.getMeter('opentelemetry-node-metrics')
require('./metrics/eventLoopLag')(meter, config)
require('./metrics/gc')(meter, config)
Expand Down
26 changes: 11 additions & 15 deletions metrics/eventLoopLag.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,41 +13,37 @@ const NODEJS_EVENTLOOP_LAG_P50 = 'nodejs_eventloop_lag_p50_seconds'
const NODEJS_EVENTLOOP_LAG_P90 = 'nodejs_eventloop_lag_p90_seconds'
const NODEJS_EVENTLOOP_LAG_P99 = 'nodejs_eventloop_lag_p99_seconds'

module.exports = (meter, config = {}) => {
const namePrefix = config.prefix ? config.prefix : ''
const labels = config.labels ? config.labels : {}

module.exports = (meter, {prefix, labels, eventLoopMonitoringPrecision}) => {
const histogram = perfHooks.monitorEventLoopDelay({
resolution: config.eventLoopMonitoringPrecision
resolution: eventLoopMonitoringPrecision
})

histogram.enable()

const lagMin = meter.createValueObserver(namePrefix + NODEJS_EVENTLOOP_LAG_MIN, {
const lagMin = meter.createValueObserver(prefix + NODEJS_EVENTLOOP_LAG_MIN, {
description: 'The minimum recorded event loop delay.'
})
const lagMax = meter.createValueObserver(namePrefix + NODEJS_EVENTLOOP_LAG_MAX, {
const lagMax = meter.createValueObserver(prefix + NODEJS_EVENTLOOP_LAG_MAX, {
description: 'The maximum recorded event loop delay.'
})
const lagMean = meter.createValueObserver(namePrefix + NODEJS_EVENTLOOP_LAG_MEAN, {
const lagMean = meter.createValueObserver(prefix + NODEJS_EVENTLOOP_LAG_MEAN, {
description: 'The mean of the recorded event loop delays.'
})
const lagStddev = meter.createValueObserver(namePrefix + NODEJS_EVENTLOOP_LAG_STDDEV, {
const lagStddev = meter.createValueObserver(prefix + NODEJS_EVENTLOOP_LAG_STDDEV, {
description: 'The standard deviation of the recorded event loop delays.'
})
const lagP50 = meter.createValueObserver(namePrefix + NODEJS_EVENTLOOP_LAG_P50, {
const lagP50 = meter.createValueObserver(prefix + NODEJS_EVENTLOOP_LAG_P50, {
description: 'The 50th percentile of the recorded event loop delays.'
})
const lagP90 = meter.createValueObserver(namePrefix + NODEJS_EVENTLOOP_LAG_P90, {
const lagP90 = meter.createValueObserver(prefix + NODEJS_EVENTLOOP_LAG_P90, {
description: 'The 90th percentile of the recorded event loop delays.'
})
const lagP99 = meter.createValueObserver(namePrefix + NODEJS_EVENTLOOP_LAG_P99, {
const lagP99 = meter.createValueObserver(prefix + NODEJS_EVENTLOOP_LAG_P99, {
description: 'The 99th percentile of the recorded event loop delays.'
})

const lag = meter.createValueObserver(namePrefix + NODEJS_EVENTLOOP_LAG, {
const lag = meter.createValueObserver(prefix + NODEJS_EVENTLOOP_LAG, {
description: 'Lag of event loop in seconds.'
// TODO Fix that behavior
// aggregator: 'average',
})

function reportEventloopLag (start, observerBatchResult) {
Expand Down
16 changes: 6 additions & 10 deletions metrics/gc.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,19 @@ kinds[perfHooks.constants.NODE_PERFORMANCE_GC_MINOR] = 'minor'
kinds[perfHooks.constants.NODE_PERFORMANCE_GC_INCREMENTAL] = 'incremental'
kinds[perfHooks.constants.NODE_PERFORMANCE_GC_WEAKCB] = 'weakcb'

module.exports = (meter, config = {}) => {
const namePrefix = config.prefix ? config.prefix : ''
const labels = config.labels ? config.labels : {}
const buckets = config.gcDurationBuckets
? config.gcDurationBuckets
: DEFAULT_GC_DURATION_BUCKETS

const gcHistogram = meter.createValueRecorder(namePrefix + NODEJS_GC_DURATION_SECONDS, {
module.exports = (meter, {prefix, labels, gcDurationBuckets}) => {
const boundaries = gcDurationBuckets || DEFAULT_GC_DURATION_BUCKETS

const gcHistogram = meter.createValueRecorder(prefix + NODEJS_GC_DURATION_SECONDS, {
description: 'Garbage collection duration by kind, one of major, minor, incremental or weakcb.',
boundaries: buckets
boundaries
})

const obs = new perfHooks.PerformanceObserver(list => {
const entry = list.getEntries()[0]

gcHistogram
.bind({kind: kinds[entry.kind], ...labels})
.bind({...labels, kind: kinds[entry.kind]})
// Convert duration from milliseconds to seconds
.record(entry.duration / 1000)
})
Expand Down
11 changes: 4 additions & 7 deletions metrics/heapSizeAndUsed.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,16 @@ const NODEJS_HEAP_SIZE_TOTAL = 'nodejs_heap_size_total_bytes'
const NODEJS_HEAP_SIZE_USED = 'nodejs_heap_size_used_bytes'
const NODEJS_EXTERNAL_MEMORY = 'nodejs_external_memory_bytes'

module.exports = (meter, config = {}) => {
const labels = config.labels ? config.labels : {}
const namePrefix = config.prefix ? config.prefix : ''

const heapSizeTotal = meter.createValueObserver(namePrefix + NODEJS_HEAP_SIZE_TOTAL, {
module.exports = (meter, {labels, prefix}) => {
const heapSizeTotal = meter.createValueObserver(prefix + NODEJS_HEAP_SIZE_TOTAL, {
description: 'Process heap size from Node.js in bytes.'
})

const heapSizeUsed = meter.createValueObserver(namePrefix + NODEJS_HEAP_SIZE_USED, {
const heapSizeUsed = meter.createValueObserver(prefix + NODEJS_HEAP_SIZE_USED, {
description: 'Process heap size used from Node.js in bytes.'
})

const externalMemUsed = meter.createValueObserver(namePrefix + NODEJS_EXTERNAL_MEMORY, {
const externalMemUsed = meter.createValueObserver(prefix + NODEJS_EXTERNAL_MEMORY, {
description: 'Node.js external memory size in bytes.'
})

Expand Down
7 changes: 2 additions & 5 deletions metrics/heapSpacesSizeAndUsed.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,10 @@ for (const metricType of METRICS) {
NODEJS_HEAP_SIZE[metricType] = `nodejs_heap_space_size_${metricType}_bytes`
}

module.exports = (meter, config = {}) => {
const namePrefix = config.prefix ? config.prefix : ''
const labels = config.labels ? config.labels : {}
module.exports = (meter, {prefix, labels}) => {
const gauges = {}

for (const metricType of METRICS) {
gauges[metricType] = meter.createValueObserver(namePrefix + NODEJS_HEAP_SIZE[metricType], {
gauges[metricType] = meter.createValueObserver(prefix + NODEJS_HEAP_SIZE[metricType], {
description: `Process heap space size ${metricType} from Node.js in bytes.`
})
}
Expand Down
26 changes: 12 additions & 14 deletions metrics/helpers/processMetricsHelpers.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
function aggregateByObjectName (list) {
const data = {}
function createAggregatorByObjectName () {
const all = new Map()
return function aggregateByObjectName (list) {
const current = new Map()

for (let i = 0; i < list.length; i++) {
const listElement = list[i]

if (!listElement || typeof listElement.constructor === 'undefined') {
continue
for (let i = 0; i < list.length; i++) {
const listElementConstructor = list[i] && list[i].constructor
if (typeof listElementConstructor === 'undefined') continue
current.set(listElementConstructor.name, (current.get(listElementConstructor.name) || 0) + 1)
}

if (Object.hasOwnProperty.call(data, listElement.constructor.name)) {
data[listElement.constructor.name] += 1
} else {
data[listElement.constructor.name] = 1
}
for (const key of all.keys()) all.set(key, 0)
for (const [key, value] of current) all.set(key, value)
return current
}
return data
}

module.exports = {
aggregateByObjectName
createAggregatorByObjectName
}
7 changes: 2 additions & 5 deletions metrics/osMemoryHeap.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@ const linuxVariant = require('./osMemoryHeapLinux')
const safeMemoryUsage = require('./helpers/safeMemoryUsage')
const PROCESS_RESIDENT_MEMORY = 'process_resident_memory_bytes'

function notLinuxVariant (meter, config = {}) {
const namePrefix = config.prefix ? config.prefix : ''
const labels = config.labels ? config.labels : {}

meter.createValueObserver(namePrefix + PROCESS_RESIDENT_MEMORY, {
function notLinuxVariant (meter, {prefix, labels}) {
meter.createValueObserver(prefix + PROCESS_RESIDENT_MEMORY, {
description: 'Resident memory size in bytes.'
}, (observerResult) => {
const memUsage = safeMemoryUsage()
Expand Down
11 changes: 4 additions & 7 deletions metrics/osMemoryHeapLinux.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,16 @@ function structureOutput (input) {
return returnValue
}

module.exports = (meter, config = {}) => {
const namePrefix = config.prefix ? config.prefix : ''
const labels = config.labels ? config.labels : {}

const residentMemGauge = meter.createValueObserver(namePrefix + PROCESS_RESIDENT_MEMORY, {
module.exports = (meter, {prefix, labels}) => {
const residentMemGauge = meter.createValueObserver(prefix + PROCESS_RESIDENT_MEMORY, {
description: 'Resident memory size in bytes.'
})

const virtualMemGauge = meter.createValueObserver(namePrefix + PROCESS_VIRTUAL_MEMORY, {
const virtualMemGauge = meter.createValueObserver(prefix + PROCESS_VIRTUAL_MEMORY, {
description: 'Virtual memory size in bytes.'
})

const heapSizeMemGauge = meter.createValueObserver(namePrefix + PROCESS_HEAP, {
const heapSizeMemGauge = meter.createValueObserver(prefix + PROCESS_HEAP, {
description: 'Process heap size in bytes.'
})

Expand Down
11 changes: 4 additions & 7 deletions metrics/processCpuTotal.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,18 @@ const PROCESS_CPU_USER_SECONDS = 'process_cpu_user_seconds_total'
const PROCESS_CPU_SYSTEM_SECONDS = 'process_cpu_system_seconds_total'
const PROCESS_CPU_SECONDS = 'process_cpu_seconds_total'

module.exports = (meter, config = {}) => {
const namePrefix = config.prefix ? config.prefix : ''
const labels = config.labels ? config.labels : {}

module.exports = (meter, {prefix, labels}) => {
let lastCpuUsage = process.cpuUsage()

const cpuUserUsageCounter = meter.createCounter(namePrefix + PROCESS_CPU_USER_SECONDS, {
const cpuUserUsageCounter = meter.createCounter(prefix + PROCESS_CPU_USER_SECONDS, {
description: 'Total user CPU time spent in seconds.'
}).bind(labels)

const cpuSystemUsageCounter = meter.createCounter(namePrefix + PROCESS_CPU_SYSTEM_SECONDS, {
const cpuSystemUsageCounter = meter.createCounter(prefix + PROCESS_CPU_SYSTEM_SECONDS, {
description: 'Total system CPU time spent in seconds.'
}).bind(labels)

const cpuUsageCounter = meter.createCounter(namePrefix + PROCESS_CPU_SECONDS, {
const cpuUsageCounter = meter.createCounter(prefix + PROCESS_CPU_SECONDS, {
description: 'Total user and system CPU time spent in seconds.'
}).bind(labels)

Expand Down
9 changes: 3 additions & 6 deletions metrics/processHandles.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,11 @@ const {aggregateByObjectName} = require('./helpers/processMetricsHelpers')
const NODEJS_ACTIVE_HANDLES = 'nodejs_active_handles'
const NODEJS_ACTIVE_HANDLES_TOTAL = 'nodejs_active_handles_total'

module.exports = (meter, config = {}) => {
module.exports = (meter, {prefix, labels}) => {
// Don't do anything if the function is removed in later nodes (exists in node@6-12...)
if (typeof process._getActiveHandles !== 'function') return

const namePrefix = config.prefix ? config.prefix : ''
const labels = config.labels ? config.labels : {}

meter.createValueObserver(namePrefix + NODEJS_ACTIVE_HANDLES, {
meter.createValueObserver(prefix + NODEJS_ACTIVE_HANDLES, {
description: 'Number of active libuv handles grouped by handle type. Every handle type is C++ class name.' // eslint-disable-line max-len
}, (observerResult) => {
// TODO do we need to reset labels?
Expand All @@ -19,7 +16,7 @@ module.exports = (meter, config = {}) => {
for (const key in data) observerResult.observe(data[key], {...labels, type: key})
})

meter.createValueObserver(namePrefix + NODEJS_ACTIVE_HANDLES_TOTAL, {
meter.createValueObserver(prefix + NODEJS_ACTIVE_HANDLES_TOTAL, {
description: 'Total number of active handles.'
}, (observerResult) => {
const handles = process._getActiveHandles()
Expand Down
10 changes: 3 additions & 7 deletions metrics/processMaxFileDescriptors.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const fs = require('fs')
const PROCESS_MAX_FDS = 'process_max_fds'
let maxFds

module.exports = (meter, config = {}) => {
module.exports = (meter, {prefix, labels}) => {
if (maxFds === undefined) {
// This will fail if a linux-like procfs is not available.
try {
Expand All @@ -21,14 +21,10 @@ module.exports = (meter, config = {}) => {
}

if (maxFds === undefined) return
const namePrefix = config.prefix ? config.prefix : ''
const labels = config.labels ? config.labels : {}

meter.createValueObserver(namePrefix + PROCESS_MAX_FDS, {
meter.createUpDownCounter(prefix + PROCESS_MAX_FDS, {
description: 'Maximum number of open file descriptors.'
}, (observerResult) => {
observerResult.observe(maxFds, labels)
})
}).bind(labels).add(maxFds)
}

module.exports.metricNames = [PROCESS_MAX_FDS]
6 changes: 2 additions & 4 deletions metrics/processOpenFileDescriptors.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ const fs = require('fs')
const process = require('process')
const PROCESS_OPEN_FDS = 'process_open_fds'

module.exports = (meter, config = {}) => {
module.exports = (meter, {prefix, labels}) => {
if (process.platform !== 'linux') return
const namePrefix = config.prefix ? config.prefix : ''
const labels = config.labels ? config.labels : {}

meter.createValueObserver(namePrefix + PROCESS_OPEN_FDS, {
meter.createValueObserver(prefix + PROCESS_OPEN_FDS, {
description: 'Number of open file descriptors.'
}, (observerResult) => {
try {
Expand Down
12 changes: 4 additions & 8 deletions metrics/processRequests.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,11 @@ const {aggregateByObjectName} = require('./helpers/processMetricsHelpers')
const NODEJS_ACTIVE_REQUESTS = 'nodejs_active_requests'
const NODEJS_ACTIVE_REQUESTS_TOTAL = 'nodejs_active_requests_total'

module.exports = (meter, config = {}) => {
module.exports = (meter, {prefix, labels}) => {
// Don't do anything if the function is removed in later nodes (exists in node@6)
if (typeof process._getActiveRequests !== 'function') return

const namePrefix = config.prefix ? config.prefix : ''
const labels = config.labels ? config.labels : {}

meter.createValueObserver(namePrefix + NODEJS_ACTIVE_REQUESTS, {
meter.createValueObserver(prefix + NODEJS_ACTIVE_REQUESTS, {
description: 'Number of active libuv requests grouped by request type. Every request type is C++ class name.' // eslint-disable-line max-len
}, (observerResult) => {
const requests = process._getActiveRequests()
Expand All @@ -22,11 +19,10 @@ module.exports = (meter, config = {}) => {
}
})

meter.createValueObserver(namePrefix + NODEJS_ACTIVE_REQUESTS_TOTAL, {
meter.createValueObserver(prefix + NODEJS_ACTIVE_REQUESTS_TOTAL, {
description: 'Total number of active requests.'
}, (observerResult) => {
const requests = process._getActiveRequests()
observerResult.observe(requests.length, labels)
observerResult.observe(process._getActiveRequests().length, labels)
})
}

Expand Down
11 changes: 3 additions & 8 deletions metrics/processStartTime.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
const startInSeconds = Math.round((Date.now() / 1000) - process.uptime())
const PROCESS_START_TIME = 'process_start_time_seconds'

module.exports = (meter, config = {}) => {
const namePrefix = config.prefix ? config.prefix : ''
const labels = config.labels ? config.labels : {}

meter.createValueObserver(namePrefix + PROCESS_START_TIME, {
module.exports = (meter, {prefix, labels}) => {
meter.createUpDownCounter(prefix + PROCESS_START_TIME, {
description: 'Start time of the process since unix epoch in seconds.'
}, (observerResult) => {
observerResult.observe(startInSeconds, labels)
})
}).bind(labels).add(startInSeconds)
}

module.exports.metricNames = [PROCESS_START_TIME]
Loading

0 comments on commit b354ecc

Please sign in to comment.