javadoc: Adding javadoc for ethstats module (#7269)

* javadoc: Adding javadoc for ethstats module

---------

Signed-off-by: Usman Saleem <usman@usmans.info>
This commit is contained in:
Usman Saleem
2024-06-27 13:09:00 +10:00
committed by GitHub
parent 67637fa3f0
commit 77183f6d60
18 changed files with 462 additions and 10 deletions

View File

@@ -102,7 +102,7 @@ public class XmlExtensionConfiguration extends XmlConfiguration {
dim("%t"),
colorize("%-5level"),
dim("%c{1}"),
colorize("%msg%n%throwable")))
colorize("%msgc%n%throwable")))
.build();
final ConsoleAppender consoleAppender =
ConsoleAppender.newBuilder().setName("Console").setLayout(patternLayout).build();

View File

@@ -368,7 +368,6 @@ allprojects {
// TODO: these are temporary disabled (ethereum and sub modules), it should be removed in a future PR.
'-org.hyperledger.besu.ethereum,' +
'-org.hyperledger.besu.ethereum.*,' +
'-org.hyperledger.besu.ethstats.*,' +
'-org.hyperledger.besu.evmtool',
true)
options.addStringOption('Xmaxerrs','65535')

View File

@@ -80,8 +80,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class describes the behaviour of the EthStats service. This class is used to report pending
* transactions, blocks, and several node-related information to a netstats server.
* This class describes the behaviour of the EthStatsService. This class is used to report pending
* transactions, blocks, and several node-related information to an ethstats server.
*/
public class EthStatsService {
@@ -112,18 +112,18 @@ public class EthStatsService {
private long pingTimestamp;
/**
* Instantiates a new EthStats service.
* Instantiates a new EthStatsService.
*
* @param ethStatsConnectOptions the netstats url
* @param ethStatsConnectOptions the ethstats options
* @param blockchainQueries the blockchain queries
* @param protocolManager the protocol manager
* @param transactionPool the transaction pool
* @param miningCoordinator the mining coordinator
* @param syncState the sync state
* @param vertx the vertx
* @param syncState the SyncState
* @param vertx the vertx instance
* @param clientVersion the client version
* @param genesisConfigOptions the genesis config options
* @param p2PNetwork the p 2 p network
* @param p2PNetwork the p2p network
*/
public EthStatsService(
final EthStatsConnectOptions ethStatsConnectOptions,

View File

@@ -19,18 +19,37 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.immutables.value.Value;
/**
* This interface represents the authentication data. It provides methods to get the id, info, and
* secret of the authentication data.
*/
@Value.Immutable
@JsonSerialize(as = ImmutableAuthenticationData.class)
@JsonDeserialize(as = ImmutableAuthenticationData.class)
@Value.Style(allParameters = true)
public interface AuthenticationData {
/**
* Gets the id of the authentication data.
*
* @return the id of the authentication data.
*/
@JsonProperty("id")
String getId();
/**
* Gets the info of the authentication data.
*
* @return the info of the authentication data.
*/
@JsonProperty("info")
NodeInfo getInfo();
/**
* Gets the secret of the authentication data.
*
* @return the secret of the authentication data.
*/
@JsonProperty("secret")
String getSecret();
}

View File

@@ -19,42 +19,102 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.immutables.value.Value;
/**
* This interface represents the information of a node. It provides methods to get the name, node,
* port, network, protocol, api, os, os version, client, update history capability, and contact of
* the node.
*/
@Value.Immutable
@JsonSerialize(as = ImmutableNodeInfo.class)
@JsonDeserialize(as = ImmutableNodeInfo.class)
@Value.Style(allParameters = true)
public interface NodeInfo {
/**
* Gets the name of the node.
*
* @return the name of the node.
*/
@JsonProperty("name")
String getName();
/**
* Gets the node.
*
* @return the node.
*/
@JsonProperty("node")
String getNode();
/**
* Gets the port of the node.
*
* @return the port of the node.
*/
@JsonProperty("port")
String getPort();
/**
* Gets the network of the node.
*
* @return the network of the node.
*/
@JsonProperty("net")
String getNetwork();
/**
* Gets the protocol of the node.
*
* @return the protocol of the node.
*/
@JsonProperty("protocol")
String getProtocol();
/**
* Gets the api of the node.
*
* @return the api of the node.
*/
@JsonProperty("api")
String getApi();
/**
* Gets the operating system of the node.
*
* @return the operating system of the node.
*/
@JsonProperty("os")
String getOs();
/**
* Gets the operating system version of the node.
*
* @return the operating system version of the node.
*/
@JsonProperty("os_v")
String getOsVer();
/**
* Gets the client of the node.
*
* @return the client of the node.
*/
@JsonProperty("client")
String getClient();
/**
* Gets the update history capability of the node.
*
* @return the update history capability of the node.
*/
@JsonProperty("canUpdateHistory")
Boolean getCanUpdateHistory();
/**
* Gets the contact of the node.
*
* @return the contact of the node.
*/
@JsonProperty("contact")
String getContact();
}

View File

@@ -21,15 +21,29 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.immutables.value.Value;
/**
* This interface represents a block report. It provides methods to get the id and block result of
* the block report.
*/
@Value.Immutable
@Value.Style(allParameters = true)
@JsonSerialize(as = ImmutableBlockReport.class)
@JsonDeserialize(as = ImmutableBlockReport.class)
public interface BlockReport {
/**
* Gets the id of the block report.
*
* @return the id of the block report.
*/
@JsonProperty("id")
String getId();
/**
* Gets the block result of the block report.
*
* @return the block result of the block report.
*/
@JsonProperty("block")
BlockResult getBlock();
}

View File

@@ -23,15 +23,29 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.immutables.value.Value;
/**
* This interface represents a history report. It provides methods to get the id and history of the
* history report.
*/
@Value.Immutable
@Value.Style(allParameters = true)
@JsonSerialize(as = ImmutableHistoryReport.class)
@JsonDeserialize(as = ImmutableHistoryReport.class)
public interface HistoryReport {
/**
* Gets the id of the history report.
*
* @return the id of the history report.
*/
@JsonProperty(value = "id")
String getId();
/**
* Gets the block results of the history report.
*
* @return the list of block results of the history report.
*/
@JsonProperty("history")
List<BlockResult> getHistory();
}

View File

@@ -19,15 +19,29 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.immutables.value.Value;
/**
* This interface represents a latency report. It provides methods to get the id and latency of the
* latency report.
*/
@Value.Immutable
@Value.Style(allParameters = true)
@JsonSerialize(as = ImmutableLatencyReport.class)
@JsonDeserialize(as = ImmutableLatencyReport.class)
public interface LatencyReport {
/**
* Gets the id of the latency report.
*
* @return the id of the latency report.
*/
@JsonProperty("id")
String getId();
/**
* Gets the latency of the latency report.
*
* @return the latency of the latency report.
*/
@JsonProperty("latency")
String getLatency();
}

View File

@@ -19,42 +19,92 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.immutables.value.Value;
/**
* This interface represents a node stats report. It provides methods to get the id and stats of the
* node stats report.
*/
@Value.Immutable
@Value.Style(deepImmutablesDetection = true, depluralize = true)
@JsonSerialize(as = ImmutableNodeStatsReport.class)
@JsonDeserialize(as = ImmutableNodeStatsReport.class)
public interface NodeStatsReport {
/**
* Gets the id of the node stats report.
*
* @return the id of the node stats report.
*/
@JsonProperty("id")
String getId();
/**
* Gets the stats of the node stats report.
*
* @return the stats of the node stats report.
*/
@JsonProperty("stats")
NStats getStats();
/** This interface represents the stats of a node. */
@Value.Immutable
@Value.Style(allParameters = true)
@JsonSerialize(as = ImmutableNStats.class)
@JsonDeserialize(as = ImmutableNStats.class)
interface NStats {
/**
* Checks if the node is active.
*
* @return true if the node is active, false otherwise.
*/
@JsonProperty("active")
boolean isActive();
/**
* Checks if the node is mining.
*
* @return true if the node is mining, false otherwise.
*/
@JsonProperty("mining")
boolean isMining();
/**
* Gets the hashrate of the node.
*
* @return the hashrate of the node.
*/
@JsonProperty("hashrate")
long getHashrate();
/**
* Gets the number of peers of the node.
*
* @return the number of peers of the node.
*/
@JsonProperty("peers")
int getPeers();
/**
* Gets the gas price of the node.
*
* @return the gas price of the node.
*/
@JsonProperty("gasPrice")
long getGasPrice();
/**
* Checks if the node is syncing.
*
* @return true if the node is syncing, false otherwise.
*/
@JsonProperty("syncing")
boolean isSyncing();
/**
* Gets the uptime of the node.
*
* @return the uptime of the node.
*/
@JsonProperty("uptime")
int getUpTime();
}

View File

@@ -19,24 +19,44 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.immutables.value.Value;
/**
* This interface represents a pending transactions report. It provides methods to get the id and
* stats of the pending transactions report.
*/
@Value.Immutable
@Value.Style(deepImmutablesDetection = true, depluralize = true)
@JsonSerialize(as = ImmutablePendingTransactionsReport.class)
@JsonDeserialize(as = ImmutablePendingTransactionsReport.class)
public interface PendingTransactionsReport {
/**
* Gets the id of the pending transactions report.
*
* @return the id of the pending transactions report.
*/
@JsonProperty("id")
String getId();
/**
* Gets the stats of the pending transactions report.
*
* @return the stats of the pending transactions report.
*/
@JsonProperty("stats")
PStats getStats();
/** This interface represents the stats of a pending transactions report. */
@Value.Immutable
@Value.Style(allParameters = true)
@JsonSerialize(as = ImmutablePStats.class)
@JsonDeserialize(as = ImmutablePStats.class)
interface PStats {
/**
* Gets the number of pending transactions.
*
* @return the number of pending transactions.
*/
@JsonProperty("pending")
int getPending();
}

View File

@@ -19,15 +19,29 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.immutables.value.Value;
/**
* This interface represents a ping report. It provides methods to get the id and current time of
* the ping report.
*/
@Value.Immutable
@Value.Style(allParameters = true)
@JsonSerialize(as = ImmutablePingReport.class)
@JsonDeserialize(as = ImmutablePingReport.class)
public interface PingReport {
/**
* Gets the id of the ping report.
*
* @return the id of the ping report.
*/
@JsonProperty("id")
String getId();
/**
* Gets the current time of the ping report.
*
* @return the current time of the ping report.
*/
@JsonProperty("clientTime")
String getCurrentTime();
}

View File

@@ -23,10 +23,16 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* This class represents an Ethereum statistics request. It provides methods to get the type of the
* request and the parameters associated with it.
*/
public class EthStatsRequest {
/** The constant MAPPER. */
public static final ObjectMapper MAPPER = new ObjectMapper();
/** The constant EMIT_FIELD. */
public static final String EMIT_FIELD = "emit";
@JsonProperty(EMIT_FIELD)
@@ -34,11 +40,22 @@ public class EthStatsRequest {
private EthStatsRequest() {}
/**
* Constructs a new EthStatsRequest with the given type and parameters.
*
* @param type the type of the request
* @param parameters the parameters of the request
*/
public EthStatsRequest(final Type type, final Object... parameters) {
this.emit =
Stream.concat(Stream.of(type.value), Stream.of(parameters)).collect(Collectors.toList());
}
/**
* Gets the type of the request.
*
* @return the type of the request
*/
@JsonIgnore
public Type getType() {
return getEmit().stream()
@@ -49,14 +66,31 @@ public class EthStatsRequest {
.orElse(Type.UNKNOWN);
}
/**
* Gets the parameters of the request.
*
* @return the parameters of the request
*/
public List<Object> getEmit() {
return emit;
}
/**
* Generates a command string from the request.
*
* @return the command string
* @throws JsonProcessingException if there is an error processing the JSON
*/
public String generateCommand() throws JsonProcessingException {
return MAPPER.writeValueAsString(this);
}
/**
* Creates an EthStatsRequest from a response string.
*
* @param value the response string
* @return the EthStatsRequest
*/
public static EthStatsRequest fromResponse(final String value) {
try {
return MAPPER.readValue(value, EthStatsRequest.class);
@@ -65,16 +99,36 @@ public class EthStatsRequest {
}
}
/** The enum Type represents the type of the request. */
public enum Type {
/** Represents the 'hello' type of the request. */
HELLO("hello"),
/** Represents the 'ready' type of the request. */
READY("ready"),
/** Represents the 'node-ping' type of the request. */
NODE_PING("node-ping"),
/** Represents the 'node-pong' type of the request. */
NODE_PONG("node-pong"),
/** Represents the 'latency' type of the request. */
LATENCY("latency"),
/** Represents the 'block' type of the request. */
BLOCK("block"),
/** Represents the 'history' type of the request. */
HISTORY("history"),
/** Represents the 'pending' type of the request. */
PENDING("pending"),
/** Represents the 'stats' type of the request. */
STATS("stats"),
/** Represents an unknown type of the request. */
UNKNOWN("");
String value;
@@ -83,10 +137,21 @@ public class EthStatsRequest {
this.value = value;
}
/**
* Gets the value of the type.
*
* @return the value of the type
*/
public String getValue() {
return value;
}
/**
* Gets the type from a value string.
*
* @param value the value string
* @return the type
*/
public static Type fromValue(final String value) {
for (Type type : values()) {
if (type.value.equalsIgnoreCase(value)) {

View File

@@ -23,24 +23,71 @@ import javax.annotation.Nullable;
import org.immutables.value.Value;
import org.slf4j.LoggerFactory;
/**
* This interface represents the connection options for Ethereum statistics. It provides methods to
* get the scheme, node name, secret, host, port, contact, and CA certificate.
*/
@Value.Immutable
public interface EthStatsConnectOptions {
/**
* Gets the scheme of the connection.
*
* @return the scheme of the connection.
*/
@Nullable
String getScheme();
/**
* Gets the node name of the connection.
*
* @return the node name of the connection.
*/
String getNodeName();
/**
* Gets the secret of the connection.
*
* @return the secret of the connection.
*/
String getSecret();
/**
* Gets the host of the connection.
*
* @return the host of the connection.
*/
String getHost();
/**
* Gets the port of the connection.
*
* @return the port of the connection.
*/
Integer getPort();
/**
* Gets the contact of the connection.
*
* @return the contact of the connection.
*/
String getContact();
/**
* Gets the CA certificate of the connection.
*
* @return the CA certificate of the connection.
*/
@Nullable
Path getCaCert();
/**
* Creates an EthStatsConnectOptions from the given parameters.
*
* @param url the url of the connection
* @param contact the contact of the connection
* @param caCert the CA certificate of the connection
* @return the EthStatsConnectOptions
*/
static EthStatsConnectOptions fromParams(
final String url, final String contact, final Path caCert) {
try {

View File

@@ -18,14 +18,29 @@ import java.util.regex.Pattern;
import io.vertx.core.http.WebSocket;
/** This class provides helper methods for handling Primus heartbeats. */
public final class PrimusHeartBeatsHelper {
/** The constant PRIMUS_PING_REGEX. */
public static final Pattern PRIMUS_PING_REGEX = Pattern.compile("primus::ping::([\\d]+)");
private PrimusHeartBeatsHelper() {}
/**
* Checks if the given request is a heartbeat request.
*
* @param request the request to check
* @return true if the request is a heartbeat request, false otherwise
*/
public static boolean isHeartBeatsRequest(final String request) {
return PRIMUS_PING_REGEX.matcher(request).find();
}
/**
* Sends a heartbeat response through the given WebSocket.
*
* @param webSocket the WebSocket to send the response through
*/
public static void sendHeartBeatsResponse(final WebSocket webSocket) {
if (webSocket != null) {
webSocket.writeTextMessage(String.format("\"primus::pong::%d\"", System.currentTimeMillis()));

View File

@@ -6,7 +6,7 @@
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSSZZZ} | %t | %-5level | %c{1} | %msg%n" />
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSSZZZ} | %t | %-5level | %c{1} | %msgc%n" />
</Console>
</Appenders>
<Loggers>

View File

@@ -31,6 +31,8 @@ jar {
dependencies {
api 'org.slf4j:slf4j-api'
annotationProcessor 'org.apache.logging.log4j:log4j-core'
implementation 'com.google.guava:guava'
implementation 'net.java.dev.jna:jna'
implementation 'org.apache.commons:commons-lang3'

View File

@@ -0,0 +1,80 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.util.log4j.plugin;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.pattern.ConverterKeys;
import org.apache.logging.log4j.core.pattern.LogEventPatternConverter;
import org.apache.logging.log4j.core.pattern.PatternConverter;
/**
* Besu Log4j2 plugin for cleaner message logging.
*
* <p>Usage: In the pattern layout configuration, replace {@code %msg} with {@code %msgc}.
*/
@Plugin(name = "BesuLogMessageConverter", category = PatternConverter.CATEGORY)
@ConverterKeys({"msgc"})
public class BesuLogMessageConverter extends LogEventPatternConverter {
private BesuLogMessageConverter() {
super("BesuLogMessageConverter", null);
}
/**
* Creates new instance of this class. Required by Log4j2.
*
* @param options Array of options
* @return instance of this class
*/
@SuppressWarnings("unused") // used by Log4j2
public static BesuLogMessageConverter newInstance(final String[] options) {
return new BesuLogMessageConverter();
}
@Override
public void format(final LogEvent event, final StringBuilder toAppendTo) {
final String filteredString = formatBesuLogMessage(event.getMessage().getFormattedMessage());
toAppendTo.append(filteredString);
}
/**
* Format Besu log message.
*
* @param input The log message
* @return The formatted log message
*/
public static String formatBesuLogMessage(final String input) {
final StringBuilder builder = new StringBuilder(input.length());
char prevChar = 0;
for (int i = 0; i < input.length(); i++) {
final char c = input.charAt(i);
if (c == 0x0A) {
if (prevChar == 0x0D) {
builder.append(prevChar);
}
builder.append(c);
} else if (c == 0x09 || !Character.isISOControl(c)) {
builder.append(c);
}
prevChar = c;
}
return builder.toString();
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.util.log4j.plugin;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;
public class BesuLogMessageConverterTest {
@Test
public void logCleanup() {
final StringBuilder testDataBuilder = new StringBuilder("log ");
for (int i = 0; i <= 0x001F; i++) {
testDataBuilder.append((char) i);
}
for (int i = 0x007F; i <= 0x009F; i++) {
testDataBuilder.append((char) i);
}
testDataBuilder.append((char) 0x0D).append((char) 0x0A).append("message");
String testData = testDataBuilder.toString();
String cleanedData = BesuLogMessageConverter.formatBesuLogMessage(testData);
String expectedData = String.format("log %c%c%c%cmessage", 0x09, 0x0A, 0x0D, 0x0A);
assertThat(cleanedData).isEqualTo(expectedData);
}
}