From 77183f6d600cfdc17d2f309aac507a8d038a56b5 Mon Sep 17 00:00:00 2001 From: Usman Saleem Date: Thu, 27 Jun 2024 13:09:00 +1000 Subject: [PATCH] javadoc: Adding javadoc for ethstats module (#7269) * javadoc: Adding javadoc for ethstats module --------- Signed-off-by: Usman Saleem --- .../logging/XmlExtensionConfiguration.java | 2 +- build.gradle | 1 - .../besu/ethstats/EthStatsService.java | 14 ++-- .../authentication/AuthenticationData.java | 19 +++++ .../ethstats/authentication/NodeInfo.java | 60 ++++++++++++++ .../besu/ethstats/report/BlockReport.java | 14 ++++ .../besu/ethstats/report/HistoryReport.java | 14 ++++ .../besu/ethstats/report/LatencyReport.java | 14 ++++ .../besu/ethstats/report/NodeStatsReport.java | 50 ++++++++++++ .../report/PendingTransactionsReport.java | 20 +++++ .../besu/ethstats/report/PingReport.java | 14 ++++ .../ethstats/request/EthStatsRequest.java | 65 +++++++++++++++ .../ethstats/util/EthStatsConnectOptions.java | 47 +++++++++++ .../ethstats/util/PrimusHeartBeatsHelper.java | 15 ++++ .../evmtool/src/main/resources/log4j2.xml | 2 +- util/build.gradle | 2 + .../log4j/plugin/BesuLogMessageConverter.java | 80 +++++++++++++++++++ .../plugin/BesuLogMessageConverterTest.java | 39 +++++++++ 18 files changed, 462 insertions(+), 10 deletions(-) create mode 100644 util/src/main/java/org/hyperledger/besu/util/log4j/plugin/BesuLogMessageConverter.java create mode 100644 util/src/test/java/org/hyperledger/besu/util/log4j/plugin/BesuLogMessageConverterTest.java diff --git a/besu/src/main/java/org/hyperledger/besu/cli/logging/XmlExtensionConfiguration.java b/besu/src/main/java/org/hyperledger/besu/cli/logging/XmlExtensionConfiguration.java index d2ae7071bdb..1e873276557 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/logging/XmlExtensionConfiguration.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/logging/XmlExtensionConfiguration.java @@ -102,7 +102,7 @@ private void createConsoleAppender() { 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(); diff --git a/build.gradle b/build.gradle index 3db0da35ce2..d869daf5e69 100644 --- a/build.gradle +++ b/build.gradle @@ -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') diff --git a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/EthStatsService.java b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/EthStatsService.java index 0fa93e1b68c..b96a48dc5e6 100644 --- a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/EthStatsService.java +++ b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/EthStatsService.java @@ -80,8 +80,8 @@ 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, diff --git a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/authentication/AuthenticationData.java b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/authentication/AuthenticationData.java index 2e222f08b0c..cb68ebc7d13 100644 --- a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/authentication/AuthenticationData.java +++ b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/authentication/AuthenticationData.java @@ -19,18 +19,37 @@ 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(); } diff --git a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/authentication/NodeInfo.java b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/authentication/NodeInfo.java index 19c34db4b33..b54fd9fa395 100644 --- a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/authentication/NodeInfo.java +++ b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/authentication/NodeInfo.java @@ -19,42 +19,102 @@ 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(); } diff --git a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/BlockReport.java b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/BlockReport.java index ccedbb03950..c4816d6486a 100644 --- a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/BlockReport.java +++ b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/BlockReport.java @@ -21,15 +21,29 @@ 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(); } diff --git a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/HistoryReport.java b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/HistoryReport.java index 3aafa6200b8..5df2c848cab 100644 --- a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/HistoryReport.java +++ b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/HistoryReport.java @@ -23,15 +23,29 @@ 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 getHistory(); } diff --git a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/LatencyReport.java b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/LatencyReport.java index 58201332b9d..5c588427243 100644 --- a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/LatencyReport.java +++ b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/LatencyReport.java @@ -19,15 +19,29 @@ 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(); } diff --git a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/NodeStatsReport.java b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/NodeStatsReport.java index 67bc977a198..af95de720aa 100644 --- a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/NodeStatsReport.java +++ b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/NodeStatsReport.java @@ -19,42 +19,92 @@ 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(); } diff --git a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/PendingTransactionsReport.java b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/PendingTransactionsReport.java index 5c168e29071..dbb19ac34b3 100644 --- a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/PendingTransactionsReport.java +++ b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/PendingTransactionsReport.java @@ -19,24 +19,44 @@ 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(); } diff --git a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/PingReport.java b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/PingReport.java index 945f35530b2..d7470a65cf9 100644 --- a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/PingReport.java +++ b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/report/PingReport.java @@ -19,15 +19,29 @@ 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(); } diff --git a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/request/EthStatsRequest.java b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/request/EthStatsRequest.java index dbd8b9ccf66..8d2acf3a056 100644 --- a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/request/EthStatsRequest.java +++ b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/request/EthStatsRequest.java @@ -23,10 +23,16 @@ 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 Type getType() { .orElse(Type.UNKNOWN); } + /** + * Gets the parameters of the request. + * + * @return the parameters of the request + */ public List 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 static EthStatsRequest fromResponse(final String value) { } } + /** 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 enum Type { 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)) { diff --git a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/util/EthStatsConnectOptions.java b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/util/EthStatsConnectOptions.java index 7f020adf452..1db74735239 100644 --- a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/util/EthStatsConnectOptions.java +++ b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/util/EthStatsConnectOptions.java @@ -23,24 +23,71 @@ 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 { diff --git a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/util/PrimusHeartBeatsHelper.java b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/util/PrimusHeartBeatsHelper.java index e96019ef818..03b6634af1d 100644 --- a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/util/PrimusHeartBeatsHelper.java +++ b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/util/PrimusHeartBeatsHelper.java @@ -18,14 +18,29 @@ 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())); diff --git a/ethereum/evmtool/src/main/resources/log4j2.xml b/ethereum/evmtool/src/main/resources/log4j2.xml index 0d3a7de136c..8e70c35eea9 100644 --- a/ethereum/evmtool/src/main/resources/log4j2.xml +++ b/ethereum/evmtool/src/main/resources/log4j2.xml @@ -6,7 +6,7 @@ - + diff --git a/util/build.gradle b/util/build.gradle index b2a93b1c785..41e4badb333 100644 --- a/util/build.gradle +++ b/util/build.gradle @@ -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' diff --git a/util/src/main/java/org/hyperledger/besu/util/log4j/plugin/BesuLogMessageConverter.java b/util/src/main/java/org/hyperledger/besu/util/log4j/plugin/BesuLogMessageConverter.java new file mode 100644 index 00000000000..5598f92f9d2 --- /dev/null +++ b/util/src/main/java/org/hyperledger/besu/util/log4j/plugin/BesuLogMessageConverter.java @@ -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. + * + *

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(); + } +} diff --git a/util/src/test/java/org/hyperledger/besu/util/log4j/plugin/BesuLogMessageConverterTest.java b/util/src/test/java/org/hyperledger/besu/util/log4j/plugin/BesuLogMessageConverterTest.java new file mode 100644 index 00000000000..777e5c31a38 --- /dev/null +++ b/util/src/test/java/org/hyperledger/besu/util/log4j/plugin/BesuLogMessageConverterTest.java @@ -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); + } +}