From 1a870c408527aa0a890ab52a50d018f2dbc704c6 Mon Sep 17 00:00:00 2001
From: Reiner Jung <reiner.jung@email.uni-kiel.de>
Date: Fri, 2 Sep 2022 10:57:09 +0200
Subject: [PATCH] Refactored and cleanup of the compile-results tool. Also
 improved file-names.

---
 .../tools/results/ChartAssemblerStage.java    |  57 --------
 .../tools/results/CompileResultsMain.java     |  88 +++++++-----
 .../java/moobench/tools/results/FileSink.java |  22 ---
 .../moobench/tools/results/JsonChartSink.java |  44 ++++++
 .../moobench/tools/results/JsonLogSink.java   |  44 ------
 .../moobench/tools/results/OrderedSet.java    |  16 +++
 .../java/moobench/tools/results/Settings.java |  85 ++++++-----
 .../tools/results/TailChartStage.java         |  40 ------
 .../tools/results/TeetimeConfiguration.java   |  28 +++-
 .../moobench/tools/results/YamlLogSink.java   |  67 ---------
 .../tools/results/data/Experiment.java        |  65 +++++----
 .../tools/results/data/ExperimentLog.java     |  54 ++++---
 .../tools/results/data/Measurements.java      | 132 ++++++++++--------
 .../tools/results/data/OutputFile.java        |  22 +++
 .../tools/results/data/TableInformation.java  |  16 +++
 .../results/stages/ChartAssemblerStage.java   |  71 ++++++++++
 .../{ => stages}/ComputeTableStage.java       |  23 ++-
 .../results/{ => stages}/ElementProducer.java |   2 +-
 .../tools/results/stages/FileSink.java        |  38 +++++
 .../{ => stages}/GenerateHtmlTableStage.java  |  15 +-
 .../{ => stages}/LogAppenderStage.java        |   2 +-
 .../tools/results/stages/TailChartStage.java  |  52 +++++++
 .../tools/results/stages/YamlLogSink.java     |  83 +++++++++++
 .../results/{ => stages}/YamlReaderStage.java |   2 +-
 upload.sh                                     |  10 +-
 25 files changed, 655 insertions(+), 423 deletions(-)
 delete mode 100644 tools/compile-results/src/main/java/moobench/tools/results/ChartAssemblerStage.java
 delete mode 100644 tools/compile-results/src/main/java/moobench/tools/results/FileSink.java
 create mode 100644 tools/compile-results/src/main/java/moobench/tools/results/JsonChartSink.java
 delete mode 100644 tools/compile-results/src/main/java/moobench/tools/results/JsonLogSink.java
 delete mode 100644 tools/compile-results/src/main/java/moobench/tools/results/TailChartStage.java
 delete mode 100644 tools/compile-results/src/main/java/moobench/tools/results/YamlLogSink.java
 create mode 100644 tools/compile-results/src/main/java/moobench/tools/results/stages/ChartAssemblerStage.java
 rename tools/compile-results/src/main/java/moobench/tools/results/{ => stages}/ComputeTableStage.java (76%)
 rename tools/compile-results/src/main/java/moobench/tools/results/{ => stages}/ElementProducer.java (93%)
 create mode 100644 tools/compile-results/src/main/java/moobench/tools/results/stages/FileSink.java
 rename tools/compile-results/src/main/java/moobench/tools/results/{ => stages}/GenerateHtmlTableStage.java (81%)
 rename tools/compile-results/src/main/java/moobench/tools/results/{ => stages}/LogAppenderStage.java (96%)
 create mode 100644 tools/compile-results/src/main/java/moobench/tools/results/stages/TailChartStage.java
 create mode 100644 tools/compile-results/src/main/java/moobench/tools/results/stages/YamlLogSink.java
 rename tools/compile-results/src/main/java/moobench/tools/results/{ => stages}/YamlReaderStage.java (94%)

diff --git a/tools/compile-results/src/main/java/moobench/tools/results/ChartAssemblerStage.java b/tools/compile-results/src/main/java/moobench/tools/results/ChartAssemblerStage.java
deleted file mode 100644
index 66a525b..0000000
--- a/tools/compile-results/src/main/java/moobench/tools/results/ChartAssemblerStage.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * 
- */
-package moobench.tools.results;
-
-import java.util.List;
-import java.util.Map;
-
-import moobench.tools.results.data.Chart;
-import moobench.tools.results.data.Experiment;
-import moobench.tools.results.data.ExperimentLog;
-import moobench.tools.results.data.Measurements;
-import moobench.tools.results.data.ValueTuple;
-import teetime.stage.basic.AbstractTransformation;
-
-/**
- * @author Reiner Jung
- * @since 1.3.0
- *
- */
-public class ChartAssemblerStage extends AbstractTransformation<ExperimentLog, Chart> {
-
-	@Override
-	protected void execute(ExperimentLog element) throws Exception {
-		Chart chart = new Chart(element.getKind());
-		for (Experiment experiment : element.getExperiments()) {
-			long timestamp = Double.valueOf(experiment.getTimestamp()).longValue();
-			ValueTuple tuple = new ValueTuple(timestamp);
-			
-			addHeaderIfMissing(chart.getHeaders(), experiment.getMeasurements());
-			fillInData(chart.getHeaders(), tuple.getValues(), experiment.getMeasurements());
-			
-			chart.getValues().add(tuple);
-		}
-		
-		this.outputPort.send(chart);
-	}
-
-	private void fillInData(List<String> headers, List<Double> values, Map<String, Measurements> measurements) {
-		for (String key : headers) {
-			Measurements value = measurements.get(key);
-			if (value != null) {
-				values.add(value.getMean());
-			} else
-				values.add(Double.NaN);
-		}
-	}
-
-	private void addHeaderIfMissing(List<String> headers, Map<String, Measurements> measurements) {
-		for (String key : measurements.keySet()) {
-			if (!headers.stream().anyMatch(header -> header.equals(key))) {
-				headers.add(key);
-			}
-		}		
-	}
-
-}
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/CompileResultsMain.java b/tools/compile-results/src/main/java/moobench/tools/results/CompileResultsMain.java
index 9dd450d..c87e408 100644
--- a/tools/compile-results/src/main/java/moobench/tools/results/CompileResultsMain.java
+++ b/tools/compile-results/src/main/java/moobench/tools/results/CompileResultsMain.java
@@ -1,9 +1,23 @@
-/**
- * 
- */
+/***************************************************************************
+ * Copyright (C) 2022 Kieker (https://kieker-monitoring.net)
+
+ *
+ * Licensed 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 moobench.tools.results;
 
 import java.io.File;
+import java.nio.file.Path;
 
 import com.beust.jcommander.JCommander;
 
@@ -12,41 +26,47 @@ import kieker.common.exception.ConfigurationException;
 import kieker.tools.common.AbstractService;
 
 /**
- * Read the CSV output of the R script and the existing JSON file and append a
- * record to the JSON file based on the CSV dataset. Further compute a list of
- * the last 50 runs and the last relative values.
+ * Integrate new measurements into the YAML log and create derived outputs: HTML tables and
+ * JSON files for measruement overview and mean execution time graphs, respectively.
  *
  * @author Reiner Jung
+ * @since 1.3.0
  *
  */
 public class CompileResultsMain extends AbstractService<TeetimeConfiguration, Settings> {
 
-	 public static void main(final String[] args) {
-		 final CompileResultsMain main = new CompileResultsMain();
-		 System.exit(main.run("compile-result", "Compile Results", args, new Settings()));
-	 }
-	
-	@Override
-	protected TeetimeConfiguration createTeetimeConfiguration() throws ConfigurationException {
-		return new TeetimeConfiguration(this.parameterConfiguration);
-	}
-
-	@Override
-	protected File getConfigurationFile() {
-		return null;
-	}
-
-	@Override
-	protected boolean checkConfiguration(Configuration configuration, JCommander commander) {
-		return true;
-	}
-
-	@Override
-	protected boolean checkParameters(JCommander commander) throws ConfigurationException {
-		return true;
-	}
-
-	@Override
-	protected void shutdownService() {
-	}
+    public static void main(final String[] args) {
+        final CompileResultsMain main = new CompileResultsMain();
+        System.exit(main.run("compile-result", "Compile Results", args, new Settings()));
+    }
+
+    @Override
+    protected TeetimeConfiguration createTeetimeConfiguration() throws ConfigurationException {
+        return new TeetimeConfiguration(this.parameterConfiguration);
+    }
+
+    @Override
+    protected File getConfigurationFile() {
+        return null;
+    }
+
+    @Override
+    protected boolean checkConfiguration(final Configuration configuration, final JCommander commander) {
+        return true;
+    }
+
+    @Override
+    protected boolean checkParameters(final JCommander commander) throws ConfigurationException {
+        for (final Path inputPath : this.parameterConfiguration.getInputPaths()) {
+            if (!inputPath.toFile().isFile() || !inputPath.toFile().exists()) {
+                this.logger.error("Cannot read input file {}", inputPath.toString());
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    protected void shutdownService() {
+    }
 }
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/FileSink.java b/tools/compile-results/src/main/java/moobench/tools/results/FileSink.java
deleted file mode 100644
index df1b3e0..0000000
--- a/tools/compile-results/src/main/java/moobench/tools/results/FileSink.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package moobench.tools.results;
-
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.nio.file.Files;
-
-import moobench.tools.results.data.OutputFile;
-import teetime.framework.AbstractConsumerStage;
-
-public class FileSink extends AbstractConsumerStage<OutputFile> {
-
-    @Override
-    protected void execute(final OutputFile outputFile) throws Exception {
-        try (final BufferedWriter writer = Files.newBufferedWriter(outputFile.getFilePath())) {
-            writer.write(outputFile.getContent());
-            writer.close();
-        } catch(final IOException e) {
-            this.logger.error("Cannot write file {}", outputFile.getFilePath().toString());
-        }
-    }
-
-}
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/JsonChartSink.java b/tools/compile-results/src/main/java/moobench/tools/results/JsonChartSink.java
new file mode 100644
index 0000000..8cda0f4
--- /dev/null
+++ b/tools/compile-results/src/main/java/moobench/tools/results/JsonChartSink.java
@@ -0,0 +1,44 @@
+package moobench.tools.results;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import moobench.tools.results.data.Chart;
+import moobench.tools.results.data.ValueTuple;
+import teetime.framework.AbstractConsumerStage;
+
+public class JsonChartSink extends AbstractConsumerStage<Chart> {
+
+    private final Path path;
+
+    public JsonChartSink(final Path path) {
+        this.path = path;
+    }
+
+    @Override
+    protected void execute(final Chart chart) throws Exception {
+        final Path jsonLog = this.path.resolve(chart.getName() + "-partial.json");
+        final ObjectMapper mapper = new ObjectMapper();
+
+        final ObjectNode node = mapper.createObjectNode();
+        final ArrayNode arrayNode = node.putArray("results");
+
+        for(final ValueTuple value : chart.getValues()) {
+            final ObjectNode objectNode = mapper.createObjectNode();
+            for (int i = 0;i < chart.getHeaders().size();i++) {
+                final String name = chart.getHeaders().get(i);
+                final Double number = value.getValues().get(i);
+                objectNode.put(name, number);
+            }
+            objectNode.put("time", value.getTimestamp());
+            arrayNode.add(objectNode);
+        }
+
+        mapper.writeValue(Files.newBufferedWriter(jsonLog), node);
+    }
+
+}
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/JsonLogSink.java b/tools/compile-results/src/main/java/moobench/tools/results/JsonLogSink.java
deleted file mode 100644
index 9dd23fc..0000000
--- a/tools/compile-results/src/main/java/moobench/tools/results/JsonLogSink.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package moobench.tools.results;
-
-import java.nio.file.Files;
-import java.nio.file.Path;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-
-import moobench.tools.results.data.Chart;
-import moobench.tools.results.data.ValueTuple;
-import teetime.framework.AbstractConsumerStage;
-
-public class JsonLogSink extends AbstractConsumerStage<Chart> {
-
-	private Path path;
-
-	public JsonLogSink(Path path) {
-		this.path = path;
-	}
-
-	@Override
-	protected void execute(Chart chart) throws Exception {
-		Path jsonLog = this.path.resolve(chart.getName() + ".json");
-	    ObjectMapper mapper = new ObjectMapper();
-	    
-		ObjectNode node = mapper.createObjectNode();
-		ArrayNode arrayNode = node.putArray("results");
-		
-		for(ValueTuple value : chart.getValues()) {
-			ObjectNode objectNode = mapper.createObjectNode();
-			for (int i = 0;i < chart.getHeaders().size();i++) {
-				String name = chart.getHeaders().get(i);
-				Double number = value.getValues().get(i);
-				objectNode.put(name, number);
-			}
-			objectNode.put("time", value.getTimestamp());
-			arrayNode.add(objectNode);
-		}
-		
-		mapper.writeValue(Files.newBufferedWriter(jsonLog), node);
-	}
-
-}
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/OrderedSet.java b/tools/compile-results/src/main/java/moobench/tools/results/OrderedSet.java
index b2f6bb6..72a5a6c 100644
--- a/tools/compile-results/src/main/java/moobench/tools/results/OrderedSet.java
+++ b/tools/compile-results/src/main/java/moobench/tools/results/OrderedSet.java
@@ -1,3 +1,19 @@
+/***************************************************************************
+ * Copyright (C) 2022 Kieker (https://kieker-monitoring.net)
+
+ *
+ * Licensed 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 moobench.tools.results;
 
 import java.util.ArrayList;
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/Settings.java b/tools/compile-results/src/main/java/moobench/tools/results/Settings.java
index 024471b..aad1f0a 100644
--- a/tools/compile-results/src/main/java/moobench/tools/results/Settings.java
+++ b/tools/compile-results/src/main/java/moobench/tools/results/Settings.java
@@ -1,4 +1,19 @@
+/***************************************************************************
+ * Copyright (C) 2022 Kieker (https://kieker-monitoring.net)
 
+ *
+ * Licensed 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 moobench.tools.results;
 
 import java.nio.file.Path;
@@ -8,39 +23,39 @@ import com.beust.jcommander.Parameter;
 import com.beust.jcommander.converters.PathConverter;
 
 public class Settings {
-	
-	@Parameter(names = { "-i", "--input" }, variableArity = true, required = true, converter = PathConverter.class, description = "List of input data sets")
-	private List<Path> inputPaths;
-
-	@Parameter(names= { "-l", "--log" }, required = true, converter = PathConverter.class, description = "YAML log file root path")
-	private Path logPath;
-	
-	@Parameter(names= { "-t", "--table" }, required = true, converter = PathConverter.class, description = "Output HTML table for results")
-	private Path tablePath;
-	
-	@Parameter(names= { "-j", "--json-log" }, required = true, converter = PathConverter.class, description = "Partial JSON log for viewing")
-	private Path jsonLogPath;
-	
-	@Parameter(names= { "-w", "--window" }, required = true, description = "Time Window Size")
-	private Integer window;
-
-	public List<Path> getInputPaths() {
-		return inputPaths;
-	}
-	
-	public Path getLogPath() {
-		return logPath;
-	}
-	
-	public Path getTablePath() {
-		return tablePath;
-	}
-	
-	public Path getJsonLogPath() {
-		return jsonLogPath;
-	}
-	
-	public Integer getWindow() {
-		return window;
-	}
+
+    @Parameter(names = { "-i", "--input" }, variableArity = true, required = true, converter = PathConverter.class, description = "List of input data sets")
+    private List<Path> inputPaths;
+
+    @Parameter(names= { "-l", "--log" }, required = true, converter = PathConverter.class, description = "YAML log file root path")
+    private Path logPath;
+
+    @Parameter(names= { "-t", "--table" }, required = true, converter = PathConverter.class, description = "Output HTML table for results")
+    private Path tablePath;
+
+    @Parameter(names= { "-c", "--chart" }, required = true, converter = PathConverter.class, description = "Partial JSON log for charts")
+    private Path jsonChartPath;
+
+    @Parameter(names= { "-w", "--window" }, required = true, description = "Time Window Size")
+    private Integer window;
+
+    public List<Path> getInputPaths() {
+        return this.inputPaths;
+    }
+
+    public Path getLogPath() {
+        return this.logPath;
+    }
+
+    public Path getTablePath() {
+        return this.tablePath;
+    }
+
+    public Path getJsonChartPath() {
+        return this.jsonChartPath;
+    }
+
+    public Integer getWindow() {
+        return this.window;
+    }
 }
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/TailChartStage.java b/tools/compile-results/src/main/java/moobench/tools/results/TailChartStage.java
deleted file mode 100644
index 5d0e484..0000000
--- a/tools/compile-results/src/main/java/moobench/tools/results/TailChartStage.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * 
- */
-package moobench.tools.results;
-
-import moobench.tools.results.data.Chart;
-import teetime.stage.basic.AbstractFilter;
-
-/**
- * @author reiner
- *
- */
-public class TailChartStage extends AbstractFilter<Chart> {
-
-	private Integer window;
-
-	public TailChartStage(Integer window) {
-		this.window = window;
-	}
-
-	@Override
-	protected void execute(Chart chart) throws Exception {
-		if (window != null) {
-			int size = chart.getValues().size();
-			if (size > window) {
-				Chart newChart = new Chart(chart.getName());
-				newChart.getHeaders().addAll(chart.getHeaders());
-				for (int i = size - window; i < size;i++) {
-					newChart.getValues().add(chart.getValues().get(i));
-				}
-				this.outputPort.send(newChart);
-			} else {
-				this.outputPort.send(chart);
-			}
-		} else {
-			this.outputPort.send(chart);
-		}
-	}
-
-}
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/TeetimeConfiguration.java b/tools/compile-results/src/main/java/moobench/tools/results/TeetimeConfiguration.java
index 90b56ac..5296ea7 100644
--- a/tools/compile-results/src/main/java/moobench/tools/results/TeetimeConfiguration.java
+++ b/tools/compile-results/src/main/java/moobench/tools/results/TeetimeConfiguration.java
@@ -1,3 +1,19 @@
+/***************************************************************************
+ * Copyright (C) 2022 Kieker (https://kieker-monitoring.net)
+
+ *
+ * Licensed 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 moobench.tools.results;
 
 import java.io.File;
@@ -7,6 +23,15 @@ import java.util.ArrayList;
 import java.util.List;
 
 import moobench.tools.results.data.ExperimentLog;
+import moobench.tools.results.stages.ChartAssemblerStage;
+import moobench.tools.results.stages.ComputeTableStage;
+import moobench.tools.results.stages.ElementProducer;
+import moobench.tools.results.stages.FileSink;
+import moobench.tools.results.stages.GenerateHtmlTableStage;
+import moobench.tools.results.stages.LogAppenderStage;
+import moobench.tools.results.stages.TailChartStage;
+import moobench.tools.results.stages.YamlLogSink;
+import moobench.tools.results.stages.YamlReaderStage;
 import teetime.framework.Configuration;
 import teetime.stage.basic.distributor.Distributor;
 import teetime.stage.basic.distributor.strategy.CopyByReferenceStrategy;
@@ -27,7 +52,8 @@ public class TeetimeConfiguration extends Configuration {
 
         final ChartAssemblerStage chartAssemblerStage = new ChartAssemblerStage();
         final TailChartStage tailChartStage = new TailChartStage(settings.getWindow());
-        final JsonLogSink jsonLogSink = new JsonLogSink(settings.getJsonLogPath());
+        final JsonChartSink jsonLogSink = new JsonChartSink(settings.getJsonChartPath());
+
         final ComputeTableStage computeTableStage = new ComputeTableStage();
         final GenerateHtmlTableStage generateHtmlTableStage = new GenerateHtmlTableStage(settings.getTablePath());
         final FileSink fileSink = new FileSink();
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/YamlLogSink.java b/tools/compile-results/src/main/java/moobench/tools/results/YamlLogSink.java
deleted file mode 100644
index de3d918..0000000
--- a/tools/compile-results/src/main/java/moobench/tools/results/YamlLogSink.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package moobench.tools.results;
-
-import java.io.FileWriter;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.yaml.snakeyaml.DumperOptions;
-import org.yaml.snakeyaml.Yaml;
-import org.yaml.snakeyaml.nodes.Node;
-import org.yaml.snakeyaml.nodes.Tag;
-import org.yaml.snakeyaml.representer.Represent;
-import org.yaml.snakeyaml.representer.Representer;
-
-import moobench.tools.results.data.ExperimentLog;
-import moobench.tools.results.data.Measurements;
-import teetime.framework.AbstractConsumerStage;
-
-public class YamlLogSink extends AbstractConsumerStage<ExperimentLog> {
-
-	Path logPath;
-	
-	public YamlLogSink(Path logPath) {
-		this.logPath = logPath;
-	}
-	
-	@Override
-	protected void execute(ExperimentLog log) throws Exception {
-		Path logPath = this.logPath.resolve(String.format("%s.yaml", log.getKind()));
-
-		Representer representer = new LogRepresenter();
-		DumperOptions options = new DumperOptions();
-		Yaml yaml = new Yaml(representer, options);
-    
-	    FileWriter writer = new FileWriter(logPath.toFile());
-	    yaml.dump(log, writer);        
-	}
-	
-	private class LogRepresenter extends Representer {
-		
-		public LogRepresenter() {
-	        this.representers.put(Measurements.class, new RepresentMeasurements());
-	    }
-		
-		private class RepresentMeasurements implements Represent {
-
-			@Override
-			public Node representData(Object data) {
-				Measurements measurements = (Measurements)data;
-				
-				List<Double> values = new ArrayList<>();
-				values.add(measurements.getMean());
-				values.add(measurements.getStandardDeviation());
-				values.add(measurements.getConvidence());
-				values.add(measurements.getLowerQuartile());
-				values.add(measurements.getMedian());
-				values.add(measurements.getUpperQuartile());
-				values.add(measurements.getMin());
-				values.add(measurements.getMax());
-				
-				return representSequence(new Tag("!!" + Measurements.class.getCanonicalName()), values, defaultFlowStyle);
-			}
-			
-		}
-	}
-
-}
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/data/Experiment.java b/tools/compile-results/src/main/java/moobench/tools/results/data/Experiment.java
index d08c2dc..58d88c9 100644
--- a/tools/compile-results/src/main/java/moobench/tools/results/data/Experiment.java
+++ b/tools/compile-results/src/main/java/moobench/tools/results/data/Experiment.java
@@ -1,6 +1,19 @@
-/**
- * 
- */
+/***************************************************************************
+ * Copyright (C) 2022 Kieker (https://kieker-monitoring.net)
+
+ *
+ * Licensed 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 moobench.tools.results.data;
 
 import java.util.HashMap;
@@ -12,27 +25,27 @@ import java.util.Map;
  */
 public class Experiment {
 
-	double timestamp;
-	Map<String,Measurements> measurements = new HashMap<>();
-	
-	public double getTimestamp() {
-		return timestamp;
-	}
-	
-	public void setTimestamp(double timestamp) {
-		this.timestamp = timestamp;
-	}
-	
-	public Map<String,Measurements> getMeasurements() {
-		return measurements;
-	}
-	public void setMeasurements(Map<String,Measurements> measurements) {
-		this.measurements = measurements;
-	}
-	
-	@Override
-	public String toString() {
-		return String.format("time: %f, measurements: %d\n", timestamp, measurements.size());
-	}
-	
+    double timestamp;
+    Map<String,Measurements> measurements = new HashMap<>();
+
+    public double getTimestamp() {
+        return this.timestamp;
+    }
+
+    public void setTimestamp(final double timestamp) {
+        this.timestamp = timestamp;
+    }
+
+    public Map<String,Measurements> getMeasurements() {
+        return this.measurements;
+    }
+    public void setMeasurements(final Map<String,Measurements> measurements) {
+        this.measurements = measurements;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("time: %f, measurements: %d\n", this.timestamp, this.measurements.size());
+    }
+
 }
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/data/ExperimentLog.java b/tools/compile-results/src/main/java/moobench/tools/results/data/ExperimentLog.java
index e619816..f8f3b90 100644
--- a/tools/compile-results/src/main/java/moobench/tools/results/data/ExperimentLog.java
+++ b/tools/compile-results/src/main/java/moobench/tools/results/data/ExperimentLog.java
@@ -1,26 +1,42 @@
+/***************************************************************************
+ * Copyright (C) 2022 Kieker (https://kieker-monitoring.net)
+
+ *
+ * Licensed 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 moobench.tools.results.data;
 
 import java.util.ArrayList;
 import java.util.List;
 
 public class ExperimentLog {
-	
-	String kind;
-	List<Experiment> experiments = new ArrayList<>();
-	
-	public String getKind() {
-		return kind;
-	}
-	
-	public void setKind(String kind) {
-		this.kind = kind;
-	}
-	
-	public List<Experiment> getExperiments() {
-		return experiments;
-	}
-
-	public void setExperiments(List<Experiment> experiments) {
-		this.experiments = experiments;
-	}
+
+    String kind;
+    List<Experiment> experiments = new ArrayList<>();
+
+    public String getKind() {
+        return this.kind;
+    }
+
+    public void setKind(final String kind) {
+        this.kind = kind;
+    }
+
+    public List<Experiment> getExperiments() {
+        return this.experiments;
+    }
+
+    public void setExperiments(final List<Experiment> experiments) {
+        this.experiments = experiments;
+    }
 }
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/data/Measurements.java b/tools/compile-results/src/main/java/moobench/tools/results/data/Measurements.java
index a14f9bd..366ae35 100644
--- a/tools/compile-results/src/main/java/moobench/tools/results/data/Measurements.java
+++ b/tools/compile-results/src/main/java/moobench/tools/results/data/Measurements.java
@@ -1,63 +1,79 @@
+/***************************************************************************
+ * Copyright (C) 2022 Kieker (https://kieker-monitoring.net)
+
+ *
+ * Licensed 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 moobench.tools.results.data;
 
 public class Measurements {
-		
-	private Double mean;
-	private Double convidence;
-	private Double standardDeviation;
-	private Double lowerQuartile;
-	private Double median;
-	private Double upperQuartile;
-	private Double max;
-	private Double min;
-
-	public Measurements(Double mean, Double standardDeviation, Double convidence, Double lowerQuartile, Double median, Double upperQuartile, Double min, Double max) {
-		this.mean = mean;
-		this.convidence = convidence;
-		this.standardDeviation = standardDeviation;
-		this.lowerQuartile = lowerQuartile;
-		this.median = median;
-		this.upperQuartile = upperQuartile;
-		this.min = min;
-		this.max = max;
-	}
-	
-	public Double getMean() {
-		return mean;
-	}
-	
-	/**
-	 * Returns the convidence value, to get the convidence interval you need to compute the interval as
-	 * [mean-convidence:mean+convidence]
-	 * 
-	 * @return convidence value
-	 */
-	public Double getConvidence() {
-		return convidence;
-	}
-	
-	public Double getStandardDeviation() {
-		return standardDeviation;
-	}
-	
-	public Double getLowerQuartile() {
-		return lowerQuartile;
-	}
-	
-	public Double getMedian() {
-		return median;
-	}
-	
-	public Double getUpperQuartile() {
-		return upperQuartile;
-	}
-	
-	public Double getMin() {
-		return min;
-	}
-	
-	public Double getMax() {
-		return max;
-	}
+
+    private final Double mean;
+    private final Double convidence;
+    private final Double standardDeviation;
+    private final Double lowerQuartile;
+    private final Double median;
+    private final Double upperQuartile;
+    private final Double max;
+    private final Double min;
+
+    public Measurements(final Double mean, final Double standardDeviation, final Double convidence, final Double lowerQuartile, final Double median, final Double upperQuartile, final Double min, final Double max) {
+        this.mean = mean;
+        this.convidence = convidence;
+        this.standardDeviation = standardDeviation;
+        this.lowerQuartile = lowerQuartile;
+        this.median = median;
+        this.upperQuartile = upperQuartile;
+        this.min = min;
+        this.max = max;
+    }
+
+    public Double getMean() {
+        return this.mean;
+    }
+
+    /**
+     * Returns the convidence value, to get the convidence interval you need to compute the interval as
+     * [mean-convidence:mean+convidence]
+     *
+     * @return convidence value
+     */
+    public Double getConvidence() {
+        return this.convidence;
+    }
+
+    public Double getStandardDeviation() {
+        return this.standardDeviation;
+    }
+
+    public Double getLowerQuartile() {
+        return this.lowerQuartile;
+    }
+
+    public Double getMedian() {
+        return this.median;
+    }
+
+    public Double getUpperQuartile() {
+        return this.upperQuartile;
+    }
+
+    public Double getMin() {
+        return this.min;
+    }
+
+    public Double getMax() {
+        return this.max;
+    }
 
 }
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/data/OutputFile.java b/tools/compile-results/src/main/java/moobench/tools/results/data/OutputFile.java
index b1bdfe1..4176bd6 100644
--- a/tools/compile-results/src/main/java/moobench/tools/results/data/OutputFile.java
+++ b/tools/compile-results/src/main/java/moobench/tools/results/data/OutputFile.java
@@ -1,7 +1,29 @@
+/***************************************************************************
+ * Copyright (C) 2022 Kieker (https://kieker-monitoring.net)
+
+ *
+ * Licensed 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 moobench.tools.results.data;
 
 import java.nio.file.Path;
 
+/**
+ * Pass down file path and content for the file to a data sink.
+ *
+ * @author Reiner Jung
+ * @since 1.3.0
+ */
 public class OutputFile {
 
     Path filePath;
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/data/TableInformation.java b/tools/compile-results/src/main/java/moobench/tools/results/data/TableInformation.java
index 8a73e5d..e79bf6d 100644
--- a/tools/compile-results/src/main/java/moobench/tools/results/data/TableInformation.java
+++ b/tools/compile-results/src/main/java/moobench/tools/results/data/TableInformation.java
@@ -1,3 +1,19 @@
+/***************************************************************************
+ * Copyright (C) 2022 Kieker (https://kieker-monitoring.net)
+
+ *
+ * Licensed 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 moobench.tools.results.data;
 
 public class TableInformation {
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/stages/ChartAssemblerStage.java b/tools/compile-results/src/main/java/moobench/tools/results/stages/ChartAssemblerStage.java
new file mode 100644
index 0000000..a51709e
--- /dev/null
+++ b/tools/compile-results/src/main/java/moobench/tools/results/stages/ChartAssemblerStage.java
@@ -0,0 +1,71 @@
+/***************************************************************************
+ * Copyright (C) 2022 Kieker (https://kieker-monitoring.net)
+
+ *
+ * Licensed 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 moobench.tools.results.stages;
+
+import java.util.List;
+import java.util.Map;
+
+import moobench.tools.results.data.Chart;
+import moobench.tools.results.data.Experiment;
+import moobench.tools.results.data.ExperimentLog;
+import moobench.tools.results.data.Measurements;
+import moobench.tools.results.data.ValueTuple;
+import teetime.stage.basic.AbstractTransformation;
+
+/**
+ * @author Reiner Jung
+ * @since 1.3.0
+ *
+ */
+public class ChartAssemblerStage extends AbstractTransformation<ExperimentLog, Chart> {
+
+    @Override
+    protected void execute(final ExperimentLog element) throws Exception {
+        final Chart chart = new Chart(element.getKind());
+        for (final Experiment experiment : element.getExperiments()) {
+            final long timestamp = Double.valueOf(experiment.getTimestamp()).longValue();
+            final ValueTuple tuple = new ValueTuple(timestamp);
+
+            this.addHeaderIfMissing(chart.getHeaders(), experiment.getMeasurements());
+            this.fillInData(chart.getHeaders(), tuple.getValues(), experiment.getMeasurements());
+
+            chart.getValues().add(tuple);
+        }
+
+        this.outputPort.send(chart);
+    }
+
+    private void fillInData(final List<String> headers, final List<Double> values, final Map<String, Measurements> measurements) {
+        for (final String key : headers) {
+            final Measurements value = measurements.get(key);
+            if (value != null) {
+                values.add(value.getMean());
+            } else {
+                values.add(Double.NaN);
+            }
+        }
+    }
+
+    private void addHeaderIfMissing(final List<String> headers, final Map<String, Measurements> measurements) {
+        for (final String key : measurements.keySet()) {
+            if (!headers.stream().anyMatch(header -> header.equals(key))) {
+                headers.add(key);
+            }
+        }
+    }
+
+}
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/ComputeTableStage.java b/tools/compile-results/src/main/java/moobench/tools/results/stages/ComputeTableStage.java
similarity index 76%
rename from tools/compile-results/src/main/java/moobench/tools/results/ComputeTableStage.java
rename to tools/compile-results/src/main/java/moobench/tools/results/stages/ComputeTableStage.java
index dd341ab..cb49ae8 100644
--- a/tools/compile-results/src/main/java/moobench/tools/results/ComputeTableStage.java
+++ b/tools/compile-results/src/main/java/moobench/tools/results/stages/ComputeTableStage.java
@@ -1,7 +1,20 @@
-/**
+/***************************************************************************
+ * Copyright (C) 2022 Kieker (https://kieker-monitoring.net)
+
  *
- */
-package moobench.tools.results;
+ * Licensed 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 moobench.tools.results.stages;
 
 import java.util.List;
 import java.util.Map.Entry;
@@ -13,8 +26,8 @@ import moobench.tools.results.data.TableInformation;
 import teetime.stage.basic.AbstractTransformation;
 
 /**
- * @author reiner
- *
+ * @author Reiner Jung
+ * @since 1.3.0
  */
 public class ComputeTableStage extends AbstractTransformation<ExperimentLog, TableInformation> {
 
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/ElementProducer.java b/tools/compile-results/src/main/java/moobench/tools/results/stages/ElementProducer.java
similarity index 93%
rename from tools/compile-results/src/main/java/moobench/tools/results/ElementProducer.java
rename to tools/compile-results/src/main/java/moobench/tools/results/stages/ElementProducer.java
index e27cafb..be43e38 100644
--- a/tools/compile-results/src/main/java/moobench/tools/results/ElementProducer.java
+++ b/tools/compile-results/src/main/java/moobench/tools/results/stages/ElementProducer.java
@@ -1,7 +1,7 @@
 /**
  * 
  */
-package moobench.tools.results;
+package moobench.tools.results.stages;
 
 import java.util.List;
 
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/stages/FileSink.java b/tools/compile-results/src/main/java/moobench/tools/results/stages/FileSink.java
new file mode 100644
index 0000000..a472a45
--- /dev/null
+++ b/tools/compile-results/src/main/java/moobench/tools/results/stages/FileSink.java
@@ -0,0 +1,38 @@
+/***************************************************************************
+ * Copyright (C) 2022 Kieker (https://kieker-monitoring.net)
+
+ *
+ * Licensed 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 moobench.tools.results.stages;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+
+import moobench.tools.results.data.OutputFile;
+import teetime.framework.AbstractConsumerStage;
+
+public class FileSink extends AbstractConsumerStage<OutputFile> {
+
+    @Override
+    protected void execute(final OutputFile outputFile) throws Exception {
+        try (final BufferedWriter writer = Files.newBufferedWriter(outputFile.getFilePath())) {
+            writer.write(outputFile.getContent());
+            writer.close();
+        } catch(final IOException e) {
+            this.logger.error("Cannot write file {}", outputFile.getFilePath().toString());
+        }
+    }
+
+}
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/GenerateHtmlTableStage.java b/tools/compile-results/src/main/java/moobench/tools/results/stages/GenerateHtmlTableStage.java
similarity index 81%
rename from tools/compile-results/src/main/java/moobench/tools/results/GenerateHtmlTableStage.java
rename to tools/compile-results/src/main/java/moobench/tools/results/stages/GenerateHtmlTableStage.java
index 4780590..47fa81a 100644
--- a/tools/compile-results/src/main/java/moobench/tools/results/GenerateHtmlTableStage.java
+++ b/tools/compile-results/src/main/java/moobench/tools/results/stages/GenerateHtmlTableStage.java
@@ -1,8 +1,9 @@
-package moobench.tools.results;
+package moobench.tools.results.stages;
 
 import java.nio.file.Path;
 import java.util.Set;
 
+import moobench.tools.results.OrderedSet;
 import moobench.tools.results.data.Measurements;
 import moobench.tools.results.data.OutputFile;
 import moobench.tools.results.data.TableInformation;
@@ -17,13 +18,13 @@ public class GenerateHtmlTableStage extends AbstractTransformation<TableInformat
     }
 
     @Override
-    protected void execute(final TableInformation element) throws Exception {
+    protected void execute(final TableInformation tableInformation) throws Exception {
         String content = "<table>\n" + "  <tr>\n" + "    <th>setup</th>\n" + "    <th>run</th>\n"
                 + "    <th>mean</th>\n" + "    <th>ci</th>\n" + "    <th>sd</th>\n" + "    <th>1.quartile</th>\n"
                 + "    <th>median</th>\n" + "    <th>3.quartile</th>\n" + "    <th>min</th>\n" + "    <th>max</th>\n"
                 + "  </tr>\n";
-        final Set<String> currentKeySet = element.getCurrent().getMeasurements().keySet();
-        final Set<String> previousKeySet = element.getPrevious().getMeasurements().keySet();
+        final Set<String> currentKeySet = tableInformation.getCurrent().getMeasurements().keySet();
+        final Set<String> previousKeySet = tableInformation.getPrevious().getMeasurements().keySet();
         final Set<String> completeKeySet = new OrderedSet<>();
         if (currentKeySet != null) {
             completeKeySet.addAll(currentKeySet);
@@ -33,11 +34,11 @@ public class GenerateHtmlTableStage extends AbstractTransformation<TableInformat
         }
 
         for (final String key : completeKeySet) {
-            content += this.addMode(key, element.getCurrent().getMeasurements().get(key),
-                    element.getPrevious().getMeasurements().get(key));
+            content += this.addMode(key, tableInformation.getCurrent().getMeasurements().get(key),
+                    tableInformation.getPrevious().getMeasurements().get(key));
         }
         content += "</table>\n";
-        this.outputPort.send(new OutputFile(this.tablePath.resolve(element.getName() + ".html"), content));
+        this.outputPort.send(new OutputFile(this.tablePath.resolve(tableInformation.getName() + "-table.html"), content));
     }
 
     private String addMode(final String key, final Measurements current, final Measurements previous) {
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/LogAppenderStage.java b/tools/compile-results/src/main/java/moobench/tools/results/stages/LogAppenderStage.java
similarity index 96%
rename from tools/compile-results/src/main/java/moobench/tools/results/LogAppenderStage.java
rename to tools/compile-results/src/main/java/moobench/tools/results/stages/LogAppenderStage.java
index 128eab4..e1c4e9e 100644
--- a/tools/compile-results/src/main/java/moobench/tools/results/LogAppenderStage.java
+++ b/tools/compile-results/src/main/java/moobench/tools/results/stages/LogAppenderStage.java
@@ -1,7 +1,7 @@
 /**
  * 
  */
-package moobench.tools.results;
+package moobench.tools.results.stages;
 
 import java.util.HashMap;
 import java.util.Map;
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/stages/TailChartStage.java b/tools/compile-results/src/main/java/moobench/tools/results/stages/TailChartStage.java
new file mode 100644
index 0000000..f5e4a76
--- /dev/null
+++ b/tools/compile-results/src/main/java/moobench/tools/results/stages/TailChartStage.java
@@ -0,0 +1,52 @@
+/***************************************************************************
+ * Copyright (C) 2022 Kieker (https://kieker-monitoring.net)
+ *
+ * Licensed 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 moobench.tools.results.stages;
+
+import moobench.tools.results.data.Chart;
+import teetime.stage.basic.AbstractFilter;
+
+/**
+ * @author Reiner Jung
+ * @since 1.3.0
+ */
+public class TailChartStage extends AbstractFilter<Chart> {
+
+    private final Integer window;
+
+    public TailChartStage(final Integer window) {
+        this.window = window;
+    }
+
+    @Override
+    protected void execute(final Chart chart) throws Exception {
+        if (this.window != null) {
+            final int size = chart.getValues().size();
+            if (size > this.window) {
+                final Chart newChart = new Chart(chart.getName());
+                newChart.getHeaders().addAll(chart.getHeaders());
+                for (int i = size - this.window; i < size;i++) {
+                    newChart.getValues().add(chart.getValues().get(i));
+                }
+                this.outputPort.send(newChart);
+            } else {
+                this.outputPort.send(chart);
+            }
+        } else {
+            this.outputPort.send(chart);
+        }
+    }
+
+}
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/stages/YamlLogSink.java b/tools/compile-results/src/main/java/moobench/tools/results/stages/YamlLogSink.java
new file mode 100644
index 0000000..5088dd9
--- /dev/null
+++ b/tools/compile-results/src/main/java/moobench/tools/results/stages/YamlLogSink.java
@@ -0,0 +1,83 @@
+/***************************************************************************
+ * Copyright (C) 2022 Kieker (https://kieker-monitoring.net)
+
+ *
+ * Licensed 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 moobench.tools.results.stages;
+
+import java.io.FileWriter;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+import moobench.tools.results.data.ExperimentLog;
+import moobench.tools.results.data.Measurements;
+import teetime.framework.AbstractConsumerStage;
+
+public class YamlLogSink extends AbstractConsumerStage<ExperimentLog> {
+
+    Path logPath;
+
+    public YamlLogSink(final Path logPath) {
+        this.logPath = logPath;
+    }
+
+    @Override
+    protected void execute(final ExperimentLog log) throws Exception {
+        final Path logPath = this.logPath.resolve(String.format("%s-log.yaml", log.getKind()));
+
+        final Representer representer = new LogRepresenter();
+        final DumperOptions options = new DumperOptions();
+        final Yaml yaml = new Yaml(representer, options);
+
+        final FileWriter writer = new FileWriter(logPath.toFile());
+        yaml.dump(log, writer);
+    }
+
+    private class LogRepresenter extends Representer {
+
+        public LogRepresenter() {
+            this.representers.put(Measurements.class, new RepresentMeasurements());
+        }
+
+        private class RepresentMeasurements implements Represent {
+
+            @Override
+            public Node representData(final Object data) {
+                final Measurements measurements = (Measurements)data;
+
+                final List<Double> values = new ArrayList<>();
+                values.add(measurements.getMean());
+                values.add(measurements.getStandardDeviation());
+                values.add(measurements.getConvidence());
+                values.add(measurements.getLowerQuartile());
+                values.add(measurements.getMedian());
+                values.add(measurements.getUpperQuartile());
+                values.add(measurements.getMin());
+                values.add(measurements.getMax());
+
+                return LogRepresenter.this.representSequence(new Tag("!!" + Measurements.class.getCanonicalName()), values, LogRepresenter.this.defaultFlowStyle);
+            }
+
+        }
+    }
+
+}
diff --git a/tools/compile-results/src/main/java/moobench/tools/results/YamlReaderStage.java b/tools/compile-results/src/main/java/moobench/tools/results/stages/YamlReaderStage.java
similarity index 94%
rename from tools/compile-results/src/main/java/moobench/tools/results/YamlReaderStage.java
rename to tools/compile-results/src/main/java/moobench/tools/results/stages/YamlReaderStage.java
index 0cbbe6c..43bfabf 100644
--- a/tools/compile-results/src/main/java/moobench/tools/results/YamlReaderStage.java
+++ b/tools/compile-results/src/main/java/moobench/tools/results/stages/YamlReaderStage.java
@@ -1,4 +1,4 @@
-package moobench.tools.results;
+package moobench.tools.results.stages;
 
 import java.io.InputStream;
 import java.nio.file.Files;
diff --git a/upload.sh b/upload.sh
index af56104..af6b8f9 100755
--- a/upload.sh
+++ b/upload.sh
@@ -37,17 +37,17 @@ checkExecutable compile-results "${COMPILE_RESULTS_BIN}"
 KEYSTORE="$1"
 UPDATE_SITE_RUL="$2"
 
-mkdir all
-cd all
+mkdir results
+cd results
 sftp -oNoHostAuthenticationForLocalhost=yes -oStrictHostKeyChecking=no -oUser=repo -F /dev/null -i ${KEYSTORE} ${UPDATE_SITE_URL}/kieker-java.yaml
 sftp -oNoHostAuthenticationForLocalhost=yes -oStrictHostKeyChecking=no -oUser=repo -F /dev/null -i ${KEYSTORE} ${UPDATE_SITE_URL}/kieker-python.yaml
 sftp -oNoHostAuthenticationForLocalhost=yes -oStrictHostKeyChecking=no -oUser=repo -F /dev/null -i ${KEYSTORE} ${UPDATE_SITE_URL}/opentelemetry.yaml
 sftp -oNoHostAuthenticationForLocalhost=yes -oStrictHostKeyChecking=no -oUser=repo -F /dev/null -i ${KEYSTORE} ${UPDATE_SITE_URL}/inspectit.yaml
 cd ..
-"${COMPILE_RESULTS_BIN}" -i *-results.yaml -l all -t all -j all -w 100
-cd all
+"${COMPILE_RESULTS_BIN}" -i *-results.yaml -l results -t results -j results -w 100
+cd results
 echo "put *.yaml" | sftp -oNoHostAuthenticationForLocalhost=yes -oStrictHostKeyChecking=no -oUser=repo  -F /dev/null -i ${KEYSTORE} ${UPDATE_SITE_URL}
 echo "put *.html" | sftp -oNoHostAuthenticationForLocalhost=yes -oStrictHostKeyChecking=no -oUser=repo  -F /dev/null -i ${KEYSTORE} ${UPDATE_SITE_URL}
 echo "put *.json" | sftp -oNoHostAuthenticationForLocalhost=yes -oStrictHostKeyChecking=no -oUser=repo  -F /dev/null -i ${KEYSTORE} ${UPDATE_SITE_URL}
-
+cd ..
 # end
-- 
GitLab