envio 3.3.0 → 3.3.1
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 -7
- package/src/ChainFetching.res +4 -32
- package/src/ChainFetching.res.mjs +2 -12
- package/src/ChainState.res +73 -53
- package/src/ChainState.res.mjs +61 -30
- package/src/ChainState.resi +13 -17
- package/src/Config.res +5 -0
- package/src/Config.res.mjs +1 -0
- package/src/CrossChainState.res +2 -8
- package/src/CrossChainState.res.mjs +6 -8
- package/src/CrossChainState.resi +1 -0
- package/src/EffectState.res +183 -44
- package/src/EffectState.res.mjs +134 -26
- package/src/EffectState.resi +26 -3
- package/src/EventProcessing.res +14 -9
- package/src/EventProcessing.res.mjs +7 -7
- package/src/FetchState.res +18 -29
- package/src/FetchState.res.mjs +20 -37
- package/src/IndexerState.res +280 -31
- package/src/IndexerState.res.mjs +234 -25
- package/src/IndexerState.resi +22 -0
- package/src/LoadLayer.res +19 -65
- package/src/LoadLayer.res.mjs +13 -55
- package/src/Main.res +42 -23
- package/src/Main.res.mjs +32 -35
- package/src/Metrics.res +943 -66
- package/src/Metrics.res.mjs +367 -50
- package/src/Persistence.res +3 -0
- package/src/PgStorage.res +3 -8
- package/src/PgStorage.res.mjs +3 -4
- package/src/PruneStaleHistory.res +1 -1
- package/src/PruneStaleHistory.res.mjs +1 -2
- package/src/Rollback.res +4 -5
- package/src/Rollback.res.mjs +2 -3
- package/src/SimulateItems.res.mjs +3 -21
- package/src/TestIndexer.res.mjs +4 -23
- package/src/TestIndexerProxyStorage.res +1 -0
- package/src/TestIndexerProxyStorage.res.mjs +1 -1
- package/src/Writing.res +3 -5
- package/src/Writing.res.mjs +3 -6
- package/src/bindings/ClickHouse.res +101 -17
- package/src/bindings/ClickHouse.res.mjs +58 -19
- package/src/bindings/NodeJs.res +64 -0
- package/src/bindings/NodeJs.res.mjs +6 -0
- package/src/sources/HyperSyncClient.res +5 -11
- package/src/sources/SourceManager.res +72 -27
- package/src/sources/SourceManager.res.mjs +81 -11
- package/src/sources/SourceManager.resi +14 -0
- package/src/tui/Tui.res +1 -1
- package/src/tui/Tui.res.mjs +2 -2
- package/src/Prometheus.res +0 -789
- package/src/Prometheus.res.mjs +0 -847
- package/src/bindings/PromClient.res +0 -72
- package/src/bindings/PromClient.res.mjs +0 -38
package/src/Metrics.res.mjs
CHANGED
|
@@ -1,75 +1,392 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
+
import * as V8 from "v8";
|
|
3
4
|
import * as Utils from "./Utils.res.mjs";
|
|
4
|
-
import * as
|
|
5
|
-
import * as
|
|
6
|
-
import * as
|
|
7
|
-
import * as
|
|
5
|
+
import * as Process from "process";
|
|
6
|
+
import * as Perf_hooks from "perf_hooks";
|
|
7
|
+
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
8
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
8
9
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
function formatValue(value) {
|
|
12
|
+
return (Math.round(value * 1000) / 1000).toString();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function escapeLabelValue(value) {
|
|
16
|
+
if (value.includes("\\") || value.includes("\"") || value.includes("\n")) {
|
|
17
|
+
return value.replaceAll("\\", "\\\\").replaceAll("\"", "\\\"").replaceAll("\n", "\\n");
|
|
18
|
+
} else {
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function block(b, name, help, kind) {
|
|
24
|
+
let header = `# HELP ` + name + ` ` + help + `\n# TYPE ` + name + ` ` + kind;
|
|
25
|
+
b.out = b.out === "" ? header : b.out + "\n\n" + header;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function sample(b, name, labelsOpt, value) {
|
|
29
|
+
let labels = labelsOpt !== undefined ? labelsOpt : "";
|
|
30
|
+
b.out = b.out + "\n" + name + labels + " " + (Math.round(value * 1000) / 1000).toString();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function series(b, name, help, kind, entries, value) {
|
|
34
|
+
block(b, name, help, kind);
|
|
35
|
+
for (let i = 0, i_finish = entries.length; i < i_finish; ++i) {
|
|
36
|
+
let match = entries[i];
|
|
37
|
+
sample(b, name, match[0], value(match[1]));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function seriesOpt(b, name, help, kind, entries, value) {
|
|
42
|
+
block(b, name, help, kind);
|
|
43
|
+
for (let i = 0, i_finish = entries.length; i < i_finish; ++i) {
|
|
44
|
+
let match = entries[i];
|
|
45
|
+
let value$1 = value(match[1]);
|
|
46
|
+
if (value$1 !== undefined) {
|
|
47
|
+
sample(b, name, match[0], value$1);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
11
51
|
|
|
12
|
-
|
|
52
|
+
function single(b, name, help, kind, value) {
|
|
53
|
+
block(b, name, help, kind);
|
|
54
|
+
sample(b, name, undefined, value);
|
|
55
|
+
}
|
|
13
56
|
|
|
14
|
-
function
|
|
15
|
-
let
|
|
16
|
-
|
|
57
|
+
function renderMetrics(b, metrics) {
|
|
58
|
+
let chains = metrics.chains.map(m => [
|
|
59
|
+
`{chainId="` + m.chainId.toString() + `"}`,
|
|
60
|
+
m
|
|
61
|
+
]);
|
|
62
|
+
let handlers = metrics.handlers.map(s => [
|
|
63
|
+
`{contract="` + escapeLabelValue(s.contract) + `",event="` + escapeLabelValue(s.event) + `"}`,
|
|
64
|
+
s
|
|
65
|
+
]);
|
|
66
|
+
let effects = metrics.effects.map(s => [
|
|
67
|
+
`{effect="` + escapeLabelValue(s.effect) + `",scope="` + escapeLabelValue(s.scope) + `"}`,
|
|
68
|
+
s
|
|
69
|
+
]);
|
|
70
|
+
let storageLoads = metrics.storageLoads.map(s => [
|
|
71
|
+
`{operation="` + escapeLabelValue(s.operation) + `",storage="` + escapeLabelValue(s.storage) + `"}`,
|
|
72
|
+
s
|
|
73
|
+
]);
|
|
74
|
+
let storageWrites = metrics.storageWrites.map(s => [
|
|
75
|
+
`{storage="` + escapeLabelValue(s.storage) + `"}`,
|
|
76
|
+
s
|
|
77
|
+
]);
|
|
78
|
+
let historyPrunes = metrics.historyPrunes.map(s => [
|
|
79
|
+
`{entity="` + escapeLabelValue(s.entity) + `"}`,
|
|
80
|
+
s
|
|
81
|
+
]);
|
|
82
|
+
let byLabels = {};
|
|
83
|
+
metrics.sourceRequests.forEach(s => {
|
|
84
|
+
let labels = `{source="` + escapeLabelValue(s.source) + `",chainId="` + s.chainId.toString() + `",method="` + escapeLabelValue(s.method) + `"}`;
|
|
85
|
+
let existing = byLabels[labels];
|
|
86
|
+
if (existing !== undefined) {
|
|
87
|
+
byLabels[labels] = {
|
|
88
|
+
source: existing.source,
|
|
89
|
+
chainId: existing.chainId,
|
|
90
|
+
method: existing.method,
|
|
91
|
+
count: existing.count + s.count | 0,
|
|
92
|
+
seconds: existing.seconds + s.seconds
|
|
93
|
+
};
|
|
94
|
+
} else {
|
|
95
|
+
byLabels[labels] = s;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
let sourceRequests = Object.entries(byLabels);
|
|
99
|
+
let byLabels$1 = {};
|
|
100
|
+
metrics.sourceHeights.forEach(s => {
|
|
101
|
+
let labels = `{source="` + escapeLabelValue(s.source) + `",chainId="` + s.chainId.toString() + `"}`;
|
|
102
|
+
let existing = byLabels$1[labels];
|
|
103
|
+
if (existing !== undefined && existing >= s.height) {
|
|
104
|
+
return;
|
|
105
|
+
} else {
|
|
106
|
+
byLabels$1[labels] = s.height;
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
let sources = Object.entries(byLabels$1);
|
|
111
|
+
single(b, "envio_preload_seconds", "Cumulative time spent on preloading entities during batch processing.", "counter", metrics.preloadSeconds);
|
|
112
|
+
single(b, "envio_processing_seconds", "Cumulative time spent executing event handlers during batch processing.", "counter", metrics.processingSeconds);
|
|
113
|
+
series(b, "envio_progress_ready", "Whether the chain is fully synced to the head.", "gauge", chains, m => {
|
|
114
|
+
if (m.isReady) {
|
|
115
|
+
return 1;
|
|
116
|
+
} else {
|
|
117
|
+
return 0;
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
single(b, "hyperindex_synced_to_head", "All chains fully synced", "gauge", Utils.$$Array.notEmpty(metrics.chains) && metrics.chains.every(m => m.isReady) ? 1 : 0);
|
|
121
|
+
series(b, "envio_processing_handler_seconds", "Cumulative time spent inside individual event handler executions.", "counter", handlers, s => s.processingSeconds);
|
|
122
|
+
series(b, "envio_processing_handler_total", "Total number of individual event handler executions.", "counter", handlers, s => s.processingCount);
|
|
123
|
+
series(b, "envio_preload_handler_seconds", "Wall-clock time spent inside individual preload handler executions.", "counter", handlers, s => s.preloadSeconds);
|
|
124
|
+
series(b, "envio_preload_handler_total", "Total number of individual preload handler executions.", "counter", handlers, s => s.preloadCount);
|
|
125
|
+
series(b, "envio_preload_handler_seconds_total", "Cumulative time spent inside individual preload handler executions. Can exceed wall-clock time due to parallel execution.", "counter", handlers, s => s.preloadSecondsTotal);
|
|
126
|
+
series(b, "envio_fetching_block_range_seconds", "Cumulative time spent fetching block ranges.", "counter", chains, m => m.blockRangeFetchSeconds);
|
|
127
|
+
series(b, "envio_fetching_block_range_parse_seconds", "Cumulative time spent parsing block range fetch responses.", "counter", chains, m => m.blockRangeParseSeconds);
|
|
128
|
+
series(b, "envio_fetching_block_range_total", "Total number of block range fetch operations.", "counter", chains, m => m.blockRangeFetchCount);
|
|
129
|
+
series(b, "envio_fetching_block_range_events_total", "Cumulative number of events fetched across all block range operations.", "counter", chains, m => m.blockRangeFetchedEvents);
|
|
130
|
+
series(b, "envio_fetching_block_range_size", "Cumulative number of blocks covered across all block range fetch operations.", "counter", chains, m => m.blockRangeFetchedBlocks);
|
|
131
|
+
series(b, "envio_indexing_known_height", "The latest known block number reported by the active indexing source. This value may lag behind the actual chain height, as it is updated only when needed.", "gauge", chains, m => m.sourceBlockNumber);
|
|
132
|
+
single(b, "envio_process_start_time_seconds", "Start time of the process since unix epoch in seconds.", "gauge", metrics.startTime.getTime() / 1000);
|
|
133
|
+
series(b, "envio_indexing_concurrency", "The number of executing concurrent queries to the chain data-source.", "gauge", chains, m => m.concurrency);
|
|
134
|
+
series(b, "envio_indexing_partitions", "The number of partitions used to split fetching logic by addresses and block ranges.", "gauge", chains, m => m.partitionsCount);
|
|
135
|
+
series(b, "envio_indexing_idle_seconds", "The time the indexer source syncing has been idle. A high value may indicate the source sync is a bottleneck.", "counter", chains, m => m.idleSeconds);
|
|
136
|
+
series(b, "envio_indexing_source_waiting_seconds", "The time the indexer has been waiting for new blocks.", "counter", chains, m => m.waitingForNewBlockSeconds);
|
|
137
|
+
series(b, "envio_indexing_source_querying_seconds", "The time spent performing queries to the chain data-source.", "counter", chains, m => m.queryingSeconds);
|
|
138
|
+
series(b, "envio_indexing_buffer_size", "The current number of items in the indexing buffer.", "gauge", chains, m => m.bufferSize);
|
|
139
|
+
single(b, "envio_indexing_target_buffer_size", "The indexer-wide target buffer size shared across all chains. The actual number of items in the queue may exceed this value, but the indexer always tries to keep the buffer filled up to this target.", "gauge", metrics.targetBufferSize);
|
|
140
|
+
series(b, "envio_indexing_buffer_block", "The highest block number that has been fully fetched by the indexer.", "gauge", chains, m => m.bufferBlockNumber);
|
|
141
|
+
seriesOpt(b, "envio_indexing_end_block", "The block number to stop indexing at. (inclusive)", "gauge", chains, m => Stdlib_Option.map(m.endBlock, prim => prim));
|
|
142
|
+
series(b, "envio_source_request_total", "The number of requests made to data sources.", "counter", sourceRequests, s => s.count);
|
|
143
|
+
seriesOpt(b, "envio_source_request_seconds_total", "Cumulative time spent on data source requests.", "counter", sourceRequests, s => {
|
|
144
|
+
if (s.seconds !== 0) {
|
|
145
|
+
return s.seconds;
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
series(b, "envio_source_known_height", "The latest known block number reported by the source. This value may lag behind the actual chain height, as it is updated only when queried.", "gauge", sources, height => height);
|
|
149
|
+
seriesOpt(b, "envio_reorg_detected_total", "Total number of reorgs detected", "counter", chains, m => {
|
|
150
|
+
if (m.reorgCount > 0) {
|
|
151
|
+
return m.reorgCount;
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
seriesOpt(b, "envio_reorg_detected_block", "The block number where reorg was detected the last time. This doesn't mean that the block was reorged, this is simply where we found block hash to be different.", "gauge", chains, m => Stdlib_Option.map(m.reorgDetectedBlock, prim => prim));
|
|
155
|
+
single(b, "envio_reorg_threshold", "Whether indexing is currently within the reorg threshold", "gauge", metrics.isInReorgThreshold ? 1 : 0);
|
|
156
|
+
single(b, "envio_rollback_enabled", "Whether rollback on reorg is enabled", "gauge", metrics.rollbackEnabled ? 1 : 0);
|
|
157
|
+
single(b, "envio_rollback_seconds", "Rollback on reorg total time.", "counter", metrics.rollbackSeconds);
|
|
158
|
+
single(b, "envio_rollback_total", "Number of successful rollbacks on reorg", "counter", metrics.rollbackCount);
|
|
159
|
+
single(b, "envio_rollback_events", "Number of events rollbacked on reorg", "counter", metrics.rollbackEventsCount);
|
|
160
|
+
series(b, "envio_rollback_history_prune_seconds", "The total time spent pruning entity history which is not in the reorg threshold.", "counter", historyPrunes, s => s.seconds);
|
|
161
|
+
series(b, "envio_rollback_history_prune_total", "Number of successful entity history prunes", "counter", historyPrunes, s => s.count);
|
|
162
|
+
seriesOpt(b, "envio_rollback_target_block", "The block number reorg was rollbacked to the last time.", "gauge", chains, m => Stdlib_Option.map(m.rollbackTargetBlock, prim => prim));
|
|
163
|
+
single(b, "envio_processing_max_batch_size", "The maximum number of items to process in a single batch.", "gauge", metrics.maxBatchSize);
|
|
164
|
+
series(b, "envio_progress_block", "The block number of the latest block processed and stored in the database.", "gauge", chains, m => m.progressBlockNumber);
|
|
165
|
+
series(b, "envio_progress_events", "The number of events processed and reflected in the database.", "gauge", chains, m => m.numEventsProcessed);
|
|
166
|
+
seriesOpt(b, "envio_progress_latency", "The latency in milliseconds between the latest processed event creation and the time it was written to storage.", "gauge", chains, m => Stdlib_Option.map(m.progressLatencyMs, prim => prim));
|
|
167
|
+
let ifCalled = (s, value) => {
|
|
168
|
+
if (s.callCount > 0 || s.activeCallsCount > 0) {
|
|
169
|
+
return Primitive_option.some(value);
|
|
170
|
+
}
|
|
17
171
|
};
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
172
|
+
seriesOpt(b, "envio_effect_call_seconds", "Processing time taken to call the Effect function.", "counter", effects, s => ifCalled(s, s.callSeconds));
|
|
173
|
+
seriesOpt(b, "envio_effect_call_seconds_total", "Cumulative time spent calling the Effect function during the indexing process.", "counter", effects, s => ifCalled(s, s.callSecondsTotal));
|
|
174
|
+
seriesOpt(b, "envio_effect_call_total", "Cumulative number of resolved Effect function calls during the indexing process.", "counter", effects, s => ifCalled(s, s.callCount));
|
|
175
|
+
seriesOpt(b, "envio_effect_active_calls", "The number of Effect function calls that are currently running.", "gauge", effects, s => ifCalled(s, s.activeCallsCount));
|
|
176
|
+
seriesOpt(b, "envio_effect_cache", "The number of items in the effect cache.", "gauge", effects, s => Stdlib_Option.map(s.cacheCount, prim => prim));
|
|
177
|
+
let byEffect = {};
|
|
178
|
+
metrics.effects.forEach(s => {
|
|
179
|
+
let match = byEffect[s.effect];
|
|
180
|
+
if (match !== undefined) {
|
|
181
|
+
byEffect[s.effect] = [
|
|
182
|
+
match[0] + s.invalidationsCount,
|
|
183
|
+
match[1] + s.queueWaitSeconds
|
|
184
|
+
];
|
|
185
|
+
} else {
|
|
186
|
+
byEffect[s.effect] = [
|
|
187
|
+
s.invalidationsCount,
|
|
188
|
+
s.queueWaitSeconds
|
|
189
|
+
];
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
let entries = [];
|
|
193
|
+
Utils.Dict.forEachWithKey(byEffect, (totals, effect) => {
|
|
194
|
+
entries.push([
|
|
195
|
+
`{effect="` + escapeLabelValue(effect) + `"}`,
|
|
196
|
+
totals
|
|
197
|
+
]);
|
|
198
|
+
});
|
|
199
|
+
seriesOpt(b, "envio_effect_cache_invalidations", "The number of effect cache invalidations.", "counter", entries, param => {
|
|
200
|
+
let invalidations = param[0];
|
|
201
|
+
if (invalidations > 0) {
|
|
202
|
+
return invalidations;
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
seriesOpt(b, "envio_effect_queue", "The number of effect calls waiting in the rate limit queue.", "gauge", effects, s => {
|
|
206
|
+
if (s.queueCount > 0 || s.queueWaitSeconds > 0) {
|
|
207
|
+
return s.queueCount;
|
|
208
|
+
}
|
|
21
209
|
});
|
|
22
|
-
|
|
210
|
+
seriesOpt(b, "envio_effect_queue_wait_seconds", "The time spent waiting in the rate limit queue.", "counter", entries, param => {
|
|
211
|
+
let queueWaitSeconds = param[1];
|
|
212
|
+
if (queueWaitSeconds !== 0) {
|
|
213
|
+
return queueWaitSeconds;
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
series(b, "envio_storage_load_seconds", "Processing time taken to load data from storage.", "counter", storageLoads, s => s.seconds);
|
|
217
|
+
series(b, "envio_storage_load_seconds_total", "Cumulative time spent loading data from storage during the indexing process.", "counter", storageLoads, s => s.secondsTotal);
|
|
218
|
+
series(b, "envio_storage_load_total", "Cumulative number of successful storage load operations during the indexing process.", "counter", storageLoads, s => s.count);
|
|
219
|
+
series(b, "envio_storage_load_where_size", "Cumulative number of filter conditions ('where' items) used in storage load operations during the indexing process.", "counter", storageLoads, s => s.whereSize);
|
|
220
|
+
series(b, "envio_storage_load_size", "Cumulative number of records loaded from storage during the indexing process.", "counter", storageLoads, s => s.size);
|
|
221
|
+
series(b, "envio_storage_write_seconds", "Cumulative time spent writing batch data to storage.", "counter", storageWrites, s => s.seconds);
|
|
222
|
+
series(b, "envio_storage_write_total", "Cumulative number of successful storage write operations during the indexing process.", "counter", storageWrites, s => s.count);
|
|
223
|
+
series(b, "envio_indexing_addresses", "The number of addresses indexed on chain. Includes both static and dynamic addresses.", "gauge", chains, m => m.numAddresses);
|
|
23
224
|
}
|
|
24
225
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
226
|
+
function collect(metrics) {
|
|
227
|
+
let b = {
|
|
228
|
+
out: ""
|
|
229
|
+
};
|
|
230
|
+
series(b, "envio_info", "Information about the indexer", "gauge", [[
|
|
231
|
+
`{version="` + escapeLabelValue(Utils.EnvioPackage.value.version) + `"}`,
|
|
232
|
+
undefined
|
|
233
|
+
]], () => 1);
|
|
234
|
+
if (metrics !== undefined) {
|
|
235
|
+
renderMetrics(b, metrics);
|
|
236
|
+
}
|
|
237
|
+
return b.out + "\n";
|
|
238
|
+
}
|
|
28
239
|
|
|
29
|
-
|
|
240
|
+
function gcKindName(kind) {
|
|
241
|
+
switch (kind) {
|
|
242
|
+
case 1 :
|
|
243
|
+
return "minor";
|
|
244
|
+
case 4 :
|
|
245
|
+
return "major";
|
|
246
|
+
case 8 :
|
|
247
|
+
return "incremental";
|
|
248
|
+
case 16 :
|
|
249
|
+
return "weakcb";
|
|
250
|
+
default:
|
|
251
|
+
return "unknown";
|
|
252
|
+
}
|
|
253
|
+
}
|
|
30
254
|
|
|
31
|
-
let
|
|
255
|
+
let runtimeCollectors = {
|
|
256
|
+
contents: undefined
|
|
257
|
+
};
|
|
32
258
|
|
|
33
|
-
function
|
|
34
|
-
|
|
35
|
-
|
|
259
|
+
function getRuntimeCollectors() {
|
|
260
|
+
let collectors = runtimeCollectors.contents;
|
|
261
|
+
if (collectors !== undefined) {
|
|
262
|
+
return collectors;
|
|
36
263
|
}
|
|
37
|
-
let
|
|
38
|
-
|
|
264
|
+
let eventLoopDelay = Perf_hooks.monitorEventLoopDelay({
|
|
265
|
+
resolution: 10
|
|
266
|
+
});
|
|
267
|
+
eventLoopDelay.enable();
|
|
268
|
+
let gcStats = {};
|
|
269
|
+
let observer = new Perf_hooks.PerformanceObserver(list => {
|
|
270
|
+
list.getEntries().forEach(entry => {
|
|
271
|
+
let kind = gcKindName(entry.detail.kind);
|
|
272
|
+
let stat = gcStats[kind];
|
|
273
|
+
let stat$1;
|
|
274
|
+
if (stat !== undefined) {
|
|
275
|
+
stat$1 = stat;
|
|
276
|
+
} else {
|
|
277
|
+
let stat$2 = {
|
|
278
|
+
count: 0,
|
|
279
|
+
seconds: 0
|
|
280
|
+
};
|
|
281
|
+
gcStats[kind] = stat$2;
|
|
282
|
+
stat$1 = stat$2;
|
|
283
|
+
}
|
|
284
|
+
stat$1.count = stat$1.count + 1;
|
|
285
|
+
stat$1.seconds = stat$1.seconds + entry.duration / 1000;
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
observer.observe({
|
|
289
|
+
entryTypes: ["gc"]
|
|
290
|
+
});
|
|
291
|
+
let collectors_processStartTimeSeconds = Date.now() / 1000 - Process.uptime();
|
|
292
|
+
let collectors$1 = {
|
|
293
|
+
eventLoopDelay: eventLoopDelay,
|
|
294
|
+
gcStats: gcStats,
|
|
295
|
+
processStartTimeSeconds: collectors_processStartTimeSeconds
|
|
39
296
|
};
|
|
40
|
-
|
|
41
|
-
|
|
297
|
+
runtimeCollectors.contents = collectors$1;
|
|
298
|
+
return collectors$1;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function startRuntimeCollectors() {
|
|
302
|
+
getRuntimeCollectors();
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function collectRuntime() {
|
|
306
|
+
let b = {
|
|
307
|
+
out: ""
|
|
42
308
|
};
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
309
|
+
let memory = Process.memoryUsage();
|
|
310
|
+
let cpu = Process.cpuUsage();
|
|
311
|
+
let elu = Perf_hooks.performance.eventLoopUtilization();
|
|
312
|
+
let match = getRuntimeCollectors();
|
|
313
|
+
let eventLoopDelay = match.eventLoopDelay;
|
|
314
|
+
single(b, "process_cpu_user_seconds_total", "Total user CPU time spent in seconds.", "counter", cpu.user / 1000000);
|
|
315
|
+
single(b, "process_cpu_system_seconds_total", "Total system CPU time spent in seconds.", "counter", cpu.system / 1000000);
|
|
316
|
+
single(b, "process_cpu_seconds_total", "Total user and system CPU time spent in seconds.", "counter", (cpu.user + cpu.system) / 1000000);
|
|
317
|
+
single(b, "process_start_time_seconds", "Start time of the process since unix epoch in seconds.", "gauge", match.processStartTimeSeconds);
|
|
318
|
+
single(b, "process_resident_memory_bytes", "Resident memory size in bytes.", "gauge", memory.rss);
|
|
319
|
+
single(b, "nodejs_heap_size_total_bytes", "Process heap size from Node.js in bytes.", "gauge", memory.heapTotal);
|
|
320
|
+
single(b, "nodejs_heap_size_used_bytes", "Process heap size used from Node.js in bytes.", "gauge", memory.heapUsed);
|
|
321
|
+
single(b, "nodejs_external_memory_bytes", "Node.js external memory size in bytes.", "gauge", memory.external);
|
|
322
|
+
single(b, "nodejs_eventloop_utilization", "Ratio of time the event loop is active, since process start.", "gauge", elu.utilization);
|
|
323
|
+
let hasLagSamples = eventLoopDelay.max > 0;
|
|
324
|
+
let nsToSeconds = ns => {
|
|
325
|
+
if (hasLagSamples && !Number.isNaN(ns)) {
|
|
326
|
+
return ns / 1000000000;
|
|
327
|
+
} else {
|
|
328
|
+
return 0;
|
|
49
329
|
}
|
|
330
|
+
};
|
|
331
|
+
single(b, "nodejs_eventloop_lag_mean_seconds", "The mean of the recorded event loop delays.", "gauge", nsToSeconds(eventLoopDelay.mean));
|
|
332
|
+
single(b, "nodejs_eventloop_lag_min_seconds", "The minimum recorded event loop delay.", "gauge", nsToSeconds(eventLoopDelay.min));
|
|
333
|
+
single(b, "nodejs_eventloop_lag_max_seconds", "The maximum recorded event loop delay.", "gauge", nsToSeconds(eventLoopDelay.max));
|
|
334
|
+
single(b, "nodejs_eventloop_lag_stddev_seconds", "The standard deviation of the recorded event loop delays.", "gauge", nsToSeconds(eventLoopDelay.stddev));
|
|
335
|
+
single(b, "nodejs_eventloop_lag_p50_seconds", "The 50th percentile of the recorded event loop delays.", "gauge", nsToSeconds(eventLoopDelay.percentile(50)));
|
|
336
|
+
single(b, "nodejs_eventloop_lag_p90_seconds", "The 90th percentile of the recorded event loop delays.", "gauge", nsToSeconds(eventLoopDelay.percentile(90)));
|
|
337
|
+
single(b, "nodejs_eventloop_lag_p99_seconds", "The 99th percentile of the recorded event loop delays.", "gauge", nsToSeconds(eventLoopDelay.percentile(99)));
|
|
338
|
+
eventLoopDelay.reset();
|
|
339
|
+
let heapSpaces = V8.getHeapSpaceStatistics().map(s => [
|
|
340
|
+
`{space="` + s.space_name.replace("_space", "") + `"}`,
|
|
341
|
+
s
|
|
342
|
+
]);
|
|
343
|
+
series(b, "nodejs_heap_space_size_total_bytes", "Process heap space size total from Node.js in bytes.", "gauge", heapSpaces, s => s.space_size);
|
|
344
|
+
series(b, "nodejs_heap_space_size_used_bytes", "Process heap space size used from Node.js in bytes.", "gauge", heapSpaces, s => s.space_used_size);
|
|
345
|
+
series(b, "nodejs_heap_space_size_available_bytes", "Process heap space size available from Node.js in bytes.", "gauge", heapSpaces, s => s.space_available_size);
|
|
346
|
+
let byType = {};
|
|
347
|
+
Process.getActiveResourcesInfo().forEach(resource => {
|
|
348
|
+
let label = `{type="` + escapeLabelValue(resource) + `"}`;
|
|
349
|
+
byType[label] = Stdlib_Option.getOr(byType[label], 0) + 1;
|
|
50
350
|
});
|
|
51
|
-
|
|
351
|
+
let activeResources = Object.entries(byType);
|
|
352
|
+
series(b, "nodejs_active_resources", "Number of active resources that are currently keeping the event loop alive, grouped by async resource type.", "gauge", activeResources, count => count);
|
|
353
|
+
single(b, "nodejs_active_resources_total", "Total number of active resources.", "gauge", Stdlib_Array.reduce(activeResources, 0, (acc, param) => acc + param[1]));
|
|
354
|
+
let gcEntries = [];
|
|
355
|
+
Utils.Dict.forEachWithKey(match.gcStats, (stat, kind) => {
|
|
356
|
+
gcEntries.push([
|
|
357
|
+
`{kind="` + kind + `"}`,
|
|
358
|
+
stat
|
|
359
|
+
]);
|
|
360
|
+
});
|
|
361
|
+
series(b, "nodejs_gc_duration_seconds_sum", "Cumulative garbage collection pause time by kind, one of major, minor, incremental or weakcb.", "counter", gcEntries, s => s.seconds);
|
|
362
|
+
series(b, "nodejs_gc_duration_seconds_count", "Number of garbage collection pauses by kind, one of major, minor, incremental or weakcb.", "counter", gcEntries, s => s.count);
|
|
363
|
+
let version = Process.version;
|
|
364
|
+
let versionParts = version.replace("v", "").split(".");
|
|
365
|
+
let versionPart = i => Stdlib_Option.getOr(versionParts[i], "0");
|
|
366
|
+
series(b, "nodejs_version_info", "Node.js version info.", "gauge", [[
|
|
367
|
+
`{version="` + version + `",major="` + versionPart(0) + `",minor="` + versionPart(1) + `",patch="` + versionPart(2) + `"}`,
|
|
368
|
+
undefined
|
|
369
|
+
]], () => 1);
|
|
370
|
+
return b.out + "\n";
|
|
52
371
|
}
|
|
53
372
|
|
|
54
|
-
|
|
55
|
-
let base = await PromClient.register.metrics();
|
|
56
|
-
if (state === undefined) {
|
|
57
|
-
return base;
|
|
58
|
-
}
|
|
59
|
-
let chainStates = IndexerState.chainStates(Primitive_option.valFromOption(state));
|
|
60
|
-
let sourceRequestSamples = Object.values(chainStates).flatMap(cs => SourceManager.getRequestStatSamples(ChainState.sourceManager(cs)));
|
|
61
|
-
return base + renderGauge(indexingAddressesName, indexingAddressesHelp, chainStates, cs => ChainState.toChainData(cs).numAddresses) + renderSourceRequests(sourceRequestSamples) + `\n`;
|
|
62
|
-
}
|
|
373
|
+
let contentType = "text/plain; version=0.0.4; charset=utf-8";
|
|
63
374
|
|
|
64
375
|
export {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
376
|
+
formatValue,
|
|
377
|
+
escapeLabelValue,
|
|
378
|
+
block,
|
|
379
|
+
sample,
|
|
380
|
+
series,
|
|
381
|
+
seriesOpt,
|
|
382
|
+
single,
|
|
383
|
+
renderMetrics,
|
|
384
|
+
contentType,
|
|
73
385
|
collect,
|
|
386
|
+
gcKindName,
|
|
387
|
+
runtimeCollectors,
|
|
388
|
+
getRuntimeCollectors,
|
|
389
|
+
startRuntimeCollectors,
|
|
390
|
+
collectRuntime,
|
|
74
391
|
}
|
|
75
|
-
/*
|
|
392
|
+
/* v8 Not a pure module */
|
package/src/Persistence.res
CHANGED
|
@@ -134,6 +134,9 @@ type storage = {
|
|
|
134
134
|
// Chain metadata stale since the last write, persisted in the same
|
|
135
135
|
// transaction so it never races the batch write.
|
|
136
136
|
~chainMetaData: option<dict<InternalTable.Chains.metaFields>>,
|
|
137
|
+
// Reports each underlying storage's write duration (e.g. postgres and a
|
|
138
|
+
// configured sink separately), accumulated into the write metrics.
|
|
139
|
+
~onWrite: (~storage: string, ~timeSeconds: float) => unit,
|
|
137
140
|
) => promise<unit>,
|
|
138
141
|
// Release any long-lived resources (e.g. the postgres connection pool) so
|
|
139
142
|
// short-lived CLI commands like `db-migrate setup` can exit cleanly.
|
package/src/PgStorage.res
CHANGED
|
@@ -1763,6 +1763,7 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
|
|
|
1763
1763
|
~updatedEffectsCache,
|
|
1764
1764
|
~updatedEntities,
|
|
1765
1765
|
~chainMetaData,
|
|
1766
|
+
~onWrite,
|
|
1766
1767
|
) => {
|
|
1767
1768
|
let pgUpdates = []
|
|
1768
1769
|
let chUpdates = []
|
|
@@ -1784,10 +1785,7 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
|
|
|
1784
1785
|
Some(
|
|
1785
1786
|
sink.writeBatch(~batch, ~updatedEntities=chUpdates)
|
|
1786
1787
|
->Promise.thenResolve(_ => {
|
|
1787
|
-
|
|
1788
|
-
~storage=sink.name,
|
|
1789
|
-
~timeSeconds=timerRef->Performance.secondsSince,
|
|
1790
|
-
)
|
|
1788
|
+
onWrite(~storage=sink.name, ~timeSeconds=timerRef->Performance.secondsSince)
|
|
1791
1789
|
None
|
|
1792
1790
|
})
|
|
1793
1791
|
// Otherwise it fails with unhandled exception
|
|
@@ -1812,10 +1810,7 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
|
|
|
1812
1810
|
~sinkPromise,
|
|
1813
1811
|
~chainMetaData,
|
|
1814
1812
|
)
|
|
1815
|
-
|
|
1816
|
-
~storage="postgres",
|
|
1817
|
-
~timeSeconds=primaryTimerRef->Performance.secondsSince,
|
|
1818
|
-
)
|
|
1813
|
+
onWrite(~storage="postgres", ~timeSeconds=primaryTimerRef->Performance.secondsSince)
|
|
1819
1814
|
}
|
|
1820
1815
|
|
|
1821
1816
|
let close = () => sql->Postgres.endSql
|
package/src/PgStorage.res.mjs
CHANGED
|
@@ -13,7 +13,6 @@ import * as Logging from "./Logging.res.mjs";
|
|
|
13
13
|
import * as Internal from "./Internal.res.mjs";
|
|
14
14
|
import Postgres from "postgres";
|
|
15
15
|
import * as ChainState from "./ChainState.res.mjs";
|
|
16
|
-
import * as Prometheus from "./Prometheus.res.mjs";
|
|
17
16
|
import * as Performance from "./bindings/Performance.res.mjs";
|
|
18
17
|
import * as Persistence from "./Persistence.res.mjs";
|
|
19
18
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
@@ -1154,7 +1153,7 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
|
|
|
1154
1153
|
restoredEntitiesResult
|
|
1155
1154
|
];
|
|
1156
1155
|
};
|
|
1157
|
-
let writeBatchMethod = async (batch, rollback, isInReorgThreshold, config, allEntities, updatedEffectsCache, updatedEntities, chainMetaData) => {
|
|
1156
|
+
let writeBatchMethod = async (batch, rollback, isInReorgThreshold, config, allEntities, updatedEffectsCache, updatedEntities, chainMetaData, onWrite) => {
|
|
1158
1157
|
let pgUpdates = [];
|
|
1159
1158
|
let chUpdates = [];
|
|
1160
1159
|
for (let i = 0, i_finish = updatedEntities.length; i < i_finish; ++i) {
|
|
@@ -1171,14 +1170,14 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
|
|
|
1171
1170
|
if (sink !== undefined) {
|
|
1172
1171
|
let timerRef = Performance.now();
|
|
1173
1172
|
sinkPromise = sink.writeBatch(batch, chUpdates).then(() => {
|
|
1174
|
-
|
|
1173
|
+
onWrite(sink.name, Performance.secondsSince(timerRef));
|
|
1175
1174
|
}).catch(exn => exn);
|
|
1176
1175
|
} else {
|
|
1177
1176
|
sinkPromise = undefined;
|
|
1178
1177
|
}
|
|
1179
1178
|
let primaryTimerRef = Performance.now();
|
|
1180
1179
|
await writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, config, allEntities, setEffectCacheOrThrow, updatedEffectsCache, pgUpdates, sinkPromise, chainMetaData, undefined);
|
|
1181
|
-
return
|
|
1180
|
+
return onWrite("postgres", Performance.secondsSince(primaryTimerRef));
|
|
1182
1181
|
};
|
|
1183
1182
|
let close = () => sql.end();
|
|
1184
1183
|
return {
|
|
@@ -106,7 +106,7 @@ let pruneEntities = async (state: IndexerState.t, ~entities, ~safeCheckpointId)
|
|
|
106
106
|
~safeCheckpointId,
|
|
107
107
|
) {
|
|
108
108
|
| () =>
|
|
109
|
-
|
|
109
|
+
state->IndexerState.recordHistoryPrune(
|
|
110
110
|
~timeSeconds=Performance.secondsSince(timeRef),
|
|
111
111
|
~entityName=entityConfig.name,
|
|
112
112
|
)
|
|
@@ -4,7 +4,6 @@ import * as Env from "./Env.res.mjs";
|
|
|
4
4
|
import * as Utils from "./Utils.res.mjs";
|
|
5
5
|
import * as Config from "./Config.res.mjs";
|
|
6
6
|
import * as Logging from "./Logging.res.mjs";
|
|
7
|
-
import * as Prometheus from "./Prometheus.res.mjs";
|
|
8
7
|
import * as Performance from "./bindings/Performance.res.mjs";
|
|
9
8
|
import * as IndexerState from "./IndexerState.res.mjs";
|
|
10
9
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
@@ -80,7 +79,7 @@ async function pruneEntities(state, entities, safeCheckpointId) {
|
|
|
80
79
|
}), Utils.prettifyExn(exn), `Failed to prune stale entity history`);
|
|
81
80
|
}
|
|
82
81
|
if (exit === 1) {
|
|
83
|
-
|
|
82
|
+
IndexerState.recordHistoryPrune(state, entityConfig.name, Performance.secondsSince(timeRef));
|
|
84
83
|
}
|
|
85
84
|
}
|
|
86
85
|
}
|
package/src/Rollback.res
CHANGED
|
@@ -107,10 +107,9 @@ and executeRollback = async (
|
|
|
107
107
|
},
|
|
108
108
|
)
|
|
109
109
|
logger->Logging.childInfo("Started rollback on reorg")
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
)
|
|
110
|
+
state
|
|
111
|
+
->IndexerState.getChainState(~chain=reorgChain)
|
|
112
|
+
->ChainState.setRollbackTargetBlock(~blockNumber=rollbackTargetBlockNumber)
|
|
114
113
|
|
|
115
114
|
let reorgChainId = reorgChain->ChainMap.Chain.toChainId
|
|
116
115
|
|
|
@@ -212,7 +211,7 @@ and executeRollback = async (
|
|
|
212
211
|
"deleted": diff["deletedEntities"],
|
|
213
212
|
"upserted": diff["setEntities"],
|
|
214
213
|
})
|
|
215
|
-
|
|
214
|
+
state->IndexerState.recordRollbackSuccess(
|
|
216
215
|
~timeSeconds=Performance.secondsSince(startTime),
|
|
217
216
|
~rollbackedProcessedEvents=rollbackedProcessedEvents.contents,
|
|
218
217
|
)
|
package/src/Rollback.res.mjs
CHANGED
|
@@ -4,7 +4,6 @@ import * as Utils from "./Utils.res.mjs";
|
|
|
4
4
|
import * as Logging from "./Logging.res.mjs";
|
|
5
5
|
import * as Writing from "./Writing.res.mjs";
|
|
6
6
|
import * as ChainState from "./ChainState.res.mjs";
|
|
7
|
-
import * as Prometheus from "./Prometheus.res.mjs";
|
|
8
7
|
import * as Performance from "./bindings/Performance.res.mjs";
|
|
9
8
|
import * as IndexerState from "./IndexerState.res.mjs";
|
|
10
9
|
import * as Stdlib_Float from "@rescript/runtime/lib/es6/Stdlib_Float.js";
|
|
@@ -39,7 +38,7 @@ async function executeRollback(state, reorgChain, rollbackTargetBlockNumber, sch
|
|
|
39
38
|
targetBlockNumber: rollbackTargetBlockNumber
|
|
40
39
|
});
|
|
41
40
|
Logging.childInfo(logger, "Started rollback on reorg");
|
|
42
|
-
|
|
41
|
+
ChainState.setRollbackTargetBlock(IndexerState.getChainState(state, reorgChain), rollbackTargetBlockNumber);
|
|
43
42
|
await Writing.flush(state);
|
|
44
43
|
let checkpointId = await IndexerState.persistence(state).storage.getRollbackTargetCheckpoint(reorgChain, rollbackTargetBlockNumber);
|
|
45
44
|
let rollbackTargetCheckpointId = checkpointId !== undefined ? checkpointId : 0n;
|
|
@@ -83,7 +82,7 @@ async function executeRollback(state, reorgChain, rollbackTargetBlockNumber, sch
|
|
|
83
82
|
deleted: diff$1.deletedEntities,
|
|
84
83
|
upserted: diff$1.setEntities
|
|
85
84
|
});
|
|
86
|
-
|
|
85
|
+
IndexerState.recordRollbackSuccess(state, Performance.secondsSince(startTime), rollbackedProcessedEvents);
|
|
87
86
|
IndexerState.completeRollback(state, eventsProcessedDiffByChain);
|
|
88
87
|
scheduleFetch();
|
|
89
88
|
return scheduleProcessing();
|
|
@@ -323,27 +323,9 @@ function patchConfig(config, processConfig, registrationsByChainId) {
|
|
|
323
323
|
};
|
|
324
324
|
return newrecord$1;
|
|
325
325
|
});
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
handlers: config.handlers,
|
|
330
|
-
contractHandlers: config.contractHandlers,
|
|
331
|
-
shouldRollbackOnReorg: config.shouldRollbackOnReorg,
|
|
332
|
-
shouldSaveFullHistory: config.shouldSaveFullHistory,
|
|
333
|
-
storage: config.storage,
|
|
334
|
-
chainMap: newChainMap,
|
|
335
|
-
defaultChain: config.defaultChain,
|
|
336
|
-
ecosystem: config.ecosystem,
|
|
337
|
-
enableRawEvents: config.enableRawEvents,
|
|
338
|
-
maxAddrInPartition: config.maxAddrInPartition,
|
|
339
|
-
batchSize: config.batchSize,
|
|
340
|
-
lowercaseAddresses: config.lowercaseAddresses,
|
|
341
|
-
isDev: config.isDev,
|
|
342
|
-
userEntitiesByName: config.userEntitiesByName,
|
|
343
|
-
userEntities: config.userEntities,
|
|
344
|
-
allEntities: config.allEntities,
|
|
345
|
-
allEnums: config.allEnums
|
|
346
|
-
};
|
|
326
|
+
let newrecord = {...config};
|
|
327
|
+
newrecord.chainMap = newChainMap;
|
|
328
|
+
return newrecord;
|
|
347
329
|
}
|
|
348
330
|
|
|
349
331
|
export {
|