diff --git a/src/main/java/kieker/analysis/graph/GraphTester.java b/src/main/java/kieker/analysis/graph/GraphTester.java
index 1e3afc6c58848665d268c506d9e1b1ba2c517ee8..de9a11b636a076d5183e82320fa70be956e3124a 100644
--- a/src/main/java/kieker/analysis/graph/GraphTester.java
+++ b/src/main/java/kieker/analysis/graph/GraphTester.java
@@ -1,9 +1,14 @@
 package kieker.analysis.graph;
 
+import java.io.IOException;
+import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
 
 import kieker.analysis.graph.export.graphml.GraphMLExporter;
 import kieker.analysis.graph.impl.GraphImpl;
+import kieker.analysis.util.dot.DotWriter;
 
 public class GraphTester {
 
@@ -100,6 +105,28 @@ public class GraphTester {
 		// DotExporter dotExporter = new DotExporter();
 		// dotExporter.export(graph, System.out);
 
+		// Could be useful for testing
+		System.out.println("DotWriter Test");
+
+		DotWriter dotWriter = new DotWriter(new PrintWriter(System.out));
+		try {
+			dotWriter.start("G");
+			dotWriter.addGraphAttribute("rotate", "90");
+			Map<String, String> defaultNodeAttributes = new HashMap<>();
+			defaultNodeAttributes.put("style", "filled");
+			dotWriter.addDefaultNodeAttributes(defaultNodeAttributes);
+			Map<String, String> nodeAttributes = new HashMap<>();
+			nodeAttributes.put("label", "LABEL Title");
+			dotWriter.addNode("102", nodeAttributes);
+			dotWriter.addNode("#id", nodeAttributes);
+			dotWriter.addEdge("102", "#id", new HashMap<>());
+			dotWriter.finish();
+
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+
 	}
 
 }
diff --git a/src/main/java/kieker/analysis/util/DotBuilder.java b/src/main/java/kieker/analysis/util/DotBuilder.java
index ca284f0c8ee82f706e2e7ea834d14d84f3c24c31..1b82af13b2e71e556e2795d9a80b40a833af4078 100644
--- a/src/main/java/kieker/analysis/util/DotBuilder.java
+++ b/src/main/java/kieker/analysis/util/DotBuilder.java
@@ -1,146 +1,97 @@
-package kieker.analysis.util;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import com.google.common.base.Joiner;
-
-/**
- * Simple class for building and representing dot graph files.
- *
- * @author Sören Henning
- *
- */
-public class DotBuilder {
-
-	private final String start;
-	private final String end;
-	private final StringBuilder body = new StringBuilder();
-
-	private Map<String, String> defaultNodeProperties;
-	private Map<String, String> defaultEdgeProperties;
-	private Map<String, String> defaultProperties;
-
-	private static final String START_BRACKET = "{";
-	private static final String END_BRACKET = "}";
-	private static final String DEFAULT_GRAPH_NAME = "G";
-	private static final String DEFAULT_GRAPH_TYPE = "digraph";
-
-	public DotBuilder() {
-		this(DEFAULT_GRAPH_NAME);
-	}
-
-	public DotBuilder(final String graphName) {
-		this(graphName, DEFAULT_GRAPH_TYPE);
-	}
-
-	// TODO graphType has to be one of "graph", "digraph" or "subgraph" so maybe use an enum
-	public DotBuilder(final String graphName, final String graphType) {
-		start = graphType + " " + graphName + " " + START_BRACKET + "\n";
-		end = END_BRACKET;
-	}
-
-	// TODO Deprecated
-	public DotBuilder(final String name, final Map<String, String> defaultNodeProperties, final Map<String, String> defaultEdgeProperties) {
-		this(name);
-		this.defaultNodeProperties = defaultNodeProperties;
-		this.defaultEdgeProperties = defaultEdgeProperties;
-	}
-
-	// TODO Deprecated
-	public DotBuilder(final String name, final Map<String, String> defaultNodeProperties, final Map<String, String> defaultEdgeProperties,
-			final Map<String, String> defaultProperties) {
-		this(name, defaultNodeProperties, defaultEdgeProperties);
-		this.defaultProperties = defaultProperties;
-	}
-
-	public void setDefaultNodeProperties(final Map<String, String> defaultNodeProperties) {
-		this.defaultNodeProperties = defaultNodeProperties;
-	}
-
-	public void setDefaultEdgeProperties(final Map<String, String> defaultEdgeProperties) {
-		this.defaultEdgeProperties = defaultEdgeProperties;
-	}
-
-	public void setDefaultProperties(final Map<String, String> defaultProperties) {
-		this.defaultProperties = defaultProperties;
-	}
-
-	public String get() {
-		return start + body.toString() + end;
-	}
-
-	@Override
-	public String toString() {
-		return get();
-	}
-
-	public void addNode(final String id) {
-		addNode(id, new HashMap<>());
-	}
-
-	public void addNode(final String id, final String label) {
-		Map<String, String> properties = new HashMap<String, String>();
-		properties.put("label", label);
-		addNode(id, properties);
-	}
-
-	public void addNode(final String id, final Map<String, String> properties) {
-		addElement('"' + id + '"', extendNodeProperties(properties));
-	}
-
-	public void addEdge(final String source, final String target) {
-		addEdge(source, target, new HashMap<>());
-	}
-
-	public void addEdge(final String source, final String target, final String label) {
-		Map<String, String> properties = new HashMap<String, String>();
-		properties.put("label", label);
-		addEdge(source, target, properties);
-	}
-
-	public void addEdge(final String source, final String target, final Map<String, String> properties) {
-		addElement('"' + source + '"' + " -> " + '"' + target + '"', extendEdgeProperties(properties));
-	}
-
-	public void addSubgraph(final String subgraph) {
-		body.append(subgraph + '\n');
-	}
-
-	private void addElement(final String element, final Map<String, String> properties) {
-		body.append(element);
-		if (properties != null && !properties.isEmpty()) {
-			body.append(" [");
-			Joiner.on("\", ").withKeyValueSeparator("=\"").appendTo(body, properties);
-			body.append("\"]");
-		}
-		body.append('\n');
-	}
-
-	private Map<String, String> extendNodeProperties(final Map<String, String> properties) {
-		return extendElementProperties(properties, defaultNodeProperties);
-	}
-
-	private Map<String, String> extendEdgeProperties(final Map<String, String> properties) {
-		return extendElementProperties(properties, defaultEdgeProperties);
-	}
-
-	private Map<String, String> extendElementProperties(final Map<String, String> properties, final Map<String, String> defaultElementProperties) {
-
-		if (defaultElementProperties != null) {
-			for (Entry<String, String> property : defaultElementProperties.entrySet()) {
-				properties.putIfAbsent(property.getKey(), property.getValue());
-			}
-		}
-
-		if (defaultProperties != null) {
-			for (Entry<String, String> property : defaultProperties.entrySet()) {
-				properties.putIfAbsent(property.getKey(), property.getValue());
-			}
-		}
-
-		return properties;
-	}
-
-}
+package kieker.analysis.util;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.base.Joiner;
+
+/**
+ * Simple class for building and representing dot graph files.
+ *
+ * @author Sören Henning
+ *
+ */
+public class DotBuilder {
+
+	private final String start;
+	private final String end;
+	private final StringBuilder body = new StringBuilder();
+
+	private Map<String, String> graphProperties;
+	private Map<String, String> defaultNodeProperties;
+	private Map<String, String> defaultEdgeProperties;
+
+	private Map<String, Map<String, String>> nodes;
+	private Map<String, Map<String, String>> edges;
+	private List<DotBuilder> subgraphs;
+
+	private static final String START_BRACKET = "{";
+	private static final String END_BRACKET = "}";
+	private static final String DEFAULT_GRAPH_NAME = "G";
+	private static final String DEFAULT_GRAPH_TYPE = "digraph";
+
+	public DotBuilder() {
+		this(DEFAULT_GRAPH_NAME);
+	}
+
+	public DotBuilder(final String graphName) {
+		this(graphName, DEFAULT_GRAPH_TYPE);
+	}
+
+	// TODO graphType has to be one of "graph", "digraph" or "subgraph" so maybe use an enum
+	public DotBuilder(final String graphName, final String graphType) {
+		start = graphType + " " + graphName + " " + START_BRACKET + "\n";
+		end = END_BRACKET;
+	}
+
+	// TODO maybe rename
+	public void setDefaultNodeProperties(final Map<String, String> defaultNodeProperties) {
+		this.defaultNodeProperties = defaultNodeProperties;
+	}
+
+	// TODO maybe rename
+	public void setDefaultEdgeProperties(final Map<String, String> defaultEdgeProperties) {
+		this.defaultEdgeProperties = defaultEdgeProperties;
+	}
+
+	public String get() {
+		return start + body.toString() + end;
+	}
+
+	@Override
+	public String toString() {
+		return get();
+	}
+
+	public void addNode(final String id) {
+		addNode(id, new HashMap<>());
+	}
+
+	public void addNode(final String id, final Map<String, String> properties) {
+		addElement('"' + id + '"', properties);
+	}
+
+	public void addEdge(final String source, final String target) {
+		addEdge(source, target, new HashMap<>());
+	}
+
+	public void addEdge(final String source, final String target, final Map<String, String> properties) {
+		addElement('"' + source + '"' + " -> " + '"' + target + '"', properties);
+	}
+
+	public void addSubgraph(final String subgraph) {
+		body.append(subgraph + '\n');
+	}
+
+	private void addElement(final String element, final Map<String, String> properties) {
+		body.append(element);
+		if (properties != null && !properties.isEmpty()) {
+			body.append(" [");
+			Joiner.on("\", ").withKeyValueSeparator("=\"").appendTo(body, properties);
+			body.append("\"]");
+		}
+		body.append('\n');
+	}
+
+}
diff --git a/src/main/java/kieker/analysis/util/DotBuilderSupport.java b/src/main/java/kieker/analysis/util/DotBuilderSupport.java
new file mode 100644
index 0000000000000000000000000000000000000000..1c8a7a0e097e871c454538a094d1ed9c6f9fb8f5
--- /dev/null
+++ b/src/main/java/kieker/analysis/util/DotBuilderSupport.java
@@ -0,0 +1,149 @@
+package kieker.analysis.util;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import com.google.common.base.Joiner;
+
+/**
+ * Simple class for building and representing dot graph files.
+ *
+ * @deprecated use {@link dot.DotWriter} instead.
+ *
+ * @author Sören Henning
+ *
+ */
+@Deprecated
+public class DotBuilderSupport {
+
+	private final String start;
+	private final String end;
+	private final StringBuilder body = new StringBuilder();
+
+	private Map<String, String> defaultNodeProperties;
+	private Map<String, String> defaultEdgeProperties;
+	private Map<String, String> defaultProperties;
+
+	private static final String START_BRACKET = "{";
+	private static final String END_BRACKET = "}";
+	private static final String DEFAULT_GRAPH_NAME = "G";
+	private static final String DEFAULT_GRAPH_TYPE = "digraph";
+
+	public DotBuilderSupport() {
+		this(DEFAULT_GRAPH_NAME);
+	}
+
+	public DotBuilderSupport(final String graphName) {
+		this(graphName, DEFAULT_GRAPH_TYPE);
+	}
+
+	// TODO graphType has to be one of "graph", "digraph" or "subgraph" so maybe use an enum
+	public DotBuilderSupport(final String graphName, final String graphType) {
+		start = graphType + " " + graphName + " " + START_BRACKET + "\n";
+		end = END_BRACKET;
+	}
+
+	// TODO Deprecated
+	public DotBuilderSupport(final String name, final Map<String, String> defaultNodeProperties, final Map<String, String> defaultEdgeProperties) {
+		this(name);
+		this.defaultNodeProperties = defaultNodeProperties;
+		this.defaultEdgeProperties = defaultEdgeProperties;
+	}
+
+	// TODO Deprecated
+	public DotBuilderSupport(final String name, final Map<String, String> defaultNodeProperties, final Map<String, String> defaultEdgeProperties,
+			final Map<String, String> defaultProperties) {
+		this(name, defaultNodeProperties, defaultEdgeProperties);
+		this.defaultProperties = defaultProperties;
+	}
+
+	public void setDefaultNodeProperties(final Map<String, String> defaultNodeProperties) {
+		this.defaultNodeProperties = defaultNodeProperties;
+	}
+
+	public void setDefaultEdgeProperties(final Map<String, String> defaultEdgeProperties) {
+		this.defaultEdgeProperties = defaultEdgeProperties;
+	}
+
+	public void setDefaultProperties(final Map<String, String> defaultProperties) {
+		this.defaultProperties = defaultProperties;
+	}
+
+	public String get() {
+		return start + body.toString() + end;
+	}
+
+	@Override
+	public String toString() {
+		return get();
+	}
+
+	public void addNode(final String id) {
+		addNode(id, new HashMap<>());
+	}
+
+	public void addNode(final String id, final String label) {
+		Map<String, String> properties = new HashMap<String, String>();
+		properties.put("label", label);
+		addNode(id, properties);
+	}
+
+	public void addNode(final String id, final Map<String, String> properties) {
+		addElement('"' + id + '"', extendNodeProperties(properties));
+	}
+
+	public void addEdge(final String source, final String target) {
+		addEdge(source, target, new HashMap<>());
+	}
+
+	public void addEdge(final String source, final String target, final String label) {
+		Map<String, String> properties = new HashMap<String, String>();
+		properties.put("label", label);
+		addEdge(source, target, properties);
+	}
+
+	public void addEdge(final String source, final String target, final Map<String, String> properties) {
+		addElement('"' + source + '"' + " -> " + '"' + target + '"', extendEdgeProperties(properties));
+	}
+
+	public void addSubgraph(final String subgraph) {
+		body.append(subgraph + '\n');
+	}
+
+	private void addElement(final String element, final Map<String, String> properties) {
+		body.append(element);
+		if (properties != null && !properties.isEmpty()) {
+			body.append(" [");
+			Joiner.on("\", ").withKeyValueSeparator("=\"").appendTo(body, properties);
+			body.append("\"]");
+		}
+		body.append('\n');
+	}
+
+	private Map<String, String> extendNodeProperties(final Map<String, String> properties) {
+		return extendElementProperties(properties, defaultNodeProperties);
+	}
+
+	private Map<String, String> extendEdgeProperties(final Map<String, String> properties) {
+		return extendElementProperties(properties, defaultEdgeProperties);
+	}
+
+	private Map<String, String> extendElementProperties(final Map<String, String> properties, final Map<String, String> defaultElementProperties) {
+
+		if (defaultElementProperties != null) {
+			for (Entry<String, String> property : defaultElementProperties.entrySet()) {
+				properties.putIfAbsent(property.getKey(), property.getValue());
+			}
+		}
+
+		if (defaultProperties != null) {
+			for (Entry<String, String> property : defaultProperties.entrySet()) {
+				properties.putIfAbsent(property.getKey(), property.getValue());
+			}
+		}
+
+		return properties;
+	}
+
+}
diff --git a/src/main/java/kieker/analysis/util/IndentWriter.java b/src/main/java/kieker/analysis/util/IndentWriter.java
index be9dd60ce1092a491fb4828e0bd291451abc5492..0ba2edb28a1c6e7388e37135c91ec43be5c687c5 100644
--- a/src/main/java/kieker/analysis/util/IndentWriter.java
+++ b/src/main/java/kieker/analysis/util/IndentWriter.java
@@ -40,7 +40,7 @@ public class IndentWriter extends Writer {
 	}
 
 	private String getIndentChars() {
-		return new String(new char[indentLength]).replace('\0', indentChar);
+		return new String(new char[indented * indentLength]).replace('\0', indentChar);
 	}
 
 	@Override
diff --git a/src/main/java/kieker/analysis/util/dot/DotGraph.java b/src/main/java/kieker/analysis/util/dot/DotGraph.java
new file mode 100644
index 0000000000000000000000000000000000000000..132e340a938a33b577fd96e6ec8a1d08901041bb
--- /dev/null
+++ b/src/main/java/kieker/analysis/util/dot/DotGraph.java
@@ -0,0 +1,31 @@
+package kieker.analysis.util.dot;
+
+public final class DotGraph {
+
+	public static final String START_GRAPH_BRACKET = "{";
+
+	public static final String END_GRAPH_BRACKET = "}";
+
+	public static final String START_ATTRS_BRACKET = "[";
+
+	public static final String END_ATTRS_BRACKET = "]";
+
+	public static final String ATTR_CONNECTOR = "=";
+
+	public static final String DIRECTED_START_TOKEN = "digraph";
+
+	public static final String UNDIRECTED_START_TOKEN = "graph";
+
+	public static final String SUB_START_TOKEN = "subgraph";
+
+	public static final String NODE = "node";
+
+	public static final String EDGE = "edge";
+
+	public static final String CLUSTER_PREFIX = "cluster_";
+
+	public static final String DIRECTED_EDGE_CONNECTOR = "->";
+
+	public static final String UNDIRECTED_EDGE_CONNECTOR = "--";
+
+}
diff --git a/src/main/java/kieker/analysis/util/dot/DotGraphType.java b/src/main/java/kieker/analysis/util/dot/DotGraphType.java
new file mode 100644
index 0000000000000000000000000000000000000000..97d1a709f7345eae635d9386c8810d51fdd14d50
--- /dev/null
+++ b/src/main/java/kieker/analysis/util/dot/DotGraphType.java
@@ -0,0 +1,7 @@
+package kieker.analysis.util.dot;
+
+public enum DotGraphType {
+
+	DIRECTED, UNDIRECTED
+
+}
diff --git a/src/main/java/kieker/analysis/util/dot/DotWriter.java b/src/main/java/kieker/analysis/util/dot/DotWriter.java
new file mode 100644
index 0000000000000000000000000000000000000000..2d3e3da75f63af629db1a5a99bec58b89462e655
--- /dev/null
+++ b/src/main/java/kieker/analysis/util/dot/DotWriter.java
@@ -0,0 +1,157 @@
+package kieker.analysis.util.dot;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import kieker.analysis.util.IndentWriter;
+
+/**
+ * Class to build and write a DOT Graph to a writer.
+ *
+ * @author Sören Henning
+ *
+ */
+public class DotWriter {
+
+	private final IndentWriter writer;
+	private DotWriterState state = DotWriterState.CREATED;
+	private int openSubgraphs = 0;
+
+	private DotGraphType graphType = DotGraphType.DIRECTED;
+
+	public DotWriter(final Writer writer) {
+		this.writer = new IndentWriter(writer);
+	}
+
+	public void start(final String name) throws IOException {
+		start(DotGraphType.DIRECTED, name);
+	}
+
+	public void start(final DotGraphType graphType, final String name) throws IOException {
+		checkState(DotWriterState.CREATED);
+
+		this.graphType = graphType;
+
+		String openToken;
+		if (graphType == DotGraphType.UNDIRECTED) {
+			openToken = DotGraph.UNDIRECTED_START_TOKEN;
+		} else {
+			openToken = DotGraph.DIRECTED_START_TOKEN;
+		}
+		writer.writeln(openToken + ' ' + name + ' ' + DotGraph.START_GRAPH_BRACKET);
+		writer.indent();
+		state = DotWriterState.STARTED;
+	}
+
+	public void finish() throws IOException {
+		checkState(DotWriterState.STARTED);
+
+		if (openSubgraphs > 0) {
+			throw new IllegalStateException("There are unclosed subgraphs.");
+		}
+
+		writer.unindent();
+		writer.writeln(DotGraph.END_GRAPH_BRACKET);
+		state = DotWriterState.FINISHED;
+
+		writer.close();
+	}
+
+	public void addDefaultNodeAttributes(final Map<String, String> attributes) throws IOException {
+		checkState(DotWriterState.STARTED);
+
+		writer.writeln(DotGraph.NODE + ' ' + assembleAttributes(attributes));
+	}
+
+	public void addDefaultEdgeAttributes(final Map<String, String> attributes) throws IOException {
+		checkState(DotWriterState.STARTED);
+
+		writer.writeln(DotGraph.EDGE + ' ' + assembleAttributes(attributes));
+	}
+
+	public void addGraphAttribute(final String key, final String value) throws IOException {
+		checkState(DotWriterState.STARTED);
+
+		writer.writeln(assembleAttribute(key, value));
+	}
+
+	public void addNode(final String id, final Map<String, String> attributes) throws IOException {
+		checkState(DotWriterState.STARTED);
+
+		writer.writeln('"' + id + '"' + ' ' + assembleAttributes(attributes));
+	}
+
+	public void addEdge(final String sourceId, final String targetId, final Map<String, String> attributes) throws IOException {
+		checkState(DotWriterState.STARTED);
+
+		String edgeConnector;
+		if (graphType == DotGraphType.UNDIRECTED) {
+			edgeConnector = DotGraph.UNDIRECTED_EDGE_CONNECTOR;
+		} else {
+			edgeConnector = DotGraph.DIRECTED_EDGE_CONNECTOR;
+		}
+		writer.writeln('"' + sourceId + '"' + ' ' + edgeConnector + ' ' + '"' + targetId + '"' + ' ' + assembleAttributes(attributes));
+	}
+
+	public void addSubgraphStart(final String name) throws IOException {
+		checkState(DotWriterState.STARTED);
+
+		writer.writeln(DotGraph.SUB_START_TOKEN + ' ' + name + ' ' + DotGraph.START_GRAPH_BRACKET);
+		writer.indent();
+		openSubgraphs++;
+	}
+
+	public void addSubgraphStop() throws IOException {
+		checkState(DotWriterState.STARTED);
+
+		if (openSubgraphs == 0) {
+			throw new IllegalStateException("There is no subgraph to close.");
+		}
+
+		writer.unindent();
+		writer.writeln(DotGraph.END_GRAPH_BRACKET);
+		openSubgraphs--;
+	}
+
+	public void addClusterStart(final String name) throws IOException {
+		addSubgraphStart(DotGraph.CLUSTER_PREFIX + name);
+	}
+
+	public void addClusterStop() throws IOException {
+		addSubgraphStop();
+	}
+
+	private void checkState(final DotWriterState expectedState) {
+		if (state != expectedState) {
+			switch (expectedState) {
+			case CREATED:
+				throw new IllegalStateException("The writing has already been started.");
+			case STARTED:
+				throw new IllegalStateException("The writing has never started or already been finished.");
+			case FINISHED:
+				throw new IllegalStateException("The writing has not been finished.");
+			default:
+				throw new IllegalStateException();
+			}
+		}
+	}
+
+	private String assembleAttributes(final Map<String, String> attributes) {
+		return DotGraph.START_ATTRS_BRACKET
+				+ attributes.entrySet().stream()
+						.map(e -> assembleAttribute(e.getKey(), e.getValue()))
+						.collect(Collectors.joining(","))
+				+ DotGraph.END_ATTRS_BRACKET;
+	}
+
+	private String assembleAttribute(final String key, final String value) {
+		return key + DotGraph.ATTR_CONNECTOR + '"' + value + '"';
+	}
+
+	private enum DotWriterState {
+		CREATED, STARTED, FINISHED
+	}
+
+}