mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2025-03-13 17:38:03 +08:00
Adds a Dump command for easy issue reporting
This commit is contained in:
parent
36e9414362
commit
433561a293
@ -57,5 +57,6 @@ public class ManageCommand extends TreeCommand<Plan> {
|
||||
commands.add(new ManageRemoveCommand(plugin));
|
||||
// commands.add(new ManageCleanCommand(plugin));
|
||||
commands.add(new ManageClearCommand(plugin));
|
||||
commands.add(new ManageDumpCommand(plugin));
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ public class ManageClearCommand extends SubCommand {
|
||||
* @param plugin Current instance of Plan
|
||||
*/
|
||||
public ManageClearCommand(Plan plugin) {
|
||||
super("clear", CommandType.CONSOLE_WITH_ARGUMENTS, Permissions.MANAGE.getPermission(), Phrase.CMD_USG_MANAGE_CLEAR + "", "<DB> [-a]");
|
||||
super("clear", CommandType.CONSOLE_WITH_ARGUMENTS, Permissions.MANAGE.getPermission(), Phrase.CMD_USG_MANAGE_CLEAR.toString(), "<DB> [-a]");
|
||||
|
||||
this.plugin = plugin;
|
||||
setHelp(plugin);
|
||||
|
@ -0,0 +1,65 @@
|
||||
package main.java.com.djrapitops.plan.command.commands.manage;
|
||||
|
||||
import com.djrapitops.plugin.command.CommandType;
|
||||
import com.djrapitops.plugin.command.ISender;
|
||||
import com.djrapitops.plugin.command.SubCommand;
|
||||
import com.djrapitops.plugin.settings.ColorScheme;
|
||||
import com.djrapitops.plugin.task.AbsRunnable;
|
||||
import main.java.com.djrapitops.plan.Permissions;
|
||||
import main.java.com.djrapitops.plan.Phrase;
|
||||
import main.java.com.djrapitops.plan.Plan;
|
||||
import main.java.com.djrapitops.plan.utilities.dump.DumpUtils;
|
||||
|
||||
/**
|
||||
* This manage subcommand is used to dump important data to pastebin,
|
||||
* so it's easier to write an issue.
|
||||
*
|
||||
* @author Fuzzlemann
|
||||
* @since 3.7.0
|
||||
*/
|
||||
public class ManageDumpCommand extends SubCommand {
|
||||
|
||||
private final Plan plugin;
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param plugin Current instance of Plan
|
||||
*/
|
||||
public ManageDumpCommand(Plan plugin) {
|
||||
super("dump", CommandType.CONSOLE, Permissions.MANAGE.getPermission(), Phrase.CMD_USG_MANAGE_CLEAR.toString());
|
||||
|
||||
this.plugin = plugin;
|
||||
setHelp(plugin);
|
||||
}
|
||||
|
||||
private void setHelp(Plan plugin) {
|
||||
ColorScheme colorScheme = plugin.getColorScheme();
|
||||
|
||||
String mCol = colorScheme.getMainColor();
|
||||
String tCol = colorScheme.getTertiaryColor();
|
||||
|
||||
String[] help = new String[]{
|
||||
mCol + "Manage Dump command",
|
||||
tCol + " Used to dump important data for bug reporting to hastebin.",
|
||||
};
|
||||
|
||||
setInDepthHelp(help);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(ISender sender, String commandLabel, String[] args) {
|
||||
dump(sender);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void dump(ISender sender) {
|
||||
plugin.getRunnableFactory().createNew(new AbsRunnable("DumpTask") {
|
||||
@Override
|
||||
public void run() {
|
||||
sender.sendLink("Link to the Dump", DumpUtils.dump(plugin));
|
||||
sender.sendLink("Report Issues here", "https://github.com/Rsl1122/Plan-PlayerAnalytics/issues/new");
|
||||
}
|
||||
}).runTaskAsynchronously();
|
||||
}
|
||||
}
|
@ -39,6 +39,7 @@ public class ManageImportCommand extends SubCommand {
|
||||
*/
|
||||
public ManageImportCommand(Plan plugin) {
|
||||
super("import", CommandType.CONSOLE, Permissions.MANAGE.getPermission(), Phrase.CMD_USG_MANAGE_IMPORT.toString(), Phrase.ARG_IMPORT.toString());
|
||||
|
||||
this.plugin = plugin;
|
||||
setHelp(plugin);
|
||||
}
|
||||
|
@ -0,0 +1,137 @@
|
||||
package main.java.com.djrapitops.plan.utilities.dump;
|
||||
|
||||
import main.java.com.djrapitops.plan.Log;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Fuzzlemann
|
||||
* @since 3.7.0
|
||||
*/
|
||||
public class DumpLog {
|
||||
|
||||
private List<CharSequence> lines = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Writes a header
|
||||
*
|
||||
* @param header The name of the header
|
||||
*/
|
||||
void addHeader(String header) {
|
||||
addLine("");
|
||||
addLine("--- " + header + " ---");
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a String {@code value} to a String {@code key}
|
||||
*
|
||||
* @param key The key
|
||||
* @param value The value
|
||||
*/
|
||||
void add(String key, String value) {
|
||||
addLine(key + ": " + value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a boolean {@code value} to a String {@code key}
|
||||
*
|
||||
* @param key The key
|
||||
* @param value The value
|
||||
*/
|
||||
void add(String key, boolean value) {
|
||||
addLine(key + ": " + value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds multiple {@link CharSequence CharSequences} stored in an {@link Iterable}
|
||||
* to a String {@code key}
|
||||
*
|
||||
* @param key The key
|
||||
* @param value The CharSequences stored in an Iterable
|
||||
*/
|
||||
void add(String key, Iterable<? extends CharSequence> value) {
|
||||
addLine(key + ": " + String.join(", ", value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds multiple lines
|
||||
*
|
||||
* @param lines The CharSequences stored in an Iterable
|
||||
*/
|
||||
void addLines(Iterable<? extends CharSequence> lines) {
|
||||
lines.forEach(this::addLine);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds multiple lines
|
||||
*
|
||||
* @param lines The lines
|
||||
*/
|
||||
void addLines(CharSequence... lines) {
|
||||
Arrays.stream(lines).forEach(this::addLine);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds one line
|
||||
*
|
||||
* @param line The content of the line
|
||||
*/
|
||||
private void addLine(CharSequence line) {
|
||||
lines.add(line.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads the dump log to Hastebin using HTTPS and POST
|
||||
*
|
||||
* @return The link to the Dump Log
|
||||
*/
|
||||
String upload() {
|
||||
String content = this.toString();
|
||||
HttpsURLConnection connection = null;
|
||||
try {
|
||||
URL url = new URL("https://hastebin.com/documents");
|
||||
connection = (HttpsURLConnection) url.openConnection();
|
||||
|
||||
connection.setRequestProperty("Content-length", String.valueOf(content.length()));
|
||||
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||
connection.setRequestProperty("User-Agent", "Mozilla/4.0");
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setDoInput(true);
|
||||
connection.setDoOutput(true);
|
||||
|
||||
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
|
||||
wr.writeBytes(this.toString());
|
||||
wr.flush();
|
||||
wr.close();
|
||||
|
||||
BufferedReader rd = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
JSONParser parser = new JSONParser();
|
||||
JSONObject json = (JSONObject) parser.parse(rd.readLine());
|
||||
|
||||
return "https://hastebin.com/" + json.get("key");
|
||||
} catch (IOException | ParseException e) {
|
||||
Log.toLog("DumpLog.upload", e);
|
||||
return "Error";
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.join("\n", lines);
|
||||
}
|
||||
}
|
@ -0,0 +1,312 @@
|
||||
package main.java.com.djrapitops.plan.utilities.dump;
|
||||
|
||||
import main.java.com.djrapitops.plan.Log;
|
||||
import main.java.com.djrapitops.plan.Plan;
|
||||
import main.java.com.djrapitops.plan.Settings;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.RuntimeMXBean;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.MalformedInputException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author Fuzzlemann
|
||||
* @since 3.7.0
|
||||
*/
|
||||
public class DumpUtils {
|
||||
|
||||
/**
|
||||
* Dumps the following things to Hastebin
|
||||
* <ul>
|
||||
* <li>The current time with the time zone</li>
|
||||
* <li>The system details</li>
|
||||
* <li>The server details</li>
|
||||
* <li>The Plan details</li>
|
||||
* <li>Some important Configuration details</li>
|
||||
* <li>The Plan timings</li>
|
||||
* <li>The error log (if present)</li>
|
||||
* <li>The debug log (if present)</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param plugin The Plan instance
|
||||
* @return The link to the Dump Log
|
||||
*/
|
||||
public static String dump(Plan plugin) {
|
||||
DumpLog log = new DumpLog();
|
||||
|
||||
addTime(log);
|
||||
addSystemDetails(log);
|
||||
addServerDetails(log, plugin);
|
||||
addPlanDetails(log, plugin);
|
||||
addConfigurationDetails(log, plugin);
|
||||
addTimings(log, plugin);
|
||||
try {
|
||||
addErrorLog(log, plugin);
|
||||
addDebugLog(log, plugin);
|
||||
} catch (IOException e) {
|
||||
Log.toLog("DumpUtils.dump", e);
|
||||
return "Error";
|
||||
}
|
||||
|
||||
return log.upload();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the current time to the Dump log
|
||||
* <p>
|
||||
* The format of the time is "dd.MM.yyy HH:mm:ss z"
|
||||
*
|
||||
* @param log The log
|
||||
*/
|
||||
private static void addTime(DumpLog log) {
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss z");
|
||||
String time = simpleDateFormat.format(new Date());
|
||||
|
||||
log.add("Time", time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the following system details to the Dump log
|
||||
* <ul>
|
||||
* <li>The Operating System Name</li>
|
||||
* <li>The Operating System Version</li>
|
||||
* <li>The Operating System Architecture</li>
|
||||
* <li>The Java Vendor</li>
|
||||
* <li>The Java Version</li>
|
||||
* <li>The JVM Vendor</li>
|
||||
* <li>The JVM Version</li>
|
||||
* <li>The JVM Name</li>
|
||||
* <li>The JVM Flags</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param log The log
|
||||
*/
|
||||
private static void addSystemDetails(DumpLog log) {
|
||||
RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
|
||||
Properties properties = System.getProperties();
|
||||
|
||||
String osName = properties.getProperty("os.name");
|
||||
String osVersion = properties.getProperty("os.version");
|
||||
String osArch = properties.getProperty("os.arch");
|
||||
|
||||
String javaVendor = properties.getProperty("java.vendor");
|
||||
String javaVersion = properties.getProperty("java.version");
|
||||
|
||||
String javaVMVendor = properties.getProperty("java.vm.vendor");
|
||||
String javaVMName = properties.getProperty("java.vm.name");
|
||||
String javaVMVersion = properties.getProperty("java.vm.version");
|
||||
List<String> javaVMFlags = runtimeMxBean.getInputArguments();
|
||||
|
||||
log.addHeader("System Details");
|
||||
|
||||
log.add("Operating System ", osName + " (" + osArch + ") version " + osVersion);
|
||||
|
||||
log.add("Java Version", javaVersion + ", " + javaVendor);
|
||||
log.add("Java VM Version", javaVMName + " version " + javaVMVersion + ", " + javaVMVendor);
|
||||
log.add("Java VM Flags", javaVMFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the following server details to the Dump log
|
||||
* <ul>
|
||||
* <li>The Minecraft Version</li>
|
||||
* <li>The Server Type</li>
|
||||
* <li>The installed plugins with the version</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param log The log
|
||||
* @param plan The Plan instance
|
||||
*/
|
||||
private static void addServerDetails(DumpLog log, Plan plan) {
|
||||
Server server = plan.getServer();
|
||||
|
||||
String minecraftVersion = server.getVersion();
|
||||
String serverType = server.getName();
|
||||
|
||||
List<String> plugins = Arrays.stream(server.getPluginManager().getPlugins())
|
||||
.map(Plugin::getDescription)
|
||||
.map(description -> description.getName() + " " + description.getVersion())
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
log.addHeader("Server Details");
|
||||
|
||||
log.add("Minecraft Version", minecraftVersion);
|
||||
log.add("Server Type", serverType);
|
||||
|
||||
log.addHeader("Plugins");
|
||||
log.addLines(plugins);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the following Plan details to the Dump log
|
||||
* <ul>
|
||||
* <li>The Plan Version</li>
|
||||
* <li>The Abstract Plugin Framework Version</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param log The log
|
||||
* @param plan The Plan instance
|
||||
*/
|
||||
private static void addPlanDetails(DumpLog log, Plan plan) {
|
||||
String planVersion = plan.getVersion();
|
||||
String apfVersion = plan.getAPFVersion();
|
||||
|
||||
log.addHeader("Plan Details");
|
||||
|
||||
log.add("Plan Version", planVersion);
|
||||
log.add("Abstract Plugin Framework Version", apfVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the following Configuration Details to the Dump Log
|
||||
* <ul>
|
||||
* <li>WebServer enabled</li>
|
||||
* <li>HTTPS used</li>
|
||||
* <li>Analysis on enable refresh</li>
|
||||
* <li>Analysis Export</li>
|
||||
* <li>Alternative Server IP usage</li>
|
||||
* <li>Chat Gathering</li>
|
||||
* <li>Kill Gathering</li>
|
||||
* <li>Command Gathering</li>
|
||||
* <li>Alias Combining</li>
|
||||
* <li>Unknown Command Logging</li>
|
||||
* <li>The locale</li>
|
||||
* <li>The DB Type</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param log The log
|
||||
* @param plan The Plan instance
|
||||
*/
|
||||
private static void addConfigurationDetails(DumpLog log, Plan plan) {
|
||||
boolean webServerEnabled = Settings.WEBSERVER_ENABLED.isTrue();
|
||||
boolean usingHTTPS = plan.getUiServer().usingHttps();
|
||||
boolean refreshAnalysisOnEnable = Settings.ANALYSIS_REFRESH_ON_ENABLE.isTrue();
|
||||
boolean analysisExport = Settings.ANALYSIS_EXPORT.isTrue();
|
||||
boolean usingAlternativeServerIP = Settings.USE_ALTERNATIVE_UI.isTrue();
|
||||
|
||||
boolean chatGathering = Settings.GATHERCHAT.isTrue();
|
||||
boolean killGathering = Settings.GATHERKILLS.isTrue();
|
||||
boolean commandGathering = Settings.GATHERCOMMANDS.isTrue();
|
||||
|
||||
boolean combineAliases = Settings.COMBINE_COMMAND_ALIASES_TO_MAIN_COMMAND.isTrue();
|
||||
boolean unknownCommandLogging = Settings.DO_NOT_LOG_UNKNOWN_COMMANDS.isTrue();
|
||||
|
||||
String locale = Settings.LOCALE.toString();
|
||||
String dbType = Settings.DB_TYPE.toString();
|
||||
|
||||
log.addHeader("Plan Configuration");
|
||||
|
||||
log.add("Webserver Enabled", webServerEnabled);
|
||||
log.add("Webserver HTTPS", usingHTTPS);
|
||||
log.add("Refresh Analysis on Enable", refreshAnalysisOnEnable);
|
||||
log.add("Analysis Export", analysisExport);
|
||||
log.add("Alternative Server IP", usingAlternativeServerIP);
|
||||
|
||||
log.add("Chat Gathering", chatGathering);
|
||||
log.add("Kill Gathering", killGathering);
|
||||
log.add("Command Gathering", commandGathering);
|
||||
|
||||
log.add("Combine Aliases", combineAliases);
|
||||
log.add("Unknown Command Logging", unknownCommandLogging);
|
||||
log.add("Locale", locale);
|
||||
|
||||
log.add("Database Type", dbType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the timings to the Dump log
|
||||
*
|
||||
* @param log The log
|
||||
* @param plan The Plan instance
|
||||
*/
|
||||
private static void addTimings(DumpLog log, Plan plan) {
|
||||
String[] timings = plan.benchmark().getTimings().getTimings();
|
||||
|
||||
log.addHeader("Timings");
|
||||
log.addLines(timings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the error log to the Dump Log if present
|
||||
*
|
||||
* @param log The log
|
||||
* @param plan The Plan instance
|
||||
* @throws IOException when an error while reading occurred
|
||||
*/
|
||||
private static void addErrorLog(DumpLog log, Plan plan) throws IOException {
|
||||
Path errorFile = FileSystems.getDefault().getPath(plan.getDataFolder().getAbsolutePath(), Log.getErrorsFilename());
|
||||
|
||||
if (Files.notExists(errorFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> lines = readLines(errorFile);
|
||||
|
||||
log.addHeader("Error Log");
|
||||
log.addLines(lines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the debug log to the Dump Log if present
|
||||
*
|
||||
* @param log The log
|
||||
* @param plan The Plan instance
|
||||
* @throws IOException when an error while reading occurred
|
||||
*/
|
||||
private static void addDebugLog(DumpLog log, Plan plan) throws IOException {
|
||||
Path debugFile = FileSystems.getDefault().getPath(plan.getDataFolder().getAbsolutePath(), "DebugLog.txt");
|
||||
|
||||
if (Files.notExists(debugFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> lines = readLines(debugFile);
|
||||
|
||||
log.addHeader("Debug Log");
|
||||
log.addLines(lines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the lines of a file
|
||||
*
|
||||
* @param file The file
|
||||
* @return The lines
|
||||
* @throws IOException when an error while reading occurred
|
||||
*/
|
||||
private static List<String> readLines(Path file) throws IOException {
|
||||
for (Charset charset : Charset.availableCharsets().values()) {
|
||||
try {
|
||||
return readLines(file, charset);
|
||||
} catch (MalformedInputException ignored) {
|
||||
/* Ignores MalformedInputException, just trying the next charset */
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the lines of a file with that specific charset
|
||||
*
|
||||
* @param file The file
|
||||
* @param charset The CharSet
|
||||
* @return The lines
|
||||
* @throws IOException when an error while reading occurred
|
||||
*/
|
||||
private static List<String> readLines(Path file, Charset charset) throws IOException {
|
||||
return Files.lines(file, charset).collect(Collectors.toList());
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user