Skip to content

Commit c0bc44e

Browse files
committed
implement telemetry for exceeding thresholds
1 parent 422fa1d commit c0bc44e

File tree

3 files changed

+41
-10
lines changed

3 files changed

+41
-10
lines changed

packages/core/src/shared/telemetry/vscodeTelemetry.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
{
22
"types": [
3+
{
4+
"name": "systemResource",
5+
"type": "string",
6+
"allowedValues": ["cpu", "memory"],
7+
"description": "The type of system resource being measured"
8+
},
39
{
410
"name": "amazonGenerateApproachLatency",
511
"type": "double",
@@ -372,6 +378,16 @@
372378
}
373379
]
374380
},
381+
{
382+
"name": "ide_childProcessWarning",
383+
"description": "Child Process warning due to high system usage",
384+
"metadata": [
385+
{
386+
"type": "systemResource",
387+
"required": true
388+
}
389+
]
390+
},
375391
{
376392
"name": "vscode_executeCommand",
377393
"description": "Emitted whenever a registered Toolkit command is executed",

packages/core/src/shared/utilities/processUtils.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import * as logger from '../logger'
99
import { Timeout, CancellationError, waitUntil } from './timeoutUtils'
1010
import { PollingSet } from './pollingSet'
1111
import { getLogger } from '../logger/logger'
12+
import { telemetry } from '../telemetry'
1213

1314
export interface RunParameterContext {
1415
/** Reports an error parsed from the stdin/stdout streams. */
@@ -100,18 +101,29 @@ export class ChildProcessTracker {
100101
}
101102

102103
private async checkProcessUsage(pid: number): Promise<void> {
104+
const doesExceedThreshold = (resource: keyof ProcessStats, value: number) => {
105+
const threshold = ChildProcessTracker.thresholds[resource]
106+
return value > threshold
107+
}
108+
const warn = (resource: keyof ProcessStats, value: number) => {
109+
telemetry.ide_childProcessWarning.run((span) => {
110+
ChildProcessTracker.logger.warn(`Process ${pid} exceeded ${resource} threshold: ${value}`)
111+
span.record({ systemResource: resource })
112+
})
113+
}
114+
103115
if (!this.#pids.has(pid)) {
104116
ChildProcessTracker.logger.warn(`Missing process with id ${pid}`)
105117
return
106118
}
107119
const stats = await this.getUsage(pid)
108-
if (stats) {
109-
ChildProcessTracker.logger.debug(`Process ${pid} usage: %O`, stats)
110-
if (stats.memory > ChildProcessTracker.thresholds.memory) {
111-
ChildProcessTracker.logger.warn(`Process ${pid} exceeded memory threshold: ${stats.memory}`)
112-
}
113-
if (stats.cpu > ChildProcessTracker.thresholds.cpu) {
114-
ChildProcessTracker.logger.warn(`Process ${pid} exceeded cpu threshold: ${stats.cpu}`)
120+
if (!stats) {
121+
ChildProcessTracker.logger.warn(`Failed to get process stats for ${pid}`)
122+
return
123+
}
124+
for (const resource of Object.keys(ChildProcessTracker.thresholds) as (keyof ProcessStats)[]) {
125+
if (doesExceedThreshold(resource, stats[resource])) {
126+
warn(resource as keyof ProcessStats, stats[resource])
115127
}
116128
}
117129
}

packages/core/src/test/shared/utilities/processUtils.test.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { sleep } from '../../../shared/utilities/timeoutUtils'
1919
import { Timeout, waitUntil } from '../../../shared/utilities/timeoutUtils'
2020
import { fs } from '../../../shared'
2121
import * as FakeTimers from '@sinonjs/fake-timers'
22-
import { installFakeClock } from '../../testUtil'
22+
import { assertTelemetry, installFakeClock } from '../../testUtil'
2323
import { isWin } from '../../../shared/vscode/env'
2424
import { assertLogsContain } from '../../globalSetup.test'
2525

@@ -445,7 +445,7 @@ describe('ChildProcessTracker', function () {
445445
assert.strictEqual(tracker.size, 0, 'expected tracker to be empty')
446446
})
447447

448-
it('logs a warning message when system usage exceeds threshold', async function () {
448+
it('logs a warning message and emits metric when system usage exceeds threshold', async function () {
449449
const runningProcess = startSleepProcess()
450450
tracker.add(runningProcess.childProcess)
451451

@@ -462,10 +462,12 @@ describe('ChildProcessTracker', function () {
462462

463463
await clock.tickAsync(ChildProcessTracker.pollingInterval)
464464
assertLogsContain('exceeded cpu threshold', false, 'warn')
465+
assertTelemetry('ide_childProcessWarning', { systemResource: 'cpu' })
465466

466467
usageMock.resolves(highMemory)
467468
await clock.tickAsync(ChildProcessTracker.pollingInterval)
468469
assertLogsContain('exceeded memory threshold', false, 'warn')
470+
assertTelemetry('ide_childProcessWarning', { systemResource: 'memory' })
469471

470472
await stopAndWait(runningProcess)
471473
})
@@ -485,7 +487,7 @@ describe('ChildProcessTracker', function () {
485487
await stopAndWait(runningProcess)
486488
})
487489

488-
it('does not log for processes within threshold', async function () {
490+
it('does not log or emit telemetry for processes within threshold', async function () {
489491
const runningProcess = startSleepProcess()
490492

491493
usageMock.resolves({
@@ -496,6 +498,7 @@ describe('ChildProcessTracker', function () {
496498
await clock.tickAsync(ChildProcessTracker.pollingInterval)
497499

498500
assert.throws(() => assertLogsContain(runningProcess.childProcess.pid().toString(), false, 'warn'))
501+
assert.throws(() => assertTelemetry('ide_childProcessWarning', {}))
499502

500503
await stopAndWait(runningProcess)
501504
})

0 commit comments

Comments
 (0)