envio 3.12.1 → 3.13.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -8
- package/src/BatchProcessing.res +15 -14
- package/src/BatchProcessing.res.mjs +8 -15
- package/src/Bin.res +24 -17
- package/src/Bin.res.mjs +5 -0
- package/src/ChainFetching.res +18 -24
- package/src/ChainFetching.res.mjs +14 -15
- package/src/ChainState.res +103 -38
- package/src/ChainState.res.mjs +79 -22
- package/src/ChainState.resi +14 -2
- package/src/Config.res +32 -0
- package/src/Config.res.mjs +24 -0
- package/src/Core.res +4 -0
- package/src/Core.res.mjs +4 -0
- package/src/CrossChainState.res +109 -11
- package/src/CrossChainState.res.mjs +71 -7
- package/src/CrossChainState.resi +11 -1
- package/src/Env.res +4 -0
- package/src/ErrorHandling.res +15 -4
- package/src/ErrorHandling.res.mjs +16 -5
- package/src/FinalizeBackfill.res +10 -4
- package/src/FinalizeBackfill.res.mjs +5 -3
- package/src/HandlerRegister.res +0 -37
- package/src/HandlerRegister.res.mjs +0 -18
- package/src/IndexerLoop.res +2 -0
- package/src/IndexerLoop.res.mjs +1 -0
- package/src/IndexerState.res +43 -1
- package/src/IndexerState.res.mjs +48 -4
- package/src/IndexerState.resi +11 -0
- package/src/Main.res +128 -268
- package/src/Main.res.mjs +27 -153
- package/src/Metrics.res +268 -102
- package/src/Metrics.res.mjs +227 -48
- package/src/Persistence.res +30 -2
- package/src/Persistence.res.mjs +12 -3
- package/src/PgStorage.res +19 -11
- package/src/PgStorage.res.mjs +13 -10
- package/src/Rollback.res +3 -3
- package/src/Server.res +178 -0
- package/src/Server.res.mjs +143 -0
- package/src/SimulateItems.res +1 -1
- package/src/SimulateItems.res.mjs +1 -1
- package/src/Supervisor.res +542 -0
- package/src/Supervisor.res.mjs +455 -0
- package/src/TestIndexer.res +1 -1
- package/src/TestIndexer.res.mjs +2 -2
- package/src/Worker.res +101 -0
- package/src/Worker.res.mjs +81 -0
- package/src/bindings/NodeJs.res +50 -0
- package/src/bindings/NodeJs.res.mjs +8 -1
- package/src/db/InternalTable.res +8 -1
- package/src/db/InternalTable.res.mjs +5 -1
- package/src/sources/AddressSet.res +5 -3
- package/src/sources/AddressStore.res +19 -11
- package/src/sources/AddressStore.res.mjs +2 -7
- package/src/sources/BlockStore.res +10 -9
- package/src/sources/BlockStore.res.mjs +4 -4
- package/src/sources/ChainSources.res +4 -0
- package/src/sources/ChainSources.res.mjs +2 -2
- package/src/sources/EvmChain.res +4 -0
- package/src/sources/EvmChain.res.mjs +3 -1
- package/src/sources/EvmEventItem.res +56 -0
- package/src/sources/EvmEventItem.res.mjs +32 -0
- package/src/sources/EvmHyperSyncSource.res +7 -37
- package/src/sources/EvmHyperSyncSource.res.mjs +8 -29
- package/src/sources/EvmRpcClient.res +41 -59
- package/src/sources/EvmRpcClient.res.mjs +4 -54
- package/src/sources/EvmRpcWs.res +4 -1
- package/src/sources/EvmRpcWs.res.mjs +6 -2
- package/src/sources/FuelHyperSyncSource.res +6 -4
- package/src/sources/FuelHyperSyncSource.res.mjs +7 -9
- package/src/sources/HeightFeed.res +7 -1
- package/src/sources/HeightFeed.res.mjs +9 -7
- package/src/sources/HyperSyncClient.res +1 -14
- package/src/sources/RequestStat.res +7 -0
- package/src/sources/RequestStat.res.mjs +14 -1
- package/src/sources/RpcSource.res +100 -1043
- package/src/sources/RpcSource.res.mjs +81 -1056
- package/src/sources/SimulateSource.res +2 -5
- package/src/sources/SimulateSource.res.mjs +2 -3
- package/src/sources/Source.res +34 -12
- package/src/sources/Source.res.mjs +11 -0
- package/src/sources/SourceManager.res +111 -31
- package/src/sources/SourceManager.res.mjs +65 -31
- package/src/sources/SourceManager.resi +4 -0
- package/src/sources/StartBlockResolver.res +8 -5
- package/src/sources/StartBlockResolver.res.mjs +4 -2
- package/src/sources/SvmHyperSyncSource.res +4 -2
- package/src/sources/SvmHyperSyncSource.res.mjs +4 -6
- package/src/sources/TransactionStore.res +9 -6
- package/src/sources/TransactionStore.res.mjs +2 -2
- package/src/tui/Tui.res +10 -0
- package/src/tui/Tui.res.mjs +15 -0
- package/src/tui/components/SyncETA.res +12 -6
- package/src/tui/components/SyncETA.res.mjs +12 -8
- package/src/LazyLoader.res +0 -135
- package/src/LazyLoader.res.mjs +0 -118
- package/src/bindings/SDSL.res +0 -12
- package/src/bindings/SDSL.res.mjs +0 -9
- package/src/bindings/Yargs.res +0 -8
- package/src/bindings/Yargs.res.mjs +0 -2
- package/src/sources/Rpc.res +0 -185
- package/src/sources/Rpc.res.mjs +0 -183
package/src/Metrics.res
CHANGED
|
@@ -129,6 +129,9 @@ type t = {
|
|
|
129
129
|
elapsedSeconds: float,
|
|
130
130
|
targetBufferSize: int,
|
|
131
131
|
isInReorgThreshold: bool,
|
|
132
|
+
// This process has got as far as it can without the run's leave. What a
|
|
133
|
+
// supervisor reads to decide that a split run may go realtime as one.
|
|
134
|
+
hasArrivedAtHead: bool,
|
|
132
135
|
rollbackEnabled: bool,
|
|
133
136
|
maxBatchSize: int,
|
|
134
137
|
preloadSeconds: float,
|
|
@@ -149,6 +152,115 @@ type t = {
|
|
|
149
152
|
sourceHeightStreams: array<sourceHeightStreamMetrics>,
|
|
150
153
|
}
|
|
151
154
|
|
|
155
|
+
// Folds items that share a key into one, keeping first-seen order so the
|
|
156
|
+
// rendered series doesn't reshuffle between scrapes.
|
|
157
|
+
let sumByKey = (items: array<'item>, ~key: 'item => string, ~add: ('item, 'item) => 'item) => {
|
|
158
|
+
let byKey = Dict.make()
|
|
159
|
+
let order = []
|
|
160
|
+
items->Array.forEach(item => {
|
|
161
|
+
let k = item->key
|
|
162
|
+
switch byKey->Utils.Dict.dangerouslyGetNonOption(k) {
|
|
163
|
+
| Some(existing) => byKey->Dict.set(k, add(existing, item))
|
|
164
|
+
| None => {
|
|
165
|
+
byKey->Dict.set(k, item)
|
|
166
|
+
order->Array.push(k)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
})
|
|
170
|
+
order->Array.map(k => byKey->Dict.getUnsafe(k))
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Combines the snapshots a supervised run's workers reported into the one an
|
|
174
|
+
// unsplit run would have produced. Series keyed by chain concatenate, since a
|
|
175
|
+
// chain belongs to exactly one worker; series keyed by name are summed, since
|
|
176
|
+
// every worker runs the same handlers and effects over its own chains. The
|
|
177
|
+
// clock and the buffer target are the caller's: both belong to the group, and
|
|
178
|
+
// the target is what the run was configured with rather than anything a worker
|
|
179
|
+
// could add up to.
|
|
180
|
+
let merge = (snapshots: array<t>, ~startTime, ~metricTime, ~elapsedSeconds, ~targetBufferSize) => {
|
|
181
|
+
let concat = select => snapshots->Array.flatMap(select)
|
|
182
|
+
let sumInt = select => snapshots->Array.reduce(0, (acc, snapshot) => acc + snapshot->select)
|
|
183
|
+
let sumFloat = select => snapshots->Array.reduce(0., (acc, snapshot) => acc +. snapshot->select)
|
|
184
|
+
|
|
185
|
+
{
|
|
186
|
+
startTime,
|
|
187
|
+
metricTime,
|
|
188
|
+
elapsedSeconds,
|
|
189
|
+
targetBufferSize,
|
|
190
|
+
// Chains cross into the threshold as one indexer, so a run is in it once
|
|
191
|
+
// every process is, the same reading as the arrival below.
|
|
192
|
+
isInReorgThreshold: snapshots->Utils.Array.notEmpty &&
|
|
193
|
+
snapshots->Array.every(s => s.isInReorgThreshold),
|
|
194
|
+
// The run has arrived only once every process has: one still backfilling
|
|
195
|
+
// speaks for the whole indexer.
|
|
196
|
+
hasArrivedAtHead: snapshots->Utils.Array.notEmpty &&
|
|
197
|
+
snapshots->Array.every(s => s.hasArrivedAtHead),
|
|
198
|
+
rollbackEnabled: snapshots->Array.some(s => s.rollbackEnabled),
|
|
199
|
+
maxBatchSize: snapshots->Array.reduce(0, (acc, s) => Pervasives.max(acc, s.maxBatchSize)),
|
|
200
|
+
preloadSeconds: sumFloat(s => s.preloadSeconds),
|
|
201
|
+
processingSeconds: sumFloat(s => s.processingSeconds),
|
|
202
|
+
processingStalledOnFetchSeconds: sumFloat(s => s.processingStalledOnFetchSeconds),
|
|
203
|
+
processingStalledOnStorageWriteSeconds: sumFloat(s => s.processingStalledOnStorageWriteSeconds),
|
|
204
|
+
rollbackSeconds: sumFloat(s => s.rollbackSeconds),
|
|
205
|
+
rollbackCount: sumInt(s => s.rollbackCount),
|
|
206
|
+
rollbackEventsCount: sumFloat(s => s.rollbackEventsCount),
|
|
207
|
+
chains: concat(s => s.chains),
|
|
208
|
+
sourceRequests: concat(s => s.sourceRequests),
|
|
209
|
+
sourceHeights: concat(s => s.sourceHeights),
|
|
210
|
+
sourceHeightStreams: concat(s => s.sourceHeightStreams),
|
|
211
|
+
handlers: concat(s => s.handlers)->sumByKey(
|
|
212
|
+
~key=h => `${h.contract}.${h.event}`,
|
|
213
|
+
~add=(a, b) => {
|
|
214
|
+
...a,
|
|
215
|
+
processingSeconds: a.processingSeconds +. b.processingSeconds,
|
|
216
|
+
processingCount: a.processingCount +. b.processingCount,
|
|
217
|
+
preloadSeconds: a.preloadSeconds +. b.preloadSeconds,
|
|
218
|
+
preloadCount: a.preloadCount +. b.preloadCount,
|
|
219
|
+
preloadSecondsTotal: a.preloadSecondsTotal +. b.preloadSecondsTotal,
|
|
220
|
+
},
|
|
221
|
+
),
|
|
222
|
+
effects: concat(s => s.effects)->sumByKey(
|
|
223
|
+
~key=e => `${e.effect}.${e.scope}`,
|
|
224
|
+
~add=(a, b) => {
|
|
225
|
+
...a,
|
|
226
|
+
callSeconds: a.callSeconds +. b.callSeconds,
|
|
227
|
+
callSecondsTotal: a.callSecondsTotal +. b.callSecondsTotal,
|
|
228
|
+
callCount: a.callCount +. b.callCount,
|
|
229
|
+
activeCallsCount: a.activeCallsCount + b.activeCallsCount,
|
|
230
|
+
queueCount: a.queueCount + b.queueCount,
|
|
231
|
+
queueWaitSeconds: a.queueWaitSeconds +. b.queueWaitSeconds,
|
|
232
|
+
invalidationsCount: a.invalidationsCount +. b.invalidationsCount,
|
|
233
|
+
// An effect's cache rows are per chain, so worker counts are disjoint.
|
|
234
|
+
// Absent unless some worker persists the cache at all.
|
|
235
|
+
cacheCount: switch (a.cacheCount, b.cacheCount) {
|
|
236
|
+
| (Some(x), Some(y)) => Some(x + y)
|
|
237
|
+
| (Some(x), None) => Some(x)
|
|
238
|
+
| (None, y) => y
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
),
|
|
242
|
+
storageLoads: concat(s => s.storageLoads)->sumByKey(
|
|
243
|
+
~key=l => `${l.storage}.${l.operation}`,
|
|
244
|
+
~add=(a, b) => {
|
|
245
|
+
...a,
|
|
246
|
+
seconds: a.seconds +. b.seconds,
|
|
247
|
+
secondsTotal: a.secondsTotal +. b.secondsTotal,
|
|
248
|
+
count: a.count +. b.count,
|
|
249
|
+
whereSize: a.whereSize +. b.whereSize,
|
|
250
|
+
size: a.size +. b.size,
|
|
251
|
+
},
|
|
252
|
+
),
|
|
253
|
+
storageWrites: concat(s => s.storageWrites)->sumByKey(
|
|
254
|
+
~key=w => w.storage,
|
|
255
|
+
~add=(a, b) => {...a, seconds: a.seconds +. b.seconds, count: a.count + b.count},
|
|
256
|
+
),
|
|
257
|
+
historyPrunes: concat(s => s.historyPrunes)->sumByKey(
|
|
258
|
+
~key=p => p.entity,
|
|
259
|
+
~add=(a, b) => {...a, seconds: a.seconds +. b.seconds, count: a.count + b.count},
|
|
260
|
+
),
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
152
264
|
// Prometheus floats keep at most 3 decimals; integral values render without a
|
|
153
265
|
// fractional part.
|
|
154
266
|
@inline
|
|
@@ -912,199 +1024,253 @@ let getRuntimeCollectors = () =>
|
|
|
912
1024
|
// from the beginning of the run, not from the first scrape.
|
|
913
1025
|
let startRuntimeCollectors = () => getRuntimeCollectors()->ignore
|
|
914
1026
|
|
|
915
|
-
|
|
916
|
-
|
|
1027
|
+
type runtimeGc = {kind: string, count: float, seconds: float}
|
|
1028
|
+
type runtimeHeapSpace = {space: string, size: float, used: float, available: float}
|
|
1029
|
+
|
|
1030
|
+
// One process's runtime readings at one moment. Plain numbers, so a worker can
|
|
1031
|
+
// hand its sample to the supervisor over the fork's channel and the supervisor
|
|
1032
|
+
// can render every process's under one label set.
|
|
1033
|
+
type runtimeSample = {
|
|
1034
|
+
cpuUserSeconds: float,
|
|
1035
|
+
cpuSystemSeconds: float,
|
|
1036
|
+
processStartTimeSeconds: float,
|
|
1037
|
+
residentMemoryBytes: float,
|
|
1038
|
+
heapTotalBytes: float,
|
|
1039
|
+
heapUsedBytes: float,
|
|
1040
|
+
externalMemoryBytes: float,
|
|
1041
|
+
eventLoopUtilization: float,
|
|
1042
|
+
eventLoopLagMeanSeconds: float,
|
|
1043
|
+
eventLoopLagMinSeconds: float,
|
|
1044
|
+
eventLoopLagMaxSeconds: float,
|
|
1045
|
+
eventLoopLagStddevSeconds: float,
|
|
1046
|
+
eventLoopLagP50Seconds: float,
|
|
1047
|
+
eventLoopLagP90Seconds: float,
|
|
1048
|
+
eventLoopLagP99Seconds: float,
|
|
1049
|
+
heapSpaces: array<runtimeHeapSpace>,
|
|
1050
|
+
activeResources: array<(string, float)>,
|
|
1051
|
+
gc: array<runtimeGc>,
|
|
1052
|
+
nodeVersion: string,
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
let sampleRuntime = (): runtimeSample => {
|
|
917
1056
|
let memory = NodeJs.Process.memoryUsage()
|
|
918
1057
|
let cpu = NodeJs.Process.cpuUsage()
|
|
919
1058
|
let elu = NodeJs.PerfHooks.performance->NodeJs.PerfHooks.eventLoopUtilization
|
|
920
1059
|
let {eventLoopDelay, gcStats, processStartTimeSeconds} = getRuntimeCollectors()
|
|
921
|
-
|
|
1060
|
+
// Nanoseconds in the histogram; reset after sampling so each scrape reports
|
|
1061
|
+
// the delay distribution since the previous one, matching prom-client. With
|
|
1062
|
+
// no samples yet (e.g. the first scrape, which starts the sampler) the
|
|
1063
|
+
// histogram reports NaN means and a sentinel min — report 0 instead.
|
|
1064
|
+
let hasLagSamples = eventLoopDelay.max > 0.
|
|
1065
|
+
let nsToSeconds = ns => hasLagSamples && !(ns->Float.isNaN) ? ns /. 1_000_000_000. : 0.
|
|
1066
|
+
let sample = {
|
|
1067
|
+
cpuUserSeconds: cpu.user /. 1_000_000.,
|
|
1068
|
+
cpuSystemSeconds: cpu.system /. 1_000_000.,
|
|
1069
|
+
processStartTimeSeconds,
|
|
1070
|
+
residentMemoryBytes: memory.rss,
|
|
1071
|
+
heapTotalBytes: memory.heapTotal,
|
|
1072
|
+
heapUsedBytes: memory.heapUsed,
|
|
1073
|
+
externalMemoryBytes: memory.external_,
|
|
1074
|
+
eventLoopUtilization: elu.utilization,
|
|
1075
|
+
eventLoopLagMeanSeconds: eventLoopDelay.mean->nsToSeconds,
|
|
1076
|
+
eventLoopLagMinSeconds: eventLoopDelay.min->nsToSeconds,
|
|
1077
|
+
eventLoopLagMaxSeconds: eventLoopDelay.max->nsToSeconds,
|
|
1078
|
+
eventLoopLagStddevSeconds: eventLoopDelay.stddev->nsToSeconds,
|
|
1079
|
+
eventLoopLagP50Seconds: eventLoopDelay->NodeJs.PerfHooks.percentile(50)->nsToSeconds,
|
|
1080
|
+
eventLoopLagP90Seconds: eventLoopDelay->NodeJs.PerfHooks.percentile(90)->nsToSeconds,
|
|
1081
|
+
eventLoopLagP99Seconds: eventLoopDelay->NodeJs.PerfHooks.percentile(99)->nsToSeconds,
|
|
1082
|
+
heapSpaces: NodeJs.V8.getHeapSpaceStatistics()->Array.map(s => {
|
|
1083
|
+
space: s.spaceName->String.replace("_space", ""),
|
|
1084
|
+
size: s.spaceSize,
|
|
1085
|
+
used: s.spaceUsedSize,
|
|
1086
|
+
available: s.spaceAvailableSize,
|
|
1087
|
+
}),
|
|
1088
|
+
activeResources: {
|
|
1089
|
+
let byType = Dict.make()
|
|
1090
|
+
NodeJs.Process.getActiveResourcesInfo()->Array.forEach(resource =>
|
|
1091
|
+
byType->Dict.set(
|
|
1092
|
+
resource,
|
|
1093
|
+
byType->Utils.Dict.dangerouslyGetNonOption(resource)->Option.getOr(0.) +. 1.,
|
|
1094
|
+
)
|
|
1095
|
+
)
|
|
1096
|
+
byType->Dict.toArray
|
|
1097
|
+
},
|
|
1098
|
+
gc: gcStats
|
|
1099
|
+
->Dict.toArray
|
|
1100
|
+
->Array.map(((kind, stat)) => {kind, count: stat.count, seconds: stat.seconds}),
|
|
1101
|
+
nodeVersion: NodeJs.Process.version,
|
|
1102
|
+
}
|
|
1103
|
+
eventLoopDelay->NodeJs.PerfHooks.reset
|
|
1104
|
+
sample
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
// Renders every sample under `scope`, the labels telling one process's readings
|
|
1108
|
+
// from another's (`worker="0"`), or "" for a run that is one process.
|
|
1109
|
+
let renderRuntime = (samples: array<(string, runtimeSample)>) => {
|
|
1110
|
+
let b = {out: ""}
|
|
1111
|
+
let labels = (scope, own) =>
|
|
1112
|
+
switch (scope, own) {
|
|
1113
|
+
| ("", "") => ""
|
|
1114
|
+
| ("", own) | (own, "") => `{${own}}`
|
|
1115
|
+
| (scope, own) => `{${scope},${own}}`
|
|
1116
|
+
}
|
|
1117
|
+
let scoped = samples->Array.map(((scope, sample)) => (labels(scope, ""), sample))
|
|
1118
|
+
let each = select =>
|
|
1119
|
+
samples->Array.flatMap(((scope, sample)) =>
|
|
1120
|
+
select(sample)->Array.map(((own, value)) => (labels(scope, own), value))
|
|
1121
|
+
)
|
|
1122
|
+
let gauge = (~name, ~help, ~value) =>
|
|
1123
|
+
b->series(~name, ~help, ~kind="gauge", ~entries=scoped, ~value)
|
|
1124
|
+
let counter = (~name, ~help, ~value) =>
|
|
1125
|
+
b->series(~name, ~help, ~kind="counter", ~entries=scoped, ~value)
|
|
1126
|
+
|
|
1127
|
+
counter(
|
|
922
1128
|
~name="process_cpu_user_seconds_total",
|
|
923
1129
|
~help="Total user CPU time spent in seconds.",
|
|
924
|
-
~
|
|
925
|
-
~value=cpu.user /. 1_000_000.,
|
|
1130
|
+
~value=s => s.cpuUserSeconds,
|
|
926
1131
|
)
|
|
927
|
-
|
|
1132
|
+
counter(
|
|
928
1133
|
~name="process_cpu_system_seconds_total",
|
|
929
1134
|
~help="Total system CPU time spent in seconds.",
|
|
930
|
-
~
|
|
931
|
-
~value=cpu.system /. 1_000_000.,
|
|
1135
|
+
~value=s => s.cpuSystemSeconds,
|
|
932
1136
|
)
|
|
933
|
-
|
|
1137
|
+
counter(
|
|
934
1138
|
~name="process_cpu_seconds_total",
|
|
935
1139
|
~help="Total user and system CPU time spent in seconds.",
|
|
936
|
-
~
|
|
937
|
-
~value=(cpu.user +. cpu.system) /. 1_000_000.,
|
|
1140
|
+
~value=s => s.cpuUserSeconds +. s.cpuSystemSeconds,
|
|
938
1141
|
)
|
|
939
|
-
|
|
1142
|
+
gauge(
|
|
940
1143
|
~name="process_start_time_seconds",
|
|
941
1144
|
~help="Start time of the process since unix epoch in seconds.",
|
|
942
|
-
~
|
|
943
|
-
~value=processStartTimeSeconds,
|
|
1145
|
+
~value=s => s.processStartTimeSeconds,
|
|
944
1146
|
)
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
~help="Resident memory size in bytes.",
|
|
948
|
-
~kind="gauge",
|
|
949
|
-
~value=memory.rss,
|
|
1147
|
+
gauge(~name="process_resident_memory_bytes", ~help="Resident memory size in bytes.", ~value=s =>
|
|
1148
|
+
s.residentMemoryBytes
|
|
950
1149
|
)
|
|
951
|
-
|
|
1150
|
+
gauge(
|
|
952
1151
|
~name="nodejs_heap_size_total_bytes",
|
|
953
1152
|
~help="Process heap size from Node.js in bytes.",
|
|
954
|
-
~
|
|
955
|
-
~value=memory.heapTotal,
|
|
1153
|
+
~value=s => s.heapTotalBytes,
|
|
956
1154
|
)
|
|
957
|
-
|
|
1155
|
+
gauge(
|
|
958
1156
|
~name="nodejs_heap_size_used_bytes",
|
|
959
1157
|
~help="Process heap size used from Node.js in bytes.",
|
|
960
|
-
~
|
|
961
|
-
~value=memory.heapUsed,
|
|
1158
|
+
~value=s => s.heapUsedBytes,
|
|
962
1159
|
)
|
|
963
|
-
|
|
1160
|
+
gauge(
|
|
964
1161
|
~name="nodejs_external_memory_bytes",
|
|
965
1162
|
~help="Node.js external memory size in bytes.",
|
|
966
|
-
~
|
|
967
|
-
~value=memory.external_,
|
|
1163
|
+
~value=s => s.externalMemoryBytes,
|
|
968
1164
|
)
|
|
969
|
-
|
|
1165
|
+
gauge(
|
|
970
1166
|
~name="nodejs_eventloop_utilization",
|
|
971
1167
|
~help="Ratio of time the event loop is active, since process start.",
|
|
972
|
-
~
|
|
973
|
-
~value=elu.utilization,
|
|
1168
|
+
~value=s => s.eventLoopUtilization,
|
|
974
1169
|
)
|
|
975
|
-
|
|
976
|
-
// the delay distribution since the previous one, matching prom-client. With
|
|
977
|
-
// no samples yet (e.g. the first scrape, which starts the sampler) the
|
|
978
|
-
// histogram reports NaN means and a sentinel min — render 0 instead.
|
|
979
|
-
let hasLagSamples = eventLoopDelay.max > 0.
|
|
980
|
-
let nsToSeconds = ns => hasLagSamples && !(ns->Float.isNaN) ? ns /. 1_000_000_000. : 0.
|
|
981
|
-
b->single(
|
|
1170
|
+
gauge(
|
|
982
1171
|
~name="nodejs_eventloop_lag_mean_seconds",
|
|
983
1172
|
~help="The mean of the recorded event loop delays.",
|
|
984
|
-
~
|
|
985
|
-
~value=eventLoopDelay.mean->nsToSeconds,
|
|
1173
|
+
~value=s => s.eventLoopLagMeanSeconds,
|
|
986
1174
|
)
|
|
987
|
-
|
|
1175
|
+
gauge(
|
|
988
1176
|
~name="nodejs_eventloop_lag_min_seconds",
|
|
989
1177
|
~help="The minimum recorded event loop delay.",
|
|
990
|
-
~
|
|
991
|
-
~value=eventLoopDelay.min->nsToSeconds,
|
|
1178
|
+
~value=s => s.eventLoopLagMinSeconds,
|
|
992
1179
|
)
|
|
993
|
-
|
|
1180
|
+
gauge(
|
|
994
1181
|
~name="nodejs_eventloop_lag_max_seconds",
|
|
995
1182
|
~help="The maximum recorded event loop delay.",
|
|
996
|
-
~
|
|
997
|
-
~value=eventLoopDelay.max->nsToSeconds,
|
|
1183
|
+
~value=s => s.eventLoopLagMaxSeconds,
|
|
998
1184
|
)
|
|
999
|
-
|
|
1185
|
+
gauge(
|
|
1000
1186
|
~name="nodejs_eventloop_lag_stddev_seconds",
|
|
1001
1187
|
~help="The standard deviation of the recorded event loop delays.",
|
|
1002
|
-
~
|
|
1003
|
-
~value=eventLoopDelay.stddev->nsToSeconds,
|
|
1188
|
+
~value=s => s.eventLoopLagStddevSeconds,
|
|
1004
1189
|
)
|
|
1005
|
-
|
|
1190
|
+
gauge(
|
|
1006
1191
|
~name="nodejs_eventloop_lag_p50_seconds",
|
|
1007
1192
|
~help="The 50th percentile of the recorded event loop delays.",
|
|
1008
|
-
~
|
|
1009
|
-
~value=eventLoopDelay->NodeJs.PerfHooks.percentile(50)->nsToSeconds,
|
|
1193
|
+
~value=s => s.eventLoopLagP50Seconds,
|
|
1010
1194
|
)
|
|
1011
|
-
|
|
1195
|
+
gauge(
|
|
1012
1196
|
~name="nodejs_eventloop_lag_p90_seconds",
|
|
1013
1197
|
~help="The 90th percentile of the recorded event loop delays.",
|
|
1014
|
-
~
|
|
1015
|
-
~value=eventLoopDelay->NodeJs.PerfHooks.percentile(90)->nsToSeconds,
|
|
1198
|
+
~value=s => s.eventLoopLagP90Seconds,
|
|
1016
1199
|
)
|
|
1017
|
-
|
|
1200
|
+
gauge(
|
|
1018
1201
|
~name="nodejs_eventloop_lag_p99_seconds",
|
|
1019
1202
|
~help="The 99th percentile of the recorded event loop delays.",
|
|
1020
|
-
~
|
|
1021
|
-
~value=eventLoopDelay->NodeJs.PerfHooks.percentile(99)->nsToSeconds,
|
|
1203
|
+
~value=s => s.eventLoopLagP99Seconds,
|
|
1022
1204
|
)
|
|
1023
|
-
|
|
1024
|
-
let heapSpaces =
|
|
1025
|
-
NodeJs.V8.getHeapSpaceStatistics()->Array.map(s => (
|
|
1026
|
-
`{space="${s.spaceName->String.replace("_space", "")}"}`,
|
|
1027
|
-
s,
|
|
1028
|
-
))
|
|
1205
|
+
|
|
1206
|
+
let heapSpaces = each(s => s.heapSpaces->Array.map(h => (`space="${h.space}"`, h)))
|
|
1029
1207
|
b->series(
|
|
1030
1208
|
~name="nodejs_heap_space_size_total_bytes",
|
|
1031
1209
|
~help="Process heap space size total from Node.js in bytes.",
|
|
1032
1210
|
~kind="gauge",
|
|
1033
1211
|
~entries=heapSpaces,
|
|
1034
|
-
~value=
|
|
1212
|
+
~value=h => h.size,
|
|
1035
1213
|
)
|
|
1036
1214
|
b->series(
|
|
1037
1215
|
~name="nodejs_heap_space_size_used_bytes",
|
|
1038
1216
|
~help="Process heap space size used from Node.js in bytes.",
|
|
1039
1217
|
~kind="gauge",
|
|
1040
1218
|
~entries=heapSpaces,
|
|
1041
|
-
~value=
|
|
1219
|
+
~value=h => h.used,
|
|
1042
1220
|
)
|
|
1043
1221
|
b->series(
|
|
1044
1222
|
~name="nodejs_heap_space_size_available_bytes",
|
|
1045
1223
|
~help="Process heap space size available from Node.js in bytes.",
|
|
1046
1224
|
~kind="gauge",
|
|
1047
1225
|
~entries=heapSpaces,
|
|
1048
|
-
~value=
|
|
1049
|
-
)
|
|
1050
|
-
|
|
1051
|
-
let byType = Dict.make()
|
|
1052
|
-
NodeJs.Process.getActiveResourcesInfo()->Array.forEach(resource => {
|
|
1053
|
-
let label = `{type="${resource->escapeLabelValue}"}`
|
|
1054
|
-
byType->Dict.set(
|
|
1055
|
-
label,
|
|
1056
|
-
byType->Utils.Dict.dangerouslyGetNonOption(label)->Option.getOr(0.) +. 1.,
|
|
1057
|
-
)
|
|
1058
|
-
})
|
|
1059
|
-
byType->Dict.toArray
|
|
1060
|
-
}
|
|
1226
|
+
~value=h => h.available,
|
|
1227
|
+
)
|
|
1228
|
+
|
|
1061
1229
|
b->series(
|
|
1062
1230
|
~name="nodejs_active_resources",
|
|
1063
1231
|
~help="Number of active resources that are currently keeping the event loop alive, grouped by async resource type.",
|
|
1064
1232
|
~kind="gauge",
|
|
1065
|
-
~entries=
|
|
1233
|
+
~entries=each(s =>
|
|
1234
|
+
s.activeResources->Array.map(
|
|
1235
|
+
((resource, count)) => (`type="${resource->escapeLabelValue}"`, count),
|
|
1236
|
+
)
|
|
1237
|
+
),
|
|
1066
1238
|
~value=count => count,
|
|
1067
1239
|
)
|
|
1068
|
-
|
|
1240
|
+
gauge(
|
|
1069
1241
|
~name="nodejs_active_resources_total",
|
|
1070
1242
|
~help="Total number of active resources.",
|
|
1071
|
-
~
|
|
1072
|
-
~value=activeResources->Array.reduce(0., (acc, (_, count)) => acc +. count),
|
|
1073
|
-
)
|
|
1074
|
-
let gcEntries = []
|
|
1075
|
-
gcStats->Utils.Dict.forEachWithKey((stat, kind) =>
|
|
1076
|
-
gcEntries->Array.push((`{kind="${kind}"}`, stat))
|
|
1243
|
+
~value=s => s.activeResources->Array.reduce(0., (acc, (_, count)) => acc +. count),
|
|
1077
1244
|
)
|
|
1245
|
+
|
|
1246
|
+
let gc = each(s => s.gc->Array.map(g => (`kind="${g.kind}"`, g)))
|
|
1078
1247
|
b->series(
|
|
1079
1248
|
~name="nodejs_gc_duration_seconds_sum",
|
|
1080
1249
|
~help="Cumulative garbage collection pause time by kind, one of major, minor, incremental or weakcb.",
|
|
1081
1250
|
~kind="counter",
|
|
1082
|
-
~entries=
|
|
1083
|
-
~value=
|
|
1251
|
+
~entries=gc,
|
|
1252
|
+
~value=g => g.seconds,
|
|
1084
1253
|
)
|
|
1085
1254
|
b->series(
|
|
1086
1255
|
~name="nodejs_gc_duration_seconds_count",
|
|
1087
1256
|
~help="Number of garbage collection pauses by kind, one of major, minor, incremental or weakcb.",
|
|
1088
1257
|
~kind="counter",
|
|
1089
|
-
~entries=
|
|
1090
|
-
~value=
|
|
1258
|
+
~entries=gc,
|
|
1259
|
+
~value=g => g.count,
|
|
1091
1260
|
)
|
|
1092
|
-
|
|
1093
|
-
let versionParts = version->String.replace("v", "")->String.split(".")
|
|
1094
|
-
let versionPart = i => versionParts->Array.get(i)->Option.getOr("0")
|
|
1261
|
+
|
|
1095
1262
|
b->series(
|
|
1096
1263
|
~name="nodejs_version_info",
|
|
1097
1264
|
~help="Node.js version info.",
|
|
1098
1265
|
~kind="gauge",
|
|
1099
|
-
~entries=
|
|
1100
|
-
(
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
(),
|
|
1105
|
-
),
|
|
1106
|
-
],
|
|
1266
|
+
~entries=each(s => {
|
|
1267
|
+
let parts = s.nodeVersion->String.replace("v", "")->String.split(".")
|
|
1268
|
+
let part = i => parts->Array.get(i)->Option.getOr("0")
|
|
1269
|
+
[(`version="${s.nodeVersion}",major="${part(0)}",minor="${part(1)}",patch="${part(2)}"`, ())]
|
|
1270
|
+
}),
|
|
1107
1271
|
~value=() => 1.,
|
|
1108
1272
|
)
|
|
1109
1273
|
b.out ++ "\n"
|
|
1110
1274
|
}
|
|
1275
|
+
|
|
1276
|
+
let collectRuntime = () => renderRuntime([("", sampleRuntime())])
|