Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Dev UI Logging #19893

Merged
merged 1 commit into from
Sep 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ protected Boolean initialValue() {
static final TreeMap<Integer, StatusLineImpl> statusMap = new TreeMap<>();
private final ReadWriteLock positionLock = new ReentrantReadWriteLock();
private volatile boolean closed;
private final StatusLine prompt;

public AeshConsole(Connection connection) {
INSTANCE = this;
Expand All @@ -67,6 +68,7 @@ public void run() {
connection.close();
}
}, "Console Shutdown Hook"));
prompt = registerStatusLine(0);
}

private void updatePromptOnChange(StringBuilder buffer, int newLines) {
Expand Down Expand Up @@ -109,7 +111,7 @@ public StatusLine registerStatusLine(int priority) {

@Override
public void setPromptMessage(String promptMessage) {
setMessage(0, promptMessage);
prompt.setMessage(promptMessage);
}

private AeshConsole setMessage(int position, String message) {
Expand Down Expand Up @@ -386,6 +388,11 @@ public void write(boolean errorStream, byte[] buf, int off, int len) {
write(errorStream, new String(buf, off, len, connection.outputEncoding()));
}

@Override
public boolean isAnsiSupported() {
return true;
}

@Override
public void doReadLine() {
setPromptMessage("");
Expand All @@ -395,10 +402,13 @@ public void doReadLine() {
}

void rebalance() {
int count = 1;
for (var val : statusMap.values()) {
val.position = count;
setMessage(count++, val.message);
synchronized (this) {
int count = 1;
messages = new String[statusMap.size()];
for (var val : statusMap.values()) {
val.position = count;
setMessage(count++, val.message);
}
}
}

Expand All @@ -407,17 +417,20 @@ class StatusLineImpl implements StatusLine {
final int priority;
int position;
String message;
boolean closed;

StatusLineImpl(int priority) {
this.priority = priority;
}

@Override
public void setMessage(String message) {
this.message = message;
try {
positionLock.readLock().lock();
AeshConsole.this.setMessage(position, message);
this.message = message;
if (!closed) {
AeshConsole.this.setMessage(position, message);
}
} finally {
positionLock.readLock().unlock();
}
Expand All @@ -426,6 +439,7 @@ public void setMessage(String message) {
@Override
public void close() {
positionLock.writeLock().lock();
closed = true;
try {
AeshConsole.this.setMessage(position, null);
statusMap.remove(priority);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.quarkus.deployment.console;

import java.io.IOException;
import java.io.PrintStream;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.function.Consumer;
import java.util.function.Supplier;
Expand All @@ -12,30 +11,11 @@
import io.quarkus.deployment.dev.testing.TestConfig;
import io.quarkus.dev.console.BasicConsole;
import io.quarkus.dev.console.QuarkusConsole;
import io.quarkus.dev.console.RedirectPrintStream;
import io.quarkus.runtime.console.ConsoleRuntimeConfig;
import io.quarkus.runtime.util.ColorSupport;

public class ConsoleHelper {

static boolean redirectsInstalled = false;

final static PrintStream out = System.out;
final static PrintStream err = System.err;

public synchronized static void installRedirects() {
if (redirectsInstalled) {
return;
}
redirectsInstalled = true;

//force console init
//otherwise you can get a stack overflow as it sees the redirected output
QuarkusConsole.INSTANCE.isInputSupported();
System.setOut(new RedirectPrintStream(false));
System.setErr(new RedirectPrintStream(true));
}

public static synchronized void installConsole(TestConfig config, ConsoleConfig consoleConfig,
ConsoleRuntimeConfig consoleRuntimeConfig, io.quarkus.runtime.logging.ConsoleConfig logConfig, boolean test) {
if (QuarkusConsole.installed) {
Expand All @@ -50,7 +30,7 @@ public static synchronized void installConsole(TestConfig config, ConsoleConfig
if (!inputSupport) {
//note that in this case we don't hold onto anything from this class loader
//which is important for the test suite
QuarkusConsole.INSTANCE = new BasicConsole(colorEnabled, false, out, System.console());
QuarkusConsole.INSTANCE = new BasicConsole(colorEnabled, false, QuarkusConsole.ORIGINAL_OUT, System.console());
return;
}
try {
Expand Down Expand Up @@ -109,8 +89,8 @@ public Integer get() {
}
});
} catch (IOException e) {
QuarkusConsole.INSTANCE = new BasicConsole(colorEnabled, false, out, System.console());
QuarkusConsole.INSTANCE = new BasicConsole(colorEnabled, false, QuarkusConsole.ORIGINAL_OUT, System.console());
}
installRedirects();
QuarkusConsole.installRedirects();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.quarkus.deployment.console;

import io.quarkus.builder.item.SimpleBuildItem;

/**
* Build item that signifies that the interactive console is ready.
*
* This will not always be present, as the console may not be installed
*/
public final class ConsoleInstalledBuildItem extends SimpleBuildItem {

public static final ConsoleInstalledBuildItem INSTANCE = new ConsoleInstalledBuildItem();
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ public class ConsoleProcessor {
*/
@BuildStep(onlyIf = IsDevelopment.class)
@Produce(TestSetupBuildItem.class)
void setupConsole(TestConfig config, BuildProducer<TestListenerBuildItem> testListenerBuildItemBuildProducer,
ConsoleInstalledBuildItem setupConsole(TestConfig config,
BuildProducer<TestListenerBuildItem> testListenerBuildItemBuildProducer,
LaunchModeBuildItem launchModeBuildItem, ConsoleConfig consoleConfig) {

if (consoleInstalled) {
return;
return ConsoleInstalledBuildItem.INSTANCE;
}
consoleInstalled = true;
if (config.console.orElse(consoleConfig.enabled)) {
Expand All @@ -49,11 +50,12 @@ void setupConsole(TestConfig config, BuildProducer<TestListenerBuildItem> testLi
//note that this bit needs to be refactored so it is no longer tied to continuous testing
if (!TestSupport.instance().isPresent() || config.continuousTesting == TestConfig.Mode.DISABLED
|| config.flatClassPath) {
return;
return ConsoleInstalledBuildItem.INSTANCE;
}
TestConsoleHandler consoleHandler = new TestConsoleHandler(launchModeBuildItem.getDevModeType().get());
consoleHandler.install();
testListenerBuildItemBuildProducer.produce(new TestListenerBuildItem(consoleHandler));
}
return ConsoleInstalledBuildItem.INSTANCE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package io.quarkus.deployment.console;

import java.io.Closeable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiPredicate;

import io.quarkus.deployment.dev.testing.MessageFormat;
import io.quarkus.deployment.logging.LoggingSetupBuildItem;
import io.quarkus.dev.console.QuarkusConsole;
import io.quarkus.dev.console.StatusLine;

/**
* special filter that can be used to compress log messages to a status line
* <p>
* This is useful for Dev Services to show progress without cluttering up the logs
*/
public class StartupLogCompressor implements Closeable, BiPredicate<String, Boolean> {

final Thread thread;
final String name;
final StatusLine sl;
final List<String> toDump = new ArrayList<>();
final AtomicInteger COUNTER = new AtomicInteger();

public StartupLogCompressor(String name,
@SuppressWarnings("unused") Optional<ConsoleInstalledBuildItem> consoleInstalledBuildItem,
@SuppressWarnings("unused") LoggingSetupBuildItem loggingSetupBuildItem) {
if (QuarkusConsole.INSTANCE.isAnsiSupported()) {
QuarkusConsole.installRedirects();
this.name = name;
this.thread = Thread.currentThread();
QuarkusConsole.addOutputFilter(this);
sl = QuarkusConsole.INSTANCE.registerStatusLine(1000 + COUNTER.incrementAndGet());
sl.setMessage(MessageFormat.BLUE + name + MessageFormat.RESET);
} else {
thread = null;
this.name = null;
sl = null;
}
}

@Override
public void close() {
if (thread == null) {
return;
}
QuarkusConsole.removeOutputFilter(this);
sl.close();
}

public void closeAndDumpCaptured() {
if (thread == null) {
return;
}
QuarkusConsole.removeOutputFilter(this);
sl.close();
for (var i : toDump) {
QuarkusConsole.INSTANCE.write(true, i);
}
}

@Override
public boolean test(String s, Boolean errorStream) {
if (thread == null) {
//not installed
return true;
}
if (Thread.currentThread() == thread) {
toDump.add(s);
sl.setMessage(MessageFormat.BLUE + name + MessageFormat.RESET + " " + s.replace("\n", ""));
return false;
}
return true;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ public FilterResult apply(TestDescriptor testDescriptor) {
listener.runStarted(toRun);
}
log.debug("Starting test run with " + testPlan.countTestIdentifiers((s) -> true) + " tests");
QuarkusConsole.INSTANCE.addOutputFilter(logHandler);
QuarkusConsole.addOutputFilter(logHandler);

final Deque<Set<String>> touchedClasses = new LinkedBlockingDeque<>();
Map<TestIdentifier, Long> startTimes = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.quarkus.dev.console;

import java.io.PrintStream;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.CopyOnWriteArrayList;
Expand Down Expand Up @@ -45,6 +46,24 @@ public abstract class QuarkusConsole {

private volatile boolean started = false;

static boolean redirectsInstalled = false;

public final static PrintStream ORIGINAL_OUT = System.out;
public final static PrintStream ORIGINAL_ERR = System.err;

public synchronized static void installRedirects() {
if (redirectsInstalled) {
return;
}
redirectsInstalled = true;

//force console init
//otherwise you can get a stack overflow as it sees the redirected output
QuarkusConsole.INSTANCE.isInputSupported();
System.setOut(new RedirectPrintStream(false));
System.setErr(new RedirectPrintStream(true));
}

public static boolean hasColorSupport() {
if (Boolean.getBoolean(FORCE_COLOR_SUPPORT)) {
return true; //assume the IDE run window has color support
Expand Down Expand Up @@ -120,4 +139,8 @@ protected boolean shouldWrite(boolean errorStream, String s) {
public boolean isInputSupported() {
return true;
}

public boolean isAnsiSupported() {
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
import io.quarkus.deployment.builditem.DevServicesConfigResultBuildItem;
import io.quarkus.deployment.builditem.DevServicesSharedNetworkBuildItem;
import io.quarkus.deployment.builditem.LaunchModeBuildItem;
import io.quarkus.deployment.console.ConsoleInstalledBuildItem;
import io.quarkus.deployment.console.StartupLogCompressor;
import io.quarkus.deployment.dev.devservices.GlobalDevServicesConfig;
import io.quarkus.deployment.logging.LoggingSetupBuildItem;
import io.quarkus.devservices.common.ContainerLocator;
import io.quarkus.runtime.LaunchMode;
import io.quarkus.runtime.configuration.ConfigUtils;
Expand Down Expand Up @@ -57,7 +60,9 @@ public class DevServicesApicurioRegistryProcessor {
public void startApicurioRegistryDevService(LaunchModeBuildItem launchMode,
ApicurioRegistryDevServicesBuildTimeConfig apicurioRegistryDevServices,
Optional<DevServicesSharedNetworkBuildItem> devServicesSharedNetworkBuildItem,
BuildProducer<DevServicesConfigResultBuildItem> devServicesConfiguration) {
BuildProducer<DevServicesConfigResultBuildItem> devServicesConfiguration,
Optional<ConsoleInstalledBuildItem> consoleInstalledBuildItem,
LoggingSetupBuildItem loggingSetupBuildItem) {

ApicurioRegistryDevServiceCfg configuration = getConfiguration(apicurioRegistryDevServices);

Expand All @@ -69,11 +74,20 @@ public void startApicurioRegistryDevService(LaunchModeBuildItem launchMode,
shutdownApicurioRegistry();
cfg = null;
}

ApicurioRegistry apicurioRegistry = startApicurioRegistry(configuration, launchMode,
devServicesSharedNetworkBuildItem.isPresent());
if (apicurioRegistry == null) {
return;
ApicurioRegistry apicurioRegistry;
StartupLogCompressor compressor = new StartupLogCompressor(
(launchMode.isTest() ? "(test) " : "") + "Apicurio Registry Dev Services Starting:",
consoleInstalledBuildItem, loggingSetupBuildItem);
try {
apicurioRegistry = startApicurioRegistry(configuration, launchMode,
devServicesSharedNetworkBuildItem.isPresent());
if (apicurioRegistry == null) {
return;
}
compressor.close();
} catch (Throwable t) {
compressor.closeAndDumpCaptured();
throw new RuntimeException(t);
}

cfg = configuration;
Expand Down
Loading