envio 3.12.0 → 3.13.0-alpha.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 -6
- package/src/BatchProcessing.res +9 -9
- package/src/BatchProcessing.res.mjs +5 -5
- package/src/Bin.res +24 -17
- package/src/Bin.res.mjs +5 -0
- package/src/ChainFetching.res +31 -13
- package/src/ChainFetching.res.mjs +9 -4
- package/src/ChainState.res +55 -3
- package/src/ChainState.res.mjs +46 -3
- package/src/ChainState.resi +3 -1
- package/src/Config.res +35 -0
- package/src/Config.res.mjs +39 -0
- package/src/Core.res +4 -0
- package/src/Core.res.mjs +4 -0
- package/src/CrossChainState.res +61 -4
- package/src/CrossChainState.res.mjs +39 -5
- package/src/CrossChainState.resi +10 -1
- package/src/Env.res +4 -0
- package/src/FetchState.res +51 -46
- package/src/FetchState.res.mjs +54 -36
- package/src/InMemoryTable.res +155 -67
- package/src/InMemoryTable.res.mjs +151 -60
- package/src/IndexerLoop.res +2 -0
- package/src/IndexerLoop.res.mjs +1 -0
- package/src/IndexerState.res +41 -1
- package/src/IndexerState.res.mjs +43 -4
- package/src/IndexerState.resi +10 -0
- package/src/LoadLayer.res +57 -34
- package/src/LoadLayer.res.mjs +45 -62
- package/src/LoadLayer.resi +1 -1
- package/src/Logging.res +38 -6
- package/src/Logging.res.mjs +32 -5
- package/src/Main.res +131 -268
- package/src/Main.res.mjs +28 -152
- package/src/Metrics.res +263 -102
- package/src/Metrics.res.mjs +227 -48
- package/src/Persistence.res +27 -2
- package/src/Persistence.res.mjs +9 -2
- package/src/PgStorage.res +109 -71
- package/src/PgStorage.res.mjs +88 -58
- package/src/Server.res +181 -0
- package/src/Server.res.mjs +143 -0
- package/src/Supervisor.res +415 -0
- package/src/Supervisor.res.mjs +325 -0
- package/src/TestIndexer.res +9 -25
- package/src/TestIndexer.res.mjs +5 -4
- package/src/UserContext.res +13 -32
- package/src/UserContext.res.mjs +1 -7
- package/src/Utils.res +1 -4
- package/src/Utils.res.mjs +7 -16
- package/src/Worker.res +95 -0
- package/src/Worker.res.mjs +80 -0
- package/src/bindings/NodeJs.res +41 -0
- package/src/db/EntityFilter.res +487 -275
- package/src/db/EntityFilter.res.mjs +557 -309
- package/src/db/InternalTable.res +8 -1
- package/src/db/InternalTable.res.mjs +5 -1
- package/src/db/Table.res +21 -6
- package/src/db/Table.res.mjs +13 -4
- package/src/sources/BlockStore.res +7 -2
- package/src/sources/EvmHyperSyncSource.res +2 -0
- package/src/sources/EvmHyperSyncSource.res.mjs +2 -2
- package/src/sources/FuelHyperSyncSource.res +1 -0
- package/src/sources/FuelHyperSyncSource.res.mjs +1 -1
- package/src/sources/HyperSync.res +4 -0
- package/src/sources/HyperSync.res.mjs +4 -2
- package/src/sources/HyperSync.resi +1 -0
- package/src/sources/HyperSyncClient.res +3 -0
- package/src/sources/HyperSyncSSE.res +1 -1
- package/src/sources/HyperSyncSSE.res.mjs +4 -10
- package/src/sources/RpcSource.res +1 -0
- package/src/sources/RpcSource.res.mjs +1 -1
- package/src/sources/SimulateSource.res +1 -0
- package/src/sources/SimulateSource.res.mjs +1 -1
- package/src/sources/Source.res +7 -0
- package/src/sources/SourceManager.res +4 -3
- package/src/sources/SourceManager.res.mjs +2 -2
- package/src/sources/SvmHyperSyncClient.res +5 -0
- package/src/sources/SvmHyperSyncSource.res +3 -0
- package/src/sources/SvmHyperSyncSource.res.mjs +4 -2
- package/src/tui/Tui.res +24 -0
- package/src/tui/Tui.res.mjs +18 -0
- package/src/tui/components/SyncETA.res +12 -6
- package/src/tui/components/SyncETA.res.mjs +12 -8
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,110 @@ 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 is the caller's: it belongs to the group, not to any worker.
|
|
178
|
+
let merge = (snapshots: array<t>, ~startTime, ~metricTime, ~elapsedSeconds) => {
|
|
179
|
+
let concat = select => snapshots->Array.flatMap(select)
|
|
180
|
+
let sumInt = select => snapshots->Array.reduce(0, (acc, snapshot) => acc + snapshot->select)
|
|
181
|
+
let sumFloat = select => snapshots->Array.reduce(0., (acc, snapshot) => acc +. snapshot->select)
|
|
182
|
+
|
|
183
|
+
{
|
|
184
|
+
startTime,
|
|
185
|
+
metricTime,
|
|
186
|
+
elapsedSeconds,
|
|
187
|
+
targetBufferSize: sumInt(s => s.targetBufferSize),
|
|
188
|
+
isInReorgThreshold: snapshots->Array.some(s => s.isInReorgThreshold),
|
|
189
|
+
// The run has arrived only once every process has: one still backfilling
|
|
190
|
+
// speaks for the whole indexer.
|
|
191
|
+
hasArrivedAtHead: snapshots->Utils.Array.notEmpty &&
|
|
192
|
+
snapshots->Array.every(s => s.hasArrivedAtHead),
|
|
193
|
+
rollbackEnabled: snapshots->Array.some(s => s.rollbackEnabled),
|
|
194
|
+
maxBatchSize: snapshots->Array.reduce(0, (acc, s) => Pervasives.max(acc, s.maxBatchSize)),
|
|
195
|
+
preloadSeconds: sumFloat(s => s.preloadSeconds),
|
|
196
|
+
processingSeconds: sumFloat(s => s.processingSeconds),
|
|
197
|
+
processingStalledOnFetchSeconds: sumFloat(s => s.processingStalledOnFetchSeconds),
|
|
198
|
+
processingStalledOnStorageWriteSeconds: sumFloat(s => s.processingStalledOnStorageWriteSeconds),
|
|
199
|
+
rollbackSeconds: sumFloat(s => s.rollbackSeconds),
|
|
200
|
+
rollbackCount: sumInt(s => s.rollbackCount),
|
|
201
|
+
rollbackEventsCount: sumFloat(s => s.rollbackEventsCount),
|
|
202
|
+
chains: concat(s => s.chains),
|
|
203
|
+
sourceRequests: concat(s => s.sourceRequests),
|
|
204
|
+
sourceHeights: concat(s => s.sourceHeights),
|
|
205
|
+
sourceHeightStreams: concat(s => s.sourceHeightStreams),
|
|
206
|
+
handlers: concat(s => s.handlers)->sumByKey(
|
|
207
|
+
~key=h => `${h.contract}.${h.event}`,
|
|
208
|
+
~add=(a, b) => {
|
|
209
|
+
...a,
|
|
210
|
+
processingSeconds: a.processingSeconds +. b.processingSeconds,
|
|
211
|
+
processingCount: a.processingCount +. b.processingCount,
|
|
212
|
+
preloadSeconds: a.preloadSeconds +. b.preloadSeconds,
|
|
213
|
+
preloadCount: a.preloadCount +. b.preloadCount,
|
|
214
|
+
preloadSecondsTotal: a.preloadSecondsTotal +. b.preloadSecondsTotal,
|
|
215
|
+
},
|
|
216
|
+
),
|
|
217
|
+
effects: concat(s => s.effects)->sumByKey(
|
|
218
|
+
~key=e => `${e.effect}.${e.scope}`,
|
|
219
|
+
~add=(a, b) => {
|
|
220
|
+
...a,
|
|
221
|
+
callSeconds: a.callSeconds +. b.callSeconds,
|
|
222
|
+
callSecondsTotal: a.callSecondsTotal +. b.callSecondsTotal,
|
|
223
|
+
callCount: a.callCount +. b.callCount,
|
|
224
|
+
activeCallsCount: a.activeCallsCount + b.activeCallsCount,
|
|
225
|
+
queueCount: a.queueCount + b.queueCount,
|
|
226
|
+
queueWaitSeconds: a.queueWaitSeconds +. b.queueWaitSeconds,
|
|
227
|
+
invalidationsCount: a.invalidationsCount +. b.invalidationsCount,
|
|
228
|
+
// An effect's cache rows are per chain, so worker counts are disjoint.
|
|
229
|
+
// Absent unless some worker persists the cache at all.
|
|
230
|
+
cacheCount: switch (a.cacheCount, b.cacheCount) {
|
|
231
|
+
| (Some(x), Some(y)) => Some(x + y)
|
|
232
|
+
| (Some(x), None) => Some(x)
|
|
233
|
+
| (None, y) => y
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
),
|
|
237
|
+
storageLoads: concat(s => s.storageLoads)->sumByKey(
|
|
238
|
+
~key=l => `${l.storage}.${l.operation}`,
|
|
239
|
+
~add=(a, b) => {
|
|
240
|
+
...a,
|
|
241
|
+
seconds: a.seconds +. b.seconds,
|
|
242
|
+
secondsTotal: a.secondsTotal +. b.secondsTotal,
|
|
243
|
+
count: a.count +. b.count,
|
|
244
|
+
whereSize: a.whereSize +. b.whereSize,
|
|
245
|
+
size: a.size +. b.size,
|
|
246
|
+
},
|
|
247
|
+
),
|
|
248
|
+
storageWrites: concat(s => s.storageWrites)->sumByKey(
|
|
249
|
+
~key=w => w.storage,
|
|
250
|
+
~add=(a, b) => {...a, seconds: a.seconds +. b.seconds, count: a.count + b.count},
|
|
251
|
+
),
|
|
252
|
+
historyPrunes: concat(s => s.historyPrunes)->sumByKey(
|
|
253
|
+
~key=p => p.entity,
|
|
254
|
+
~add=(a, b) => {...a, seconds: a.seconds +. b.seconds, count: a.count + b.count},
|
|
255
|
+
),
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
152
259
|
// Prometheus floats keep at most 3 decimals; integral values render without a
|
|
153
260
|
// fractional part.
|
|
154
261
|
@inline
|
|
@@ -912,199 +1019,253 @@ let getRuntimeCollectors = () =>
|
|
|
912
1019
|
// from the beginning of the run, not from the first scrape.
|
|
913
1020
|
let startRuntimeCollectors = () => getRuntimeCollectors()->ignore
|
|
914
1021
|
|
|
915
|
-
|
|
916
|
-
|
|
1022
|
+
type runtimeGc = {kind: string, count: float, seconds: float}
|
|
1023
|
+
type runtimeHeapSpace = {space: string, size: float, used: float, available: float}
|
|
1024
|
+
|
|
1025
|
+
// One process's runtime readings at one moment. Plain numbers, so a worker can
|
|
1026
|
+
// hand its sample to the supervisor over the fork's channel and the supervisor
|
|
1027
|
+
// can render every process's under one label set.
|
|
1028
|
+
type runtimeSample = {
|
|
1029
|
+
cpuUserSeconds: float,
|
|
1030
|
+
cpuSystemSeconds: float,
|
|
1031
|
+
processStartTimeSeconds: float,
|
|
1032
|
+
residentMemoryBytes: float,
|
|
1033
|
+
heapTotalBytes: float,
|
|
1034
|
+
heapUsedBytes: float,
|
|
1035
|
+
externalMemoryBytes: float,
|
|
1036
|
+
eventLoopUtilization: float,
|
|
1037
|
+
eventLoopLagMeanSeconds: float,
|
|
1038
|
+
eventLoopLagMinSeconds: float,
|
|
1039
|
+
eventLoopLagMaxSeconds: float,
|
|
1040
|
+
eventLoopLagStddevSeconds: float,
|
|
1041
|
+
eventLoopLagP50Seconds: float,
|
|
1042
|
+
eventLoopLagP90Seconds: float,
|
|
1043
|
+
eventLoopLagP99Seconds: float,
|
|
1044
|
+
heapSpaces: array<runtimeHeapSpace>,
|
|
1045
|
+
activeResources: array<(string, float)>,
|
|
1046
|
+
gc: array<runtimeGc>,
|
|
1047
|
+
nodeVersion: string,
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
let sampleRuntime = (): runtimeSample => {
|
|
917
1051
|
let memory = NodeJs.Process.memoryUsage()
|
|
918
1052
|
let cpu = NodeJs.Process.cpuUsage()
|
|
919
1053
|
let elu = NodeJs.PerfHooks.performance->NodeJs.PerfHooks.eventLoopUtilization
|
|
920
1054
|
let {eventLoopDelay, gcStats, processStartTimeSeconds} = getRuntimeCollectors()
|
|
921
|
-
|
|
1055
|
+
// Nanoseconds in the histogram; reset after sampling so each scrape reports
|
|
1056
|
+
// the delay distribution since the previous one, matching prom-client. With
|
|
1057
|
+
// no samples yet (e.g. the first scrape, which starts the sampler) the
|
|
1058
|
+
// histogram reports NaN means and a sentinel min — report 0 instead.
|
|
1059
|
+
let hasLagSamples = eventLoopDelay.max > 0.
|
|
1060
|
+
let nsToSeconds = ns => hasLagSamples && !(ns->Float.isNaN) ? ns /. 1_000_000_000. : 0.
|
|
1061
|
+
let sample = {
|
|
1062
|
+
cpuUserSeconds: cpu.user /. 1_000_000.,
|
|
1063
|
+
cpuSystemSeconds: cpu.system /. 1_000_000.,
|
|
1064
|
+
processStartTimeSeconds,
|
|
1065
|
+
residentMemoryBytes: memory.rss,
|
|
1066
|
+
heapTotalBytes: memory.heapTotal,
|
|
1067
|
+
heapUsedBytes: memory.heapUsed,
|
|
1068
|
+
externalMemoryBytes: memory.external_,
|
|
1069
|
+
eventLoopUtilization: elu.utilization,
|
|
1070
|
+
eventLoopLagMeanSeconds: eventLoopDelay.mean->nsToSeconds,
|
|
1071
|
+
eventLoopLagMinSeconds: eventLoopDelay.min->nsToSeconds,
|
|
1072
|
+
eventLoopLagMaxSeconds: eventLoopDelay.max->nsToSeconds,
|
|
1073
|
+
eventLoopLagStddevSeconds: eventLoopDelay.stddev->nsToSeconds,
|
|
1074
|
+
eventLoopLagP50Seconds: eventLoopDelay->NodeJs.PerfHooks.percentile(50)->nsToSeconds,
|
|
1075
|
+
eventLoopLagP90Seconds: eventLoopDelay->NodeJs.PerfHooks.percentile(90)->nsToSeconds,
|
|
1076
|
+
eventLoopLagP99Seconds: eventLoopDelay->NodeJs.PerfHooks.percentile(99)->nsToSeconds,
|
|
1077
|
+
heapSpaces: NodeJs.V8.getHeapSpaceStatistics()->Array.map(s => {
|
|
1078
|
+
space: s.spaceName->String.replace("_space", ""),
|
|
1079
|
+
size: s.spaceSize,
|
|
1080
|
+
used: s.spaceUsedSize,
|
|
1081
|
+
available: s.spaceAvailableSize,
|
|
1082
|
+
}),
|
|
1083
|
+
activeResources: {
|
|
1084
|
+
let byType = Dict.make()
|
|
1085
|
+
NodeJs.Process.getActiveResourcesInfo()->Array.forEach(resource =>
|
|
1086
|
+
byType->Dict.set(
|
|
1087
|
+
resource,
|
|
1088
|
+
byType->Utils.Dict.dangerouslyGetNonOption(resource)->Option.getOr(0.) +. 1.,
|
|
1089
|
+
)
|
|
1090
|
+
)
|
|
1091
|
+
byType->Dict.toArray
|
|
1092
|
+
},
|
|
1093
|
+
gc: gcStats
|
|
1094
|
+
->Dict.toArray
|
|
1095
|
+
->Array.map(((kind, stat)) => {kind, count: stat.count, seconds: stat.seconds}),
|
|
1096
|
+
nodeVersion: NodeJs.Process.version,
|
|
1097
|
+
}
|
|
1098
|
+
eventLoopDelay->NodeJs.PerfHooks.reset
|
|
1099
|
+
sample
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
// Renders every sample under `scope`, the labels telling one process's readings
|
|
1103
|
+
// from another's (`worker="0"`), or "" for a run that is one process.
|
|
1104
|
+
let renderRuntime = (samples: array<(string, runtimeSample)>) => {
|
|
1105
|
+
let b = {out: ""}
|
|
1106
|
+
let labels = (scope, own) =>
|
|
1107
|
+
switch (scope, own) {
|
|
1108
|
+
| ("", "") => ""
|
|
1109
|
+
| ("", own) | (own, "") => `{${own}}`
|
|
1110
|
+
| (scope, own) => `{${scope},${own}}`
|
|
1111
|
+
}
|
|
1112
|
+
let scoped = samples->Array.map(((scope, sample)) => (labels(scope, ""), sample))
|
|
1113
|
+
let each = select =>
|
|
1114
|
+
samples->Array.flatMap(((scope, sample)) =>
|
|
1115
|
+
select(sample)->Array.map(((own, value)) => (labels(scope, own), value))
|
|
1116
|
+
)
|
|
1117
|
+
let gauge = (~name, ~help, ~value) =>
|
|
1118
|
+
b->series(~name, ~help, ~kind="gauge", ~entries=scoped, ~value)
|
|
1119
|
+
let counter = (~name, ~help, ~value) =>
|
|
1120
|
+
b->series(~name, ~help, ~kind="counter", ~entries=scoped, ~value)
|
|
1121
|
+
|
|
1122
|
+
counter(
|
|
922
1123
|
~name="process_cpu_user_seconds_total",
|
|
923
1124
|
~help="Total user CPU time spent in seconds.",
|
|
924
|
-
~
|
|
925
|
-
~value=cpu.user /. 1_000_000.,
|
|
1125
|
+
~value=s => s.cpuUserSeconds,
|
|
926
1126
|
)
|
|
927
|
-
|
|
1127
|
+
counter(
|
|
928
1128
|
~name="process_cpu_system_seconds_total",
|
|
929
1129
|
~help="Total system CPU time spent in seconds.",
|
|
930
|
-
~
|
|
931
|
-
~value=cpu.system /. 1_000_000.,
|
|
1130
|
+
~value=s => s.cpuSystemSeconds,
|
|
932
1131
|
)
|
|
933
|
-
|
|
1132
|
+
counter(
|
|
934
1133
|
~name="process_cpu_seconds_total",
|
|
935
1134
|
~help="Total user and system CPU time spent in seconds.",
|
|
936
|
-
~
|
|
937
|
-
~value=(cpu.user +. cpu.system) /. 1_000_000.,
|
|
1135
|
+
~value=s => s.cpuUserSeconds +. s.cpuSystemSeconds,
|
|
938
1136
|
)
|
|
939
|
-
|
|
1137
|
+
gauge(
|
|
940
1138
|
~name="process_start_time_seconds",
|
|
941
1139
|
~help="Start time of the process since unix epoch in seconds.",
|
|
942
|
-
~
|
|
943
|
-
~value=processStartTimeSeconds,
|
|
1140
|
+
~value=s => s.processStartTimeSeconds,
|
|
944
1141
|
)
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
~help="Resident memory size in bytes.",
|
|
948
|
-
~kind="gauge",
|
|
949
|
-
~value=memory.rss,
|
|
1142
|
+
gauge(~name="process_resident_memory_bytes", ~help="Resident memory size in bytes.", ~value=s =>
|
|
1143
|
+
s.residentMemoryBytes
|
|
950
1144
|
)
|
|
951
|
-
|
|
1145
|
+
gauge(
|
|
952
1146
|
~name="nodejs_heap_size_total_bytes",
|
|
953
1147
|
~help="Process heap size from Node.js in bytes.",
|
|
954
|
-
~
|
|
955
|
-
~value=memory.heapTotal,
|
|
1148
|
+
~value=s => s.heapTotalBytes,
|
|
956
1149
|
)
|
|
957
|
-
|
|
1150
|
+
gauge(
|
|
958
1151
|
~name="nodejs_heap_size_used_bytes",
|
|
959
1152
|
~help="Process heap size used from Node.js in bytes.",
|
|
960
|
-
~
|
|
961
|
-
~value=memory.heapUsed,
|
|
1153
|
+
~value=s => s.heapUsedBytes,
|
|
962
1154
|
)
|
|
963
|
-
|
|
1155
|
+
gauge(
|
|
964
1156
|
~name="nodejs_external_memory_bytes",
|
|
965
1157
|
~help="Node.js external memory size in bytes.",
|
|
966
|
-
~
|
|
967
|
-
~value=memory.external_,
|
|
1158
|
+
~value=s => s.externalMemoryBytes,
|
|
968
1159
|
)
|
|
969
|
-
|
|
1160
|
+
gauge(
|
|
970
1161
|
~name="nodejs_eventloop_utilization",
|
|
971
1162
|
~help="Ratio of time the event loop is active, since process start.",
|
|
972
|
-
~
|
|
973
|
-
~value=elu.utilization,
|
|
1163
|
+
~value=s => s.eventLoopUtilization,
|
|
974
1164
|
)
|
|
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(
|
|
1165
|
+
gauge(
|
|
982
1166
|
~name="nodejs_eventloop_lag_mean_seconds",
|
|
983
1167
|
~help="The mean of the recorded event loop delays.",
|
|
984
|
-
~
|
|
985
|
-
~value=eventLoopDelay.mean->nsToSeconds,
|
|
1168
|
+
~value=s => s.eventLoopLagMeanSeconds,
|
|
986
1169
|
)
|
|
987
|
-
|
|
1170
|
+
gauge(
|
|
988
1171
|
~name="nodejs_eventloop_lag_min_seconds",
|
|
989
1172
|
~help="The minimum recorded event loop delay.",
|
|
990
|
-
~
|
|
991
|
-
~value=eventLoopDelay.min->nsToSeconds,
|
|
1173
|
+
~value=s => s.eventLoopLagMinSeconds,
|
|
992
1174
|
)
|
|
993
|
-
|
|
1175
|
+
gauge(
|
|
994
1176
|
~name="nodejs_eventloop_lag_max_seconds",
|
|
995
1177
|
~help="The maximum recorded event loop delay.",
|
|
996
|
-
~
|
|
997
|
-
~value=eventLoopDelay.max->nsToSeconds,
|
|
1178
|
+
~value=s => s.eventLoopLagMaxSeconds,
|
|
998
1179
|
)
|
|
999
|
-
|
|
1180
|
+
gauge(
|
|
1000
1181
|
~name="nodejs_eventloop_lag_stddev_seconds",
|
|
1001
1182
|
~help="The standard deviation of the recorded event loop delays.",
|
|
1002
|
-
~
|
|
1003
|
-
~value=eventLoopDelay.stddev->nsToSeconds,
|
|
1183
|
+
~value=s => s.eventLoopLagStddevSeconds,
|
|
1004
1184
|
)
|
|
1005
|
-
|
|
1185
|
+
gauge(
|
|
1006
1186
|
~name="nodejs_eventloop_lag_p50_seconds",
|
|
1007
1187
|
~help="The 50th percentile of the recorded event loop delays.",
|
|
1008
|
-
~
|
|
1009
|
-
~value=eventLoopDelay->NodeJs.PerfHooks.percentile(50)->nsToSeconds,
|
|
1188
|
+
~value=s => s.eventLoopLagP50Seconds,
|
|
1010
1189
|
)
|
|
1011
|
-
|
|
1190
|
+
gauge(
|
|
1012
1191
|
~name="nodejs_eventloop_lag_p90_seconds",
|
|
1013
1192
|
~help="The 90th percentile of the recorded event loop delays.",
|
|
1014
|
-
~
|
|
1015
|
-
~value=eventLoopDelay->NodeJs.PerfHooks.percentile(90)->nsToSeconds,
|
|
1193
|
+
~value=s => s.eventLoopLagP90Seconds,
|
|
1016
1194
|
)
|
|
1017
|
-
|
|
1195
|
+
gauge(
|
|
1018
1196
|
~name="nodejs_eventloop_lag_p99_seconds",
|
|
1019
1197
|
~help="The 99th percentile of the recorded event loop delays.",
|
|
1020
|
-
~
|
|
1021
|
-
~value=eventLoopDelay->NodeJs.PerfHooks.percentile(99)->nsToSeconds,
|
|
1198
|
+
~value=s => s.eventLoopLagP99Seconds,
|
|
1022
1199
|
)
|
|
1023
|
-
|
|
1024
|
-
let heapSpaces =
|
|
1025
|
-
NodeJs.V8.getHeapSpaceStatistics()->Array.map(s => (
|
|
1026
|
-
`{space="${s.spaceName->String.replace("_space", "")}"}`,
|
|
1027
|
-
s,
|
|
1028
|
-
))
|
|
1200
|
+
|
|
1201
|
+
let heapSpaces = each(s => s.heapSpaces->Array.map(h => (`space="${h.space}"`, h)))
|
|
1029
1202
|
b->series(
|
|
1030
1203
|
~name="nodejs_heap_space_size_total_bytes",
|
|
1031
1204
|
~help="Process heap space size total from Node.js in bytes.",
|
|
1032
1205
|
~kind="gauge",
|
|
1033
1206
|
~entries=heapSpaces,
|
|
1034
|
-
~value=
|
|
1207
|
+
~value=h => h.size,
|
|
1035
1208
|
)
|
|
1036
1209
|
b->series(
|
|
1037
1210
|
~name="nodejs_heap_space_size_used_bytes",
|
|
1038
1211
|
~help="Process heap space size used from Node.js in bytes.",
|
|
1039
1212
|
~kind="gauge",
|
|
1040
1213
|
~entries=heapSpaces,
|
|
1041
|
-
~value=
|
|
1214
|
+
~value=h => h.used,
|
|
1042
1215
|
)
|
|
1043
1216
|
b->series(
|
|
1044
1217
|
~name="nodejs_heap_space_size_available_bytes",
|
|
1045
1218
|
~help="Process heap space size available from Node.js in bytes.",
|
|
1046
1219
|
~kind="gauge",
|
|
1047
1220
|
~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
|
-
}
|
|
1221
|
+
~value=h => h.available,
|
|
1222
|
+
)
|
|
1223
|
+
|
|
1061
1224
|
b->series(
|
|
1062
1225
|
~name="nodejs_active_resources",
|
|
1063
1226
|
~help="Number of active resources that are currently keeping the event loop alive, grouped by async resource type.",
|
|
1064
1227
|
~kind="gauge",
|
|
1065
|
-
~entries=
|
|
1228
|
+
~entries=each(s =>
|
|
1229
|
+
s.activeResources->Array.map(
|
|
1230
|
+
((resource, count)) => (`type="${resource->escapeLabelValue}"`, count),
|
|
1231
|
+
)
|
|
1232
|
+
),
|
|
1066
1233
|
~value=count => count,
|
|
1067
1234
|
)
|
|
1068
|
-
|
|
1235
|
+
gauge(
|
|
1069
1236
|
~name="nodejs_active_resources_total",
|
|
1070
1237
|
~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))
|
|
1238
|
+
~value=s => s.activeResources->Array.reduce(0., (acc, (_, count)) => acc +. count),
|
|
1077
1239
|
)
|
|
1240
|
+
|
|
1241
|
+
let gc = each(s => s.gc->Array.map(g => (`kind="${g.kind}"`, g)))
|
|
1078
1242
|
b->series(
|
|
1079
1243
|
~name="nodejs_gc_duration_seconds_sum",
|
|
1080
1244
|
~help="Cumulative garbage collection pause time by kind, one of major, minor, incremental or weakcb.",
|
|
1081
1245
|
~kind="counter",
|
|
1082
|
-
~entries=
|
|
1083
|
-
~value=
|
|
1246
|
+
~entries=gc,
|
|
1247
|
+
~value=g => g.seconds,
|
|
1084
1248
|
)
|
|
1085
1249
|
b->series(
|
|
1086
1250
|
~name="nodejs_gc_duration_seconds_count",
|
|
1087
1251
|
~help="Number of garbage collection pauses by kind, one of major, minor, incremental or weakcb.",
|
|
1088
1252
|
~kind="counter",
|
|
1089
|
-
~entries=
|
|
1090
|
-
~value=
|
|
1253
|
+
~entries=gc,
|
|
1254
|
+
~value=g => g.count,
|
|
1091
1255
|
)
|
|
1092
|
-
|
|
1093
|
-
let versionParts = version->String.replace("v", "")->String.split(".")
|
|
1094
|
-
let versionPart = i => versionParts->Array.get(i)->Option.getOr("0")
|
|
1256
|
+
|
|
1095
1257
|
b->series(
|
|
1096
1258
|
~name="nodejs_version_info",
|
|
1097
1259
|
~help="Node.js version info.",
|
|
1098
1260
|
~kind="gauge",
|
|
1099
|
-
~entries=
|
|
1100
|
-
(
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
(),
|
|
1105
|
-
),
|
|
1106
|
-
],
|
|
1261
|
+
~entries=each(s => {
|
|
1262
|
+
let parts = s.nodeVersion->String.replace("v", "")->String.split(".")
|
|
1263
|
+
let part = i => parts->Array.get(i)->Option.getOr("0")
|
|
1264
|
+
[(`version="${s.nodeVersion}",major="${part(0)}",minor="${part(1)}",patch="${part(2)}"`, ())]
|
|
1265
|
+
}),
|
|
1107
1266
|
~value=() => 1.,
|
|
1108
1267
|
)
|
|
1109
1268
|
b.out ++ "\n"
|
|
1110
1269
|
}
|
|
1270
|
+
|
|
1271
|
+
let collectRuntime = () => renderRuntime([("", sampleRuntime())])
|