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.DataException;
import org.qortal.repository.Repository; import org.qortal.repository.Repository;
import org.qortal.repository.RepositoryManager; import org.qortal.repository.RepositoryManager;
import org.qortal.utils.ExecuteProduceConsume;
@Path("/peers") @Path("/peers")
@Tag(name = "Peers") @Tag(name = "Peers")
@ -108,6 +109,29 @@ public class PeersResource {
return Network.getInstance().getSelfPeers(); 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 @POST
@Operation( @Operation(
summary = "Add new peer address", 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.repository.RepositoryManager;
import org.qortal.settings.Settings; import org.qortal.settings.Settings;
import org.qortal.utils.ExecuteProduceConsume; import org.qortal.utils.ExecuteProduceConsume;
import org.qortal.utils.ExecuteProduceConsume.StatsSnapshot;
import org.qortal.utils.NTP; import org.qortal.utils.NTP;
// For managing peers // For managing peers
@ -199,6 +200,10 @@ public class Network {
return this.maxMessageSize; return this.maxMessageSize;
} }
public StatsSnapshot getStatsSnapshot() {
return this.networkEPC.getStatsSnapshot();
}
// Peer lists // Peer lists
public List<Peer> getConnectedPeers() { 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.RejectedExecutionException;
import java.util.concurrent.TimeUnit; 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.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
public abstract class ExecuteProduceConsume implements Runnable { 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 String className;
private final Logger logger; private final Logger logger;
@ -51,28 +66,18 @@ public abstract class ExecuteProduceConsume implements Runnable {
return this.executor.awaitTermination(timeout, TimeUnit.MILLISECONDS); return this.executor.awaitTermination(timeout, TimeUnit.MILLISECONDS);
} }
public int getActiveThreadCount() { public StatsSnapshot getStatsSnapshot() {
synchronized (this) { StatsSnapshot snapshot = new StatsSnapshot();
return this.activeThreadCount;
}
}
public int getGreatestActiveThreadCount() {
synchronized (this) { 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() { return snapshot;
synchronized (this) {
return this.tasksProduced;
}
}
public int getTasksConsumed() {
synchronized (this) {
return this.tasksConsumed;
}
} }
/** /**

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

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

Loading…
Cancel
Save