Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 0 additions & 16 deletions packages/instrumentation-runtime-node/src/consts/attributes.ts

This file was deleted.

17 changes: 5 additions & 12 deletions packages/instrumentation-runtime-node/src/instrumentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import { EventLoopUtilizationCollector } from './metrics/eventLoopUtilizationCol
import { EventLoopDelayCollector } from './metrics/eventLoopDelayCollector';
import { GCCollector } from './metrics/gcCollector';
import { HeapSpacesSizeAndUsedCollector } from './metrics/heapSpacesSizeAndUsedCollector';
import { ConventionalNamePrefix } from './types/ConventionalNamePrefix';
import { EventLoopTimeCollector } from './metrics/eventLoopTimeCollector';
/** @knipignore */
import { PACKAGE_VERSION, PACKAGE_NAME } from './version';
Expand All @@ -40,17 +39,11 @@ export class RuntimeNodeInstrumentation extends InstrumentationBase<RuntimeNodeI
Object.assign({}, DEFAULT_CONFIG, config)
);
this._collectors = [
new EventLoopUtilizationCollector(
this._config,
ConventionalNamePrefix.NodeJs
),
new EventLoopTimeCollector(this._config, ConventionalNamePrefix.NodeJs),
new EventLoopDelayCollector(this._config, ConventionalNamePrefix.NodeJs),
new GCCollector(this._config, ConventionalNamePrefix.V8js),
new HeapSpacesSizeAndUsedCollector(
this._config,
ConventionalNamePrefix.V8js
),
new EventLoopUtilizationCollector(this._config),
new EventLoopTimeCollector(this._config),
new EventLoopDelayCollector(this._config),
new GCCollector(this._config),
new HeapSpacesSizeAndUsedCollector(this._config),
];
if (this._config.enabled) {
for (const collector of this._collectors) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,8 @@ import { RuntimeNodeInstrumentationConfig } from '../types';
export abstract class BaseCollector implements MetricCollector {
protected _config: RuntimeNodeInstrumentationConfig = {};

protected namePrefix: string;

protected constructor(
config: RuntimeNodeInstrumentationConfig = {},
namePrefix: string
) {
constructor(config: RuntimeNodeInstrumentationConfig = {}) {
this._config = config;
this.namePrefix = namePrefix;
}

public disable(): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,48 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { RuntimeNodeInstrumentationConfig } from '../types';
import { Meter } from '@opentelemetry/api';
import * as perf_hooks from 'node:perf_hooks';
import { IntervalHistogram } from 'node:perf_hooks';
import { BaseCollector } from './baseCollector';

enum NodeJsEventLoopDelayAttributes {
min = 'eventloop.delay.min',
max = 'eventloop.delay.max',
mean = 'eventloop.delay.mean',
stddev = 'eventloop.delay.stddev',
p50 = 'eventloop.delay.p50',
p90 = 'eventloop.delay.p90',
p99 = 'eventloop.delay.p99',
}
import {
METRIC_NODEJS_EVENTLOOP_DELAY_MAX,
METRIC_NODEJS_EVENTLOOP_DELAY_MEAN,
METRIC_NODEJS_EVENTLOOP_DELAY_MIN,
METRIC_NODEJS_EVENTLOOP_DELAY_P50,
METRIC_NODEJS_EVENTLOOP_DELAY_P90,
METRIC_NODEJS_EVENTLOOP_DELAY_P99,
METRIC_NODEJS_EVENTLOOP_DELAY_STDDEV,
} from '../semconv';

export const metricNames: Record<
NodeJsEventLoopDelayAttributes,
{ description: string }
> = {
[NodeJsEventLoopDelayAttributes.min]: {
description: 'Event loop minimum delay.',
},
[NodeJsEventLoopDelayAttributes.max]: {
description: 'Event loop maximum delay.',
},
[NodeJsEventLoopDelayAttributes.mean]: {
description: 'Event loop mean delay.',
},
[NodeJsEventLoopDelayAttributes.stddev]: {
description: 'Event loop standard deviation delay.',
},
[NodeJsEventLoopDelayAttributes.p50]: {
description: 'Event loop 50 percentile delay.',
},
[NodeJsEventLoopDelayAttributes.p90]: {
description: 'Event loop 90 percentile delay.',
},
[NodeJsEventLoopDelayAttributes.p99]: {
description: 'Event loop 99 percentile delay.',
},
};
import type { RuntimeNodeInstrumentationConfig } from '../types';
import { BaseCollector } from './baseCollector';

export interface EventLoopLagInformation {
min: number;
Expand All @@ -69,70 +42,60 @@ export interface EventLoopLagInformation {
export class EventLoopDelayCollector extends BaseCollector {
private _histogram: IntervalHistogram;

constructor(
config: RuntimeNodeInstrumentationConfig = {},
namePrefix: string
) {
super(config, namePrefix);
constructor(config: RuntimeNodeInstrumentationConfig = {}) {
super(config);
this._histogram = perf_hooks.monitorEventLoopDelay({
resolution: config.monitoringPrecision,
});
}

updateMetricInstruments(meter: Meter): void {
const delayMin = meter.createObservableGauge(
`${this.namePrefix}.${NodeJsEventLoopDelayAttributes.min}`,
METRIC_NODEJS_EVENTLOOP_DELAY_MIN,
{
description:
metricNames[NodeJsEventLoopDelayAttributes.min].description,
description: 'Event loop minimum delay.',
unit: 's',
}
);
const delayMax = meter.createObservableGauge(
`${this.namePrefix}.${NodeJsEventLoopDelayAttributes.max}`,
METRIC_NODEJS_EVENTLOOP_DELAY_MAX,
{
description:
metricNames[NodeJsEventLoopDelayAttributes.max].description,
description: 'Event loop maximum delay.',
unit: 's',
}
);
const delayMean = meter.createObservableGauge(
`${this.namePrefix}.${NodeJsEventLoopDelayAttributes.mean}`,
METRIC_NODEJS_EVENTLOOP_DELAY_MEAN,
{
description:
metricNames[NodeJsEventLoopDelayAttributes.mean].description,
description: 'Event loop mean delay.',
unit: 's',
}
);
const delayStddev = meter.createObservableGauge(
`${this.namePrefix}.${NodeJsEventLoopDelayAttributes.stddev}`,
METRIC_NODEJS_EVENTLOOP_DELAY_STDDEV,
{
description:
metricNames[NodeJsEventLoopDelayAttributes.stddev].description,
description: 'Event loop standard deviation delay.',
unit: 's',
}
);
const delayp50 = meter.createObservableGauge(
`${this.namePrefix}.${NodeJsEventLoopDelayAttributes.p50}`,
METRIC_NODEJS_EVENTLOOP_DELAY_P50,
{
description:
metricNames[NodeJsEventLoopDelayAttributes.p50].description,
description: 'Event loop 50 percentile delay.',
unit: 's',
}
);
const delayp90 = meter.createObservableGauge(
`${this.namePrefix}.${NodeJsEventLoopDelayAttributes.p90}`,
METRIC_NODEJS_EVENTLOOP_DELAY_P90,
{
description:
metricNames[NodeJsEventLoopDelayAttributes.p90].description,
description: 'Event loop 90 percentile delay.',
unit: 's',
}
);
const delayp99 = meter.createObservableGauge(
`${this.namePrefix}.${NodeJsEventLoopDelayAttributes.p99}`,
METRIC_NODEJS_EVENTLOOP_DELAY_P99,
{
description:
metricNames[NodeJsEventLoopDelayAttributes.p99].description,
description: 'Event loop 99 percentile delay.',
unit: 's',
}
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { EventLoopUtilization, performance } from 'node:perf_hooks';
import { RuntimeNodeInstrumentationConfig } from '../types';
import { Meter } from '@opentelemetry/api';
import { BaseCollector } from './baseCollector';
import {
METRIC_NODEJS_EVENTLOOP_TIME,
ATTR_NODEJS_EVENTLOOP_STATE,
NODEJS_EVENTLOOP_STATE_VALUE_ACTIVE,
NODEJS_EVENTLOOP_STATE_VALUE_IDLE,
} from '../semconv';

const { eventLoopUtilization: eventLoopUtilizationCollector } = performance;

export const ATTR_NODEJS_EVENT_LOOP_TIME = 'eventloop.time';

export class EventLoopTimeCollector extends BaseCollector {
constructor(
config: RuntimeNodeInstrumentationConfig = {},
namePrefix: string
) {
super(config, namePrefix);
}

public updateMetricInstruments(meter: Meter): void {
const timeCounter = meter.createObservableCounter(
`${this.namePrefix}.${ATTR_NODEJS_EVENT_LOOP_TIME}`,
METRIC_NODEJS_EVENTLOOP_TIME,
{
description:
'Cumulative duration of time the event loop has been in each state.',
Expand All @@ -48,10 +45,10 @@ export class EventLoopTimeCollector extends BaseCollector {
if (data === undefined) return;

observableResult.observe(timeCounter, data.active / 1000, {
[`${this.namePrefix}.eventloop.state`]: 'active',
[ATTR_NODEJS_EVENTLOOP_STATE]: NODEJS_EVENTLOOP_STATE_VALUE_ACTIVE,
});
observableResult.observe(timeCounter, data.idle / 1000, {
[`${this.namePrefix}.eventloop.state`]: 'idle',
[ATTR_NODEJS_EVENTLOOP_STATE]: NODEJS_EVENTLOOP_STATE_VALUE_IDLE,
});
},
[timeCounter]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { EventLoopUtilization, performance } from 'node:perf_hooks';
import { RuntimeNodeInstrumentationConfig } from '../types';
import { Meter } from '@opentelemetry/api';
import { BaseCollector } from './baseCollector';
import { METRIC_NODEJS_EVENTLOOP_UTILIZATION } from '../semconv';

const { eventLoopUtilization: eventLoopUtilizationCollector } = performance;

export const ATTR_NODEJS_EVENT_LOOP_UTILIZATION = 'eventloop.utilization';

export class EventLoopUtilizationCollector extends BaseCollector {
private _lastValue?: EventLoopUtilization;

constructor(
config: RuntimeNodeInstrumentationConfig = {},
namePrefix: string
) {
super(config, namePrefix);
}

public updateMetricInstruments(meter: Meter): void {
meter
.createObservableGauge(
`${this.namePrefix}.${ATTR_NODEJS_EVENT_LOOP_UTILIZATION}`,
{
description: 'Event loop utilization',
unit: '1',
}
)
.createObservableGauge(METRIC_NODEJS_EVENTLOOP_UTILIZATION, {
description: 'Event loop utilization',
unit: '1',
})
.addCallback(async observableResult => {
if (!this._config.enabled) return;

Expand Down
25 changes: 11 additions & 14 deletions packages/instrumentation-runtime-node/src/metrics/gcCollector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { RuntimeNodeInstrumentationConfig } from '../types';

import * as perf_hooks from 'node:perf_hooks';
import { PerformanceObserver } from 'node:perf_hooks';
import { Meter } from '@opentelemetry/api';
import { RuntimeNodeInstrumentationConfig } from '../types';
import { Histogram, ValueType } from '@opentelemetry/api';
import { BaseCollector } from './baseCollector';
import * as perf_hooks from 'node:perf_hooks';
import { PerformanceObserver } from 'node:perf_hooks';
import { ATTR_V8JS_GC_TYPE, METRIC_V8JS_GC_DURATION } from '../semconv';

const ATTR_NODEJS_GC_DURATION_SECONDS = 'gc.duration';
const DEFAULT_GC_DURATION_BUCKETS = [0.01, 0.1, 1, 10];

const kinds: string[] = [];
Expand All @@ -33,11 +34,8 @@ export class GCCollector extends BaseCollector {
private _gcDurationByKindHistogram?: Histogram;
private _observer: PerformanceObserver;

constructor(
config: RuntimeNodeInstrumentationConfig = {},
namePrefix: string
) {
super(config, namePrefix);
constructor(config: RuntimeNodeInstrumentationConfig = {}) {
super(config);
this._observer = new perf_hooks.PerformanceObserver(list => {
if (!this._config.enabled) return;

Expand All @@ -48,16 +46,15 @@ export class GCCollector extends BaseCollector {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const kind = entry.detail ? kinds[entry.detail.kind] : kinds[entry.kind];
this._gcDurationByKindHistogram?.record(
entry.duration / 1000,
Object.assign({ [`${this.namePrefix}.gc.type`]: kind })
);
this._gcDurationByKindHistogram?.record(entry.duration / 1000, {
[ATTR_V8JS_GC_TYPE]: kind,
});
});
}

updateMetricInstruments(meter: Meter): void {
this._gcDurationByKindHistogram = meter.createHistogram(
`${this.namePrefix}.${ATTR_NODEJS_GC_DURATION_SECONDS}`,
METRIC_V8JS_GC_DURATION,
{
description:
'Garbage collection duration by kind, one of major, minor, incremental or weakcb.',
Expand Down
Loading
Loading