diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties
index 8b9d6fb6f4..54afe6d76c 100644
--- a/core/src/main/resources/i18n/displayStrings.properties
+++ b/core/src/main/resources/i18n/displayStrings.properties
@@ -1124,7 +1124,8 @@ settings.net.p2PPeersLabel=Connected peers
settings.net.onionAddressColumn=Onion address
settings.net.creationDateColumn=Established
settings.net.connectionTypeColumn=In/Out
-settings.net.totalTrafficLabel=Total traffic
+settings.net.sentDataLabel=Sent data statistics
+settings.net.receivedDataLabel=Received data statistics
settings.net.roundTripTimeColumn=Roundtrip
settings.net.sentBytesColumn=Sent
settings.net.receivedBytesColumn=Received
@@ -1137,7 +1138,8 @@ settings.net.heightColumn=Height
settings.net.needRestart=You need to restart the application to apply that change.\nDo you want to do that now?
settings.net.notKnownYet=Not known yet...
-settings.net.sentReceived=Sent: {0}, received: {1}
+settings.net.sentData=Sent data: {0}, {1} messages, {2} messages/sec, {3} messages received in last second
+settings.net.receivedData=Received data: {0}, {1} messages, {2} messages/sec, {3} messages received in last second
settings.net.ips=[IP address:port | host name:port | onion address:port] (comma separated). Port can be omitted if default is used (8333).
settings.net.seedNode=Seed node
settings.net.directPeer=Peer (direct)
diff --git a/desktop/src/main/java/bisq/desktop/main/settings/network/NetworkSettingsView.fxml b/desktop/src/main/java/bisq/desktop/main/settings/network/NetworkSettingsView.fxml
index d583b18a09..5b966f0973 100644
--- a/desktop/src/main/java/bisq/desktop/main/settings/network/NetworkSettingsView.fxml
+++ b/desktop/src/main/java/bisq/desktop/main/settings/network/NetworkSettingsView.fxml
@@ -153,10 +153,13 @@
-
-
+
+
+
diff --git a/desktop/src/main/java/bisq/desktop/main/settings/network/NetworkSettingsView.java b/desktop/src/main/java/bisq/desktop/main/settings/network/NetworkSettingsView.java
index 0e82e9b9e0..d99b4f6454 100644
--- a/desktop/src/main/java/bisq/desktop/main/settings/network/NetworkSettingsView.java
+++ b/desktop/src/main/java/bisq/desktop/main/settings/network/NetworkSettingsView.java
@@ -73,6 +73,8 @@ import javafx.collections.transformation.SortedList;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
+import static javafx.beans.binding.Bindings.createStringBinding;
+
@FxmlView
public class NetworkSettingsView extends ActivatableView {
@@ -83,7 +85,7 @@ public class NetworkSettingsView extends ActivatableView {
@FXML
InputTextField btcNodesInputTextField;
@FXML
- TextField onionAddress, totalTrafficTextField;
+ TextField onionAddress, sentDataTextField, receivedDataTextField;
@FXML
Label p2PPeersLabel, bitcoinPeersLabel;
@FXML
@@ -175,7 +177,8 @@ public class NetworkSettingsView extends ActivatableView {
onionAddressColumn.getStyleClass().add("first-column");
creationDateColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.creationDateColumn")));
connectionTypeColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.connectionTypeColumn")));
- totalTrafficTextField.setPromptText(Res.get("settings.net.totalTrafficLabel"));
+ sentDataTextField.setPromptText(Res.get("settings.net.sentDataLabel"));
+ receivedDataTextField.setPromptText(Res.get("settings.net.receivedDataLabel"));
roundTripTimeColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.roundTripTimeColumn")));
sentBytesColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.sentBytesColumn")));
receivedBytesColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.receivedBytesColumn")));
@@ -297,11 +300,20 @@ public class NetworkSettingsView extends ActivatableView {
Res.get("settings.net.notKnownYet") :
nodeAddress.getFullAddress()));
numP2PPeersSubscription = EasyBind.subscribe(p2PService.getNumConnectedPeers(), numPeers -> updateP2PTable());
- totalTrafficTextField.textProperty().bind(EasyBind.combine(Statistic.totalSentBytesProperty(),
- Statistic.totalReceivedBytesProperty(),
- (sent, received) -> Res.get("settings.net.sentReceived",
- FormattingUtils.formatBytes((long) sent),
- FormattingUtils.formatBytes((long) received))));
+
+ sentDataTextField.textProperty().bind(createStringBinding(() -> Res.get("settings.net.sentData",
+ FormattingUtils.formatBytes(Statistic.totalSentBytesProperty().get()),
+ Statistic.numTotalSentMessagesProperty().get(),
+ Statistic.numTotalSentMessagesPerSecProperty().get(),
+ Statistic.numTotalSentMessagesLastSecProperty().get()),
+ Statistic.numTotalSentMessagesLastSecProperty()));
+
+ receivedDataTextField.textProperty().bind(createStringBinding(() -> Res.get("settings.net.receivedData",
+ FormattingUtils.formatBytes(Statistic.totalReceivedBytesProperty().get()),
+ Statistic.numTotalReceivedMessagesProperty().get(),
+ Statistic.numTotalReceivedMessagesPerSecProperty().get(),
+ Statistic.numTotalReceivedMessagesLastSecProperty().get()),
+ Statistic.numTotalReceivedMessagesLastSecProperty()));
bitcoinSortedList.comparatorProperty().bind(bitcoinPeersTableView.comparatorProperty());
bitcoinPeersTableView.setItems(bitcoinSortedList);
@@ -338,7 +350,8 @@ public class NetworkSettingsView extends ActivatableView {
if (numP2PPeersSubscription != null)
numP2PPeersSubscription.unsubscribe();
- totalTrafficTextField.textProperty().unbind();
+ sentDataTextField.textProperty().unbind();
+ receivedDataTextField.textProperty().unbind();
bitcoinSortedList.comparatorProperty().unbind();
p2pSortedList.comparatorProperty().unbind();
diff --git a/p2p/src/main/java/bisq/network/p2p/network/Statistic.java b/p2p/src/main/java/bisq/network/p2p/network/Statistic.java
index 0809e49f54..ea987ae409 100644
--- a/p2p/src/main/java/bisq/network/p2p/network/Statistic.java
+++ b/p2p/src/main/java/bisq/network/p2p/network/Statistic.java
@@ -20,8 +20,10 @@ package bisq.network.p2p.network;
import bisq.common.UserThread;
import bisq.common.proto.network.NetworkEnvelope;
+import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.LongProperty;
+import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleLongProperty;
@@ -29,31 +31,98 @@ import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * Network statistics per connection. As we are also interested in total network statistics
+ * we use static properties to get traffic of all connections combined.
+ */
+@Slf4j
public class Statistic {
///////////////////////////////////////////////////////////////////////////////////////////
// Static
///////////////////////////////////////////////////////////////////////////////////////////
+
+ private final static long startTime = System.currentTimeMillis();
private final static LongProperty totalSentBytes = new SimpleLongProperty(0);
private final static LongProperty totalReceivedBytes = new SimpleLongProperty(0);
+ private final static Map totalReceivedMessages = new ConcurrentHashMap<>();
+ private final static Map totalSentMessages = new ConcurrentHashMap<>();
+ private final static Map totalReceivedMessagesPerSec = new ConcurrentHashMap<>();
+ private final static Map totalSentMessagesPerSec = new ConcurrentHashMap<>();
+ private final static LongProperty numTotalSentMessages = new SimpleLongProperty(0);
+ private final static LongProperty numTotalSentMessagesLastSec = new SimpleLongProperty(0);
+ private final static DoubleProperty numTotalSentMessagesPerSec = new SimpleDoubleProperty(0);
+ private final static LongProperty numTotalReceivedMessages = new SimpleLongProperty(0);
+ private final static LongProperty numTotalReceivedMessagesLastSec = new SimpleLongProperty(0);
+ private final static DoubleProperty numTotalReceivedMessagesPerSec = new SimpleDoubleProperty(0);
- public static long getTotalSentBytes() {
- return totalSentBytes.get();
+ static {
+ UserThread.runPeriodically(() -> {
+ numTotalSentMessages.set(totalSentMessages.values().stream().mapToInt(Integer::intValue).sum());
+ numTotalSentMessagesLastSec.set(totalSentMessagesPerSec.values().stream().mapToInt(Integer::intValue).sum());
+ numTotalReceivedMessages.set(totalReceivedMessages.values().stream().mapToInt(Integer::intValue).sum());
+ numTotalReceivedMessagesLastSec.set(totalReceivedMessagesPerSec.values().stream().mapToInt(Integer::intValue).sum());
+
+ long passed = (System.currentTimeMillis() - startTime) / 1000;
+ numTotalSentMessagesPerSec.set(((double) numTotalSentMessages.get()) / passed);
+ numTotalReceivedMessagesPerSec.set(((double) numTotalReceivedMessages.get()) / passed);
+ totalSentMessagesPerSec.clear();
+ totalReceivedMessagesPerSec.clear();
+ }, 1);
+
+ // We log statistics every minute
+ UserThread.runPeriodically(() -> {
+ log.error("Network statistics:\n" +
+ "totalSentBytes: {} kb;\n" +
+ "numTotalSentMessages/totalSentMessages: {} / {};\n" +
+ "numTotalSentMessagesLastSec/totalSentMessagesPerSec: {} / {};\n" +
+ "totalReceivedBytes: {} kb" +
+ "numTotalReceivedMessages/totalReceivedMessages: {} / {};\n" +
+ "numTotalReceivedMessagesLastSec/totalReceivedMessagesPerSec: {} / {};",
+ totalSentBytes.get() / 1024d,
+ numTotalSentMessages.get(), totalSentMessages,
+ numTotalSentMessagesLastSec.get(), totalSentMessagesPerSec,
+ totalReceivedBytes.get() / 1024d,
+ numTotalReceivedMessages.get(), totalReceivedMessages,
+ numTotalReceivedMessagesLastSec.get(), totalReceivedMessagesPerSec);
+ }, 60);
}
public static LongProperty totalSentBytesProperty() {
return totalSentBytes;
}
- public static long getTotalReceivedBytes() {
- return totalReceivedBytes.get();
- }
-
public static LongProperty totalReceivedBytesProperty() {
return totalReceivedBytes;
}
+ public static LongProperty numTotalSentMessagesProperty() {
+ return numTotalSentMessages;
+ }
+
+ public static LongProperty numTotalSentMessagesLastSecProperty() {
+ return numTotalSentMessagesLastSec;
+ }
+
+ public static DoubleProperty numTotalSentMessagesPerSecProperty() {
+ return numTotalSentMessagesPerSec;
+ }
+
+ public static LongProperty numTotalReceivedMessagesProperty() {
+ return numTotalReceivedMessages;
+ }
+
+ public static LongProperty numTotalReceivedMessagesLastSecProperty() {
+ return numTotalReceivedMessagesLastSec;
+ }
+
+ public static DoubleProperty numTotalReceivedMessagesPerSecProperty() {
+ return numTotalReceivedMessagesPerSec;
+ }
+
///////////////////////////////////////////////////////////////////////////////////////////
// Instance fields
@@ -72,7 +141,7 @@ public class Statistic {
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
- public Statistic() {
+ Statistic() {
creationDate = new Date();
}
@@ -80,18 +149,18 @@ public class Statistic {
// Update, increment
///////////////////////////////////////////////////////////////////////////////////////////
- public void updateLastActivityTimestamp() {
+ void updateLastActivityTimestamp() {
UserThread.execute(() -> lastActivityTimestamp = System.currentTimeMillis());
}
- public void addSentBytes(int value) {
+ void addSentBytes(int value) {
UserThread.execute(() -> {
sentBytes.set(sentBytes.get() + value);
totalSentBytes.set(totalSentBytes.get() + value);
});
}
- public void addReceivedBytes(int value) {
+ void addReceivedBytes(int value) {
UserThread.execute(() -> {
receivedBytes.set(receivedBytes.get() + value);
totalReceivedBytes.set(totalReceivedBytes.get() + value);
@@ -99,22 +168,46 @@ public class Statistic {
}
// TODO would need msg inspection to get useful information...
- public void addReceivedMessage(NetworkEnvelope networkEnvelope) {
+ void addReceivedMessage(NetworkEnvelope networkEnvelope) {
String messageClassName = networkEnvelope.getClass().getSimpleName();
int counter = 1;
- if (receivedMessages.containsKey(messageClassName))
+ if (receivedMessages.containsKey(messageClassName)) {
counter = receivedMessages.get(messageClassName) + 1;
-
+ }
receivedMessages.put(messageClassName, counter);
+
+ counter = 1;
+ if (totalReceivedMessages.containsKey(messageClassName)) {
+ counter = totalReceivedMessages.get(messageClassName) + 1;
+ }
+ totalReceivedMessages.put(messageClassName, counter);
+
+ counter = 1;
+ if (totalReceivedMessagesPerSec.containsKey(messageClassName)) {
+ counter = totalReceivedMessagesPerSec.get(messageClassName) + 1;
+ }
+ totalReceivedMessagesPerSec.put(messageClassName, counter);
}
- public void addSentMessage(NetworkEnvelope networkEnvelope) {
+ void addSentMessage(NetworkEnvelope networkEnvelope) {
String messageClassName = networkEnvelope.getClass().getSimpleName();
int counter = 1;
- if (sentMessages.containsKey(messageClassName))
+ if (sentMessages.containsKey(messageClassName)) {
counter = sentMessages.get(messageClassName) + 1;
-
+ }
sentMessages.put(messageClassName, counter);
+
+ counter = 1;
+ if (totalSentMessages.containsKey(messageClassName)) {
+ counter = totalSentMessages.get(messageClassName) + 1;
+ }
+ totalSentMessages.put(messageClassName, counter);
+
+ counter = 1;
+ if (totalSentMessagesPerSec.containsKey(messageClassName)) {
+ counter = totalSentMessagesPerSec.get(messageClassName) + 1;
+ }
+ totalSentMessagesPerSec.put(messageClassName, counter);
}
public void setRoundTripTime(int roundTripTime) {
@@ -160,11 +253,13 @@ public class Statistic {
@Override
public String toString() {
return "Statistic{" +
- "creationDate=" + creationDate +
- ", lastActivityTimestamp=" + lastActivityTimestamp +
- ", sentBytes=" + sentBytes +
- ", receivedBytes=" + receivedBytes +
- '}';
+ "\n creationDate=" + creationDate +
+ ",\n lastActivityTimestamp=" + lastActivityTimestamp +
+ ",\n sentBytes=" + sentBytes +
+ ",\n receivedBytes=" + receivedBytes +
+ ",\n receivedMessages=" + receivedMessages +
+ ",\n sentMessages=" + sentMessages +
+ ",\n roundTripTime=" + roundTripTime +
+ "\n}";
}
-
}