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]. * Guarantee that one [JavaProcess], one [HMCLProcessListener].
* Because every time we launched a game, we generates a new [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 HMCLGameRepository repository;
private final Version version; private final Version version;
@ -694,9 +694,11 @@ public final class LauncherHelper {
private boolean lwjgl; private boolean lwjgl;
private LogWindow logWindow; private LogWindow logWindow;
private final boolean detectWindow; 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 logWindowLatch = new CountDownLatch(1);
private final CountDownLatch launchingLatch; private final CountDownLatch launchingLatch;
private final String forbiddenAccessToken;
public HMCLProcessListener(HMCLGameRepository repository, Version version, AuthInfo authInfo, LaunchOptions launchOptions, CountDownLatch launchingLatch, boolean detectWindow) { public HMCLProcessListener(HMCLGameRepository repository, Version version, AuthInfo authInfo, LaunchOptions launchOptions, CountDownLatch launchingLatch, boolean detectWindow) {
this.repository = repository; this.repository = repository;
@ -704,8 +706,11 @@ public final class LauncherHelper {
this.launchOptions = launchOptions; this.launchOptions = launchOptions;
this.launchingLatch = launchingLatch; this.launchingLatch = launchingLatch;
this.detectWindow = detectWindow; 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 @Override
@ -764,17 +769,24 @@ public final class LauncherHelper {
} }
@Override @Override
public synchronized void onLog(String log, Log4jLevel level) { public void onLog(String log, boolean isErrorStream) {
String filteredLog = Logging.filterForbiddenToken(log); String filteredLog = forbiddenAccessToken == null ? log : log.replace(forbiddenAccessToken, "<access token>");
if (level.lessOrEqual(Log4jLevel.ERROR)) if (isErrorStream)
System.err.println(filteredLog); System.err.println(filteredLog);
else else
System.out.println(filteredLog); System.out.println(filteredLog);
logs.add(pair(filteredLog, level)); Log4jLevel level = isErrorStream ? Log4jLevel.ERROR : (showLogs ? Log4jLevel.guessLevel(filteredLog) : null);
if (logs.size() > config().getLogLines())
logs.removeFirst(); 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) { if (showLogs) {
try { try {
@ -787,7 +799,7 @@ public final class LauncherHelper {
Platform.runLater(() -> logWindow.logLine(filteredLog, level)); 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; lwjgl = true;
finishLaunch(); finishLaunch();
} }
@ -804,8 +816,11 @@ public final class LauncherHelper {
if (!lwjgl) finishLaunch(); if (!lwjgl) finishLaunch();
if (exitType != ExitType.NORMAL) { 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()); 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(); checkExit();

View File

@ -42,6 +42,7 @@ import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.ui.construct.TwoLineListItem; import org.jackhuang.hmcl.ui.construct.TwoLineListItem;
import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.Log4jLevel; import org.jackhuang.hmcl.util.Log4jLevel;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.Pair; import org.jackhuang.hmcl.util.Pair;
import org.jackhuang.hmcl.util.platform.Architecture; import org.jackhuang.hmcl.util.platform.Architecture;
import org.jackhuang.hmcl.util.platform.CommandBuilder; import org.jackhuang.hmcl.util.platform.CommandBuilder;
@ -222,7 +223,7 @@ public class GameCrashWindow extends Stage {
private void showLogWindow() { private void showLogWindow() {
LogWindow logWindow = new LogWindow(); 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); if (managedProcess.getClasspath() != null) logWindow.logLine("ClassPath: " + managedProcess.getClasspath(), Log4jLevel.INFO);
for (Map.Entry<String, Log4jLevel> entry : logs) for (Map.Entry<String, Log4jLevel> entry : logs)
logWindow.logLine(entry.getKey(), entry.getValue()); 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.apache.commons.lang3.mutable.MutableObject;
import org.jackhuang.hmcl.game.LauncherHelper; import org.jackhuang.hmcl.game.LauncherHelper;
import org.jackhuang.hmcl.util.Log4jLevel; import org.jackhuang.hmcl.util.Log4jLevel;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jackhuang.hmcl.util.platform.OperatingSystem;
import java.io.IOException; import java.io.IOException;
@ -95,8 +94,8 @@ public final class LogWindow extends Stage {
levelShownMap.values().forEach(property -> property.addListener((a, b, newValue) -> shakeLogs())); levelShownMap.values().forEach(property -> property.addListener((a, b, newValue) -> shakeLogs()));
} }
public void logLine(String line, Log4jLevel level) { public void logLine(String filteredLine, Log4jLevel level) {
Log log = new Log(Logging.filterForbiddenToken(parseEscapeSequence(line)), level); Log log = new Log(parseEscapeSequence(filteredLine), level);
logs.add(log); logs.add(log);
if (levelShownMap.get(level).get()) if (levelShownMap.get(level).get())
impl.listView.getItems().add(log); 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.download.LibraryAnalyzer;
import org.jackhuang.hmcl.game.*; import org.jackhuang.hmcl.game.*;
import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.Log4jLevel;
import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.gson.UUIDTypeAdapter; import org.jackhuang.hmcl.util.gson.UUIDTypeAdapter;
import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.FileUtils;
@ -646,15 +645,15 @@ public class DefaultLauncher extends Launcher {
throw new ExecutionPolicyLimitException(); 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); processListener.setProcess(managedProcess);
Thread stdout = Lang.thread(new StreamPump(managedProcess.getProcess().getInputStream(), it -> { 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); managedProcess.addLine(it);
}, encoding), "stdout-pump", isDaemon); }, encoding), "stdout-pump", isDaemon);
managedProcess.addRelatedThread(stdout); managedProcess.addRelatedThread(stdout);
Thread stderr = Lang.thread(new StreamPump(managedProcess.getProcess().getErrorStream(), it -> { Thread stderr = Lang.thread(new StreamPump(managedProcess.getProcess().getErrorStream(), it -> {
processListener.onLog(it, Log4jLevel.ERROR); processListener.onLog(it, true);
managedProcess.addLine(it); managedProcess.addLine(it);
}, encoding), "stderr-pump", isDaemon); }, encoding), "stderr-pump", isDaemon);
managedProcess.addRelatedThread(stderr); managedProcess.addRelatedThread(stderr);

View File

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

View File

@ -366,6 +366,13 @@ public final class Lang {
return () -> iterator; 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; private static Timer timer;
public static synchronized Timer getTimer() { public static synchronized Timer getTimer() {