Skip to content

Commit c465f4c

Browse files
feat: Core Tracing supportability metrics (#3610)
1 parent 4057e80 commit c465f4c

File tree

8 files changed

+320
-10
lines changed

8 files changed

+320
-10
lines changed

lib/metrics/names.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ const MEMORY = {
5555
USED_NONHEAP: 'Memory/NonHeap/Used'
5656
}
5757

58+
const CORE_TRACING = {
59+
PG: `${SUPPORTABILITY.NODEJS}/PartialGranularity`,
60+
FG: `${SUPPORTABILITY.NODEJS}/FullGranularity`,
61+
}
62+
5863
const CPU = {
5964
SYSTEM_TIME: 'CPU/System Time',
6065
SYSTEM_UTILIZATION: 'CPU/System/Utilization',
@@ -371,6 +376,7 @@ module.exports = {
371376
CASSANDRA,
372377
CLIENT_APPLICATION: 'ClientApplication',
373378
CONTROLLER: 'Controller',
379+
CORE_TRACING,
374380
CPU,
375381
CUSTOM: 'Custom',
376382
CUSTOM_EVENTS,

lib/samplers/index.js

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const AlwaysOnSampler = require('./always-on-sampler')
1111
const TraceIdRatioBasedSampler = require('./ratio-based-sampler')
1212
const logger = require('../logger').child({ component: 'samplers' })
1313
const { PARTIAL_TYPES } = require('../transaction')
14+
const { CORE_TRACING: { PG, FG } } = require('#agentlib/metrics/names.js')
1415

1516
/**
1617
* Manages the different samplers used for distributed tracing sampling decisions.
@@ -19,7 +20,8 @@ const { PARTIAL_TYPES } = require('../transaction')
1920
* @typedef {object} Samplers
2021
* @property {boolean} fullEnabled Whether full granularity sampling is enabled.
2122
* @property {boolean} partialEnabled Whether partial granularity sampling is enabled.
22-
* @property {AdaptiveSampler|null} adaptiveSampler The global adaptive sampler instance, this is shared if `sampling_target` is not defined for a sampler type of `adaptive`.
23+
* @property {AdaptiveSampler|null} adaptiveSampler The global adaptive sampler instance;
24+
* this is shared if `sampling_target` is not defined for a sampler type of `adaptive`.
2325
* @property {Sampler} root The root sampler for traces originating in application.
2426
* @property {Sampler} remoteParentSampled The sampler for traces with a remote parent that is sampled.
2527
* @property {Sampler} remoteParentNotSampled The sampler for traces with a remote parent that is not sampled.
@@ -39,6 +41,40 @@ class Samplers {
3941
this.partialRoot = this.determineSampler({ agent, sampler: 'root', isPartial: true })
4042
this.partialRemoteParentSampled = this.determineSampler({ agent, sampler: 'remote_parent_sampled', isPartial: true })
4143
this.partialRemoteParentNotSampled = this.determineSampler({ agent, sampler: 'remote_parent_not_sampled', isPartial: true })
44+
this.#sendCoreTracingMetrics(agent)
45+
}
46+
47+
/**
48+
* Sends relevant Core Tracing metrics on startup in the form:
49+
* `Supportability/Nodejs/<granularity type>/<sampler section>/<sampler type>`
50+
* @param {Agent} agent agent instance with these `Samplers`
51+
*/
52+
#sendCoreTracingMetrics(agent) {
53+
const metrics = agent.metrics
54+
if (this.partialEnabled) {
55+
// Supportability/Nodejs/PartialGranularity/<sampler section>/<sampler type>
56+
metrics.getOrCreateMetric(`${PG}/Root/${this.#determineSamplerType(this.partialRoot)}`)
57+
metrics.getOrCreateMetric(`${PG}/RemoteParentSampled/${this.#determineSamplerType(this.partialRemoteParentSampled)}`)
58+
metrics.getOrCreateMetric(`${PG}/RemoteParentNotSampled/${this.#determineSamplerType(this.partialRemoteParentNotSampled)}`)
59+
}
60+
if (this.fullEnabled) {
61+
// Supportability/Nodejs/PartialGranularity/<sampler section>/<sampler type>
62+
metrics.getOrCreateMetric(`${FG}/Root/${this.#determineSamplerType(this.root)}`)
63+
metrics.getOrCreateMetric(`${FG}/RemoteParentSampled/${this.#determineSamplerType(this.remoteParentSampled)}`)
64+
metrics.getOrCreateMetric(`${FG}/RemoteParentNotSampled/${this.#determineSamplerType(this.remoteParentNotSampled)}`)
65+
}
66+
}
67+
68+
/**
69+
*
70+
* @param {Sampler} sampler an instance of a Sampler
71+
* @returns {string} 'Adaptive/Shared', 'Adaptive', 'AlwaysOn', 'AlwaysOff', or 'TraceIdRatioBased'
72+
*/
73+
#determineSamplerType(sampler) {
74+
if (sampler === this.adaptiveSampler) {
75+
return 'Adaptive/Shared'
76+
}
77+
return sampler.toString().replace('Sampler', '')
4278
}
4379

4480
/**

test/integration/agent/serverless-harvest.test.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ test('sending metrics', async (t) => {
122122
'metric_data',
123123
function checkData(payload) {
124124
plan.ok(payload, 'should have a payload')
125-
plan.deepStrictEqual(payload[3][0][0], { name: 'TEST/discard' }, 'should have test metric')
125+
// First 3 are FullGranularity supportability metrics
126+
plan.deepStrictEqual(payload[3][3][0], { name: 'TEST/discard' }, 'should have test metric')
126127
}
127128
)
128129

test/integration/module-loading/module-loading.test.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ test('Should create usage metric onRequire for built-in', (t) => {
133133
assert.ok(onRequireMetric)
134134
assert.equal(onRequireMetric.callCount, 1)
135135
const domainMetrics = Object.keys(agent.metrics._metrics.unscoped)
136-
assert.equal(domainMetrics.length, 1, 'should not log a version metric for a built-in')
136+
// 3 of these are FullGranularity supportability metrics
137+
assert.equal(domainMetrics.length, 4, 'should not log a version metric for a built-in')
137138
})
138139

139140
test('should instrument a local package', (t, end) => {

test/integration/utilization/common.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ const JSONbig = require('json-bigint')({ useNativeBigInt: true })
1111
const path = require('path')
1212

1313
function checkMetrics(agent, expectedMetrics) {
14+
const metrics = agent.metrics
1415
if (!expectedMetrics) {
15-
assert.equal(agent.metrics._metrics.toJSON().length, 0, 'should not have any metrics')
16+
// 3 FullGranularity supportability metrics will always exist
17+
assert.equal(metrics._metrics.toJSON().length, 3, 'should not have any additional metrics')
1618
return
1719
}
1820

1921
Object.keys(expectedMetrics).forEach(function (expectedMetric) {
20-
const metric = agent.metrics.getOrCreateMetric(expectedMetric)
22+
const metric = metrics.getOrCreateMetric(expectedMetric)
2123
assert.equal(
2224
metric.callCount,
2325
expectedMetrics[expectedMetric].call_count,

0 commit comments

Comments
 (0)