Optimization HMCLProcessListener::onLog (#1867)

This commit is contained in:
Glavo 2022-11-25 17:16:23 +08:00 committed by GitHub
parent 2e532be34c
commit e1eb40c129
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 41 additions and 21 deletions

View File

@ -685,7 +685,7 @@ public final class LauncherHelper {
* Guarantee that one [JavaProcess], one [HMCLProcessListener].
* Because every time we launched a game, we generates a new [HMCLProcessListener]
*/
class HMCLProcessListener implements ProcessListener {
private final class HMCLProcessListener implements ProcessListener {
private final HMCLGameRepository repository;
private final Version version;
@ -694,9 +694,11 @@ public final class LauncherHelper {
private boolean lwjgl;
private LogWindow logWindow;
private final boolean detectWindow;
private final ArrayDeque<Pair<String, Log4jLevel>> logs;
private final ArrayDeque<String> logs;
private final ArrayDeque</*Log4jLevel*/Object> levels;
private final CountDownLatch logWindowLatch = new CountDownLatch(1);
private final CountDownLatch launchingLatch;
private final String forbiddenAccessToken;
public HMCLProcessListener(HMCLGameRepository repository, Version version, AuthInfo authInfo, LaunchOptions launchOptions, CountDownLatch launchingLatch, boolean detectWindow) {
this.repository = repository;
@ -704,8 +706,11 @@ public final class LauncherHelper {
this.launchOptions = launchOptions;
this.launchingLatch = launchingLatch;
this.detectWindow = detectWindow;
this.forbiddenAccessToken = authInfo != null ? authInfo.getAccessToken() : null;
this.logs = new ArrayDeque<>(config().getLogLines() + 1);
final int numLogs = config().getLogLines() + 1;
this.logs = new ArrayDeque<>(numLogs);
this.levels = new ArrayDeque<>(numLogs);
}
@Override
@ -764,17 +769,24 @@ public final class LauncherHelper {
}
@Override
public synchronized void onLog(String log, Log4jLevel level) {
String filteredLog = Logging.filterForbiddenToken(log);
public void onLog(String log, boolean isErrorStream) {
String filteredLog = forbiddenAccessToken == null ? log : log.replace(forbiddenAccessToken, "<access token>");
if (level.lessOrEqual(Log4jLevel.ERROR))
if (isErrorStream)
System.err.println(filteredLog);
else
System.out.println(filteredLog);
logs.add(pair(filteredLog, level));
if (logs.size() > config().getLogLines())
logs.removeFirst();
Log4jLevel level = isErrorStream ? Log4jLevel.ERROR : (showLogs ? Log4jLevel.guessLevel(filteredLog) : null);
synchronized (this) {
logs.add(filteredLog);
levels.add(level != null ? level : Optional.empty()); // Use 'Optional.empty()' as hole
if (logs.size() > config().getLogLines()) {
logs.removeFirst();
levels.removeFirst();
}
}
if (showLogs) {
try {
@ -787,7 +799,7 @@ public final class LauncherHelper {
Platform.runLater(() -> logWindow.logLine(filteredLog, level));
}
if (!lwjgl && (filteredLog.toLowerCase().contains("lwjgl version") || filteredLog.toLowerCase().contains("lwjgl openal") || !detectWindow)) {
if (!lwjgl && (!detectWindow || filteredLog.toLowerCase().contains("lwjgl version") || filteredLog.toLowerCase().contains("lwjgl openal"))) {
lwjgl = true;
finishLaunch();
}
@ -804,8 +816,11 @@ public final class LauncherHelper {
if (!lwjgl) finishLaunch();
if (exitType != ExitType.NORMAL) {
ArrayList<Pair<String, Log4jLevel>> pairs = new ArrayList<>(logs.size());
Lang.forEachZipped(logs, levels,
(log, l) -> pairs.add(pair(log, l instanceof Log4jLevel ? ((Log4jLevel) l) : Log4jLevel.guessLevel(log))));
repository.markVersionLaunchedAbnormally(version.getId());
Platform.runLater(() -> new GameCrashWindow(process, exitType, repository, version, launchOptions, logs).show());
Platform.runLater(() -> new GameCrashWindow(process, exitType, repository, version, launchOptions, pairs).show());
}
checkExit();

View File

@ -42,6 +42,7 @@ import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.ui.construct.TwoLineListItem;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.Log4jLevel;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.Pair;
import org.jackhuang.hmcl.util.platform.Architecture;
import org.jackhuang.hmcl.util.platform.CommandBuilder;
@ -222,7 +223,7 @@ public class GameCrashWindow extends Stage {
private void showLogWindow() {
LogWindow logWindow = new LogWindow();
logWindow.logLine("Command: " + new CommandBuilder().addAll(managedProcess.getCommands()).toString(), Log4jLevel.INFO);
logWindow.logLine(Logging.filterForbiddenToken("Command: " + new CommandBuilder().addAll(managedProcess.getCommands())), Log4jLevel.INFO);
if (managedProcess.getClasspath() != null) logWindow.logLine("ClassPath: " + managedProcess.getClasspath(), Log4jLevel.INFO);
for (Map.Entry<String, Log4jLevel> entry : logs)
logWindow.logLine(entry.getKey(), entry.getValue());

View File

@ -37,7 +37,6 @@ import javafx.stage.Stage;
import org.apache.commons.lang3.mutable.MutableObject;
import org.jackhuang.hmcl.game.LauncherHelper;
import org.jackhuang.hmcl.util.Log4jLevel;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.platform.OperatingSystem;
import java.io.IOException;
@ -95,8 +94,8 @@ public final class LogWindow extends Stage {
levelShownMap.values().forEach(property -> property.addListener((a, b, newValue) -> shakeLogs()));
}
public void logLine(String line, Log4jLevel level) {
Log log = new Log(Logging.filterForbiddenToken(parseEscapeSequence(line)), level);
public void logLine(String filteredLine, Log4jLevel level) {
Log log = new Log(parseEscapeSequence(filteredLine), level);
logs.add(log);
if (levelShownMap.get(level).get())
impl.listView.getItems().add(log);

View File

@ -21,7 +21,6 @@ import org.jackhuang.hmcl.auth.AuthInfo;
import org.jackhuang.hmcl.download.LibraryAnalyzer;
import org.jackhuang.hmcl.game.*;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.Log4jLevel;
import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.gson.UUIDTypeAdapter;
import org.jackhuang.hmcl.util.io.FileUtils;
@ -646,15 +645,15 @@ public class DefaultLauncher extends Launcher {
throw new ExecutionPolicyLimitException();
}
private void startMonitors(ManagedProcess managedProcess, ProcessListener processListener, Charset encoding, boolean isDaemon) {
private static void startMonitors(ManagedProcess managedProcess, ProcessListener processListener, Charset encoding, boolean isDaemon) {
processListener.setProcess(managedProcess);
Thread stdout = Lang.thread(new StreamPump(managedProcess.getProcess().getInputStream(), it -> {
processListener.onLog(it, Optional.ofNullable(Log4jLevel.guessLevel(it)).orElse(Log4jLevel.INFO));
processListener.onLog(it, false);
managedProcess.addLine(it);
}, encoding), "stdout-pump", isDaemon);
managedProcess.addRelatedThread(stdout);
Thread stderr = Lang.thread(new StreamPump(managedProcess.getProcess().getErrorStream(), it -> {
processListener.onLog(it, Log4jLevel.ERROR);
processListener.onLog(it, true);
managedProcess.addLine(it);
}, encoding), "stderr-pump", isDaemon);
managedProcess.addRelatedThread(stderr);

View File

@ -17,7 +17,6 @@
*/
package org.jackhuang.hmcl.launch;
import org.jackhuang.hmcl.util.Log4jLevel;
import org.jackhuang.hmcl.util.platform.ManagedProcess;
/**
@ -40,7 +39,7 @@ public interface ProcessListener {
*
* @param log the log
*/
void onLog(String log, Log4jLevel level);
void onLog(String log, boolean isErrorStream);
/**
* Called when the game process stops.

View File

@ -366,6 +366,13 @@ public final class Lang {
return () -> iterator;
}
public static <T, U> void forEachZipped(Iterable<T> i1, Iterable<U> i2, BiConsumer<T, U> action) {
Iterator<T> it1 = i1.iterator();
Iterator<U> it2 = i2.iterator();
while (it1.hasNext() && it2.hasNext())
action.accept(it1.next(), it2.next());
}
private static Timer timer;
public static synchronized Timer getTimer() {