diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/SettingsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/SettingsPage.java index 28b31a84c..367bcf58d 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/SettingsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/SettingsPage.java @@ -30,21 +30,33 @@ import javafx.scene.paint.Color; import javafx.scene.text.Font; import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.setting.*; +import org.jackhuang.hmcl.ui.construct.MessageBox; import org.jackhuang.hmcl.ui.construct.Validator; import org.jackhuang.hmcl.ui.decorator.DecoratorPage; import org.jackhuang.hmcl.upgrade.RemoteVersion; import org.jackhuang.hmcl.upgrade.UpdateChannel; import org.jackhuang.hmcl.upgrade.UpdateChecker; import org.jackhuang.hmcl.upgrade.UpdateHandler; +import org.jackhuang.hmcl.util.Logging; import org.jackhuang.hmcl.util.i18n.Locales; import org.jackhuang.hmcl.util.javafx.SafeStringConverter; +import java.awt.Desktop; +import java.io.IOException; import java.net.Proxy; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.Collections; import java.util.Optional; +import java.util.logging.Level; import static org.jackhuang.hmcl.setting.ConfigHolder.config; +import static org.jackhuang.hmcl.util.Lang.thread; +import static org.jackhuang.hmcl.util.Logging.LOG; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.reservedSelectedPropertyFor; import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.selectedItemPropertyFor; @@ -201,8 +213,29 @@ public final class SettingsPage extends SettingsView implements DecoratorPage { } @Override - protected void onOpenLogFolder() { - FXUtils.openFolder(Metadata.HMCL_DIRECTORY.resolve("logs").toFile()); + protected void onExportLogs() { + // We cannot determine which file is JUL using. + // So we write all the logs to a new file. + thread(() -> { + Path logFile = Paths.get("hmcl-exported-logs-" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH-mm-ss")) + ".log").toAbsolutePath(); + + LOG.info("Exporting logs to " + logFile); + try { + Files.write(logFile, Logging.getRawLogs()); + } catch (IOException e) { + Platform.runLater(() -> Controllers.dialog(i18n("settings.launcher.launcher_log.export.failed") + "\n" + e, null, MessageBox.ERROR_MESSAGE)); + LOG.log(Level.WARNING, "Failed to export logs", e); + return; + } + + Platform.runLater(() -> Controllers.dialog(i18n("settings.launcher.launcher_log.export.success", logFile))); + if (Desktop.isDesktopSupported()) { + try { + Desktop.getDesktop().open(logFile.toFile()); + } catch (IOException ignored) { + } + } + }); } @Override diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/SettingsView.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/SettingsView.java index 5a418b9a8..362b35ba4 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/SettingsView.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/SettingsView.java @@ -35,7 +35,6 @@ import org.jackhuang.hmcl.setting.EnumBackgroundImage; import org.jackhuang.hmcl.setting.EnumCommonDirectory; import org.jackhuang.hmcl.setting.Theme; import org.jackhuang.hmcl.ui.construct.*; -import org.jackhuang.hmcl.util.i18n.I18n; import org.jackhuang.hmcl.util.i18n.Locales.SupportedLocale; public abstract class SettingsView extends StackPane { @@ -337,8 +336,8 @@ public abstract class SettingsView extends StackPane { logPane.setTitle(i18n("settings.launcher.log")); { - JFXButton logButton = new JFXButton(i18n("settings.launcher.log.dir")); - logButton.setOnMouseClicked(e -> onOpenLogFolder()); + JFXButton logButton = new JFXButton(i18n("settings.launcher.launcher_log.export")); + logButton.setOnMouseClicked(e -> onExportLogs()); logButton.getStyleClass().setAll("jfx-button-border"); logPane.setHeaderRight(logButton); @@ -492,5 +491,5 @@ public abstract class SettingsView extends StackPane { protected abstract void onUpdate(); protected abstract void onHelp(); - protected abstract void onOpenLogFolder(); + protected abstract void onExportLogs(); } diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index d40862059..f2478bb93 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -326,9 +326,11 @@ settings.launcher.common_path.tooltip=This app will save all game libraries and settings.launcher.download_source=Download Source settings.launcher.enable_game_list=Display game list in main page settings.launcher.language=Language +settings.launcher.launcher_log.export=Export launcher logs +settings.launcher.launcher_log.export.failed=Failed to export logs +settings.launcher.launcher_log.export.success=Logs have been exported to %s settings.launcher.log=Log settings.launcher.log.font=Log Font -settings.launcher.log.dir=Open Log Directory settings.launcher.proxy=Proxy settings.launcher.proxy.authentication=Proxy Authentication settings.launcher.proxy.disable=Use system proxies diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index ae40dd7c8..ebaa9cce9 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -326,9 +326,11 @@ settings.launcher.common_path.tooltip=啟動器將所有遊戲資源及依賴庫 settings.launcher.download_source=下載來源 settings.launcher.enable_game_list=在首頁內顯示遊戲列表 settings.launcher.language=語言 +settings.launcher.launcher_log.export=導出啟動器日誌 +settings.launcher.launcher_log.export.failed=無法導出日誌 +settings.launcher.launcher_log.export.success=日誌已保存到 %s settings.launcher.log=記錄 settings.launcher.log.font=記錄字體 -settings.launcher.log.dir=打開記錄資料夾 settings.launcher.proxy=代理 settings.launcher.proxy.authentication=身份驗證 settings.launcher.proxy.disable=使用系統代理 diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index 7674b41e1..afb20d57c 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -326,9 +326,11 @@ settings.launcher.common_path.tooltip=启动器将所有游戏资源及依赖库 settings.launcher.download_source=下载源 settings.launcher.enable_game_list=在主页内显示游戏列表 settings.launcher.language=语言 +settings.launcher.launcher_log.export=导出启动器日志 +settings.launcher.launcher_log.export.failed=无法导出日志 +settings.launcher.launcher_log.export.success=日志已保存到 %s settings.launcher.log=日志 settings.launcher.log.font=日志字体 -settings.launcher.log.dir=打开日志文件夹 settings.launcher.proxy=代理 settings.launcher.proxy.authentication=身份验证 settings.launcher.proxy.disable=使用系统代理 diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Logging.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Logging.java index 5cc77b22f..61c1e4640 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Logging.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Logging.java @@ -32,21 +32,16 @@ import java.util.logging.*; */ public final class Logging { - public static final Logger LOG; - private static final ByteArrayOutputStream OUTPUT_STREAM = new ByteArrayOutputStream(); - - static { - LOG = Logger.getLogger("HMCL"); - } + public static final Logger LOG = Logger.getLogger("HMCL"); + private static ByteArrayOutputStream storedLogs = new ByteArrayOutputStream(); public static void start(Path logFolder) { - LOG.setLevel(Level.FINER); + LOG.setLevel(Level.ALL); LOG.setUseParentHandlers(false); try { Files.createDirectories(logFolder); FileHandler fileHandler = new FileHandler(logFolder.resolve("hmcl.log").toAbsolutePath().toString()); - fileHandler.setLevel(Level.FINEST); fileHandler.setFormatter(DefaultFormatter.INSTANCE); LOG.addHandler(fileHandler); } catch (IOException e) { @@ -54,31 +49,28 @@ public final class Logging { } ConsoleHandler consoleHandler = new ConsoleHandler(); - consoleHandler.setLevel(Level.FINER); consoleHandler.setFormatter(DefaultFormatter.INSTANCE); LOG.addHandler(consoleHandler); - StreamHandler streamHandler = new StreamHandler(OUTPUT_STREAM, DefaultFormatter.INSTANCE) { + StreamHandler streamHandler = new StreamHandler(storedLogs, DefaultFormatter.INSTANCE) { @Override public synchronized void publish(LogRecord record) { super.publish(record); flush(); } }; - streamHandler.setLevel(Level.FINEST); LOG.addHandler(streamHandler); } - public static void stop() { - for (Handler handler : LOG.getHandlers()) - LOG.removeHandler(handler); + public static byte[] getRawLogs() { + return storedLogs.toByteArray(); } public static String getLogs() { - return OUTPUT_STREAM.toString(); + return storedLogs.toString(); } - static final class DefaultFormatter extends Formatter { + private static final class DefaultFormatter extends Formatter { static final DefaultFormatter INSTANCE = new DefaultFormatter(); private final SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");