Skip to content

Commit 20fce37

Browse files
maarztctrueden
authored andcommitted
ConsoleService: let OutputListeners know if output is marked as log message
Added a method containsLog to OutputEvent, For OutputEvents containing a log message, the method containsLog will return true.
1 parent c86bb4e commit 20fce37

File tree

6 files changed

+97
-13
lines changed

6 files changed

+97
-13
lines changed

src/main/java/org/scijava/console/ConsoleService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
package org.scijava.console;
3434

35+
import java.io.PrintStream;
3536
import java.util.LinkedList;
3637

3738
import org.scijava.plugin.HandlerService;

src/main/java/org/scijava/console/DefaultConsoleService.java

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,16 @@
3333
package org.scijava.console;
3434

3535
import java.io.OutputStream;
36+
import java.io.PrintStream;
3637
import java.util.ArrayList;
3738
import java.util.LinkedList;
3839
import java.util.List;
3940
import java.util.concurrent.CopyOnWriteArrayList;
41+
import java.util.function.BiFunction;
4042

4143
import org.scijava.Context;
4244
import org.scijava.console.OutputEvent.Source;
45+
import org.scijava.log.LogLevel;
4346
import org.scijava.log.LogService;
4447
import org.scijava.plugin.AbstractHandlerService;
4548
import org.scijava.plugin.Parameter;
@@ -72,6 +75,13 @@ public class DefaultConsoleService extends
7275

7376
// -- ConsoleService methods --
7477

78+
@Override
79+
public void initialize() {
80+
PrintStream logErr = logStream(Source.STDERR);
81+
PrintStream logOut = logStream(Source.STDOUT);
82+
log.setPrintStreams(level -> (level <= LogLevel.WARN) ? logErr : logOut);
83+
}
84+
7585
@Override
7686
public void processArgs(final String... args) {
7787
log.debug("Received command line arguments:");
@@ -129,6 +139,27 @@ public void notifyListeners(final OutputEvent event) {
129139
l.outputOccurred(event);
130140
}
131141

142+
private PrintStream logStream(Source source) {
143+
OutputStream a = getBypassingStream(source);
144+
OutputStream b = new OutputStreamReporter((relevance, text) -> {
145+
final Context context = getContext();
146+
final boolean contextual = true;
147+
final boolean containsLog = true;
148+
return new OutputEvent(context, source, text, contextual, containsLog);
149+
});
150+
return new PrintStream(new MultiOutputStream(a, b));
151+
}
152+
153+
private OutputStream getBypassingStream(Source source) {
154+
switch (source) {
155+
case STDOUT:
156+
return ListenableSystemStreams.out().bypass();
157+
case STDERR:
158+
return ListenableSystemStreams.err().bypass();
159+
}
160+
throw new AssertionError();
161+
}
162+
132163
// -- Disposable methods --
133164

134165
@Override
@@ -143,14 +174,23 @@ public void dispose() {
143174
private synchronized void initListeners() {
144175
if (listeners != null) return; // already initialized
145176

146-
out = new OutputStreamReporter(Source.STDOUT);
177+
out = setupDefaultReporter(Source.STDOUT);
178+
err = setupDefaultReporter(Source.STDERR);
147179
ListenableSystemStreams.out().addOutputStream(out);
148-
err = new OutputStreamReporter(Source.STDERR);
149180
ListenableSystemStreams.err().addOutputStream(err);
150181

151182
listeners = new CopyOnWriteArrayList<>();
152183
}
153184

185+
private OutputStreamReporter setupDefaultReporter(Source source) {
186+
return new OutputStreamReporter((relevance, output) -> {
187+
final Context context = getContext();
188+
final boolean contextual = relevance == ThreadContext.SAME;
189+
final boolean containsLog = false;
190+
return new OutputEvent(context, source, output, contextual, containsLog);
191+
});
192+
}
193+
154194
// -- Helper methods --
155195

156196
/**
@@ -178,11 +218,12 @@ private boolean sameElements(final List<String> l1,
178218
*/
179219
private class OutputStreamReporter extends OutputStream {
180220

181-
/** Source of the output stream; i.e., {@code stdout} or {@code stderr}. */
182-
private final Source source;
221+
private final BiFunction<ThreadContext, String, OutputEvent> eventFactory;
183222

184-
public OutputStreamReporter(final Source source) {
185-
this.source = source;
223+
public OutputStreamReporter(
224+
BiFunction<ThreadContext, String, OutputEvent> eventFactory)
225+
{
226+
this.eventFactory = eventFactory;
186227
}
187228

188229
// -- OutputStream methods --
@@ -208,12 +249,8 @@ private ThreadContext getRelevance() {
208249
}
209250

210251
private void publish(final ThreadContext relevance, final String output) {
211-
final Context context = getContext();
212-
final boolean contextual = relevance == ThreadContext.SAME;
213-
final OutputEvent event =
214-
new OutputEvent(context, source, output, contextual);
252+
final OutputEvent event = eventFactory.apply(relevance, output);
215253
notifyListeners(event);
216254
}
217255
}
218-
219256
}

src/main/java/org/scijava/console/OutputEvent.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,20 +68,25 @@ public enum Source {
6868
*/
6969
private final boolean contextual;
7070

71+
/** Whether the output is a printed log message. */
72+
private final boolean containsLog;
73+
7174
/**
7275
* Creates a new output event.
73-
*
76+
*
7477
* @param source The source of the output.
7578
* @param output The output string.
7679
* @param contextual Whether the output was produced within this specific
7780
* SciJava {@link Context}.
81+
* @param containsLog Whether the output is contains a log message.
7882
*/
7983
public OutputEvent(final Context context, final Source source,
80-
final String output, final boolean contextual)
84+
final String output, final boolean contextual, boolean containsLog)
8185
{
8286
this.source = source;
8387
this.output = output;
8488
this.contextual = contextual;
89+
this.containsLog = containsLog;
8590
setContext(context);
8691
setCallingThread(Thread.currentThread());
8792
}
@@ -114,6 +119,14 @@ public boolean isStderr() {
114119
return source == Source.STDERR;
115120
}
116121

122+
/**
123+
* Returns true if the source of the output is a streams returned
124+
* {@link org.scijava.console.ConsoleService#logStream(org.scijava.console.OutputEvent.Source)}
125+
*/
126+
public boolean containsLog() {
127+
return containsLog;
128+
}
129+
117130
// -- Object methods --
118131

119132
@Override

src/main/java/org/scijava/log/LogService.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434

3535
import org.scijava.service.SciJavaService;
3636

37+
import java.io.PrintStream;
38+
import java.util.function.Function;
39+
3740
/**
3841
* Interface for the logging service.
3942
* <p>
@@ -75,6 +78,12 @@ public interface LogService extends SciJavaService, Logger {
7578
*/
7679
void setLevelForLogger(String source, int level);
7780

81+
/**
82+
* If the a LogService writes the log messages to streams,
83+
* it should implement this method for setting the output streams.
84+
*/
85+
default void setPrintStreams(Function<Integer, PrintStream> levelToStream) {}
86+
7887
// -- Deprecated --
7988

8089
/** @deprecated Use {@link LogLevel#NONE}. */
@@ -95,4 +104,5 @@ public interface LogService extends SciJavaService, Logger {
95104
/** @deprecated Use {@link LogLevel#TRACE}. */
96105
@Deprecated
97106
int TRACE = LogLevel.TRACE;
107+
98108
}

src/main/java/org/scijava/log/StderrLogService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public class StderrLogService extends AbstractLogService {
5656
private Function<Integer, PrintStream> levelToStream =
5757
level -> (level <= LogLevel.WARN) ? System.err : System.out;
5858

59+
@Override
5960
public void setPrintStreams(Function<Integer, PrintStream> levelToStream) {
6061
this.levelToStream = levelToStream;
6162
}

src/test/java/org/scijava/console/ConsoleServiceTest.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import static org.junit.Assert.assertFalse;
3737
import static org.junit.Assert.assertNotNull;
3838
import static org.junit.Assert.assertTrue;
39+
import static org.junit.Assume.assumeTrue;
3940

4041
import java.lang.reflect.InvocationTargetException;
4142
import java.util.ArrayList;
@@ -49,6 +50,8 @@
4950
import org.scijava.Context;
5051
import org.scijava.Priority;
5152
import org.scijava.console.OutputEvent.Source;
53+
import org.scijava.convert.ConvertService;
54+
import org.scijava.log.LogService;
5255
import org.scijava.plugin.Plugin;
5356
import org.scijava.thread.ThreadService;
5457

@@ -208,6 +211,25 @@ public void testMultipleContextOutput() throws InterruptedException,
208211
assertOutputEvent(Source.STDERR, c2InvokeErr, true, events2.get(5));
209212
}
210213

214+
@Test
215+
public void testLogToStream() {
216+
final Context context = new Context(LogService.class, ConsoleService.class);
217+
final ConsoleService consoleService = context.getService(ConsoleService.class);
218+
final LogService logService = context.getService(LogService.class);
219+
final ArrayList<OutputEvent> events = new ArrayList<>();
220+
final OutputListener outputListener = new OutputTracker(events);
221+
222+
consoleService.addOutputListener(outputListener);
223+
logService.warn("Hello");
224+
System.out.print("World");
225+
consoleService.removeOutputListener(outputListener);
226+
227+
assertEquals(2, events.size());
228+
assertTrue(events.get(0).containsLog());
229+
assertTrue(events.get(0).isContextual());
230+
assertFalse(events.get(1).containsLog());
231+
}
232+
211233
// -- Helper methods --
212234

213235
private void assertOutputEvent(final Source source, final String output,

0 commit comments

Comments
 (0)