Skip to content

Commit 6644e74

Browse files
svrnmvmarchaud
andauthored
fix: "host-metrics" should collect system (os) cpu metrics to comply … (#438)
Co-authored-by: Valentin Marchaud <contact@vmarchaud.fr>
1 parent ee7c40d commit 6644e74

File tree

6 files changed

+161
-68
lines changed

6 files changed

+161
-68
lines changed

packages/opentelemetry-host-metrics/src/enum.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ export enum CPU_LABELS {
2828
USER = 'user',
2929
SYSTEM = 'system',
3030
IDLE = 'idle',
31+
INTERRUPT = 'interrupt',
32+
NICE = 'nice',
3133
}
3234

3335
export enum NETWORK_LABELS {

packages/opentelemetry-host-metrics/src/metric.ts

Lines changed: 78 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -36,50 +36,90 @@ export class HostMetrics extends BaseMetrics {
3636

3737
private _updateCpuTime(
3838
observerBatchResult: api.BatchObserverResult,
39-
cpuUsage: CpuUsageData
39+
cpuUsages: CpuUsageData[]
4040
): void {
41-
observerBatchResult.observe(
42-
{
43-
state: enums.CPU_LABELS.USER,
44-
},
45-
[this._cpuTimeObserver?.observation(cpuUsage.user)]
46-
);
47-
observerBatchResult.observe(
48-
{
49-
state: enums.CPU_LABELS.SYSTEM,
50-
},
51-
[this._cpuTimeObserver?.observation(cpuUsage.system)]
52-
);
53-
observerBatchResult.observe(
54-
{
55-
state: enums.CPU_LABELS.IDLE,
56-
},
57-
[this._cpuTimeObserver?.observation(cpuUsage.idle)]
58-
);
41+
for (let i = 0, j = cpuUsages.length; i < j; i++) {
42+
const cpuUsage = cpuUsages[i];
43+
observerBatchResult.observe(
44+
{
45+
state: enums.CPU_LABELS.USER,
46+
cpu: cpuUsage.cpuNumber,
47+
},
48+
[this._cpuTimeObserver?.observation(cpuUsage.user)]
49+
);
50+
observerBatchResult.observe(
51+
{
52+
state: enums.CPU_LABELS.SYSTEM,
53+
cpu: cpuUsage.cpuNumber,
54+
},
55+
[this._cpuTimeObserver?.observation(cpuUsage.system)]
56+
);
57+
observerBatchResult.observe(
58+
{
59+
state: enums.CPU_LABELS.IDLE,
60+
cpu: cpuUsage.cpuNumber,
61+
},
62+
[this._cpuTimeObserver?.observation(cpuUsage.idle)]
63+
);
64+
observerBatchResult.observe(
65+
{
66+
state: enums.CPU_LABELS.INTERRUPT,
67+
cpu: cpuUsage.cpuNumber,
68+
},
69+
[this._cpuTimeObserver?.observation(cpuUsage.interrupt)]
70+
);
71+
observerBatchResult.observe(
72+
{
73+
state: enums.CPU_LABELS.NICE,
74+
cpu: cpuUsage.cpuNumber,
75+
},
76+
[this._cpuTimeObserver?.observation(cpuUsage.nice)]
77+
);
78+
}
5979
}
6080

6181
private _updateCpuUtilisation(
6282
observerBatchResult: api.BatchObserverResult,
63-
cpuUsage: CpuUsageData
83+
cpuUsages: CpuUsageData[]
6484
): void {
65-
observerBatchResult.observe(
66-
{
67-
state: enums.CPU_LABELS.USER,
68-
},
69-
[this._cpuUtilizationObserver?.observation(cpuUsage.userP)]
70-
);
71-
observerBatchResult.observe(
72-
{
73-
state: enums.CPU_LABELS.SYSTEM,
74-
},
75-
[this._cpuUtilizationObserver?.observation(cpuUsage.systemP)]
76-
);
77-
observerBatchResult.observe(
78-
{
79-
state: enums.CPU_LABELS.IDLE,
80-
},
81-
[this._cpuUtilizationObserver?.observation(cpuUsage.idleP)]
82-
);
85+
for (let i = 0, j = cpuUsages.length; i < j; i++) {
86+
const cpuUsage = cpuUsages[i];
87+
observerBatchResult.observe(
88+
{
89+
state: enums.CPU_LABELS.USER,
90+
cpu: cpuUsage.cpuNumber,
91+
},
92+
[this._cpuUtilizationObserver?.observation(cpuUsage.userP)]
93+
);
94+
observerBatchResult.observe(
95+
{
96+
state: enums.CPU_LABELS.SYSTEM,
97+
cpu: cpuUsage.cpuNumber,
98+
},
99+
[this._cpuUtilizationObserver?.observation(cpuUsage.systemP)]
100+
);
101+
observerBatchResult.observe(
102+
{
103+
state: enums.CPU_LABELS.IDLE,
104+
cpu: cpuUsage.cpuNumber,
105+
},
106+
[this._cpuUtilizationObserver?.observation(cpuUsage.idleP)]
107+
);
108+
observerBatchResult.observe(
109+
{
110+
state: enums.CPU_LABELS.INTERRUPT,
111+
cpu: cpuUsage.cpuNumber,
112+
},
113+
[this._cpuUtilizationObserver?.observation(cpuUsage.interruptP)]
114+
);
115+
observerBatchResult.observe(
116+
{
117+
state: enums.CPU_LABELS.NICE,
118+
cpu: cpuUsage.cpuNumber,
119+
},
120+
[this._cpuUtilizationObserver?.observation(cpuUsage.niceP)]
121+
);
122+
}
83123
}
84124

85125
private _updateMemUsage(

packages/opentelemetry-host-metrics/src/stats/common.ts

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,37 +18,47 @@ import * as os from 'os';
1818

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

21-
const MICROSECOND = 1 / 1e6;
21+
const MILLISECOND = 1 / 1e3;
2222
let cpuUsageTime: number | undefined = undefined;
2323

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

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

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

40-
const userP = user / timeElapsed;
41-
const systemP = system / timeElapsed;
42-
const idleP = idle / timeElapsed;
42+
const idleP = idle / timeElapsed;
43+
const userP = user / timeElapsed;
44+
const systemP = system / timeElapsed;
45+
const interruptP = interrupt / timeElapsed;
46+
const niceP = nice / timeElapsed;
4347

44-
return {
45-
user: user,
46-
system: system,
47-
idle: idle,
48-
userP: userP,
49-
systemP: systemP,
50-
idleP: idleP,
51-
};
48+
return {
49+
cpuNumber: String(cpuNumber),
50+
idle,
51+
user,
52+
system,
53+
interrupt,
54+
nice,
55+
userP,
56+
systemP,
57+
idleP,
58+
interruptP,
59+
niceP,
60+
};
61+
});
5262
}
5363

5464
/**

packages/opentelemetry-host-metrics/src/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,17 @@ export interface NetworkData {
3131
* CPU usage data
3232
*/
3333
export interface CpuUsageData {
34+
cpuNumber: string;
3435
system: number;
3536
user: number;
3637
idle: number;
38+
nice: number;
39+
interrupt: number;
3740
systemP: number;
3841
userP: number;
3942
idleP: number;
43+
interruptP: number;
44+
niceP: number;
4045
}
4146

4247
/**

packages/opentelemetry-host-metrics/test/metric.test.ts

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ describe('Host Metrics', () => {
9090
return mockedOS.freemem();
9191
});
9292
sandbox.stub(os, 'totalmem').returns(mockedOS.totalmem());
93-
sandbox.stub(process, 'cpuUsage').returns(cpuJson);
93+
sandbox.stub(os, 'cpus').returns(cpuJson);
9494
sandbox.stub(process, 'uptime').returns(0);
9595
sandbox.stub(SI, 'networkStats').callsFake(() => {
9696
return mockedSI.networkStats();
@@ -152,18 +152,36 @@ describe('Host Metrics', () => {
152152

153153
it('should export CPU time metrics', () => {
154154
const records = getRecords(exportSpy.args[0][0], 'system.cpu.time');
155-
assert.strictEqual(records.length, 3);
156-
ensureValue(records[0], { state: 'user' }, 1.899243);
157-
ensureValue(records[1], { state: 'system' }, 0.258553);
158-
ensureValue(records[2], { state: 'idle' }, 0.842204);
155+
assert.strictEqual(records.length, 10);
156+
157+
ensureValue(records[0], { state: 'user', cpu: '0' }, 90713.56);
158+
ensureValue(records[1], { state: 'system', cpu: '0' }, 63192.630000000005);
159+
ensureValue(records[2], { state: 'idle', cpu: '0' }, 374870.7);
160+
ensureValue(records[3], { state: 'interrupt', cpu: '0' }, 0);
161+
ensureValue(records[4], { state: 'nice', cpu: '0' }, 0);
162+
163+
ensureValue(records[5], { state: 'user', cpu: '1' }, 11005.42);
164+
ensureValue(records[6], { state: 'system', cpu: '1' }, 7678.12);
165+
ensureValue(records[7], { state: 'idle', cpu: '1' }, 510034.8);
166+
ensureValue(records[8], { state: 'interrupt', cpu: '1' }, 0);
167+
ensureValue(records[9], { state: 'nice', cpu: '1' }, 0);
159168
});
160169

161170
it('should export CPU utilization metrics', () => {
162171
const records = getRecords(exportSpy.args[0][0], 'system.cpu.utilization');
163-
assert.strictEqual(records.length, 3);
164-
ensureValue(records[0], { state: 'user' }, 0.633081);
165-
ensureValue(records[1], { state: 'system' }, 0.08618433333333332);
166-
ensureValue(records[2], { state: 'idle' }, 0.28073466666666663);
172+
assert.strictEqual(records.length, 10);
173+
174+
ensureValue(records[0], { state: 'user', cpu: '0' }, 30237.853333333333);
175+
ensureValue(records[1], { state: 'system', cpu: '0' }, 21064.210000000003);
176+
ensureValue(records[2], { state: 'idle', cpu: '0' }, 124956.90000000001);
177+
ensureValue(records[3], { state: 'interrupt', cpu: '0' }, 0);
178+
ensureValue(records[4], { state: 'nice', cpu: '0' }, 0);
179+
180+
ensureValue(records[5], { state: 'user', cpu: '1' }, 3668.4733333333334);
181+
ensureValue(records[6], { state: 'system', cpu: '1' }, 2559.3733333333334);
182+
ensureValue(records[7], { state: 'idle', cpu: '1' }, 170011.6);
183+
ensureValue(records[8], { state: 'interrupt', cpu: '1' }, 0);
184+
ensureValue(records[9], { state: 'nice', cpu: '1' }, 0);
167185
});
168186

169187
it('should export Memory usage metrics', done => {
Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,22 @@
1-
{
2-
"user": 1899243,
3-
"system": 258553
4-
}
1+
[{
2+
"model": "CPU @ 2.60GHz",
3+
"speed": 2600,
4+
"times": {
5+
"user": 90713560,
6+
"nice": 0,
7+
"sys": 63192630,
8+
"idle": 374870700,
9+
"irq": 0
10+
}
11+
}, {
12+
"model": "CPU @ 2.60GHz",
13+
"speed": 2600,
14+
"times": {
15+
"user": 11005420,
16+
"nice": 0,
17+
"sys": 7678120,
18+
"idle": 510034800,
19+
"irq": 0
20+
}
21+
}
22+
]

0 commit comments

Comments
 (0)