@@ -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) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user