Skip to content

Commit 6bece43

Browse files
committed
feat(metrics): add block transaction count histogram for empty block monitoring
Replace the dedicated tron:block_empty_total counter with a more comprehensive tron:block_transaction_count histogram that tracks the distribution of transaction counts per block. Changes: - Add overloaded init() method in MetricsHistogram to support custom buckets - Add BLOCK_TRANSACTION_COUNT histogram with buckets [0, 10, 50, 100, 200, 500, 1000, 2000, 5000, 10000] - Record transaction count for all blocks (including empty blocks with txCount=0) - Empty blocks can be queried via bucket le=0.0 - Remove unused BLOCK_EMPTY counter This provides richer insights for network analysis while still supporting empty block monitoring via histogram bucket queries. Closes #6590
1 parent bc87e2e commit 6bece43

5 files changed

Lines changed: 44 additions & 19 deletions

File tree

common/src/main/java/org/tron/common/prometheus/MetricKeys.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ public static class Counter {
1414
public static final String TXS = "tron:txs";
1515
public static final String MINER = "tron:miner";
1616
public static final String BLOCK_FORK = "tron:block_fork";
17-
public static final String BLOCK_EMPTY = "tron:block_empty";
1817
public static final String SR_SET_CHANGE = "tron:sr_set_change";
1918
public static final String P2P_ERROR = "tron:p2p_error";
2019
public static final String P2P_DISCONNECT = "tron:p2p_disconnect";
@@ -64,6 +63,7 @@ public static class Histogram {
6463
public static final String MESSAGE_PROCESS_LATENCY = "tron:message_process_latency_seconds";
6564
public static final String BLOCK_FETCH_LATENCY = "tron:block_fetch_latency_seconds";
6665
public static final String BLOCK_RECEIVE_DELAY = "tron:block_receive_delay_seconds";
66+
public static final String BLOCK_TRANSACTION_COUNT = "tron:block_transaction_count";
6767

6868
private Histogram() {
6969
throw new IllegalStateException("Histogram");

common/src/main/java/org/tron/common/prometheus/MetricsCounter.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ class MetricsCounter {
1414
init(MetricKeys.Counter.TXS, "tron txs info .", "type", "detail");
1515
init(MetricKeys.Counter.MINER, "tron miner info .", "miner", "type");
1616
init(MetricKeys.Counter.BLOCK_FORK, "tron block fork info .", "type");
17-
init(MetricKeys.Counter.BLOCK_EMPTY, "tron empty block count .", "miner");
1817
init(MetricKeys.Counter.SR_SET_CHANGE, "tron sr set change .", "action", "witness");
1918
init(MetricKeys.Counter.P2P_ERROR, "tron p2p error info .", "type");
2019
init(MetricKeys.Counter.P2P_DISCONNECT, "tron p2p disconnect .", "type");

common/src/main/java/org/tron/common/prometheus/MetricsHistogram.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ public class MetricsHistogram {
4848
init(MetricKeys.Histogram.BLOCK_FETCH_LATENCY, "fetch block latency.");
4949
init(MetricKeys.Histogram.BLOCK_RECEIVE_DELAY,
5050
"receive block delay time, receiveTime - blockTime.");
51+
52+
init(MetricKeys.Histogram.BLOCK_TRANSACTION_COUNT,
53+
"Distribution of transaction counts per block.",
54+
new double[]{0, 10, 50, 100, 200, 500, 1000, 2000, 5000, 10000},
55+
"miner");
5156
}
5257

5358
private MetricsHistogram() {
@@ -62,6 +67,17 @@ private static void init(String name, String help, String... labels) {
6267
.register());
6368
}
6469

70+
private static void init(String name, String help, double[] buckets, String... labels) {
71+
Histogram.Builder builder = Histogram.build()
72+
.name(name)
73+
.help(help)
74+
.labelNames(labels);
75+
if (buckets != null && buckets.length > 0) {
76+
builder.buckets(buckets);
77+
}
78+
container.put(name, builder.register());
79+
}
80+
6581
static Histogram.Timer startTimer(String key, String... labels) {
6682
if (Metrics.enabled()) {
6783
Histogram histogram = container.get(key);

framework/src/main/java/org/tron/core/metrics/blockchain/BlockChainMetricManager.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,11 +174,11 @@ public void applyBlock(BlockCapsule block) {
174174
MetricsUtil.meterMark(MetricsKey.BLOCKCHAIN_TPS, block.getTransactions().size());
175175
Metrics.counterInc(MetricKeys.Counter.TXS, block.getTransactions().size(),
176176
MetricLabels.Counter.TXS_SUCCESS, MetricLabels.Counter.TXS_SUCCESS);
177-
} else {
178-
// Empty block
179-
Metrics.counterInc(MetricKeys.Counter.BLOCK_EMPTY, 1,
180-
StringUtil.encode58Check(address));
181177
}
178+
// Record transaction count distribution for all blocks (including empty blocks)
179+
int txCount = block.getTransactions().size();
180+
Metrics.histogramObserve(MetricKeys.Histogram.BLOCK_TRANSACTION_COUNT, txCount,
181+
StringUtil.encode58Check(address));
182182

183183
// SR set change detection
184184
long nextMaintenanceTime = dbManager.getDynamicPropertiesStore().getNextMaintenanceTime();

framework/src/test/java/org/tron/core/metrics/prometheus/PrometheusApiServiceTest.java

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,13 @@ protected void check(byte[] address, Map<ByteString, String> witnessAndAccount)
8484
Assert.assertEquals(pushBlock.intValue(), blocks + 1);
8585

8686
String minerBase58 = StringUtil.encode58Check(address);
87+
// Query histogram bucket le="0.0" for empty blocks
8788
Double emptyBlock = CollectorRegistry.defaultRegistry.getSampleValue(
88-
"tron:block_empty_total", new String[] {"miner"}, new String[] {minerBase58});
89-
90-
Assert.assertNotNull(emptyBlock);
91-
Assert.assertEquals(emptyBlock.intValue(), 1);
89+
"tron:block_transaction_count_bucket",
90+
new String[] {"miner", "le"}, new String[] {minerBase58, "0.0"});
91+
92+
Assert.assertNotNull("Empty block bucket should exist for miner: " + minerBase58, emptyBlock);
93+
Assert.assertEquals("Should have 1 empty block", 1, emptyBlock.intValue());
9294

9395
// Check SR_REMOVE for initial address (removed when addTestWitnessAndAccount() is called)
9496
Double srRemoveCount = CollectorRegistry.defaultRegistry.getSampleValue(
@@ -99,7 +101,8 @@ protected void check(byte[] address, Map<ByteString, String> witnessAndAccount)
99101
Assert.assertNotNull(srRemoveCount);
100102
Assert.assertEquals(1, srRemoveCount.intValue());
101103

102-
// Check SR_ADD and empty blocks for each new witness in witnessAndAccount (excluding initial address)
104+
// Check SR_ADD and empty blocks for each new witness in witnessAndAccount
105+
// (excluding initial address)
103106
ByteString addressByteString = ByteString.copyFrom(address);
104107
double totalNewWitnessEmptyBlocks = 0;
105108
for (ByteString witnessAddress : witnessAndAccount.keySet()) {
@@ -114,13 +117,17 @@ protected void check(byte[] address, Map<ByteString, String> witnessAndAccount)
114117
new String[] {"action", "witness"},
115118
new String[] {MetricLabels.Counter.SR_ADD, witnessBase58}
116119
);
117-
Assert.assertNotNull("SR_ADD should be recorded for witness: " + witnessBase58, srAddCount);
118-
Assert.assertEquals("Each new witness should have 1 SR_ADD record", 1, srAddCount.intValue());
120+
Assert.assertNotNull("SR_ADD should be recorded for witness: " + witnessBase58,
121+
srAddCount);
122+
Assert.assertEquals("Each new witness should have 1 SR_ADD record", 1,
123+
srAddCount.intValue());
119124

120-
// Collect empty blocks count
125+
// Collect empty blocks count from histogram bucket
121126
Double witnessEmptyBlock = CollectorRegistry.defaultRegistry.getSampleValue(
122-
"tron:block_empty_total", new String[] {"miner"}, new String[] {witnessBase58});
123-
Assert.assertNotNull(witnessEmptyBlock);
127+
"tron:block_transaction_count_bucket",
128+
new String[] {"miner", "le"}, new String[] {witnessBase58, "0.0"});
129+
Assert.assertNotNull("Empty block bucket should exist for witness: " + witnessBase58,
130+
witnessEmptyBlock);
124131
totalNewWitnessEmptyBlocks += witnessEmptyBlock;
125132
}
126133
Assert.assertEquals(blocks, (int)totalNewWitnessEmptyBlocks);
@@ -176,14 +183,17 @@ public void testMetric() throws Exception {
176183
Map<ByteString, String> witnessAndAccount = addTestWitnessAndAccount();
177184
witnessAndAccount.put(ByteString.copyFrom(address), key);
178185

179-
// Explicitly update WitnessScheduleStore to remove initial address, triggering SR_REMOVE metric
186+
// Explicitly update WitnessScheduleStore to remove initial address,
187+
// triggering SR_REMOVE metric
180188
List<ByteString> newActiveWitnesses = new ArrayList<>(witnessAndAccount.keySet());
181189
newActiveWitnesses.remove(ByteString.copyFrom(address));
182190
chainBaseManager.getWitnessScheduleStore().saveActiveWitnesses(newActiveWitnesses);
183191

184192
// Update nextMaintenanceTime to trigger SR set change detection
185-
long nextMaintenanceTime = chainBaseManager.getDynamicPropertiesStore().getNextMaintenanceTime();
186-
chainBaseManager.getDynamicPropertiesStore().updateNextMaintenanceTime(nextMaintenanceTime + 3600_000L);
193+
long nextMaintenanceTime =
194+
chainBaseManager.getDynamicPropertiesStore().getNextMaintenanceTime();
195+
chainBaseManager.getDynamicPropertiesStore().updateNextMaintenanceTime(
196+
nextMaintenanceTime + 3600_000L);
187197

188198
for (int i = 0; i < blocks; i++) {
189199
generateBlock(witnessAndAccount);

0 commit comments

Comments
 (0)