From 08054f3026b686f090ec3522658fc1f4d40c1cb5 Mon Sep 17 00:00:00 2001 From: huanghongxun Date: Wed, 27 Oct 2021 00:21:32 +0800 Subject: [PATCH] feat(countly): initial --- .../org/jackhuang/hmcl/countly/Countly.java | 87 +++++++++++++++ .../jackhuang/hmcl/countly/CrashReport.java | 104 ++++++++++++++++++ .../jackhuang/hmcl/util/CrashReporter.java | 33 ++---- 3 files changed, 198 insertions(+), 26 deletions(-) create mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/countly/Countly.java create mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/countly/CrashReport.java diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/countly/Countly.java b/HMCL/src/main/java/org/jackhuang/hmcl/countly/Countly.java new file mode 100644 index 000000000..f22dd1d0c --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/countly/Countly.java @@ -0,0 +1,87 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2020 huangyuhui and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.jackhuang.hmcl.countly; + +import org.jackhuang.hmcl.util.io.HttpRequest; + +import java.io.IOException; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +import static org.jackhuang.hmcl.util.Pair.pair; + +public class Countly { + + private String deviceId; + private String endpoint; + private String serverURL; + + public void sendMetric(String metrics) throws IOException { + HttpRequest.GET(serverURL + endpoint, + pair("begin_session", "1"), + pair("session_id", "1"), + pair("metrics", metrics), + pair("device_id", deviceId), + pair("timestamp", Long.toString(System.currentTimeMillis())), + pair("tz", Integer.toString(TimeZone.getDefault().getOffset(new Date().getTime()) / 60000)), + pair("hour", Integer.toString(currentHour())), + pair("dow", Integer.toString(currentDayOfWeek())), + pair("app_key", APP_KEY), + pair("sdk_name", "java-native"), + pair("sdk_version", "20.11.1")) + .getString(); + } + + private static int getTimezoneOffset() { + return TimeZone.getDefault().getOffset(new Date().getTime()) / 60000; + } + + private static String getLocale() { + final Locale locale = Locale.getDefault(); + return locale.getLanguage() + "_" + locale.getCountry(); + } + + private static int currentHour() { + return Calendar.getInstance().get(Calendar.HOUR_OF_DAY); + } + + private int currentDayOfWeek() { + int day = Calendar.getInstance().get(Calendar.DAY_OF_WEEK); + switch (day) { + case Calendar.SUNDAY: + return 0; + case Calendar.MONDAY: + return 1; + case Calendar.TUESDAY: + return 2; + case Calendar.WEDNESDAY: + return 3; + case Calendar.THURSDAY: + return 4; + case Calendar.FRIDAY: + return 5; + case Calendar.SATURDAY: + return 6; + } + return 0; + } + + private static final String APP_KEY = ""; +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/countly/CrashReport.java b/HMCL/src/main/java/org/jackhuang/hmcl/countly/CrashReport.java new file mode 100644 index 000000000..4412bc042 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/countly/CrashReport.java @@ -0,0 +1,104 @@ +package org.jackhuang.hmcl.countly; + +import org.jackhuang.hmcl.Metadata; +import org.jackhuang.hmcl.util.CrashReporter; +import org.jackhuang.hmcl.util.Logging; +import org.jackhuang.hmcl.util.StringUtils; +import org.jackhuang.hmcl.util.platform.Architecture; +import org.jackhuang.hmcl.util.platform.OperatingSystem; + +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; + +import static org.jackhuang.hmcl.util.Lang.mapOf; +import static org.jackhuang.hmcl.util.Pair.pair; + +public class CrashReport { + + private final Thread thread; + private final Throwable throwable; + private final String stackTrace; + + private boolean nonFatal; + + public CrashReport(Thread thread, Throwable throwable) { + this.thread = thread; + this.throwable = throwable; + stackTrace = StringUtils.getStackTrace(throwable); + nonFatal = false; + } + + public CrashReport setNonFatal() { + nonFatal = true; + return this; + } + + public boolean shouldBeReport() { + if (!stackTrace.contains("org.jackhuang")) + return false; + + return true; + } + + public Map getMetrics(long runningTime) { + return mapOf( + pair("_run", runningTime), + pair("_app_version", Metadata.VERSION), + pair("_os", OperatingSystem.SYSTEM_NAME), + pair("_os_version", OperatingSystem.SYSTEM_VERSION), + pair("_disk_current", getDiskAvailable()), + pair("_disk_total", getDiskTotal()), + pair("_ram_current", getMemoryAvailable()), + pair("_ram_total", Runtime.getRuntime().maxMemory() / BYTES_IN_MB), + pair("_error", stackTrace), + pair("_logs", Logging.getLogs()), + pair("_name", throwable.getLocalizedMessage()), + pair("_nonfatal", nonFatal) + ); + } + + public String getDisplayText() { + return "---- Hello Minecraft! Crash Report ----\n" + + " Version: " + Metadata.VERSION + "\n" + + " Time: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "\n" + + " Thread: " + thread + "\n" + + "\n Content: \n " + + stackTrace + "\n\n" + + "-- System Details --\n" + + " Operating System: " + OperatingSystem.SYSTEM_NAME + ' ' + OperatingSystem.SYSTEM_VERSION + "\n" + + " System Architecture: " + Architecture.SYSTEM_ARCH_NAME + "\n" + + " Java Architecture: " + Architecture.CURRENT_ARCH_NAME + "\n" + + " Java Version: " + System.getProperty("java.version") + ", " + System.getProperty("java.vendor") + "\n" + + " Java VM Version: " + System.getProperty("java.vm.name") + " (" + System.getProperty("java.vm.info") + "), " + System.getProperty("java.vm.vendor") + "\n" + + " JVM Max Memory: " + Runtime.getRuntime().maxMemory() + "\n" + + " JVM Total Memory: " + Runtime.getRuntime().totalMemory() + "\n" + + " JVM Free Memory: " + Runtime.getRuntime().freeMemory() + "\n"; + } + + private static final Long BYTES_IN_MB = 1024L * 1024; + + private static long getMemoryAvailable() { + Long total = Runtime.getRuntime().totalMemory(); + Long availMem = Runtime.getRuntime().freeMemory(); + return (total - availMem) / BYTES_IN_MB; + } + + private static long getDiskAvailable() { + long total = 0, free = 0; + for (File f : File.listRoots()) { + total += f.getTotalSpace(); + free += f.getUsableSpace(); + } + return (total - free) / BYTES_IN_MB; + } + + private static long getDiskTotal() { + long total = 0; + for (File f : File.listRoots()) { + total += f.getTotalSpace(); + } + return total / BYTES_IN_MB; + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/CrashReporter.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/CrashReporter.java index 8a7e56f79..fec76dc12 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/util/CrashReporter.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/CrashReporter.java @@ -21,6 +21,7 @@ import javafx.application.Platform; import javafx.scene.control.Alert; import javafx.scene.control.Alert.AlertType; import org.jackhuang.hmcl.Metadata; +import org.jackhuang.hmcl.countly.CrashReport; import org.jackhuang.hmcl.ui.CrashWindow; import org.jackhuang.hmcl.upgrade.IntegrityChecker; import org.jackhuang.hmcl.upgrade.UpdateChecker; @@ -65,8 +66,6 @@ public class CrashReporter implements Thread.UncaughtExceptionHandler { pair("com.sun.javafx.css.StyleManager.findMatchingStyles", i18n("launcher.update_java")), pair("NoSuchAlgorithmException", "Has your operating system been installed completely or is a ghost system?") }; - - static final Set CAUGHT_EXCEPTIONS = newSetFromMap(new ConcurrentHashMap<>()); } private boolean checkThrowable(Throwable e) { @@ -101,29 +100,11 @@ public class CrashReporter implements Thread.UncaughtExceptionHandler { LOG.log(Level.SEVERE, "Uncaught exception in thread " + t.getName(), e); try { - String stackTrace = StringUtils.getStackTrace(e); - if (!stackTrace.contains("org.jackhuang")) + CrashReport report = new CrashReport(t, e); + if (!report.shouldBeReport()) return; - if (Hole.CAUGHT_EXCEPTIONS.contains(stackTrace)) - return; - Hole.CAUGHT_EXCEPTIONS.add(stackTrace); - - String text = "---- Hello Minecraft! Crash Report ----\n" + - " Version: " + Metadata.VERSION + "\n" + - " Time: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "\n" + - " Thread: " + t + "\n" + - "\n Content: \n " + - stackTrace + "\n\n" + - "-- System Details --\n" + - " Operating System: " + OperatingSystem.SYSTEM_NAME + ' ' + OperatingSystem.SYSTEM_VERSION + "\n" + - " System Architecture: " + Architecture.SYSTEM_ARCH_NAME + "\n" + - " Java Architecture: " + Architecture.CURRENT_ARCH_NAME + "\n" + - " Java Version: " + System.getProperty("java.version") + ", " + System.getProperty("java.vendor") + "\n" + - " Java VM Version: " + System.getProperty("java.vm.name") + " (" + System.getProperty("java.vm.info") + "), " + System.getProperty("java.vm.vendor") + "\n" + - " JVM Max Memory: " + Runtime.getRuntime().maxMemory() + "\n" + - " JVM Total Memory: " + Runtime.getRuntime().totalMemory() + "\n" + - " JVM Free Memory: " + Runtime.getRuntime().freeMemory() + "\n"; + String text = report.getDisplayText(); LOG.log(Level.SEVERE, text); Platform.runLater(() -> { @@ -132,7 +113,7 @@ public class CrashReporter implements Thread.UncaughtExceptionHandler { new CrashWindow(text).show(); } if (!UpdateChecker.isOutdated() && IntegrityChecker.isSelfVerified()) { - reportToServer(text); + reportToServer(report); } } }); @@ -141,10 +122,10 @@ public class CrashReporter implements Thread.UncaughtExceptionHandler { } } - private void reportToServer(final String text) { + private void reportToServer(CrashReport crashReport) { Thread t = new Thread(() -> { HashMap map = new HashMap<>(); - map.put("crash_report", text); + map.put("crash_report", crashReport.getDisplayText()); map.put("version", Metadata.VERSION); map.put("log", Logging.getLogs()); try {