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

Avoid progress bar overlap #1866

Merged
merged 8 commits into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from 7 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
14 changes: 10 additions & 4 deletions cli/src/main/java/de/jplag/cli/logger/CollectedLogger.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package de.jplag.cli.logger;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
Expand All @@ -19,7 +20,6 @@ public class CollectedLogger extends AbstractLogger {
private static final String JPLAG_LOGGER_PREFIX = "de.jplag.";
private static final Level LOG_LEVEL_FOR_EXTERNAL_LIBRARIES = Level.ERROR;
private static final int MAXIMUM_MESSAGE_LENGTH = 32;
private static final PrintStream TARGET_STREAM = System.out;
private static Level currentLogLevel = Level.INFO;

private final transient SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-hh:mm:ss_SSS");
Expand Down Expand Up @@ -148,11 +148,10 @@ private StringBuilder prepareLogOutput(LogEntry entry) {

private void printLogEntry(LogEntry entry) {
StringBuilder output = prepareLogOutput(entry);
TARGET_STREAM.println(output);
DelayablePrinter.getInstance().println(output.toString());
if (entry.cause() != null) {
entry.cause().printStackTrace(TARGET_STREAM);
this.printStackTrace(entry.cause());
}
TARGET_STREAM.flush();
}

public static Level getLogLevel() {
Expand All @@ -162,4 +161,11 @@ public static Level getLogLevel() {
public static void setLogLevel(Level logLevel) {
currentLogLevel = logLevel;
}

private void printStackTrace(Throwable error) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
error.printStackTrace(new PrintStream(outputStream));
String stackTrace = outputStream.toString();
DelayablePrinter.getInstance().println(stackTrace);
}
}
73 changes: 73 additions & 0 deletions cli/src/main/java/de/jplag/cli/logger/DelayablePrinter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package de.jplag.cli.logger;

import java.io.PrintStream;
import java.util.PriorityQueue;
import java.util.Queue;

/**
* Prints strings to stdout. Provides the option to delay the actual printing.
*/
public class DelayablePrinter {
private final Queue<String> outputQueue;
private PrintStream targetStream;

private boolean isDelayed;

private static final class InstanceHolder {
private static final DelayablePrinter instance = new DelayablePrinter();
}

/**
* Threadsafe singleton getter
* @return The singleton instance
*/
public static DelayablePrinter getInstance() {
return InstanceHolder.instance;
}

private DelayablePrinter() {
this.outputQueue = new PriorityQueue<>();
this.targetStream = System.out;
this.isDelayed = false;
}

/**
* Prints the given string to the terminal appending a line-break
* @param output The string to print
*/
public synchronized void println(String output) {
this.outputQueue.offer(output);
this.printQueue();
}

/**
* Stops printing to the terminal until {@link #resume()} is called
*/
public synchronized void delay() {
this.isDelayed = true;
}

/**
* Resumes printing if {@link #delay()} was called
*/
public synchronized void resume() {
this.isDelayed = false;
this.printQueue();
}

/**
* Changes the output stream messages are written to
*/
public void setOutputStream(PrintStream printStream) {
this.targetStream = printStream;
}

private synchronized void printQueue() {
if (!this.isDelayed) {
while (!this.outputQueue.isEmpty()) {
this.targetStream.println(this.outputQueue.poll());
}
this.targetStream.flush();
}
}
}
6 changes: 3 additions & 3 deletions cli/src/main/java/de/jplag/cli/logger/IdleBar.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@
import org.jline.terminal.Terminal;
import org.jline.terminal.TerminalBuilder;

import de.jplag.logging.ProgressBar;

/**
* Prints an idle progress bar, that does not count upwards.
*/
public class IdleBar implements ProgressBar {
public class IdleBar extends LogDelayingProgressBar {
private final PrintStream output;

private final Thread runner;
Expand All @@ -27,6 +25,7 @@ public class IdleBar implements ProgressBar {
private boolean running = false;

public IdleBar(String text) {
super();
this.output = System.out;
this.runner = new Thread(this::run);
this.length = 50;
Expand All @@ -53,6 +52,7 @@ public void start() {

@Override
public void dispose() {
super.dispose();
this.running = false;
try {
this.runner.join();
Expand Down
17 changes: 17 additions & 0 deletions cli/src/main/java/de/jplag/cli/logger/LogDelayingProgressBar.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package de.jplag.cli.logger;

import de.jplag.logging.ProgressBar;

/**
* Superclass for progress bars, that delay the log output until the bar is done
*/
public abstract class LogDelayingProgressBar implements ProgressBar {
protected LogDelayingProgressBar() {
DelayablePrinter.getInstance().delay();
}

@Override
public void dispose() {
DelayablePrinter.getInstance().resume();
}
}
6 changes: 3 additions & 3 deletions cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBar.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package de.jplag.cli.logger;

import de.jplag.logging.ProgressBar;

/**
* A ProgressBar, that used the tongfei progress bar library underneath, to show progress bars on the cli.
*/
public class TongfeiProgressBar implements ProgressBar {
public class TongfeiProgressBar extends LogDelayingProgressBar {
private final me.tongfei.progressbar.ProgressBar progressBar;

public TongfeiProgressBar(me.tongfei.progressbar.ProgressBar progressBar) {
super();
this.progressBar = progressBar;
}

Expand All @@ -19,6 +18,7 @@ public void step(int number) {

@Override
public void dispose() {
super.dispose();
this.progressBar.close();
}
}
51 changes: 51 additions & 0 deletions cli/src/test/java/de/jplag/cli/logger/DelayablePrinterTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package de.jplag.cli.logger;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

class DelayablePrinterTest {
private static final String TEST_MESSAGE = "Hello World";

private static ByteArrayOutputStream outputStream;

@BeforeAll
static void setUp() {
outputStream = new ByteArrayOutputStream();
DelayablePrinter.getInstance().setOutputStream(new PrintStream(outputStream));
}

@AfterAll
static void tearDown() {
DelayablePrinter.getInstance().setOutputStream(System.out);
}

@AfterEach
void cleanUpAfterTest() {
DelayablePrinter.getInstance().resume();
outputStream.reset();
}

@Test
void testDelay() {
DelayablePrinter.getInstance().delay();
DelayablePrinter.getInstance().println(TEST_MESSAGE);

Assertions.assertEquals("", outputStream.toString());

DelayablePrinter.getInstance().resume();

Assertions.assertEquals(TEST_MESSAGE + System.lineSeparator(), outputStream.toString());
}

@Test
void testDirectPrinting() {
DelayablePrinter.getInstance().println(TEST_MESSAGE);
Assertions.assertEquals(TEST_MESSAGE + System.lineSeparator(), outputStream.toString());
}
}