You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by sl...@apache.org on 2016/09/16 10:23:17 UTC

cassandra git commit: Fix cassandra-stress graph option

Repository: cassandra
Updated Branches:
  refs/heads/trunk cfedd4d0e -> f42e235b1


Fix cassandra-stress graph option

Patch by Christopher Batey; reviewed by Joel Knighton for CASSANDRA-12237


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/f42e235b
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/f42e235b
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/f42e235b

Branch: refs/heads/trunk
Commit: f42e235b1ee9432a157c4ee138b9d48df57d83b3
Parents: cfedd4d
Author: Christopher Batey <ch...@gmail.com>
Authored: Wed Jul 20 14:08:51 2016 +0100
Committer: Sylvain Lebresne <sy...@datastax.com>
Committed: Fri Sep 16 12:22:52 2016 +0200

----------------------------------------------------------------------
 CHANGES.txt                                     |   1 +
 .../src/org/apache/cassandra/stress/Stress.java |   4 +-
 .../apache/cassandra/stress/StressAction.java   |  19 +-
 .../apache/cassandra/stress/StressGraph.java    |   5 +-
 .../apache/cassandra/stress/StressProfile.java  |   4 +-
 .../apache/cassandra/stress/StressServer.java   |   5 +-
 .../cassandra/stress/report/StressMetrics.java  |  23 +-
 .../stress/settings/SettingsColumn.java         |   4 +-
 .../stress/settings/SettingsCommand.java        |   4 +-
 .../settings/SettingsCommandPreDefined.java     |   4 +-
 .../SettingsCommandPreDefinedMixed.java         |   4 +-
 .../stress/settings/SettingsCommandUser.java    |   4 +-
 .../stress/settings/SettingsErrors.java         |   4 +-
 .../stress/settings/SettingsGraph.java          |   4 +-
 .../stress/settings/SettingsInsert.java         |   4 +-
 .../cassandra/stress/settings/SettingsLog.java  |  11 +-
 .../cassandra/stress/settings/SettingsMode.java |   4 +-
 .../cassandra/stress/settings/SettingsNode.java |   4 +-
 .../stress/settings/SettingsPopulation.java     |   4 +-
 .../cassandra/stress/settings/SettingsPort.java |   4 +-
 .../cassandra/stress/settings/SettingsRate.java |  13 +-
 .../stress/settings/SettingsSchema.java         |   5 +-
 .../stress/settings/SettingsTokenRange.java     |   4 +-
 .../stress/settings/SettingsTransport.java      |   4 +-
 .../stress/settings/StressSettings.java         |   4 +-
 .../cassandra/stress/util/MultiPrintStream.java | 288 -------------------
 .../stress/util/MultiResultLogger.java          |  78 +++++
 .../cassandra/stress/util/NoopResultLogger.java |  44 +++
 .../cassandra/stress/util/ResultLogger.java     |  30 ++
 .../apache/cassandra/stress/graph/graph.html    |  25 +-
 .../stress/util/MultiResultLoggerTest.java      | 105 +++++++
 31 files changed, 341 insertions(+), 379 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 312713f..8e39d95 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 3.10
+ * Fix cassandra-stress graphing (CASSANDRA-12237)
  * Allow filtering on partition key columns for queries without secondary indexes (CASSANDRA-11031)
  * Fix Cassandra Stress reporting thread model and precision (CASSANDRA-12585)
  * Add JMH benchmarks.jar (CASSANDRA-12586)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/Stress.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/Stress.java b/tools/stress/src/org/apache/cassandra/stress/Stress.java
index 6382904..925f709 100644
--- a/tools/stress/src/org/apache/cassandra/stress/Stress.java
+++ b/tools/stress/src/org/apache/cassandra/stress/Stress.java
@@ -23,9 +23,9 @@ import java.net.SocketException;
 
 import org.apache.cassandra.config.DatabaseDescriptor;
 import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.MultiResultLogger;
 import org.apache.cassandra.utils.FBUtilities;
 import org.apache.cassandra.utils.WindowsTimer;
-import org.apache.cassandra.stress.util.MultiPrintStream;
 
 public final class Stress
 {
@@ -88,7 +88,7 @@ public final class Stress
                 return 1;
             }
 
-            MultiPrintStream logout = settings.log.getOutput();
+            MultiResultLogger logout = settings.log.getOutput();
 
             if (! settings.log.noSettings)
             {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/StressAction.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/StressAction.java b/tools/stress/src/org/apache/cassandra/stress/StressAction.java
index f3d9cbd..eaee752 100644
--- a/tools/stress/src/org/apache/cassandra/stress/StressAction.java
+++ b/tools/stress/src/org/apache/cassandra/stress/StressAction.java
@@ -17,9 +17,6 @@
  */
 package org.apache.cassandra.stress;
 
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintStream;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Queue;
@@ -35,6 +32,7 @@ import org.apache.cassandra.stress.settings.ConnectionAPI;
 import org.apache.cassandra.stress.settings.SettingsCommand;
 import org.apache.cassandra.stress.settings.StressSettings;
 import org.apache.cassandra.stress.util.JavaDriverClient;
+import org.apache.cassandra.stress.util.ResultLogger;
 import org.apache.cassandra.stress.util.ThriftClient;
 import org.apache.cassandra.transport.SimpleClient;
 import org.jctools.queues.SpscArrayQueue;
@@ -46,8 +44,8 @@ public class StressAction implements Runnable
 {
 
     private final StressSettings settings;
-    private final PrintStream output;
-    public StressAction(StressSettings settings, PrintStream out)
+    private final ResultLogger output;
+    public StressAction(StressSettings settings, ResultLogger out)
     {
         this.settings = settings;
         output = out;
@@ -67,6 +65,10 @@ public class StressAction implements Runnable
         if (settings.command.truncate == SettingsCommand.TruncateWhen.ONCE)
             settings.command.truncateTables(settings);
 
+        // Required for creating a graph from the output file
+        if (settings.rate.threadCount == -1)
+            output.println("Thread count was not specified");
+
         // TODO : move this to a new queue wrapper that gates progress based on a poisson (or configurable) distribution
         UniformRateLimiter rateLimiter = null;
         if (settings.rate.opsPerSecond > 0)
@@ -94,7 +96,6 @@ public class StressAction implements Runnable
     @SuppressWarnings("resource") // warmupOutput doesn't need closing
     private void warmup(OpDistributionFactory operations)
     {
-        PrintStream warmupOutput = new PrintStream(new OutputStream() { @Override public void write(int b) throws IOException { } } );
         // do 25% of iterations as warmup but no more than 50k (by default hotspot compiles methods after 10k invocations)
         int iterations = (settings.command.count > 0
                          ? Math.min(50000, (int)(settings.command.count * 0.25))
@@ -111,7 +112,7 @@ public class StressAction implements Runnable
             // we need to warm up all the nodes in the cluster ideally, but we may not be the only stress instance;
             // so warm up all the nodes we're speaking to only.
             output.println(String.format("Warming up %s with %d iterations...", single.desc(), iterations));
-            boolean success = null != run(single, threads, iterations, 0, null, null, warmupOutput, true);
+            boolean success = null != run(single, threads, iterations, 0, null, null, ResultLogger.NOOP, true);
             if (!success)
                 throw new RuntimeException("Failed to execute warmup");
         }
@@ -200,7 +201,7 @@ public class StressAction implements Runnable
                               long duration,
                               UniformRateLimiter rateLimiter,
                               TimeUnit durationUnits,
-                              PrintStream output,
+                              ResultLogger output,
                               boolean isWarmup)
     {
         output.println(String.format("Running %s with %d threads %s",
@@ -470,7 +471,7 @@ public class StressAction implements Runnable
                         if (output == null)
                             System.err.println(e.getMessage());
                         else
-                            e.printStackTrace(output);
+                            output.printException(e);
 
                         success = false;
                         opStream.abort();

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/StressGraph.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/StressGraph.java b/tools/stress/src/org/apache/cassandra/stress/StressGraph.java
index 196964c..17b718d 100644
--- a/tools/stress/src/org/apache/cassandra/stress/StressGraph.java
+++ b/tools/stress/src/org/apache/cassandra/stress/StressGraph.java
@@ -201,7 +201,8 @@ public class StressGraph
                     {
                         continue;
                     }
-                    json.put(parts[0].trim(), parts[1].trim());
+                    // the graphing js expects lower case names
+                    json.put(parts[0].trim().toLowerCase(), parts[1].trim());
                 }
                 else if (mode == ReadingMode.NEXTITERATION)
                 {
@@ -227,7 +228,7 @@ public class StressGraph
         {
             throw new RuntimeException("Couldn't read from temporary stress log file");
         }
-        stats.add(json);
+        if (json.size() != 0) stats.add(json);
         return stats;
     }
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/StressProfile.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/StressProfile.java b/tools/stress/src/org/apache/cassandra/stress/StressProfile.java
index 4fb70c6..011b7d7 100644
--- a/tools/stress/src/org/apache/cassandra/stress/StressProfile.java
+++ b/tools/stress/src/org/apache/cassandra/stress/StressProfile.java
@@ -53,7 +53,7 @@ import org.apache.cassandra.stress.operations.userdefined.ValidatingSchemaQuery;
 import org.apache.cassandra.stress.report.Timer;
 import org.apache.cassandra.stress.settings.*;
 import org.apache.cassandra.stress.util.JavaDriverClient;
-import org.apache.cassandra.stress.util.MultiPrintStream;
+import org.apache.cassandra.stress.util.ResultLogger;
 import org.apache.cassandra.stress.util.ThriftClient;
 import org.apache.cassandra.thrift.Compression;
 import org.apache.cassandra.thrift.ThriftConversion;
@@ -99,7 +99,7 @@ public class StressProfile implements Serializable
     private static final Pattern lowercaseAlphanumeric = Pattern.compile("[a-z0-9_]+");
 
 
-    public void printSettings(MultiPrintStream out, StressSettings stressSettings)
+    public void printSettings(ResultLogger out, StressSettings stressSettings)
     {
         out.printf("  Keyspace Name: %s%n", keyspaceName);
         out.printf("  Keyspace CQL: %n***%n%s***%n%n", keyspaceCql);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/StressServer.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/StressServer.java b/tools/stress/src/org/apache/cassandra/stress/StressServer.java
index a6dfaf4..793f8f0 100644
--- a/tools/stress/src/org/apache/cassandra/stress/StressServer.java
+++ b/tools/stress/src/org/apache/cassandra/stress/StressServer.java
@@ -27,6 +27,8 @@ import java.net.Socket;
 import org.apache.commons.cli.*;
 
 import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.MultiResultLogger;
+import org.apache.cassandra.stress.util.ResultLogger;
 
 public class StressServer
 {
@@ -88,8 +90,9 @@ public class StressServer
             {
                 ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
                 PrintStream out = new PrintStream(socket.getOutputStream());
+                ResultLogger log = new MultiResultLogger(out);
 
-                StressAction action = new StressAction((StressSettings) in.readObject(), out);
+                StressAction action = new StressAction((StressSettings) in.readObject(), log);
                 Thread actionThread = new Thread(action);
                 actionThread.start();
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/report/StressMetrics.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/report/StressMetrics.java b/tools/stress/src/org/apache/cassandra/stress/report/StressMetrics.java
index a596547..52e90e2 100644
--- a/tools/stress/src/org/apache/cassandra/stress/report/StressMetrics.java
+++ b/tools/stress/src/org/apache/cassandra/stress/report/StressMetrics.java
@@ -24,7 +24,6 @@ package org.apache.cassandra.stress.report;
 import static java.util.concurrent.TimeUnit.NANOSECONDS;
 
 import java.io.FileNotFoundException;
-import java.io.PrintStream;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -46,6 +45,7 @@ import org.apache.cassandra.stress.StressAction.OpMeasurement;
 import org.apache.cassandra.stress.settings.SettingsLog.Level;
 import org.apache.cassandra.stress.settings.StressSettings;
 import org.apache.cassandra.stress.util.JmxCollector;
+import org.apache.cassandra.stress.util.ResultLogger;
 import org.apache.cassandra.stress.util.JmxCollector.GcStats;
 import org.apache.cassandra.stress.util.Uncertainty;
 import org.apache.cassandra.utils.FBUtilities;
@@ -54,7 +54,7 @@ import org.apache.commons.lang3.time.DurationFormatUtils;
 public class StressMetrics implements MeasurementSink
 {
     private final List<Consumer> consumers = new ArrayList<>();
-    private final PrintStream output;
+    private final ResultLogger output;
     private final Thread thread;
     private final Uncertainty rowRateUncertainty = new Uncertainty();
     private final CountDownLatch stopped = new CountDownLatch(1);
@@ -76,7 +76,7 @@ public class StressMetrics implements MeasurementSink
     private final TimingInterval totalCurrentInterval;
     private final TimingInterval totalSummaryInterval;
 
-    public StressMetrics(PrintStream output, final long logIntervalMillis, StressSettings settings)
+    public StressMetrics(ResultLogger output, final long logIntervalMillis, StressSettings settings)
     {
         this.output = output;
         if(settings.log.hdrFile != null)
@@ -114,13 +114,7 @@ public class StressMetrics implements MeasurementSink
                 t.printStackTrace();
             }
             System.err.println("Failed to connect over JMX; not collecting these stats");
-            gcStatsCollector = new Callable<JmxCollector.GcStats>()
-            {
-                public JmxCollector.GcStats call() throws Exception
-                {
-                    return totalGcStats;
-                }
-            };
+            gcStatsCollector = () -> totalGcStats;
         }
         this.gcStatsCollector = gcStatsCollector;
         this.totalCurrentInterval = new TimingInterval(settings.rate.isFixed);
@@ -226,7 +220,7 @@ public class StressMetrics implements MeasurementSink
         t.serviceTime().recordValue(sTime);
     }
 
-    private void recordInterval(long intervalEnd, long parkIntervalNs) throws InterruptedException
+    private void recordInterval(long intervalEnd, long parkIntervalNs)
     {
 
         drainConsumerMeasurements(intervalEnd, parkIntervalNs);
@@ -351,12 +345,13 @@ public class StressMetrics implements MeasurementSink
     public static final String[] HEADMETRICS = new String[]{"type", "total ops","op/s","pk/s","row/s","mean","med",".95",".99",".999","max","time","stderr", "errors", "gc: #", "max ms", "sum ms", "sdv ms", "mb"};
     public static final String HEAD = String.format(HEADFORMAT, (Object[]) HEADMETRICS);
 
-    private static void printHeader(String prefix, PrintStream output)
+    private static void printHeader(String prefix, ResultLogger output)
     {
         output.println(prefix + HEAD);
     }
 
-    private static void printRow(String prefix, String type, TimingInterval interval, TimingInterval total, JmxCollector.GcStats gcStats, Uncertainty opRateUncertainty, PrintStream output)
+    private static void printRow(String prefix, String type, TimingInterval interval, TimingInterval total,
+                                 JmxCollector.GcStats gcStats, Uncertainty opRateUncertainty, ResultLogger output)
     {
         output.println(prefix + String.format(ROWFORMAT,
                 type + ",",
@@ -409,7 +404,7 @@ public class StressMetrics implements MeasurementSink
         output.println(""); // Newline is important here to separate the aggregates section from the END or the next stress iteration
     }
 
-    public static void summarise(List<String> ids, List<StressMetrics> summarise, PrintStream out)
+    public static void summarise(List<String> ids, List<StressMetrics> summarise, ResultLogger out)
     {
         int idLen = 0;
         for (String id : ids)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java
index d39e11b..79d8d25 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java
@@ -33,7 +33,7 @@ import org.apache.cassandra.db.marshal.*;
 import org.apache.cassandra.stress.generate.Distribution;
 import org.apache.cassandra.stress.generate.DistributionFactory;
 import org.apache.cassandra.stress.generate.DistributionFixed;
-import org.apache.cassandra.stress.util.MultiPrintStream;
+import org.apache.cassandra.stress.util.ResultLogger;
 import org.apache.cassandra.utils.ByteBufferUtil;
 
 /**
@@ -178,7 +178,7 @@ public class SettingsColumn implements Serializable
     }
 
     // CLI Utility Methods
-    public void printSettings(MultiPrintStream out)
+    public void printSettings(ResultLogger out)
     {
         out.printf("  Max Columns Per Key: %d%n",maxColumnsPerKey);
         out.printf("  Column Names: %s%n",namestrs);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommand.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommand.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommand.java
index f1f6831..c3a171e 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommand.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommand.java
@@ -31,7 +31,7 @@ import com.google.common.util.concurrent.Uninterruptibles;
 
 import org.apache.cassandra.stress.operations.OpDistributionFactory;
 import org.apache.cassandra.stress.util.JavaDriverClient;
-import org.apache.cassandra.stress.util.MultiPrintStream;
+import org.apache.cassandra.stress.util.ResultLogger;
 import org.apache.cassandra.thrift.ConsistencyLevel;
 
 // Generic command settings - common to read/write/etc
@@ -173,7 +173,7 @@ public abstract class SettingsCommand implements Serializable
 
     // CLI Utility Methods
 
-    public void printSettings(MultiPrintStream out)
+    public void printSettings(ResultLogger out)
     {
         out.printf("  Type: %s%n", type.toString().toLowerCase());
         out.printf("  Count: %,d%n", count);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java
index b7f87e9..8875576 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java
@@ -39,7 +39,7 @@ import org.apache.cassandra.stress.operations.OpDistribution;
 import org.apache.cassandra.stress.operations.OpDistributionFactory;
 import org.apache.cassandra.stress.operations.predefined.PredefinedOperation;
 import org.apache.cassandra.stress.report.Timer;
-import org.apache.cassandra.stress.util.MultiPrintStream;
+import org.apache.cassandra.stress.util.ResultLogger;
 
 // Settings unique to the mixed command type
 public class SettingsCommandPreDefined extends SettingsCommand
@@ -122,7 +122,7 @@ public class SettingsCommandPreDefined extends SettingsCommand
 
     // CLI utility methods
 
-    public void printSettings(MultiPrintStream out)
+    public void printSettings(ResultLogger out)
     {
         super.printSettings(out);
         out.printf("  Key Size (bytes): %d%n", keySize);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefinedMixed.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefinedMixed.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefinedMixed.java
index 9c58c5b..72f6c86 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefinedMixed.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefinedMixed.java
@@ -31,7 +31,7 @@ import org.apache.cassandra.stress.operations.OpDistributionFactory;
 import org.apache.cassandra.stress.operations.SampledOpDistributionFactory;
 import org.apache.cassandra.stress.operations.predefined.PredefinedOperation;
 import org.apache.cassandra.stress.report.Timer;
-import org.apache.cassandra.stress.util.MultiPrintStream;
+import org.apache.cassandra.stress.util.ResultLogger;
 
 // Settings unique to the mixed command type
 public class SettingsCommandPreDefinedMixed extends SettingsCommandPreDefined
@@ -112,7 +112,7 @@ public class SettingsCommandPreDefinedMixed extends SettingsCommandPreDefined
 
     }
 
-    public void printSettings(MultiPrintStream out)
+    public void printSettings(ResultLogger out)
     {
         super.printSettings(out);
         out.printf("  Command Ratios: %s%n", ratios);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandUser.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandUser.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandUser.java
index 66e6df3..4c7ad91 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandUser.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandUser.java
@@ -37,7 +37,7 @@ import org.apache.cassandra.stress.generate.TokenRangeIterator;
 import org.apache.cassandra.stress.operations.OpDistributionFactory;
 import org.apache.cassandra.stress.operations.SampledOpDistributionFactory;
 import org.apache.cassandra.stress.report.Timer;
-import org.apache.cassandra.stress.util.MultiPrintStream;
+import org.apache.cassandra.stress.util.ResultLogger;
 
 // Settings unique to the mixed command type
 public class SettingsCommandUser extends SettingsCommand
@@ -125,7 +125,7 @@ public class SettingsCommandUser extends SettingsCommand
 
     // CLI utility methods
 
-    public void printSettings(MultiPrintStream out)
+    public void printSettings(ResultLogger out)
     {
         super.printSettings(out);
         out.printf("  Command Ratios: %s%n", ratios);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsErrors.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsErrors.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsErrors.java
index 118312f..aae4dd9 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsErrors.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsErrors.java
@@ -26,7 +26,7 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.cassandra.stress.util.MultiPrintStream;
+import org.apache.cassandra.stress.util.ResultLogger;
 
 public class SettingsErrors implements Serializable
 {
@@ -55,7 +55,7 @@ public class SettingsErrors implements Serializable
     }
 
     // CLI Utility Methods
-    public void printSettings(MultiPrintStream out)
+    public void printSettings(ResultLogger out)
     {
         out.printf("  Ignore: %b%n", ignore);
         out.printf("  Tries: %d%n", tries);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsGraph.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsGraph.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsGraph.java
index 7b3491b..90bb99a 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsGraph.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsGraph.java
@@ -30,7 +30,7 @@ import java.util.Date;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.cassandra.stress.util.MultiPrintStream;
+import org.apache.cassandra.stress.util.ResultLogger;
 
 public class SettingsGraph implements Serializable
 {
@@ -90,7 +90,7 @@ public class SettingsGraph implements Serializable
     }
 
     // CLI Utility Methods
-    public void printSettings(MultiPrintStream out)
+    public void printSettings(ResultLogger out)
     {
         out.println("  File: " + file);
         out.println("  Revision: " + revision);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsInsert.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsInsert.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsInsert.java
index d6927ec..59edf77 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsInsert.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsInsert.java
@@ -29,7 +29,7 @@ import java.util.Map;
 import com.datastax.driver.core.BatchStatement;
 import org.apache.cassandra.stress.generate.DistributionFactory;
 import org.apache.cassandra.stress.generate.RatioDistributionFactory;
-import org.apache.cassandra.stress.util.MultiPrintStream;
+import org.apache.cassandra.stress.util.ResultLogger;
 
 public class SettingsInsert implements Serializable
 {
@@ -73,7 +73,7 @@ public class SettingsInsert implements Serializable
     }
 
     // CLI Utility Methods
-    public void printSettings(MultiPrintStream out)
+    public void printSettings(ResultLogger out)
     {
 
         if (revisit != null)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsLog.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsLog.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsLog.java
index dcc220f..ae77e0a 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsLog.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsLog.java
@@ -21,13 +21,14 @@ package org.apache.cassandra.stress.settings;
  */
 
 
-import org.apache.cassandra.stress.util.MultiPrintStream;
-
 import java.io.*;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.cassandra.stress.util.MultiResultLogger;
+import org.apache.cassandra.stress.util.ResultLogger;
+
 public class SettingsLog implements Serializable
 {
     public static enum Level
@@ -68,10 +69,10 @@ public class SettingsLog implements Serializable
         level = Level.valueOf(options.level.value().toUpperCase());
     }
 
-    public MultiPrintStream getOutput() throws FileNotFoundException
+    public MultiResultLogger getOutput() throws FileNotFoundException
     {
         // Always print to stdout regardless of whether we're graphing or not
-        MultiPrintStream stream = new MultiPrintStream(new PrintStream(System.out));
+        MultiResultLogger stream = new MultiResultLogger(new PrintStream(System.out));
 
         if (file != null)
             stream.addStream(new PrintStream(file));
@@ -98,7 +99,7 @@ public class SettingsLog implements Serializable
     }
 
     // CLI Utility Methods
-    public void printSettings(MultiPrintStream out)
+    public void printSettings(ResultLogger out)
     {
         out.printf("  No Summary: %b%n", noSummary);
         out.printf("  No Settings: %b%n", noSettings);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java
index 127b938..bebfa5f 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java
@@ -30,7 +30,7 @@ import com.datastax.driver.core.AuthProvider;
 import com.datastax.driver.core.PlainTextAuthProvider;
 import com.datastax.driver.core.ProtocolOptions;
 import com.datastax.driver.core.ProtocolVersion;
-import org.apache.cassandra.stress.util.MultiPrintStream;
+import org.apache.cassandra.stress.util.ResultLogger;
 
 public class SettingsMode implements Serializable
 {
@@ -207,7 +207,7 @@ public class SettingsMode implements Serializable
     }
 
     // CLI Utility Methods
-    public void printSettings(MultiPrintStream out)
+    public void printSettings(ResultLogger out)
     {
         out.printf("  API: %s%n", api);
         out.printf("  Connection Style: %s%n", style);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsNode.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsNode.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsNode.java
index 1a6a243..95339e3 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsNode.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsNode.java
@@ -28,7 +28,7 @@ import java.net.UnknownHostException;
 import java.util.*;
 
 import com.datastax.driver.core.Host;
-import org.apache.cassandra.stress.util.MultiPrintStream;
+import org.apache.cassandra.stress.util.ResultLogger;
 
 public class SettingsNode implements Serializable
 {
@@ -149,7 +149,7 @@ public class SettingsNode implements Serializable
     }
 
     // CLI Utility Methods
-    public void printSettings(MultiPrintStream out)
+    public void printSettings(ResultLogger out)
     {
         out.println("  Nodes: " + nodes);
         out.println("  Is White List: " + isWhiteList);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsPopulation.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsPopulation.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsPopulation.java
index 0d7b056..66984ed 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsPopulation.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsPopulation.java
@@ -30,7 +30,7 @@ import com.google.common.collect.ImmutableList;
 
 import org.apache.cassandra.stress.generate.DistributionFactory;
 import org.apache.cassandra.stress.generate.PartitionGenerator;
-import org.apache.cassandra.stress.util.MultiPrintStream;
+import org.apache.cassandra.stress.util.ResultLogger;
 
 public class SettingsPopulation implements Serializable
 {
@@ -127,7 +127,7 @@ public class SettingsPopulation implements Serializable
 
     // CLI Utility Methods
 
-    public void printSettings(MultiPrintStream out)
+    public void printSettings(ResultLogger out)
     {
         if (distribution != null)
         {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsPort.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsPort.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsPort.java
index 39259a8..e6d3838 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsPort.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsPort.java
@@ -26,7 +26,7 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.cassandra.stress.util.MultiPrintStream;
+import org.apache.cassandra.stress.util.ResultLogger;
 
 public class SettingsPort implements Serializable
 {
@@ -58,7 +58,7 @@ public class SettingsPort implements Serializable
     }
 
     // CLI Utility Methods
-    public void printSettings(MultiPrintStream out)
+    public void printSettings(ResultLogger out)
     {
         out.printf("  Native Port: %d%n", nativePort);
         out.printf("  Thrift Port: %d%n", thriftPort);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsRate.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsRate.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsRate.java
index 211a301..c7d322a 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsRate.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsRate.java
@@ -26,7 +26,7 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.cassandra.stress.util.MultiPrintStream;
+import org.apache.cassandra.stress.util.ResultLogger;
 
 public class SettingsRate implements Serializable
 {
@@ -96,7 +96,7 @@ public class SettingsRate implements Serializable
 
     // CLI Utility Methods
 
-    public void printSettings(MultiPrintStream out)
+    public void printSettings(ResultLogger out)
     {
         out.printf("  Auto: %b%n", auto);
         if (auto)
@@ -151,14 +151,7 @@ public class SettingsRate implements Serializable
 
     public static Runnable helpPrinter()
     {
-        return new Runnable()
-        {
-            @Override
-            public void run()
-            {
-                printHelp();
-            }
-        };
+        return SettingsRate::printHelp;
     }
 }
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSchema.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSchema.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSchema.java
index 4c5c99e..fc65c9a 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSchema.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSchema.java
@@ -27,7 +27,7 @@ import java.util.*;
 
 import com.datastax.driver.core.exceptions.AlreadyExistsException;
 import org.apache.cassandra.stress.util.JavaDriverClient;
-import org.apache.cassandra.stress.util.MultiPrintStream;
+import org.apache.cassandra.stress.util.ResultLogger;
 import org.apache.cassandra.thrift.*;
 import org.apache.cassandra.utils.ByteBufferUtil;
 
@@ -300,7 +300,7 @@ public class SettingsSchema implements Serializable
     }
 
     // CLI Utility Methods
-    public void printSettings(MultiPrintStream out)
+    public void printSettings(ResultLogger out)
     {
         out.println("  Keyspace: " + keyspace);
         out.println("  Replication Strategy: " + replicationStrategy);
@@ -309,7 +309,6 @@ public class SettingsSchema implements Serializable
         out.println("  Table Compression: " + compression);
         out.println("  Table Compaction Strategy: " + compactionStrategy);
         out.println("  Table Compaction Strategy Options: " + compactionStrategyOptions);
-
     }
 
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTokenRange.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTokenRange.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTokenRange.java
index 648823b..d8b6701 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTokenRange.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTokenRange.java
@@ -25,7 +25,7 @@ import java.util.Map;
 import com.google.common.collect.ImmutableList;
 import com.google.common.primitives.Ints;
 
-import org.apache.cassandra.stress.util.MultiPrintStream;
+import org.apache.cassandra.stress.util.ResultLogger;
 
 public class SettingsTokenRange implements Serializable
 {
@@ -70,7 +70,7 @@ public class SettingsTokenRange implements Serializable
         return new SettingsTokenRange(options);
     }
 
-    public void printSettings(MultiPrintStream out)
+    public void printSettings(ResultLogger out)
     {
         out.printf("  Wrap: %b%n", wrap);
         out.printf("  Split Factor: %d%n", splitFactor);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java
index e12b645..75b29b3 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java
@@ -28,7 +28,7 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.cassandra.config.EncryptionOptions;
-import org.apache.cassandra.stress.util.MultiPrintStream;
+import org.apache.cassandra.stress.util.ResultLogger;
 import org.apache.cassandra.thrift.ITransportFactory;
 import org.apache.cassandra.thrift.SSLTransportFactory;
 import org.apache.cassandra.thrift.TFramedTransportFactory;
@@ -146,7 +146,7 @@ public class SettingsTransport implements Serializable
     }
 
     // CLI Utility Methods
-    public void printSettings(MultiPrintStream out)
+    public void printSettings(ResultLogger out)
     {
         out.println("  " + options.getOptionAsString());
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java b/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
index 8f5e69a..136c8d0 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
@@ -22,13 +22,13 @@ package org.apache.cassandra.stress.settings;
 
 
 import java.io.Serializable;
-import org.apache.cassandra.stress.util.MultiPrintStream;
 import java.util.*;
 
 import com.datastax.driver.core.Metadata;
 import com.google.common.collect.ImmutableMap;
 import org.apache.cassandra.config.EncryptionOptions;
 import org.apache.cassandra.stress.util.JavaDriverClient;
+import org.apache.cassandra.stress.util.ResultLogger;
 import org.apache.cassandra.stress.util.SimpleThriftClient;
 import org.apache.cassandra.stress.util.SmartThriftClient;
 import org.apache.cassandra.stress.util.ThriftClient;
@@ -338,7 +338,7 @@ public class StressSettings implements Serializable
         SettingsMisc.printHelp();
     }
 
-    public void printSettings(MultiPrintStream out)
+    public void printSettings(ResultLogger out)
     {
         out.println("******************** Stress Settings ********************");
         // done

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/util/MultiPrintStream.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/util/MultiPrintStream.java b/tools/stress/src/org/apache/cassandra/stress/util/MultiPrintStream.java
deleted file mode 100644
index d299013..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/util/MultiPrintStream.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.cassandra.stress.util;
-
-import java.io.*;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-
-/** PrintStream that multiplexes to multiple streams */
-public class MultiPrintStream extends PrintStream
-{
-    private List<PrintStream> newStreams;
-
-    public MultiPrintStream(PrintStream baseStream)
-    {
-        super(baseStream);
-        this.newStreams = new ArrayList();
-    }
-
-    public void addStream(PrintStream printStream)
-    {
-        newStreams.add(printStream);
-    }
-
-    @Override
-    public void flush()
-    {
-        super.flush();
-        for (PrintStream s : newStreams)
-            s.flush();
-    }
-
-    @Override
-    public void close()
-    {
-        super.close();
-        for (PrintStream s : newStreams)
-            s.close();
-    }
-
-    @Override
-    public boolean checkError()
-    {
-        boolean error = super.checkError();
-        for (PrintStream s : newStreams)
-        {
-            if (s.checkError())
-                error = true;
-        }
-        return error;
-    }
-
-    @Override
-    public void write(int b)
-    {
-        super.write(b);
-        for (PrintStream s: newStreams)
-            s.write(b);
-    }
-
-    @Override
-    public void write(byte[] buf, int off, int len)
-    {
-        super.write(buf, off, len);
-        for (PrintStream s: newStreams)
-            s.write(buf, off, len);
-    }
-
-    @Override
-    public void print(boolean b)
-    {
-        super.print(b);
-        for (PrintStream s: newStreams)
-            s.print(b);
-    }
-
-    @Override
-    public void print(char c)
-    {
-        super.print(c);
-        for (PrintStream s: newStreams)
-            s.print(c);
-    }
-
-    @Override
-    public void print(int i)
-    {
-        super.print(i);
-        for (PrintStream s: newStreams)
-            s.print(i);
-    }
-
-    @Override
-    public void print(long l)
-    {
-        super.print(l);
-        for (PrintStream s: newStreams)
-            s.print(l);
-    }
-
-    @Override
-    public void print(float f)
-    {
-        super.print(f);
-        for (PrintStream s: newStreams)
-            s.print(f);
-    }
-
-    @Override
-    public void print(double d)
-    {
-        super.print(d);
-        for (PrintStream s: newStreams)
-            s.print(d);
-    }
-
-    @Override
-    public void print(char[] s)
-    {
-        super.print(s);
-        for (PrintStream stream: newStreams)
-            stream.print(s);
-    }
-
-    @Override
-    public void print(String s)
-    {
-        super.print(s);
-        for (PrintStream stream: newStreams)
-            stream.print(s);
-    }
-
-    @Override
-    public void print(Object obj)
-    {
-        super.print(obj);
-        for (PrintStream s: newStreams)
-            s.print(obj);
-    }
-
-    @Override
-    public void println()
-    {
-        super.println();
-        for (PrintStream s: newStreams)
-            s.println();
-    }
-
-    @Override
-    public void println(boolean x)
-    {
-        super.println(x);
-        for (PrintStream s: newStreams)
-            s.println(x);
-    }
-
-    @Override
-    public void println(char x)
-    {
-        super.println(x);
-        for (PrintStream s: newStreams)
-            s.println(x);
-    }
-
-    @Override
-    public void println(int x)
-    {
-        super.println(x);
-        for (PrintStream s: newStreams)
-            s.println(x);
-    }
-
-    @Override
-    public void println(long x)
-    {
-        super.println(x);
-        for (PrintStream s: newStreams)
-            s.println(x);
-    }
-
-    @Override
-    public void println(float x)
-    {
-        super.println(x);
-        for (PrintStream s: newStreams)
-            s.println(x);
-    }
-
-    @Override
-    public void println(double x)
-    {
-        super.println(x);
-        for (PrintStream s: newStreams)
-            s.println(x);
-    }
-
-    @Override
-    public void println(char[] x)
-    {
-        super.println(x);
-        for (PrintStream s: newStreams)
-            s.println(x);
-    }
-
-    @Override
-    public void println(String x)
-    {
-        super.println(x);
-        for (PrintStream s: newStreams)
-            s.println(x);
-    }
-
-    @Override
-    public void println(Object x)
-    {
-        super.println(x);
-        for (PrintStream s: newStreams)
-            s.println(x);
-    }
-
-    @Override
-    public PrintStream printf(String format, Object... args)
-    {
-        for (PrintStream s: newStreams)
-            s.printf(format, args);
-        return super.printf(format, args);
-    }
-
-    @Override
-    public PrintStream printf(Locale l, String format, Object... args)
-    {
-        for (PrintStream s: newStreams)
-            s.printf(l, format, args);
-        return super.printf(l, format, args);
-    }
-
-    @Override
-    public PrintStream append(CharSequence csq)
-    {
-        for (PrintStream s: newStreams)
-            s.append(csq);
-        return super.append(csq);
-    }
-
-    @Override
-    public PrintStream append(CharSequence csq, int start, int end)
-    {
-        for (PrintStream s: newStreams)
-            s.append(csq, start, end);
-        return super.append(csq, start, end);
-    }
-
-    @Override
-    public PrintStream append(char c)
-    {
-        for (PrintStream s: newStreams)
-            s.append(c);
-        return super.append(c);
-    }
-
-    @Override
-    public void write(byte[] b) throws IOException
-    {
-        super.write(b);
-        for (PrintStream s: newStreams)
-            s.write(b);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/util/MultiResultLogger.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/util/MultiResultLogger.java b/tools/stress/src/org/apache/cassandra/stress/util/MultiResultLogger.java
new file mode 100644
index 0000000..3d2103c
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/util/MultiResultLogger.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.stress.util;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+
+public class MultiResultLogger implements ResultLogger
+{
+    private final List<PrintStream> streams = new ArrayList<>();
+
+    public MultiResultLogger(PrintStream printStream)
+    {
+        streams.add(printStream);
+    }
+
+    public void println(String line)
+    {
+        for (PrintStream stream : streams)
+        {
+            stream.println(line);
+        }
+    }
+
+    public void println()
+    {
+        for (PrintStream stream : streams)
+        {
+            stream.println();
+        }
+    }
+
+    public void printException(Exception e)
+    {
+        for (PrintStream stream : streams)
+        {
+            e.printStackTrace(stream);
+        }
+    }
+
+    public void flush()
+    {
+        for (PrintStream stream : streams)
+        {
+            stream.flush();
+        }
+    }
+
+    public void printf(String s, Object... args)
+    {
+        for (PrintStream stream : streams)
+        {
+            stream.printf(s, args);
+        }
+    }
+
+    public void addStream(PrintStream additionalPrintStream)
+    {
+        streams.add(additionalPrintStream);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/util/NoopResultLogger.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/util/NoopResultLogger.java b/tools/stress/src/org/apache/cassandra/stress/util/NoopResultLogger.java
new file mode 100644
index 0000000..f1b2d8c
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/util/NoopResultLogger.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.stress.util;
+
+public class NoopResultLogger implements ResultLogger
+{
+    NoopResultLogger() { }
+
+    public void println(String line)
+    {
+    }
+
+    public void println()
+    {
+    }
+
+    public void printException(Exception e)
+    {
+    }
+
+    public void flush()
+    {
+    }
+
+    public void printf(String s, Object... args)
+    {
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/org/apache/cassandra/stress/util/ResultLogger.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/util/ResultLogger.java b/tools/stress/src/org/apache/cassandra/stress/util/ResultLogger.java
new file mode 100644
index 0000000..4097417
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/util/ResultLogger.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.stress.util;
+
+public interface ResultLogger
+{
+    static final ResultLogger NOOP = new NoopResultLogger();
+
+    void println(String line);
+    void println();
+    void printException(Exception e);
+    void flush();
+    void printf(String s, Object... args);
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/src/resources/org/apache/cassandra/stress/graph/graph.html
----------------------------------------------------------------------
diff --git a/tools/stress/src/resources/org/apache/cassandra/stress/graph/graph.html b/tools/stress/src/resources/org/apache/cassandra/stress/graph/graph.html
index 54cd469..86bedfc 100644
--- a/tools/stress/src/resources/org/apache/cassandra/stress/graph/graph.html
+++ b/tools/stress/src/resources/org/apache/cassandra/stress/graph/graph.html
@@ -89,7 +89,6 @@ var drawGraph = function() {
         stress_metric_names[v] = stats['stats'][0]['metrics'][i];
     });
     //Replace names of shorthand metric names with longer ones:
-    //Replace names of shorthand metric names with longer ones:
     $.extend(stress_metric_names, {
        "mean": "latency mean",
        "med" : "latency median",
@@ -224,7 +223,7 @@ var drawGraph = function() {
                 if (metric == 'num_timeouts') {
                     return d[stress_metrics.indexOf('interval_op_rate')] - d[stress_metrics.indexOf('interval_key_rate')];
                 }
-            }        
+            }
         };
 
         //Parse the dates:
@@ -321,13 +320,13 @@ var drawGraph = function() {
 
         var line = d3.svg.line()
             .interpolate("basis")
-            .x(function(d) { 
+            .x(function(d) {
                 return x(d[time_index]); //time in seconds
             })
-            .y(function(d) { 
+            .y(function(d) {
                 return y(getMetricValue(d));
             });
-        
+
         $("body").append("<div id='svg_container'>");
 
         var redrawLines = function() {
@@ -384,7 +383,7 @@ var drawGraph = function() {
             .attr("transform", "translate(0," + height + ")")
             .call(xAxis);
 
-        // x-axis label   
+        // x-axis label
         svg.append("text")
             .attr("x", width / 2 )
             .attr("y", height + 30 )
@@ -432,7 +431,7 @@ var drawGraph = function() {
                     var y_offset = 425 + (i*25) + 70;
                 }
                 var x_offset = -550;
-                return "translate(" + x_offset + "," + y_offset + ")"; 
+                return "translate(" + x_offset + "," + y_offset + ")";
             });
 
         var renderLegendText = function(linenum, getTextCallback) {
@@ -443,7 +442,7 @@ var drawGraph = function() {
                 .style("font-family", "monospace")
                 .style("font-size", "1.2em")
                 .style("text-anchor", "start")
-                .text(function(d) { 
+                .text(function(d) {
                     return getTextCallback(d);
                 });
         };
@@ -511,23 +510,23 @@ var drawGraph = function() {
             });
 
             renderLegendText(13, function(title) {
-                return padTextEnd('total gc mb', 26) + ' : ' + data_by_title[title]['total gc mb'];
+                return padTextEnd('total gc memory', 26) + ' : ' + data_by_title[title]['total gc memory'];
             });
 
             renderLegendText(14, function(title) {
-                return padTextEnd('total gc time (s)', 26) + ' : ' + data_by_title[title]['total gc time (s)'];
+                return padTextEnd('total gc time', 26) + ' : ' + data_by_title[title]['total gc time'];
             });
 
             renderLegendText(15, function(title) {
-                return padTextEnd('avg gc time(ms)', 26) + ' : ' + data_by_title[title]['avg gc time(ms)'];
+                return padTextEnd('avg gc time', 26) + ' : ' + data_by_title[title]['avg gc time'];
             });
 
             renderLegendText(16, function(title) {
-                return padTextEnd('stdev gc time(ms)', 26) + ' : ' + data_by_title[title]['stdev gc time(ms)'];
+                return padTextEnd('stddev gc time', 26) + ' : ' + data_by_title[title]['stddev gc time'];
             });
 
             renderLegendText(17, function(title) {
-                return padTextEnd('Total operation time', 26) + ' : ' + data_by_title[title]['Total operation time'];
+                return padTextEnd('Total operation time', 26) + ' : ' + data_by_title[title]['total operation time'];
             });
 
             renderLegendText(18, function(title) {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f42e235b/tools/stress/test/unit/org/apache/cassandra/stress/util/MultiResultLoggerTest.java
----------------------------------------------------------------------
diff --git a/tools/stress/test/unit/org/apache/cassandra/stress/util/MultiResultLoggerTest.java b/tools/stress/test/unit/org/apache/cassandra/stress/util/MultiResultLoggerTest.java
new file mode 100644
index 0000000..f0c99b8
--- /dev/null
+++ b/tools/stress/test/unit/org/apache/cassandra/stress/util/MultiResultLoggerTest.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.stress.util;
+
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class MultiResultLoggerTest
+{
+
+    public static final OutputStream NOOP = new OutputStream()
+    {
+        public void write(int b) throws IOException
+        {
+        }
+    };
+
+    @Test
+    public void delegatesToInitialPrintStream() throws Exception
+    {
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
+        PrintStream printStream = new PrintStream(output, true);
+        MultiResultLogger underTest = new MultiResultLogger(printStream);
+
+        underTest.println("Very important result");
+
+        assertEquals("Very important result\n", output.toString());
+    }
+
+    @Test
+    public void printingExceptions() throws Exception
+    {
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
+        PrintStream printStream = new PrintStream(output, true);
+        MultiResultLogger underTest = new MultiResultLogger(printStream);
+
+        underTest.printException(new RuntimeException("Bad things"));
+
+        String stackTrace = output.toString();
+        assertTrue("Expected strack trace to be printed but got: " + stackTrace, stackTrace.startsWith("java.lang.RuntimeException: Bad things\n" +
+                                                "\tat org.apache.cassandra.stress.util.MultiResultLoggerTest.printingExceptions"));
+    }
+
+    @Test
+    public void delegatesToAdditionalPrintStreams() throws Exception
+    {
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
+        PrintStream additionalPrintStream = new PrintStream(output, true);
+        MultiResultLogger underTest = new MultiResultLogger(new PrintStream(NOOP));
+
+        underTest.addStream(additionalPrintStream);
+        underTest.println("Very important result");
+
+        assertEquals("Very important result\n", output.toString());
+    }
+
+    @Test
+    public void delegatesPrintfToAdditionalPrintStreams() throws Exception
+    {
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
+        PrintStream additionalPrintStream = new PrintStream(output, true);
+        MultiResultLogger underTest = new MultiResultLogger(new PrintStream(NOOP));
+
+        underTest.addStream(additionalPrintStream);
+        underTest.printf("%s %s %s", "one", "two", "three");
+
+        assertEquals("one two three", output.toString());
+    }
+
+    @Test
+    public void delegatesPrintlnToAdditionalPrintStreams() throws Exception
+    {
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
+        PrintStream additionalPrintStream = new PrintStream(output, true);
+        MultiResultLogger underTest = new MultiResultLogger(new PrintStream(NOOP));
+
+        underTest.addStream(additionalPrintStream);
+        underTest.println();
+
+        assertEquals("\n", output.toString());
+    }
+}
\ No newline at end of file