diff --git a/src/main/java/redis/embedded/AbstractRedisInstance.java b/src/main/java/redis/embedded/AbstractRedisInstance.java index 7dd75428..a67644b3 100644 --- a/src/main/java/redis/embedded/AbstractRedisInstance.java +++ b/src/main/java/redis/embedded/AbstractRedisInstance.java @@ -16,7 +16,9 @@ abstract class AbstractRedisInstance implements Redis { private Process redisProcess; private final int port; - private ExecutorService executor; + private ExecutorService executor = Executors.newSingleThreadExecutor(); + private PrintStream out = null; //Ignore Redis output. + private PrintStream err = System.err; //Forward Redis error messages to STDERR. protected AbstractRedisInstance(int port) { this.port = port; @@ -42,14 +44,26 @@ public synchronized void start() throws EmbeddedRedisException { private void logErrors() { final InputStream errorStream = redisProcess.getErrorStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(errorStream)); - Runnable printReaderTask = new PrintReaderRunnable(reader); - executor = Executors.newSingleThreadExecutor(); - executor.submit(printReaderTask); + copyStreamInBackground(errorStream, err); } + private void copyStreamInBackground(final InputStream copyFrom, PrintStream copyTo) { + BufferedReader reader = new BufferedReader(new InputStreamReader(copyFrom)); + Runnable printReaderTask = new PrintReaderRunnable(reader, copyTo); + executor.submit(printReaderTask); + } + + public void outTo(PrintStream out) { + this.out = out; + } + + public void errTo(PrintStream err) { + this.err = err; + } + private void awaitRedisServerReady() throws IOException { - BufferedReader reader = new BufferedReader(new InputStreamReader(redisProcess.getInputStream())); + InputStream stdoutStream = redisProcess.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(stdoutStream)); try { StringBuffer outputStringBuffer = new StringBuffer(); String outputLine; @@ -62,10 +76,18 @@ private void awaitRedisServerReady() throws IOException { else{ outputStringBuffer.append("\n"); outputStringBuffer.append(outputLine); + if(out != null) { + out.println(outputLine); + } } } while (!outputLine.matches(redisReadyPattern())); } finally { - IOUtils.closeQuietly(reader); + if(out != null) { + /* Continue reading of STDOUT in a background thread. */ + copyStreamInBackground(stdoutStream, out); + } else { + IOUtils.closeQuietly(reader); + } } } @@ -103,9 +125,11 @@ public List ports() { private static class PrintReaderRunnable implements Runnable { private final BufferedReader reader; + private final PrintStream outputStream; - private PrintReaderRunnable(BufferedReader reader) { + private PrintReaderRunnable(BufferedReader reader, PrintStream outputStream) { this.reader = reader; + this.outputStream = outputStream; } public void run() { @@ -120,10 +144,10 @@ public void readLines() { try { String line; while ((line = reader.readLine()) != null) { - System.out.println(line); + outputStream.println(line); } } catch (IOException e) { - e.printStackTrace(); + /* reader has been closed. The connected Redis instance has possibly shut down. */ } } } diff --git a/src/main/java/redis/embedded/RedisSentinelBuilder.java b/src/main/java/redis/embedded/RedisSentinelBuilder.java index 49d7f8f5..0da48c9a 100644 --- a/src/main/java/redis/embedded/RedisSentinelBuilder.java +++ b/src/main/java/redis/embedded/RedisSentinelBuilder.java @@ -6,6 +6,7 @@ import java.io.File; import java.io.IOException; +import java.io.PrintStream; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; @@ -32,7 +33,9 @@ public class RedisSentinelBuilder { private String sentinelConf; private StringBuilder redisConfigBuilder; - + private PrintStream out = null; //Ignore Redis output. + private PrintStream err = System.err; //Forward Redis error messages to STDERR. + public RedisSentinelBuilder redisExecProvider(RedisExecProvider redisExecProvider) { this.redisExecProvider = redisExecProvider; return this; @@ -100,10 +103,39 @@ public RedisSentinelBuilder setting(String configLine) { return this; } + /** + * Redirect Redis server messages sent to STDOUT. + * Usage example: + * @code{ + * RedisServerBuilder serverBuilder = RedisServer.builder().outTo(System.out).errTo(System.err); + RedisSentinelBuilder sentinelBuilder = new RedisSentinelBuilder().outTo(System.out).errTo(System.err); + RedisCluster.builder().withServerBuilder(serverBuilder).withSentinelBuilder(sentinelBuilder)... } + * @param out Stream to redirect Redis output to. + * @return {@code this} + */ + public RedisSentinelBuilder outTo(PrintStream out) { + this.out = out; + return this; + } + + /** + * Redirect Redis server messages sent to STDERR. + * @param err Stream to redirect Redis output to. + * Usage example: @code{builder.errTo(System.err);} + * @return {@code itself} + */ + public RedisSentinelBuilder errTo(PrintStream err) { + this.err = err; + return this; + } + public RedisSentinel build() { tryResolveConfAndExec(); List args = buildCommandArgs(); - return new RedisSentinel(args, port); + RedisSentinel sentinel = new RedisSentinel(args, port); + sentinel.outTo(out); + sentinel.errTo(err); + return sentinel; } private void tryResolveConfAndExec() { diff --git a/src/main/java/redis/embedded/RedisServerBuilder.java b/src/main/java/redis/embedded/RedisServerBuilder.java index 192b9fb6..d0891070 100644 --- a/src/main/java/redis/embedded/RedisServerBuilder.java +++ b/src/main/java/redis/embedded/RedisServerBuilder.java @@ -6,6 +6,7 @@ import java.io.File; import java.io.IOException; +import java.io.PrintStream; import java.net.InetSocketAddress; import java.nio.charset.Charset; import java.util.ArrayList; @@ -21,6 +22,8 @@ public class RedisServerBuilder { private int port = 6379; private InetSocketAddress slaveOf; private String redisConf; + private PrintStream out = null; //Ignore Redis output. + private PrintStream err = System.err; //Forward Redis error messages to STDERR. private StringBuilder redisConfigBuilder; @@ -71,11 +74,36 @@ public RedisServerBuilder setting(String configLine) { return this; } + /** + * Redirect Redis server messages sent to STDOUT. + * Usage example: @code{builder.outTo(System.out);} + * @param out Stream to receive Redis output. + * @return {@code this} + */ + public RedisServerBuilder outTo(PrintStream out) { + this.out = out; + return this; + } + + /** + * Redirect Redis server messages sent to STDERR. + * @param err Stream to receive Redis output. + * Usage example: @code{builder.errTo(System.err);} + * @return {@code itself} + */ + public RedisServerBuilder errTo(PrintStream err) { + this.err = err; + return this; + } + public RedisServer build() { setting("bind "+bind); tryResolveConfAndExec(); List args = buildCommandArgs(); - return new RedisServer(args, port); + RedisServer server = new RedisServer(args, port); + server.outTo(out); + server.errTo(err); + return server; } public void reset() {