优化打包日志逻辑 (#5108)

Fix #4587
This commit is contained in:
辞庐
2026-01-02 16:13:06 +08:00
committed by GitHub
parent 110a58b3cd
commit fadd9580a2
2 changed files with 39 additions and 17 deletions

View File

@@ -17,21 +17,19 @@
*/ */
package org.jackhuang.hmcl.game; package org.jackhuang.hmcl.game;
import org.jackhuang.hmcl.util.io.IOUtils;
import org.jackhuang.hmcl.util.logging.Logger;
import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.io.IOUtils;
import org.jackhuang.hmcl.util.io.Zipper; import org.jackhuang.hmcl.util.io.Zipper;
import org.jackhuang.hmcl.util.logging.Logger;
import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jackhuang.hmcl.util.platform.OperatingSystem;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
import java.lang.management.ManagementFactory;
import java.nio.file.DirectoryStream; import java.nio.file.DirectoryStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.PathMatcher;
import java.nio.file.attribute.FileTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@@ -43,7 +41,9 @@ public final class LogExporter {
private LogExporter() { private LogExporter() {
} }
public static CompletableFuture<Void> exportLogs(Path zipFile, DefaultGameRepository gameRepository, String versionId, String logs, String launchScript) { public static CompletableFuture<Void> exportLogs(
Path zipFile, DefaultGameRepository gameRepository, String versionId, String logs, String launchScript,
PathMatcher logMatcher) {
Path runDirectory = gameRepository.getRunDirectory(versionId); Path runDirectory = gameRepository.getRunDirectory(versionId);
Path baseDirectory = gameRepository.getBaseDirectory(); Path baseDirectory = gameRepository.getBaseDirectory();
List<String> versions = new ArrayList<>(); List<String> versions = new ArrayList<>();
@@ -65,10 +65,10 @@ public final class LogExporter {
return CompletableFuture.runAsync(() -> { return CompletableFuture.runAsync(() -> {
try (Zipper zipper = new Zipper(zipFile)) { try (Zipper zipper = new Zipper(zipFile)) {
processLogs(runDirectory.resolve("liteconfig"), "*.log", "liteconfig", zipper); processLogs(runDirectory.resolve("liteconfig"), "*.log", "liteconfig", zipper, logMatcher);
processLogs(runDirectory.resolve("logs"), "*.log", "logs", zipper); processLogs(runDirectory.resolve("logs"), "*.log", "logs", zipper, logMatcher);
processLogs(runDirectory, "*.log", "runDirectory", zipper); processLogs(runDirectory, "*.log", "runDirectory", zipper, logMatcher);
processLogs(runDirectory.resolve("crash-reports"), "*.txt", "crash-reports", zipper); processLogs(runDirectory.resolve("crash-reports"), "*.txt", "crash-reports", zipper, logMatcher);
zipper.putTextFile(LOG.getLogs(), "hmcl.log"); zipper.putTextFile(LOG.getLogs(), "hmcl.log");
zipper.putTextFile(logs, "minecraft.log"); zipper.putTextFile(logs, "minecraft.log");
@@ -86,14 +86,11 @@ public final class LogExporter {
}); });
} }
private static void processLogs(Path directory, String fileExtension, String logDirectory, Zipper zipper) { private static void processLogs(Path directory, String fileExtension, String logDirectory, Zipper zipper, PathMatcher logMatcher) {
try (DirectoryStream<Path> stream = Files.newDirectoryStream(directory, fileExtension)) { try (DirectoryStream<Path> stream = Files.newDirectoryStream(directory, fileExtension)) {
long processStartTime = ManagementFactory.getRuntimeMXBean().getStartTime();
for (Path file : stream) { for (Path file : stream) {
if (Files.isRegularFile(file)) { if (Files.isRegularFile(file)) {
FileTime time = Files.readAttributes(file, BasicFileAttributes.class).lastModifiedTime(); if (logMatcher == null || logMatcher.matches(file)) {
if (time.toMillis() >= processStartTime) {
try (BufferedReader reader = IOUtils.newBufferedReaderMaybeNativeEncoding(file)) { try (BufferedReader reader = IOUtils.newBufferedReaderMaybeNativeEncoding(file)) {
zipper.putLines(reader.lines().map(Logger::filterForbiddenToken), file.getFileName().toString()); zipper.putLines(reader.lines().map(Logger::filterForbiddenToken), file.getFileName().toString());
} catch (IOException e) { } catch (IOException e) {

View File

@@ -50,9 +50,12 @@ import org.jackhuang.hmcl.util.logging.Logger;
import org.jackhuang.hmcl.util.platform.*; import org.jackhuang.hmcl.util.platform.*;
import java.io.IOException; import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.nio.file.attribute.FileTime;
import java.time.Instant;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.*; import java.util.*;
@@ -269,8 +272,30 @@ public class GameCrashWindow extends Stage {
CompletableFuture.supplyAsync(() -> CompletableFuture.supplyAsync(() ->
logs.stream().map(Log::getLog).collect(Collectors.joining("\n"))) logs.stream().map(Log::getLog).collect(Collectors.joining("\n")))
.thenComposeAsync(logs -> .thenComposeAsync(logs -> {
LogExporter.exportLogs(logFile, repository, launchOptions.getVersionName(), logs, new CommandBuilder().addAll(managedProcess.getCommands()).toString())) long processStartTime = managedProcess.getProcess().info()
.startInstant()
.map(Instant::toEpochMilli).orElseGet(() -> {
try {
return ManagementFactory.getRuntimeMXBean().getStartTime();
} catch (Throwable e) {
LOG.warning("Failed to get process start time", e);
return 0L;
}
});
return LogExporter.exportLogs(logFile, repository, launchOptions.getVersionName(), logs,
new CommandBuilder().addAll(managedProcess.getCommands()).toString(),
path -> {
try {
FileTime lastModifiedTime = Files.getLastModifiedTime(path);
return lastModifiedTime.toMillis() >= processStartTime;
} catch (Throwable e) {
LOG.warning("Failed to read file attributes", e);
return false;
}
});
})
.handleAsync((result, exception) -> { .handleAsync((result, exception) -> {
Alert alert; Alert alert;