11import { type MeterProvider } from "@opentelemetry/sdk-metrics" ;
2+ import type { ObservableGauge } from "@opentelemetry/api" ;
23import { performance , monitorEventLoopDelay } from "node:perf_hooks" ;
34
5+ function tryMonitorEventLoopDelay ( ) {
6+ try {
7+ const eld = monitorEventLoopDelay ( { resolution : 20 } ) ;
8+ eld . enable ( ) ;
9+ return eld ;
10+ } catch {
11+ // monitorEventLoopDelay is not implemented in Bun
12+ return undefined ;
13+ }
14+ }
15+
416export function startNodejsRuntimeMetrics ( meterProvider : MeterProvider ) {
517 const meter = meterProvider . getMeter ( "nodejs-runtime" , "1.0.0" ) ;
618
@@ -12,18 +24,25 @@ export function startNodejsRuntimeMetrics(meterProvider: MeterProvider) {
1224 unit : "1" ,
1325 } ) ;
1426
15- // Event loop delay histogram (from perf_hooks)
16- const eld = monitorEventLoopDelay ( { resolution : 20 } ) ;
17- eld . enable ( ) ;
27+ // Event loop delay histogram (from perf_hooks) — not available in Bun
28+ const eld = tryMonitorEventLoopDelay ( ) ;
1829
19- const eldP95 = meter . createObservableGauge ( "nodejs.event_loop.delay.p95" , {
20- description : "p95 event loop delay" ,
21- unit : "s" ,
22- } ) ;
23- const eldMax = meter . createObservableGauge ( "nodejs.event_loop.delay.max" , {
24- description : "Max event loop delay" ,
25- unit : "s" ,
26- } ) ;
30+ const observables : ObservableGauge [ ] = [ eluGauge ] ;
31+
32+ let eldP95 : ObservableGauge | undefined ;
33+ let eldMax : ObservableGauge | undefined ;
34+
35+ if ( eld ) {
36+ eldP95 = meter . createObservableGauge ( "nodejs.event_loop.delay.p95" , {
37+ description : "p95 event loop delay" ,
38+ unit : "s" ,
39+ } ) ;
40+ eldMax = meter . createObservableGauge ( "nodejs.event_loop.delay.max" , {
41+ description : "Max event loop delay" ,
42+ unit : "s" ,
43+ } ) ;
44+ observables . push ( eldP95 , eldMax ) ;
45+ }
2746
2847 // Heap metrics
2948 const heapUsed = meter . createObservableGauge ( "nodejs.heap.used" , {
@@ -34,6 +53,7 @@ export function startNodejsRuntimeMetrics(meterProvider: MeterProvider) {
3453 description : "V8 heap total allocated" ,
3554 unit : "By" ,
3655 } ) ;
56+ observables . push ( heapUsed , heapTotal ) ;
3757
3858 // Single batch callback for all metrics
3959 meter . addBatchObservableCallback (
@@ -45,15 +65,17 @@ export function startNodejsRuntimeMetrics(meterProvider: MeterProvider) {
4565 obs . observe ( eluGauge , diff . utilization ) ;
4666
4767 // Event loop delay (nanoseconds -> seconds)
48- obs . observe ( eldP95 , eld . percentile ( 95 ) / 1e9 ) ;
49- obs . observe ( eldMax , eld . max / 1e9 ) ;
50- eld . reset ( ) ;
68+ if ( eld && eldP95 && eldMax ) {
69+ obs . observe ( eldP95 , eld . percentile ( 95 ) / 1e9 ) ;
70+ obs . observe ( eldMax , eld . max / 1e9 ) ;
71+ eld . reset ( ) ;
72+ }
5173
5274 // Heap
5375 const mem = process . memoryUsage ( ) ;
5476 obs . observe ( heapUsed , mem . heapUsed ) ;
5577 obs . observe ( heapTotal , mem . heapTotal ) ;
5678 } ,
57- [ eluGauge , eldP95 , eldMax , heapUsed , heapTotal ]
79+ observables
5880 ) ;
5981}
0 commit comments