-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: metric for event loop utilization
- Loading branch information
Showing
6 changed files
with
140 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { performance } from 'perf_hooks' | ||
|
||
import { Telemetry } from '@carv/telemetry' | ||
|
||
import { ProcessEventLoopUtilizationOptions } from './types' | ||
|
||
export const isEventLoopUtilizationSupported = Boolean(performance.eventLoopUtilization) | ||
|
||
export function processEventLoopUtilization( | ||
telemetry: Telemetry, | ||
{ | ||
prefix = 'process', | ||
name = 'event_loop_utilization', | ||
description = `ELU is similar to CPU utilization, except that it only measures event loop statistics and not CPU usage. It represents the percentage of time the event loop has spent outside the event loop's event provider (e.g. epoll_wait).`, | ||
labels, | ||
}: ProcessEventLoopUtilizationOptions, | ||
done: () => void, | ||
) { | ||
if (!isEventLoopUtilizationSupported) { | ||
telemetry.log.warn( | ||
'[%s] Monitoring the event loop utilization is not supported on Node.js %s', | ||
telemetry.makeName(prefix, name), | ||
process.version, | ||
) | ||
done() | ||
return | ||
} | ||
|
||
const { eventLoopUtilization } = performance | ||
|
||
let last = eventLoopUtilization() | ||
|
||
telemetry.createValueObserver({ prefix, name, description, labels }, () => { | ||
const current = eventLoopUtilization() | ||
|
||
const { utilization } = eventLoopUtilization(last, current) | ||
|
||
last = current | ||
|
||
return utilization | ||
}) | ||
|
||
done() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/** | ||
* @jest-environment node | ||
*/ | ||
import { promisify } from 'util' | ||
import { performance } from 'perf_hooks' | ||
|
||
import { Telemetry, TestLogger } from '@carv/telemetry' | ||
|
||
import { processEventLoopUtilization, isEventLoopUtilizationSupported } from '../src' | ||
|
||
jest.useFakeTimers() | ||
|
||
const nextTick = promisify(setImmediate) | ||
|
||
let telemetry: Telemetry | ||
|
||
beforeEach(() => { | ||
telemetry = new Telemetry({ | ||
logger: new TestLogger(), | ||
}) | ||
}) | ||
|
||
afterEach(() => telemetry.shutdown()) | ||
|
||
if (isEventLoopUtilizationSupported) { | ||
test('processEventLoopUtilization', async () => { | ||
telemetry.use(processEventLoopUtilization) | ||
|
||
await telemetry.ready() | ||
|
||
// Do something | ||
const finishedTimestamp = Date.now() + 23 | ||
while (finishedTimestamp > Date.now()) { | ||
const endTimestamp = performance.now() + Math.random() | ||
while (endTimestamp > performance.now()) {} | ||
await nextTick() | ||
} | ||
|
||
const metrics = await telemetry.collect() | ||
|
||
expect(metrics).toMatch( | ||
'# HELP process_event_loop_utilization ELU is similar to CPU utilization, except that it only measures event loop statistics and not CPU usage.', | ||
) | ||
expect(metrics).toMatch('# TYPE process_event_loop_utilization gauge') | ||
expect(metrics).toMatch(/^process_event_loop_utilization \d+(?:\.\d+)? \d{13}$/m) | ||
}) | ||
} else { | ||
test('processEventLoopUtilization', async () => { | ||
telemetry.use(processEventLoopUtilization) | ||
|
||
telemetry.log.warn = jest.fn() | ||
|
||
await telemetry.ready() | ||
|
||
expect(telemetry.log.warn).toHaveBeenCalledWith( | ||
'[%s] Monitoring the event loop utilization is not supported on Node.js %s', | ||
'process_event_loop_utilization', | ||
process.version, | ||
) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters