Enable MP Metrics and add some application specific metrics

This commit is contained in:
olendvcook 2019-05-28 15:41:04 -05:00
parent 823c3b8dca
commit c5b0f505a8
13 changed files with 239 additions and 9 deletions

View File

@ -18,6 +18,8 @@ import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import org.eclipse.microprofile.metrics.MetricUnits;
import org.eclipse.microprofile.metrics.annotation.Counted;
import org.libertybikes.auth.service.ConfigBean;
import org.libertybikes.auth.service.JwtAuth;
import org.libertybikes.auth.service.github.GitHubOAuthAPI.GithubTokenResponse;
@ -50,6 +52,12 @@ public class GitHubCallback extends JwtAuth {
}
@GET
@Counted(unit = MetricUnits.NONE,
name = "num_github_logins",
monotonic = true,
displayName = "Number of Github Logins",
description = "Metrics to show how many times a user has logged in through Github Auth.",
absolute = true)
public Response getGitHubCallbackURL(@Context HttpServletRequest request) throws URISyntaxException {
try {
String githubCode = request.getParameter("code");

View File

@ -18,6 +18,8 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.eclipse.microprofile.metrics.MetricUnits;
import org.eclipse.microprofile.metrics.annotation.Counted;
import org.libertybikes.auth.service.ConfigBean;
import org.libertybikes.auth.service.JwtAuth;
@ -85,6 +87,12 @@ public class GoogleCallback extends JwtAuth {
}
@GET
@Counted(unit = MetricUnits.NONE,
name = "num_google_logins",
monotonic = true,
displayName = "Number of Google Logins",
description = "Metrics to show how many times a user has logged in through Google Auth.",
absolute = true)
public Response getGoogleAuthURL(@Context HttpServletRequest request) throws IOException, URISyntaxException {
// google calls us back at this app when a user has finished authing with them.
// when it calls us back here, it passes an oauth_verifier token that we

View File

@ -13,6 +13,8 @@ import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import org.eclipse.microprofile.metrics.MetricUnits;
import org.eclipse.microprofile.metrics.annotation.Counted;
import org.libertybikes.auth.service.ConfigBean;
import org.libertybikes.auth.service.JwtAuth;
@ -31,6 +33,12 @@ public class TwitterCallback extends JwtAuth {
ConfigBean config;
@GET
@Counted(unit = MetricUnits.NONE,
name = "num_twitter_logins",
monotonic = true,
displayName = "Number of Twitter Logins",
description = "Metrics to show how many times a user has logged in through Twitter Auth.",
absolute = true)
public Response getTwitterCallbackURL(@Context HttpServletRequest request) throws URISyntaxException {
try {
Twitter twitter = (Twitter) request.getSession().getAttribute("twitter");

View File

@ -10,7 +10,10 @@
<feature>mpJwt-1.0</feature>
<feature>mpRestClient-1.0</feature>
<feature>mpOpenAPI-1.0</feature>
<feature>mpMetrics-1.1</feature>
</featureManager>
<mpMetrics authentication="false"/>
<httpEndpoint id="defaultHttpEndpoint" host="*" httpPort="${httpPort}" httpsPort="${httpsPort}" />

View File

@ -186,7 +186,7 @@ public class GameBoard {
public void broadcastToAI() {
for (Player p : players) {
if (p.isAlive()) {
if (p.isAlive() && !p.isRealPlayer()) {
short[][] boardCopy = board.clone();
p.processAIMove(boardCopy);
}

View File

@ -32,6 +32,11 @@ import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.websocket.Session;
import org.eclipse.microprofile.metrics.Metadata;
import org.eclipse.microprofile.metrics.MetricRegistry;
import org.eclipse.microprofile.metrics.MetricType;
import org.eclipse.microprofile.metrics.MetricUnits;
import org.eclipse.microprofile.metrics.Timer.Context;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.libertybikes.game.core.Player.STATUS;
import org.libertybikes.restclient.PlayerService;
@ -87,6 +92,57 @@ public class GameRound implements Runnable {
String keyStoreAlias;
// MpMetric Metadatas
private Metadata currentRoundsCounter = new Metadata("current_num_of_rounds", // name
"Current Number of Rounds", // display name
"Number of rounds currently running", // description
MetricType.COUNTER, // type
MetricUnits.NONE); // units
private Metadata totalRoundsCounter = new Metadata("total_num_of_rounds", // name
"Total Number of Rounds", // display name
"Number of rounds that have been created", // description
MetricType.COUNTER, // type
MetricUnits.NONE); // units
private Metadata currentPlayersCounter = new Metadata("current_num_of_players", // name
"Current Number of Players", // display name
"Number of players that are currently playing in a round", // description
MetricType.COUNTER, // type
MetricUnits.NONE); // units
private Metadata totalPlayersCounter = new Metadata("total_num_of_players", // name
"Total Number of Players That Have Played", // display name
"Number of players that have played in a round, requeuing and replaying increases the count", // description
MetricType.COUNTER, // type
MetricUnits.NONE); // units
private Metadata totalMobilePlayersCounter = new Metadata("total_num_of_mobile_players", // name
"Total Number of Mobile Players That Have Played", // display name
"Number of mobile players that have played in a round, requeuing and replaying increases the count", // description
MetricType.COUNTER, // type
MetricUnits.NONE); // units
Metadata gameRoundTimerMetadata = new Metadata("game_round_timer", // name
"Game Round Timer", // display name
"The Time Game Rounds Last", // description
MetricType.TIMER, // type
MetricUnits.SECONDS); // units
private static MetricRegistry registry;
private Context timerContext;
@JsonbTransient
private static MetricRegistry getRegistry() {
try {
return registry == null ? registry = CDI.current().select(MetricRegistry.class).get() : registry;
} catch (IllegalStateException ise) {
System.out.println("WARNING: Unable to locate CDIProvider");
ise.printStackTrace();
}
return null;
}
// Get a string of 4 random uppercase letters (A-Z)
private static String getRandomId() {
char[] chars = new char[4];
@ -120,6 +176,13 @@ public class GameRound implements Runnable {
log("Unable to perform JNDI lookup to determine time between rounds, using default value");
}
MAX_TIME_BETWEEN_ROUNDS = (maxTimeBetweenRounds < 5 || maxTimeBetweenRounds > 60) ? MAX_TIME_BETWEEN_ROUNDS_DEFAULT : maxTimeBetweenRounds;
// Increment round counter metrics
MetricRegistry registry = getRegistry();
if (registry != null) {
registry.counter(totalRoundsCounter).inc();
registry.counter(currentRoundsCounter).inc();
}
}
public GameBoard getBoard() {
@ -172,6 +235,14 @@ public class GameRound implements Runnable {
isPhone = c.isPhone = hasGameBoard ? false : true;
clients.put(s, c);
log("Player " + playerId + " has joined.");
// Increment player counter metrics
getRegistry().counter(currentPlayersCounter).inc();
getRegistry().counter(totalPlayersCounter).inc();
if (isPhone) {
getRegistry().counter(totalMobilePlayersCounter).inc();
}
} else {
log("Player " + playerId + " already exists.");
}
@ -228,7 +299,7 @@ public class GameRound implements Runnable {
return c != null && c.player.isPresent();
}
private void removePlayer(Player p) {
private void removePlayer(Player p, boolean isMobile) {
p.disconnect();
log(p.name + " disconnected.");
@ -239,18 +310,29 @@ public class GameRound implements Runnable {
if (isOpen()) {
board.removePlayer(p);
// Decrement player counters because they didn't play
getRegistry().counter(totalPlayersCounter).dec();
if (isMobile) {
getRegistry().counter(totalMobilePlayersCounter).dec();
}
} else if (gameState == State.RUNNING) {
checkForWinner();
}
if (gameState != State.FINISHED)
broadcastPlayerList();
// Decrement current players counter
getRegistry().counter(currentPlayersCounter).dec();
}
public int removeClient(Session client) {
Client c = clients.remove(client);
if (c != null && c.player.isPresent())
removePlayer(c.player.get());
if (c != null && c.player.isPresent()) {
removePlayer(c.player.get(), c.isPhone);
}
return clients.size();
}
@ -263,6 +345,7 @@ public class GameRound implements Runnable {
public void run() {
gameRunning.set(true);
log(">>> Starting round");
ticksFromGameEnd = 0;
int numGames = runningGames.incrementAndGet();
if (numGames > 3)
@ -484,7 +567,13 @@ public class GameRound implements Runnable {
private void endGame() {
runningGames.decrementAndGet();
log("<<< Finished round");
// Decrement current rounds counter and close round timer
getRegistry().counter(currentRoundsCounter).dec();
timerContext.close();
broadcastPlayerList();
ManagedScheduledExecutorService exec = executor();
@ -544,6 +633,10 @@ public class GameRound implements Runnable {
executor().submit(GameRound.this);
}
gameState = State.RUNNING;
// Start round timer metric
timerContext = getRegistry().timer(gameRoundTimerMetadata).time();
}
}

View File

@ -2,12 +2,20 @@ package org.libertybikes.game.party;
import java.util.Random;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import javax.json.bind.annotation.JsonbTransient;
import javax.ws.rs.sse.Sse;
import javax.ws.rs.sse.SseEventSink;
import org.eclipse.microprofile.metrics.Counter;
import org.eclipse.microprofile.metrics.Metadata;
import org.eclipse.microprofile.metrics.MetricRegistry;
import org.eclipse.microprofile.metrics.MetricType;
import org.eclipse.microprofile.metrics.MetricUnits;
import org.eclipse.microprofile.metrics.annotation.Counted;
import org.libertybikes.game.core.GameRound;
import org.libertybikes.game.core.GameRound.LifecycleCallback;
import org.libertybikes.game.round.service.GameRoundService;
@ -27,7 +35,34 @@ public class Party {
private final PartyQueue queue = new PartyQueue(this);
private volatile GameRound currentRound;
Metadata currentPartiesCounterMetadata = new Metadata("current_number_of_parties", // name
"Current Number of Parties", // display name
"Number of parties currently running", // description
MetricType.COUNTER, // type
MetricUnits.NONE); // units
@Inject
private MetricRegistry registry;
private Counter currentPartiesCounter;
@PostConstruct
public void postConstruct() {
currentPartiesCounter = registry.counter(currentPartiesCounterMetadata);
currentPartiesCounter.inc();
}
@PreDestroy
public void preDestroy() {
currentPartiesCounter.dec();
}
@Inject
@Counted(unit = MetricUnits.NONE,
name = "number_of_parties",
monotonic = true,
description = "Total Number of Parties",
absolute = true)
public Party() {
this(getRandomPartyID());
}

View File

@ -3,11 +3,16 @@ package org.libertybikes.game.party;
import java.util.Objects;
import java.util.concurrent.ConcurrentLinkedDeque;
import javax.enterprise.inject.spi.CDI;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.sse.OutboundSseEvent;
import javax.ws.rs.sse.Sse;
import javax.ws.rs.sse.SseEventSink;
import org.eclipse.microprofile.metrics.Metadata;
import org.eclipse.microprofile.metrics.MetricRegistry;
import org.eclipse.microprofile.metrics.MetricType;
import org.eclipse.microprofile.metrics.MetricUnits;
import org.libertybikes.game.core.GameRound;
import org.libertybikes.game.core.OutboundMessage;
import org.libertybikes.game.core.Player;
@ -17,6 +22,18 @@ public class PartyQueue {
private final ConcurrentLinkedDeque<QueuedClient> waitingPlayers = new ConcurrentLinkedDeque<>();
private final Party party;
private Metadata currentPlayersCounter = new Metadata("current_num_of_players_in_queue", // name
"Current Number of Players Waiting In A Queue", // display name
"Number of players that are currently waiting in a queue", // description
MetricType.COUNTER, // type
MetricUnits.NONE); // units
private MetricRegistry registry;
private MetricRegistry getRegistry() {
return registry == null ? registry = CDI.current().select(MetricRegistry.class).get() : registry;
}
public PartyQueue(Party p) {
this.party = p;
}
@ -26,9 +43,12 @@ public class PartyQueue {
// If this client was already in the queue, remove them and add them at the end
if (waitingPlayers.removeFirstOccurrence(client)) {
party.log("Removed client " + playerId + " from queue before adding at end");
getRegistry().counter(currentPlayersCounter).dec();
}
party.log("Adding client " + playerId + " into the queue in position " + client.queuePosition());
waitingPlayers.add(client);
getRegistry().counter(currentPlayersCounter).inc();
if (party.getCurrentRound().isOpen())
promoteClients();
else
@ -42,6 +62,7 @@ public class PartyQueue {
QueuedClient first = waitingPlayers.pollFirst();
if (first != null) {
first.promoteToGame(newRound.id);
getRegistry().counter(currentPlayersCounter).dec();
}
}
for (QueuedClient client : waitingPlayers)
@ -51,8 +72,10 @@ public class PartyQueue {
public void close() {
party.log("Closing party queue");
QueuedClient client = null;
while ((client = waitingPlayers.pollFirst()) != null)
while ((client = waitingPlayers.pollFirst()) != null) {
client.close();
getRegistry().counter(currentPlayersCounter).dec();
}
}
private class QueuedClient {

View File

@ -48,14 +48,17 @@ public class GameRoundService {
@POST
public GameRound createRoundById(@QueryParam("gameId") String gameId) {
if (allRounds.containsKey(gameId)) {
System.out.println("Round " + gameId + " already exists, returning it");
return allRounds.get(gameId);
}
GameRound newRound = new GameRound(gameId);
GameRound existingRound = allRounds.putIfAbsent(gameId, newRound);
GameRound round = existingRound == null ? newRound : existingRound;
System.out.println("Created round id=" + round.id);
allRounds.put(gameId, newRound);
System.out.println("Created round id=" + newRound.id);
if (allRounds.size() > 5)
System.out.println("WARNING: Found " + allRounds.size() + " active games in GameRoundService. " +
"They are probably not being cleaned up properly: " + allRounds.keySet());
return round;
return newRound;
}
@GET

View File

@ -18,6 +18,12 @@ import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import org.eclipse.microprofile.faulttolerance.Retry;
import org.eclipse.microprofile.metrics.Metadata;
import org.eclipse.microprofile.metrics.MetricRegistry;
import org.eclipse.microprofile.metrics.MetricType;
import org.eclipse.microprofile.metrics.MetricUnits;
import org.eclipse.microprofile.metrics.Timer.Context;
import org.eclipse.microprofile.metrics.annotation.Metered;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.libertybikes.game.core.GameRound;
import org.libertybikes.game.core.GameRound.State;
@ -39,14 +45,28 @@ public class GameRoundWebsocket {
private final static Jsonb jsonb = JsonbBuilder.create();
@Inject
private MetricRegistry registry;
private Context timerContext;
Metadata openWebsocketTimerMetadata = new Metadata("open_game_websocket_timer", // name
"Open Game Round Websocket Timer", // display name
"The Time Game Round Websockets Are Open", // description
MetricType.TIMER, // type
MetricUnits.SECONDS); // units
@OnOpen
public void onOpen(@PathParam("roundId") String roundId, Session session) {
log(roundId, "Opened a session");
timerContext = registry.timer(openWebsocketTimerMetadata).time();
}
@OnClose
public void onClose(@PathParam("roundId") String roundId, Session session) {
log(roundId, "Closed a session");
timerContext.close();
try {
GameRound round = gameSvc.getRound(roundId);
if (round != null)
@ -58,6 +78,10 @@ public class GameRoundWebsocket {
}
@OnMessage
@Metered(name = "rate_of_websocket_calls",
displayName = "Rate of GameRound Websocket Calls",
description = "Rate of incoming messages to the game round websocket",
absolute = true)
public void onMessage(@PathParam("roundId") final String roundId, String message, Session session) {
try {
final InboundMessage msg = jsonb.fromJson(message, InboundMessage.class);

View File

@ -11,7 +11,12 @@
<feature>mpRestClient-1.1</feature>
<feature>mpOpenAPI-1.0</feature>
<feature>websocket-1.1</feature>
<feature>mpMetrics-1.1</feature>
</featureManager>
<mpMetrics authentication="false"/>
<logging traceSpecification="com.ibm.ws.microprofile.metrics*=all"/>
<httpEndpoint id="defaultHttpEndpoint" host="*" httpPort="${httpPort}" httpsPort="${httpsPort}" />

View File

@ -14,6 +14,10 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import org.eclipse.microprofile.jwt.JsonWebToken;
import org.eclipse.microprofile.metrics.Metadata;
import org.eclipse.microprofile.metrics.MetricRegistry;
import org.eclipse.microprofile.metrics.MetricType;
import org.eclipse.microprofile.metrics.MetricUnits;
import org.libertybikes.player.data.PlayerDB;
@Path("/player")
@ -32,6 +36,15 @@ public class PlayerService {
return db.getAll();
}
@Inject
private MetricRegistry registry;
private Metadata numLoginsCounter = new Metadata("num_player_logins", // name
"Number of Total Logins", // display name
"Metrics to show how many times a user has logged in.", // description
MetricType.COUNTER, // type
MetricUnits.NONE); // units
@POST
@Produces(MediaType.TEXT_HTML)
public String createPlayer(@QueryParam("name") String name, @QueryParam("id") String id) {
@ -49,6 +62,10 @@ public class PlayerService {
System.out.println("Created a new player with id=" + p.id);
else
System.out.println("A player already existed with id=" + p.id);
if (id != null && registry != null) {
registry.counter(numLoginsCounter).inc();
}
return p.id;
}

View File

@ -9,8 +9,11 @@
<feature>mpConfig-1.3</feature>
<feature>mpJwt-1.0</feature>
<feature>mpOpenAPI-1.0</feature>
<feature>mpMetrics-1.1</feature>
</featureManager>
<mpMetrics authentication="false"/>
<applicationManager autoExpand="true"/>
<sslDefault sslRef="RpSSLConfig" />