Improve Metrics and add /csmetrics command

This adds some more logging to the metrics for some interesting plugin
 settings as well as player account and transaction counts. This data
 about account count and average transaction and item counts is also
 exposed ingame via the /csmetrics command.

This also removes the outdated mcstats metrics as that site is long dead
 now, the last data is from two years ago...
This commit is contained in:
Phoenix616 2020-06-19 21:39:23 +01:00
parent 1f8fd09dd2
commit 183c724583
9 changed files with 225 additions and 28 deletions

45
pom.xml
View File

@ -78,26 +78,9 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mcstats.bukkit</groupId>
<artifactId>metrics</artifactId>
<version>R8-SNAPSHOT</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
</exclusion>
<exclusion>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit-lite</artifactId>
<artifactId>bstats-bukkit</artifactId>
<version>1.7</version>
<scope>compile</scope>
</dependency>
@ -326,6 +309,24 @@
<build>
<finalName>${project.name}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<forceCreation>true</forceCreation>
<archive>
<manifest>
<addDefaultEntries>true</addDefaultEntries>
</manifest>
<manifestEntries>
<Distribution-Type>${buildType}</Distribution-Type>
<Built-At>${maven.build.timestamp}</Built-At>
<Build-Jdk>${java.runtime.version}</Build-Jdk>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
@ -347,7 +348,6 @@
<configuration>
<artifactSet>
<includes>
<include>org.mcstats.bukkit</include>
<include>org.bstats:*</include>
<include>net.gravitydevelopment.updater</include>
<include>com.j256.ormlite</include>
@ -356,10 +356,6 @@
</includes>
</artifactSet>
<relocations>
<relocation>
<pattern>org.mcstats</pattern>
<shadedPattern>com.Acrobot.ChestShop.Metrics.MCStats</shadedPattern>
</relocation>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>com.Acrobot.ChestShop.Metrics.BStats</shadedPattern>
@ -394,6 +390,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<build.number>${buildNumber}</build.number>
<user.name>${buildType}</user.name>
<bukkit.plugin.version>${project.version} ${buildDescription}</bukkit.plugin.version>
</properties>
@ -463,6 +460,7 @@
</property>
</activation>
<properties>
<buildType>manual</buildType>
<buildNumber>0</buildNumber>
<buildDescription>(compiled at ${maven.build.timestamp})</buildDescription>
</properties>
@ -476,6 +474,7 @@
</property>
</activation>
<properties>
<buildType>jenkins</buildType>
<buildNumber>${env.BUILD_NUMBER}</buildNumber>
<buildDescription>(build ${env.BUILD_NUMBER})</buildDescription>
</properties>

View File

@ -154,4 +154,14 @@ public class NumberUtil {
return Integer.toString(number);
}
}
/**
* Convert a long to an integer while not overflowing but returning Integer.MAX_VALUE
*
* @param number The long to convert
* @return The integer value or Integer.MAX_VALUE on overflow
*/
public static int toInt(long number) {
return number > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) number;
}
}

View File

@ -19,6 +19,7 @@ import com.Acrobot.ChestShop.Listeners.AuthMeChestShopListener;
import com.Acrobot.ChestShop.Listeners.GarbageTextListener;
import com.Acrobot.ChestShop.Listeners.Item.ItemMoveListener;
import com.Acrobot.ChestShop.Listeners.ItemInfoListener;
import com.Acrobot.ChestShop.Listeners.Modules.MetricsModule;
import com.Acrobot.ChestShop.Listeners.SignParseListener;
import com.Acrobot.ChestShop.Listeners.Modules.DiscountModule;
import com.Acrobot.ChestShop.Listeners.Modules.PriceRestrictionModule;
@ -41,6 +42,7 @@ import com.Acrobot.ChestShop.UUIDs.NameManager;
import com.Acrobot.ChestShop.Updater.JenkinsBuildsNotifier;
import com.Acrobot.ChestShop.Updater.Updater;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
@ -53,7 +55,9 @@ import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.filter.AbstractFilter;
import org.apache.logging.log4j.message.Message;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.PluginCommand;
@ -67,9 +71,15 @@ import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.jar.JarFile;
import java.util.logging.FileHandler;
import java.util.logging.Logger;
import java.util.stream.Collectors;
/**
* Main file of the plugin
@ -111,6 +121,7 @@ public class ChestShop extends JavaPlugin {
registerCommand("iteminfo", new ItemInfo(), Permission.ITEMINFO);
registerCommand("csVersion", new Version(), Permission.ADMIN);
registerCommand("csMetrics", new com.Acrobot.ChestShop.Commands.Metrics(), Permission.ADMIN);
registerCommand("csGive", new Give(), Permission.ADMIN);
registerCommand("cstoggle", new Toggle(), Permission.NOTIFY_TOGGLE);
registerCommand("csaccess", new AccessToggle(), Permission.ACCESS_TOGGLE);
@ -376,6 +387,7 @@ public class ChestShop extends JavaPlugin {
private void registerModules() {
registerEvent(new DiscountModule());
registerEvent(new MetricsModule());
registerEvent(new PriceRestrictionModule());
registerEconomicalModules();
@ -397,12 +409,49 @@ public class ChestShop extends JavaPlugin {
}
private void startStatistics() {
Metrics bStats = new Metrics(this, 1109);
try {
new org.mcstats.Metrics(this).start();
} catch (IOException ex) {
ChestShop.getBukkitLogger().severe("There was an error while submitting MCStats statistics.");
}
new org.bstats.bukkit.MetricsLite(this, 1109);
String dist = new JarFile(this.getFile()).getManifest().getMainAttributes().getValue("Distribution-Type");
bStats.addCustomChart(new Metrics.SimplePie("distributionType", () -> dist));
} catch (IOException ignored) {}
bStats.addCustomChart(new Metrics.SingleLineChart("shopAccounts", NameManager::getAccountCount));
bStats.addCustomChart(new Metrics.MultiLineChart("transactionCount", () -> ImmutableMap.of(
"total", MetricsModule.getTotalTransactions(),
"buy", MetricsModule.getBuyTransactions(),
"sell", MetricsModule.getSellTransactions()
)));bStats.addCustomChart(new Metrics.MultiLineChart("itemCount", () -> ImmutableMap.of(
"total", MetricsModule.getTotalItemsCount(),
"buy", MetricsModule.getSoldItemsCount(),
"sell", MetricsModule.getBoughtItemsCount()
)));
bStats.addCustomChart(new Metrics.SimplePie("includeSettingsInMetrics", () -> Properties.INCLUDE_SETTINGS_IN_METRICS ? "enabled" : "disabled"));
if (!Properties.INCLUDE_SETTINGS_IN_METRICS) return;
bStats.addCustomChart(new Metrics.AdvancedBarChart("pluginProperties", () -> {
Map<String, int[]> map = new LinkedHashMap<>();
map.put("reverse-buttons", getChartArray(Properties.REVERSE_BUTTONS));
map.put("shift-sells-in-stacks", getChartArray(Properties.SHIFT_SELLS_IN_STACKS));
map.put("shift-sells-everything", getChartArray(Properties.SHIFT_SELLS_EVERYTHING));
map.put("allow-sign-chest-open", getChartArray(!Properties.ALLOW_SIGN_CHEST_OPEN));
map.put("remove-empty-shops", getChartArray(!Properties.REMOVE_EMPTY_SHOPS));
map.put("remove-empty-chests", getChartArray(!Properties.REMOVE_EMPTY_CHESTS));
map.put("uses-server-economy-account", getChartArray(!Properties.SERVER_ECONOMY_ACCOUNT.isEmpty()));
map.put("uses-server-economy-account-uuid", getChartArray(!Properties.SERVER_ECONOMY_ACCOUNT_UUID.equals(new UUID(0, 0))));
map.put("allow-multiple-shops-at-one-block", getChartArray(Properties.ALLOW_MULTIPLE_SHOPS_AT_ONE_BLOCK));
map.put("allow-partial-transactions", getChartArray(Properties.ALLOW_PARTIAL_TRANSACTIONS));
map.put("bungeecord-messages", getChartArray(Properties.BUNGEECORD_MESSAGES));
map.put("log-to-console", getChartArray(Properties.LOG_TO_CONSOLE));
map.put("log-to-file", getChartArray(Properties.LOG_TO_FILE));
return map;
}));
bStats.addCustomChart(new Metrics.SimpleBarChart("shopContainers",
() -> Properties.SHOP_CONTAINERS.stream().map(Material::name).collect(Collectors.toMap(k -> k, k -> 1))));
}
private int[] getChartArray(boolean value) {
return new int[]{value ? 1 : 0, value ? 0 : 1};
}
private static final int PROJECT_BUKKITDEV_ID = 31263;

View File

@ -0,0 +1,26 @@
package com.Acrobot.ChestShop.Commands;
import com.Acrobot.ChestShop.Configuration.Messages;
import com.Acrobot.ChestShop.Listeners.Modules.MetricsModule;
import com.Acrobot.ChestShop.UUIDs.NameManager;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
/**
* @author Acrobot
*/
public class Metrics implements CommandExecutor {
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
sender.sendMessage(Messages.replace(Messages.METRICS,
"accounts", String.valueOf(NameManager.getAccountCount()),
"totalTransactions", String.valueOf(MetricsModule.getTotalTransactions()),
"buyTransactions", String.valueOf(MetricsModule.getBuyTransactions()),
"sellTransactions", String.valueOf(MetricsModule.getSellTransactions()),
"totalItems", String.valueOf(MetricsModule.getTotalItemsCount()),
"boughtItems", String.valueOf(MetricsModule.getBoughtItemsCount()),
"soldItems", String.valueOf(MetricsModule.getSoldItemsCount())
));
return true;
}
}

View File

@ -16,6 +16,12 @@ public class Messages {
public static String iteminfo_book_generatopm = "&fBook Generation: &7%generation";
public static String iteminfo_lore = "&fLore: \n&r%lore";
@PrecededBySpace
public static String METRICS = "&a[Shop] &fMetrics:\n" +
"&fAccounts: &7%accounts\n" +
"&fAverage transactions: &7%totalTransactions &f(buy: &7%buyTransactions &fsell: &7%sellTransactions&f)\n" +
"&fAverage items traded: &7%totalItems &f(bought: &7%boughtItems &fsold: &7%soldItems&f)";
@PrecededBySpace
public static String ACCESS_DENIED = "You don't have permission to access that shop's storage container!";
public static String TRADE_DENIED = "You don't have permission to trade with that shop!";

View File

@ -105,6 +105,9 @@ public class Properties {
@ConfigurationComment("Do you want to turn off the automatic notifications for new development builds?")
public static boolean TURN_OFF_DEV_UPDATE_NOTIFIER = false;
@ConfigurationComment("Do you want to include some values of this config in the metrics? (This will not leak sensitive data but help in the development process)")
public static boolean INCLUDE_SETTINGS_IN_METRICS = true;
@PrecededBySpace
@ConfigurationComment("How large should the internal caches be?")
public static int CACHE_SIZE = 1000;

View File

@ -0,0 +1,92 @@
package com.Acrobot.ChestShop.Listeners.Modules;
import com.Acrobot.Breeze.Utils.NumberUtil;
import com.Acrobot.ChestShop.Events.TransactionEvent;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
/**
* @author Acrobot
*/
public class MetricsModule implements Listener {
private static final long RESET_MINUTES = 30;
private static long lastReset = System.currentTimeMillis();
private static int buyTransactionsLast = 0;
private static int sellTransactionsLast = 0;
private static long buyTransactionsCurrent = 0;
private static long sellTransactionsCurrent = 0;
private static int boughtItemsLast = 0;
private static int soldItemsLast = 0;
private static long boughtItemsCurrent = 0;
private static long soldItemsCurrent = 0;
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public static void onTransaction(final TransactionEvent event) {
checkReset();
switch (event.getTransactionType()) {
case BUY:
buyTransactionsCurrent++;
for (ItemStack itemStack : event.getStock()) {
boughtItemsCurrent += itemStack.getAmount();
}
break;
case SELL:
sellTransactionsCurrent++;
for (ItemStack itemStack : event.getStock()) {
soldItemsCurrent += itemStack.getAmount();
}
break;
}
}
public static int getBuyTransactions() {
checkReset();
return buyTransactionsLast;
}
public static int getSellTransactions() {
checkReset();
return sellTransactionsLast;
}
public static int getTotalTransactions() {
checkReset();
return buyTransactionsLast + sellTransactionsLast;
}
public static int getBoughtItemsCount() {
checkReset();
return boughtItemsLast;
}
public static int getSoldItemsCount() {
checkReset();
return soldItemsLast;
}
public static int getTotalItemsCount() {
checkReset();
return boughtItemsLast + soldItemsLast;
}
private static void checkReset() {
if (lastReset + RESET_MINUTES * 60 * 1000 < System.currentTimeMillis()) {
lastReset = System.currentTimeMillis();
buyTransactionsLast = NumberUtil.toInt(buyTransactionsCurrent);
buyTransactionsCurrent = 0;
sellTransactionsLast = NumberUtil.toInt(sellTransactionsCurrent);
sellTransactionsCurrent = 0;
boughtItemsLast = NumberUtil.toInt(boughtItemsCurrent);
boughtItemsCurrent = 0;
soldItemsLast = NumberUtil.toInt(soldItemsCurrent);
soldItemsCurrent = 0;
}
}
}

View File

@ -3,6 +3,7 @@ package com.Acrobot.ChestShop.UUIDs;
import com.Acrobot.Breeze.Utils.Encoding.Base62;
import com.Acrobot.Breeze.Utils.NameUtil;
import com.Acrobot.Breeze.Collection.SimpleCache;
import com.Acrobot.Breeze.Utils.NumberUtil;
import com.Acrobot.ChestShop.ChestShop;
import com.Acrobot.ChestShop.Configuration.Properties;
import com.Acrobot.ChestShop.Database.Account;
@ -48,6 +49,14 @@ public class NameManager implements Listener {
private static Account serverEconomyAccount;
private static int uuidVersion = -1;
public static int getAccountCount() {
try {
return NumberUtil.toInt(accounts.queryBuilder().countOf() - 1);
} catch (SQLException e) {
return 0;
}
}
/**
* Get or create an account for a player
*

View File

@ -22,6 +22,9 @@ commands:
aliases: [chestshop]
description: Shows the ChestShop's version
usage: /<command>
csMetrics:
description: Shows ChestShop's metrics
usage: /<command>
cstoggle:
description: Toggle messages to the owner of a shop
usage: /<command>