Browse Source

Add access to network engine stats

Added API call GET /peers/enginestats to allow external monitoring.

Extract all engine stats in one synchronized block, instead of
separate calls, for better consistency.
pull/67/head
catbref 5 years ago
parent
commit
51fd177d79
  1. 24
      src/main/java/org/qortal/api/resource/PeersResource.java
  2. 5
      src/main/java/org/qortal/network/Network.java
  3. 41
      src/main/java/org/qortal/utils/ExecuteProduceConsume.java
  4. 20
      src/test/java/org/qortal/test/EPCTests.java

24
src/main/java/org/qortal/api/resource/PeersResource.java

@ -31,6 +31,7 @@ import org.qortal.network.PeerAddress;
import org.qortal.repository.DataException;
import org.qortal.repository.Repository;
import org.qortal.repository.RepositoryManager;
import org.qortal.utils.ExecuteProduceConsume;
@Path("/peers")
@Tag(name = "Peers")
@ -108,6 +109,29 @@ public class PeersResource {
return Network.getInstance().getSelfPeers();
}
@GET
@Path("/enginestats")
@Operation(
summary = "Fetch statistics snapshot for networking engine",
responses = {
@ApiResponse(
content = @Content(
mediaType = MediaType.APPLICATION_JSON,
array = @ArraySchema(
schema = @Schema(
implementation = ExecuteProduceConsume.StatsSnapshot.class
)
)
)
)
}
)
public ExecuteProduceConsume.StatsSnapshot getEngineStats() {
Security.checkApiCallAllowed(request);
return Network.getInstance().getStatsSnapshot();
}
@POST
@Operation(
summary = "Add new peer address",

5
src/main/java/org/qortal/network/Network.java

@ -56,6 +56,7 @@ import org.qortal.repository.Repository;
import org.qortal.repository.RepositoryManager;
import org.qortal.settings.Settings;
import org.qortal.utils.ExecuteProduceConsume;
import org.qortal.utils.ExecuteProduceConsume.StatsSnapshot;
import org.qortal.utils.NTP;
// For managing peers
@ -199,6 +200,10 @@ public class Network {
return this.maxMessageSize;
}
public StatsSnapshot getStatsSnapshot() {
return this.networkEPC.getStatsSnapshot();
}
// Peer lists
public List<Peer> getConnectedPeers() {

41
src/main/java/org/qortal/utils/ExecuteProduceConsume.java

@ -5,11 +5,26 @@ import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public abstract class ExecuteProduceConsume implements Runnable {
@XmlAccessorType(XmlAccessType.FIELD)
public static class StatsSnapshot {
public int activeThreadCount = 0;
public int greatestActiveThreadCount = 0;
public int consumerCount = 0;
public int tasksProduced = 0;
public int tasksConsumed = 0;
public StatsSnapshot() {
}
}
private final String className;
private final Logger logger;
@ -51,28 +66,18 @@ public abstract class ExecuteProduceConsume implements Runnable {
return this.executor.awaitTermination(timeout, TimeUnit.MILLISECONDS);
}
public int getActiveThreadCount() {
synchronized (this) {
return this.activeThreadCount;
}
}
public StatsSnapshot getStatsSnapshot() {
StatsSnapshot snapshot = new StatsSnapshot();
public int getGreatestActiveThreadCount() {
synchronized (this) {
return this.greatestActiveThreadCount;
snapshot.activeThreadCount = this.activeThreadCount;
snapshot.greatestActiveThreadCount = this.greatestActiveThreadCount;
snapshot.consumerCount = this.consumerCount;
snapshot.tasksProduced = this.tasksProduced;
snapshot.tasksConsumed = this.tasksConsumed;
}
}
public int getTasksProduced() {
synchronized (this) {
return this.tasksProduced;
}
}
public int getTasksConsumed() {
synchronized (this) {
return this.tasksConsumed;
}
return snapshot;
}
/**

20
src/test/java/org/qortal/test/EPCTests.java

@ -11,6 +11,7 @@ import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.qortal.utils.ExecuteProduceConsume;
import org.qortal.utils.ExecuteProduceConsume.StatsSnapshot;
public class EPCTests {
@ -60,13 +61,12 @@ public class EPCTests {
ScheduledExecutorService statusExecutor = Executors.newSingleThreadScheduledExecutor();
statusExecutor.scheduleAtFixedRate(() -> {
synchronized (testEPC) {
final long seconds = (System.currentTimeMillis() - start) / 1000L;
System.out.println(String.format("After %d second%s, active threads: %d, greatest thread count: %d, tasks produced: %d, tasks consumed: %d",
seconds, (seconds != 1 ? "s" : ""),
testEPC.getActiveThreadCount(), testEPC.getGreatestActiveThreadCount(),
testEPC.getTasksProduced(), testEPC.getTasksConsumed()));
}
StatsSnapshot snapshot = testEPC.getStatsSnapshot();
final long seconds = (System.currentTimeMillis() - start) / 1000L;
System.out.println(String.format("After %d second%s, active threads: %d, greatest thread count: %d, tasks produced: %d, tasks consumed: %d",
seconds, (seconds != 1 ? "s" : ""),
snapshot.activeThreadCount, snapshot.greatestActiveThreadCount,
snapshot.tasksProduced, snapshot.tasksConsumed));
}, 1L, 1L, TimeUnit.SECONDS);
// Let it run for a minute
@ -78,10 +78,10 @@ public class EPCTests {
final long after = System.currentTimeMillis();
System.out.println(String.format("Shutdown took %d milliseconds", after - before));
System.out.println(String.format("Greatest thread count: %d", testEPC.getGreatestActiveThreadCount()));
System.out.println(String.format("Tasks produced: %d", testEPC.getTasksProduced()));
System.out.println(String.format("Tasks consumed: %d", testEPC.getTasksConsumed()));
StatsSnapshot snapshot = testEPC.getStatsSnapshot();
System.out.println(String.format("Greatest thread count: %d, tasks produced: %d, tasks consumed: %d",
snapshot.greatestActiveThreadCount, snapshot.tasksProduced, snapshot.tasksConsumed));
}
@Test

Loading…
Cancel
Save