Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve seednode monitoring #6432

7 changes: 6 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ configure([project(':cli'),
build.dependsOn installDist
installDist.destinationDir = file('build/app')
distZip.enabled = false
distTar.enabled = false

// the 'installDist' and 'startScripts' blocks below configure bisq executables to put
// generated shell scripts in the root project directory, such that users can easily
Expand Down Expand Up @@ -235,7 +236,7 @@ configure(project(':common')) {
ext.getHash = {
def p1 = 'git rev-parse HEAD'.execute()
p1.waitFor()
return p1.text.substring(0,7)
return p1.text
}

jar.manifest.attributes(
Expand Down Expand Up @@ -516,6 +517,10 @@ configure(project(':desktop')) {
configure(project(':seednode')) {
apply plugin: 'com.github.johnrengelman.shadow'

jar.manifest.attributes(
"Implementation-Title": project.name,
"Implementation-Version": version)

mainClassName = 'bisq.seednode.SeedNodeMain'

dependencies {
Expand Down
13 changes: 8 additions & 5 deletions common/src/main/java/bisq/common/app/Version.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.jar.Attributes;
import java.util.jar.Manifest;

Expand Down Expand Up @@ -140,14 +142,15 @@ public static void printVersion() {
'}');
}

public String readCommitHash() {
public static Optional<String> findCommitHash() {
try {
String pth = getClass().getResource(getClass().getSimpleName() + ".class").toString();
String pth = Objects.requireNonNull(Version.class.getResource(Version.class.getSimpleName() + ".class")).toString();
String mnf = pth.substring(0, pth.lastIndexOf("!") + 1) + "/META-INF/MANIFEST.MF";
Attributes attr = new Manifest(new URL(mnf).openStream()).getMainAttributes();
return attr.getValue("Implementation-Version");
} catch (Exception ignored) { }
return "unknown";
return Optional.of(attr.getValue("Implementation-Version"));
} catch (Exception ignored) {
return Optional.empty();
}
}

public static final byte COMPENSATION_REQUEST = (byte) 0x01;
Expand Down
8 changes: 8 additions & 0 deletions common/src/main/java/bisq/common/config/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ public class Config {
public static final String BYPASS_MEMPOOL_VALIDATION = "bypassMempoolValidation";
public static final String DAO_NODE_API_URL = "daoNodeApiUrl";
public static final String DAO_NODE_API_PORT = "daoNodeApiPort";
public static final String SEED_NODE_REPORTING_SERVER_URL = "seedNodeReportingServerUrl";

// Default values for certain options
public static final int UNSPECIFIED_PORT = -1;
Expand Down Expand Up @@ -220,6 +221,7 @@ public class Config {
public final boolean bypassMempoolValidation;
public final String daoNodeApiUrl;
public final int daoNodeApiPort;
public final String seedNodeReportingServerUrl;

// Properties derived from options but not exposed as options themselves
public final File torDir;
Expand Down Expand Up @@ -679,6 +681,11 @@ public Config(String defaultAppName, File defaultUserDataDir, String... args) {
.withRequiredArg()
.ofType(Integer.class)
.defaultsTo(8082);
ArgumentAcceptingOptionSpec<String> seedNodeReportingServerUrlOpt =
parser.accepts(SEED_NODE_REPORTING_SERVER_URL, "URL of seed node reporting server")
.withRequiredArg()
.ofType(String.class)
.defaultsTo("");

try {
CompositeOptionSet options = new CompositeOptionSet();
Expand Down Expand Up @@ -799,6 +806,7 @@ public Config(String defaultAppName, File defaultUserDataDir, String... args) {
this.bypassMempoolValidation = options.valueOf(bypassMempoolValidationOpt);
this.daoNodeApiUrl = options.valueOf(daoNodeApiUrlOpt);
this.daoNodeApiPort = options.valueOf(daoNodeApiPortOpt);
this.seedNodeReportingServerUrl = options.valueOf(seedNodeReportingServerUrlOpt);
} catch (OptionException ex) {
throw new ConfigException("problem parsing option '%s': %s",
ex.options().get(0),
Expand Down
1 change: 1 addition & 0 deletions common/src/main/java/bisq/common/setup/CommonSetup.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ public static void setupUncaughtExceptionHandler(UncaughtExceptionHandler uncaug
private static void setupLog(Config config) {
String logPath = Paths.get(config.appDataDir.getPath(), "bisq").toString();
Log.setup(logPath);
log.info("Log file at: {}.log", logPath);
Utilities.printSysInfo();
Log.setLevel(Level.toLevel(config.logLevel));
}
Expand Down
57 changes: 57 additions & 0 deletions common/src/main/java/bisq/common/util/CompletableFutureUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.common.util;

import java.util.Collection;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.Stream;

//todo
public class CompletableFutureUtil {
public static <T> CompletableFuture<List<T>> allOf(Collection<CompletableFuture<T>> collection) {
//noinspection unchecked
return allOf(collection.toArray(new CompletableFuture[0]));
}

public static <T> CompletableFuture<List<T>> allOf(Stream<CompletableFuture<T>> stream) {
return allOf(stream.collect(Collectors.toList()));
}

public static <T> CompletableFuture<List<T>> allOf(CompletableFuture<T>... list) {
CompletableFuture<List<T>> result = CompletableFuture.allOf(list).thenApply(v ->
Stream.of(list)
.map(future -> {
// We want to return the results in list, not the futures. Once allOf call is complete
// we know that all futures have completed (normally, exceptional or cancelled).
// For exceptional and canceled cases we throw an exception.
T res = future.join();
if (future.isCompletedExceptionally()) {
throw new RuntimeException((future.handle((r, throwable) -> throwable).join()));
}
if (future.isCancelled()) {
throw new RuntimeException("Future got canceled");
}
return res;
})
.collect(Collectors.<T>toList())
);
return result;
}
}
7 changes: 7 additions & 0 deletions common/src/main/java/bisq/common/util/Utilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -135,6 +136,12 @@ private static ThreadPoolExecutor getThreadPoolExecutor(String name,
return executor;
}

public static ExecutorService newCachedThreadPool(int maximumPoolSize) {
return new ThreadPoolExecutor(0, maximumPoolSize,
60, TimeUnit.SECONDS,
new SynchronousQueue<>());
}

@SuppressWarnings("SameParameterValue")
public static ScheduledThreadPoolExecutor getScheduledThreadPoolExecutor(String name,
int corePoolSize,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ protected void configure() {
bindConstant().annotatedWith(named(USE_DEV_MODE_HEADER)).to(config.useDevModeHeader);
bindConstant().annotatedWith(named(REFERRAL_ID)).to(config.referralId);
bindConstant().annotatedWith(named(PREVENT_PERIODIC_SHUTDOWN_AT_SEED_NODE)).to(config.preventPeriodicShutdownAtSeedNode);
bindConstant().annotatedWith(named(SEED_NODE_REPORTING_SERVER_URL)).to(config.seedNodeReportingServerUrl);

// ordering is used for shut down sequence
install(new TradeModule(config));
Expand Down
86 changes: 86 additions & 0 deletions core/src/main/java/bisq/core/monitor/DoubleValueItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.core.monitor;

import lombok.Getter;
import lombok.Setter;


public enum DoubleValueItem implements ReportingItem {
Unspecified("", "Unspecified"),
sentBytesPerSec("network", "sentBytesPerSec"),
receivedBytesPerSec("network", "receivedBytesPerSec"),
receivedMessagesPerSec("network", "receivedMessagesPerSec"),
sentMessagesPerSec("network", "sentMessagesPerSec");


@Getter
@Setter
private String key;
@Getter
@Setter
private String group;
@Getter
@Setter
private double value;

DoubleValueItem(String group, String key) {
this.group = group;
this.key = key;
}

public DoubleValueItem withValue(double value) {
setValue(value);
return this;
}

public static DoubleValueItem from(String key, double value) {
DoubleValueItem item;
try {
item = DoubleValueItem.valueOf(key);
} catch (Throwable t) {
item = DoubleValueItem.Unspecified;
item.setKey(key);
}

item.setValue(value);
return item;
}

@Override
public protobuf.ReportingItem toProtoMessage() {
return getBuilder().setDoubleValueItem(protobuf.DoubleValueItem.newBuilder()
.setValue(value))
.build();
}

public static DoubleValueItem fromProto(protobuf.ReportingItem baseProto, protobuf.DoubleValueItem proto) {
return DoubleValueItem.from(baseProto.getKey(), proto.getValue());
}

@Override
public String getPath() {
return group + "." + key;
}


@Override
public String toString() {
return name() + "=" + value;
}
}
107 changes: 107 additions & 0 deletions core/src/main/java/bisq/core/monitor/LongValueItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.core.monitor;

import lombok.Getter;
import lombok.Setter;


public enum LongValueItem implements ReportingItem {
Unspecified("", "Unspecified"),
OfferPayload("data", "OfferPayload"),
MailboxStoragePayload("data", "MailboxStoragePayload"),
TradeStatistics3("data", "TradeStatistics3"),
AccountAgeWitness("data", "AccountAgeWitness"),
SignedWitness("data", "SignedWitness"),
Alert("data", "Alert"),
Filter("data", "Filter"),
Arbitrator("data", "Arbitrator"),
Mediator("data", "Mediator"),
RefundAgent("data", "RefundAgent"),

TempProposalPayload("dao", "TempProposalPayload"),
ProposalPayload("dao", "ProposalPayload"),
BlindVotePayload("dao", "BlindVotePayload"),
daoStateChainHeight("dao", "daoStateChainHeight"),
blockTimeIsSec("dao", "blockTimeIsSec"),

maxConnections("network", "maxConnections"),
numConnections("network", "numConnections"),
peakNumConnections("network", "peakNumConnections"),
numAllConnectionsLostEvents("network", "numAllConnectionsLostEvents"),
sentBytes("network", "sentBytes"),
receivedBytes("network", "receivedBytes"),

usedMemoryInMB("node", "usedMemoryInMB"),
totalMemoryInMB("node", "totalMemoryInMB"),
jvmStartTimeInSec("node", "jvmStartTimeInSec");

@Getter
@Setter
private String key;
@Getter
@Setter
private String group;
@Getter
@Setter
private long value;

LongValueItem(String group, String key) {
this.group = group;
this.key = key;
}

public LongValueItem withValue(long value) {
setValue(value);
return this;
}

public static LongValueItem from(String key, long value) {
LongValueItem item;
try {
item = LongValueItem.valueOf(key);
} catch (Throwable t) {
item = LongValueItem.Unspecified;
item.setKey(key);
}

item.setValue(value);
return item;
}

@Override
public protobuf.ReportingItem toProtoMessage() {
return getBuilder().setLongValueItem(protobuf.LongValueItem.newBuilder()
.setValue(value))
.build();
}

public static LongValueItem fromProto(protobuf.ReportingItem baseProto, protobuf.LongValueItem proto) {
return LongValueItem.from(baseProto.getKey(), proto.getValue());
}

@Override
public String getPath() {
return group + "." + key;
}

@Override
public String toString() {
return name() + "=" + value;
}
}
Loading