Skip to content

Commit

Permalink
fix: "host-metrics" should collect system (os) cpu metrics to comply … (
Browse files Browse the repository at this point in the history
open-telemetry#438)

Co-authored-by: Valentin Marchaud <[email protected]>
  • Loading branch information
svrnm and vmarchaud authored Apr 23, 2021
1 parent ee7c40d commit 6644e74
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 68 deletions.
2 changes: 2 additions & 0 deletions packages/opentelemetry-host-metrics/src/enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ export enum CPU_LABELS {
USER = 'user',
SYSTEM = 'system',
IDLE = 'idle',
INTERRUPT = 'interrupt',
NICE = 'nice',
}

export enum NETWORK_LABELS {
Expand Down
116 changes: 78 additions & 38 deletions packages/opentelemetry-host-metrics/src/metric.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,50 +36,90 @@ export class HostMetrics extends BaseMetrics {

private _updateCpuTime(
observerBatchResult: api.BatchObserverResult,
cpuUsage: CpuUsageData
cpuUsages: CpuUsageData[]
): void {
observerBatchResult.observe(
{
state: enums.CPU_LABELS.USER,
},
[this._cpuTimeObserver?.observation(cpuUsage.user)]
);
observerBatchResult.observe(
{
state: enums.CPU_LABELS.SYSTEM,
},
[this._cpuTimeObserver?.observation(cpuUsage.system)]
);
observerBatchResult.observe(
{
state: enums.CPU_LABELS.IDLE,
},
[this._cpuTimeObserver?.observation(cpuUsage.idle)]
);
for (let i = 0, j = cpuUsages.length; i < j; i++) {
const cpuUsage = cpuUsages[i];
observerBatchResult.observe(
{
state: enums.CPU_LABELS.USER,
cpu: cpuUsage.cpuNumber,
},
[this._cpuTimeObserver?.observation(cpuUsage.user)]
);
observerBatchResult.observe(
{
state: enums.CPU_LABELS.SYSTEM,
cpu: cpuUsage.cpuNumber,
},
[this._cpuTimeObserver?.observation(cpuUsage.system)]
);
observerBatchResult.observe(
{
state: enums.CPU_LABELS.IDLE,
cpu: cpuUsage.cpuNumber,
},
[this._cpuTimeObserver?.observation(cpuUsage.idle)]
);
observerBatchResult.observe(
{
state: enums.CPU_LABELS.INTERRUPT,
cpu: cpuUsage.cpuNumber,
},
[this._cpuTimeObserver?.observation(cpuUsage.interrupt)]
);
observerBatchResult.observe(
{
state: enums.CPU_LABELS.NICE,
cpu: cpuUsage.cpuNumber,
},
[this._cpuTimeObserver?.observation(cpuUsage.nice)]
);
}
}

private _updateCpuUtilisation(
observerBatchResult: api.BatchObserverResult,
cpuUsage: CpuUsageData
cpuUsages: CpuUsageData[]
): void {
observerBatchResult.observe(
{
state: enums.CPU_LABELS.USER,
},
[this._cpuUtilizationObserver?.observation(cpuUsage.userP)]
);
observerBatchResult.observe(
{
state: enums.CPU_LABELS.SYSTEM,
},
[this._cpuUtilizationObserver?.observation(cpuUsage.systemP)]
);
observerBatchResult.observe(
{
state: enums.CPU_LABELS.IDLE,
},
[this._cpuUtilizationObserver?.observation(cpuUsage.idleP)]
);
for (let i = 0, j = cpuUsages.length; i < j; i++) {
const cpuUsage = cpuUsages[i];
observerBatchResult.observe(
{
state: enums.CPU_LABELS.USER,
cpu: cpuUsage.cpuNumber,
},
[this._cpuUtilizationObserver?.observation(cpuUsage.userP)]
);
observerBatchResult.observe(
{
state: enums.CPU_LABELS.SYSTEM,
cpu: cpuUsage.cpuNumber,
},
[this._cpuUtilizationObserver?.observation(cpuUsage.systemP)]
);
observerBatchResult.observe(
{
state: enums.CPU_LABELS.IDLE,
cpu: cpuUsage.cpuNumber,
},
[this._cpuUtilizationObserver?.observation(cpuUsage.idleP)]
);
observerBatchResult.observe(
{
state: enums.CPU_LABELS.INTERRUPT,
cpu: cpuUsage.cpuNumber,
},
[this._cpuUtilizationObserver?.observation(cpuUsage.interruptP)]
);
observerBatchResult.observe(
{
state: enums.CPU_LABELS.NICE,
cpu: cpuUsage.cpuNumber,
},
[this._cpuUtilizationObserver?.observation(cpuUsage.niceP)]
);
}
}

private _updateMemUsage(
Expand Down
44 changes: 27 additions & 17 deletions packages/opentelemetry-host-metrics/src/stats/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,37 +18,47 @@ import * as os from 'os';

import { CpuUsageData, MemoryData } from '../types';

const MICROSECOND = 1 / 1e6;
const MILLISECOND = 1 / 1e3;
let cpuUsageTime: number | undefined = undefined;

/**
* It returns cpu load delta from last time - to be used with SumObservers.
* When called first time it will return 0 and then delta will be calculated
*/
export function getCpuUsageData(): CpuUsageData {
export function getCpuUsageData(): CpuUsageData[] {
if (typeof cpuUsageTime !== 'number') {
cpuUsageTime = new Date().getTime() - process.uptime() * 1000;
}

const timeElapsed = (new Date().getTime() - cpuUsageTime) / 1000;
const elapsedUsage = process.cpuUsage();

const user = elapsedUsage.user * MICROSECOND;
const system = elapsedUsage.system * MICROSECOND;
const idle = Math.max(0, timeElapsed - user - system);
return os.cpus().map((cpu, cpuNumber) => {
const idle = cpu.times.idle * MILLISECOND;
const user = cpu.times.user * MILLISECOND;
const system = cpu.times.sys * MILLISECOND;
const interrupt = cpu.times.irq * MILLISECOND;
const nice = cpu.times.nice * MILLISECOND;

const userP = user / timeElapsed;
const systemP = system / timeElapsed;
const idleP = idle / timeElapsed;
const idleP = idle / timeElapsed;
const userP = user / timeElapsed;
const systemP = system / timeElapsed;
const interruptP = interrupt / timeElapsed;
const niceP = nice / timeElapsed;

return {
user: user,
system: system,
idle: idle,
userP: userP,
systemP: systemP,
idleP: idleP,
};
return {
cpuNumber: String(cpuNumber),
idle,
user,
system,
interrupt,
nice,
userP,
systemP,
idleP,
interruptP,
niceP,
};
});
}

/**
Expand Down
5 changes: 5 additions & 0 deletions packages/opentelemetry-host-metrics/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,17 @@ export interface NetworkData {
* CPU usage data
*/
export interface CpuUsageData {
cpuNumber: string;
system: number;
user: number;
idle: number;
nice: number;
interrupt: number;
systemP: number;
userP: number;
idleP: number;
interruptP: number;
niceP: number;
}

/**
Expand Down
36 changes: 27 additions & 9 deletions packages/opentelemetry-host-metrics/test/metric.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ describe('Host Metrics', () => {
return mockedOS.freemem();
});
sandbox.stub(os, 'totalmem').returns(mockedOS.totalmem());
sandbox.stub(process, 'cpuUsage').returns(cpuJson);
sandbox.stub(os, 'cpus').returns(cpuJson);
sandbox.stub(process, 'uptime').returns(0);
sandbox.stub(SI, 'networkStats').callsFake(() => {
return mockedSI.networkStats();
Expand Down Expand Up @@ -152,18 +152,36 @@ describe('Host Metrics', () => {

it('should export CPU time metrics', () => {
const records = getRecords(exportSpy.args[0][0], 'system.cpu.time');
assert.strictEqual(records.length, 3);
ensureValue(records[0], { state: 'user' }, 1.899243);
ensureValue(records[1], { state: 'system' }, 0.258553);
ensureValue(records[2], { state: 'idle' }, 0.842204);
assert.strictEqual(records.length, 10);

ensureValue(records[0], { state: 'user', cpu: '0' }, 90713.56);
ensureValue(records[1], { state: 'system', cpu: '0' }, 63192.630000000005);
ensureValue(records[2], { state: 'idle', cpu: '0' }, 374870.7);
ensureValue(records[3], { state: 'interrupt', cpu: '0' }, 0);
ensureValue(records[4], { state: 'nice', cpu: '0' }, 0);

ensureValue(records[5], { state: 'user', cpu: '1' }, 11005.42);
ensureValue(records[6], { state: 'system', cpu: '1' }, 7678.12);
ensureValue(records[7], { state: 'idle', cpu: '1' }, 510034.8);
ensureValue(records[8], { state: 'interrupt', cpu: '1' }, 0);
ensureValue(records[9], { state: 'nice', cpu: '1' }, 0);
});

it('should export CPU utilization metrics', () => {
const records = getRecords(exportSpy.args[0][0], 'system.cpu.utilization');
assert.strictEqual(records.length, 3);
ensureValue(records[0], { state: 'user' }, 0.633081);
ensureValue(records[1], { state: 'system' }, 0.08618433333333332);
ensureValue(records[2], { state: 'idle' }, 0.28073466666666663);
assert.strictEqual(records.length, 10);

ensureValue(records[0], { state: 'user', cpu: '0' }, 30237.853333333333);
ensureValue(records[1], { state: 'system', cpu: '0' }, 21064.210000000003);
ensureValue(records[2], { state: 'idle', cpu: '0' }, 124956.90000000001);
ensureValue(records[3], { state: 'interrupt', cpu: '0' }, 0);
ensureValue(records[4], { state: 'nice', cpu: '0' }, 0);

ensureValue(records[5], { state: 'user', cpu: '1' }, 3668.4733333333334);
ensureValue(records[6], { state: 'system', cpu: '1' }, 2559.3733333333334);
ensureValue(records[7], { state: 'idle', cpu: '1' }, 170011.6);
ensureValue(records[8], { state: 'interrupt', cpu: '1' }, 0);
ensureValue(records[9], { state: 'nice', cpu: '1' }, 0);
});

it('should export Memory usage metrics', done => {
Expand Down
26 changes: 22 additions & 4 deletions packages/opentelemetry-host-metrics/test/mocks/cpu.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,22 @@
{
"user": 1899243,
"system": 258553
}
[{
"model": "CPU @ 2.60GHz",
"speed": 2600,
"times": {
"user": 90713560,
"nice": 0,
"sys": 63192630,
"idle": 374870700,
"irq": 0
}
}, {
"model": "CPU @ 2.60GHz",
"speed": 2600,
"times": {
"user": 11005420,
"nice": 0,
"sys": 7678120,
"idle": 510034800,
"irq": 0
}
}
]

0 comments on commit 6644e74

Please sign in to comment.