diff --git a/kieker-trace-diagnosis-application/pom.xml b/kieker-trace-diagnosis-application/pom.xml
index 86619b3049ab4a23939cc26127ec56d1e4ebf087..72ceead4646b232c623a2335a58dddc54d5c015a 100644
--- a/kieker-trace-diagnosis-application/pom.xml
+++ b/kieker-trace-diagnosis-application/pom.xml
@@ -1,4 +1,5 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 
 	<modelVersion>4.0.0</modelVersion>
 
@@ -24,6 +25,16 @@
 			<groupId>org.jfxtras</groupId>
 			<artifactId>jfxtras-controls</artifactId>
 		</dependency>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.hamcrest</groupId>
+			<artifactId>hamcrest-all</artifactId>
+			<scope>test</scope>
+		</dependency>
 	</dependencies>
 
 </project>
\ No newline at end of file
diff --git a/kieker-trace-diagnosis-application/src/main/java/kieker/diagnosis/service/data/MonitoringLogImporter.java b/kieker-trace-diagnosis-application/src/main/java/kieker/diagnosis/service/data/MonitoringLogImporter.java
index 86a23b400cdb3312eeb784d4e188aacdb829ca93..adc683a677b10a9f7f7223bd3dacbe8adee6d121 100644
--- a/kieker-trace-diagnosis-application/src/main/java/kieker/diagnosis/service/data/MonitoringLogImporter.java
+++ b/kieker-trace-diagnosis-application/src/main/java/kieker/diagnosis/service/data/MonitoringLogImporter.java
@@ -293,7 +293,7 @@ final class MonitoringLogImporter {
 
 		// Make sure that the timestamp is always in milliseconds
 		if ( DESTINATION_TIMESTAMP_TIME_UNIT != ivSourceTimeUnit ) {
-			final long newTimestamp = DESTINATION_TIMESTAMP_TIME_UNIT.convert( timestamp, ivSourceTimeUnit );
+			final long newTimestamp = DESTINATION_TIMESTAMP_TIME_UNIT.convert( lastMethodCall.getTimestamp( ), ivSourceTimeUnit );
 			lastMethodCall.setTimestamp( newTimestamp );
 		}
 
@@ -354,18 +354,18 @@ final class MonitoringLogImporter {
 			try {
 				final Class<?> recordClass = Class.forName( recordName );
 				final Field sizeField = recordClass.getDeclaredField( "SIZE" );
-				size = (byte) sizeField.get( null );
+				size = (byte) (int) sizeField.get( null );
 
 				ivIgnoredRecordsSizeMap.put( aRecordKey, size );
-				ivIgnoredRecords++;
 			} catch ( final Exception ex ) {
 				// We have no chance. We cannot skip the record, as we don't know its size.
-				throw new RuntimeException( String.format( ivResourceBundle.getString( "errorMessageUnknownRecord" ), recordName ) );
+				throw new RuntimeException( String.format( ivResourceBundle.getString( "errorMessageUnknownRecord" ), recordName ), ex );
 			}
 		} else {
 			size = ivIgnoredRecordsSizeMap.get( aRecordKey );
 		}
 
+		ivIgnoredRecords++;
 		skipBytes( size, aByteBuffer );
 	}
 
@@ -496,33 +496,44 @@ final class MonitoringLogImporter {
 
 		@Override
 		public boolean equals( final Object obj ) {
-			if ( this == obj )
+			if ( this == obj ) {
 				return true;
-			if ( obj == null )
+			}
+			if ( obj == null ) {
 				return false;
-			if ( getClass( ) != obj.getClass( ) )
+			}
+			if ( getClass( ) != obj.getClass( ) ) {
 				return false;
+			}
 			final AggregationKey other = (AggregationKey) obj;
 			if ( ivClass == null ) {
-				if ( other.ivClass != null )
+				if ( other.ivClass != null ) {
 					return false;
-			} else if ( !ivClass.equals( other.ivClass ) )
+				}
+			} else if ( !ivClass.equals( other.ivClass ) ) {
 				return false;
+			}
 			if ( ivException == null ) {
-				if ( other.ivException != null )
+				if ( other.ivException != null ) {
 					return false;
-			} else if ( !ivException.equals( other.ivException ) )
+				}
+			} else if ( !ivException.equals( other.ivException ) ) {
 				return false;
+			}
 			if ( ivHost == null ) {
-				if ( other.ivHost != null )
+				if ( other.ivHost != null ) {
 					return false;
-			} else if ( !ivHost.equals( other.ivHost ) )
+				}
+			} else if ( !ivHost.equals( other.ivHost ) ) {
 				return false;
+			}
 			if ( ivMethod == null ) {
-				if ( other.ivMethod != null )
+				if ( other.ivMethod != null ) {
 					return false;
-			} else if ( !ivMethod.equals( other.ivMethod ) )
+				}
+			} else if ( !ivMethod.equals( other.ivMethod ) ) {
 				return false;
+			}
 			return true;
 		}
 
diff --git a/kieker-trace-diagnosis-application/src/test/java/kieker/diagnosis/service/data/MonitoringLogServiceTest.java b/kieker-trace-diagnosis-application/src/test/java/kieker/diagnosis/service/data/MonitoringLogServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e122ee7393e414d5266497f464c4356881a892f1
--- /dev/null
+++ b/kieker-trace-diagnosis-application/src/test/java/kieker/diagnosis/service/data/MonitoringLogServiceTest.java
@@ -0,0 +1,358 @@
+package kieker.diagnosis.service.data;
+
+import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
+import static org.hamcrest.collection.IsEmptyCollection.empty;
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.number.OrderingComparison.greaterThan;
+import static org.junit.Assert.assertThat;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.BufferOverflowException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+
+import com.carrotsearch.hppc.ByteArrayList;
+import com.google.common.io.Files;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+
+import kieker.common.record.AbstractMonitoringRecord;
+import kieker.common.record.flow.trace.TraceMetadata;
+import kieker.common.record.flow.trace.operation.AfterOperationEvent;
+import kieker.common.record.flow.trace.operation.AfterOperationFailedEvent;
+import kieker.common.record.flow.trace.operation.BeforeOperationEvent;
+import kieker.common.record.misc.KiekerMetadataRecord;
+import kieker.common.record.system.CPUUtilizationRecord;
+import kieker.common.util.registry.IRegistry;
+import kieker.common.util.registry.Registry;
+import kieker.diagnosis.KiekerTraceDiagnosisModule;
+
+public class MonitoringLogServiceTest {
+
+	@Rule
+	public TemporaryFolder ivTemporaryFolder = new TemporaryFolder( );
+
+	@Rule
+	public ExpectedException ivExpectedException = ExpectedException.none( );
+
+	private ByteArrayList ivByteList;
+	private IRegistry<String> ivStringRegistry;
+	private MonitoringLogService ivService;
+
+	@Before
+	public void setUp( ) {
+		ivByteList = new ByteArrayList( );
+		ivStringRegistry = new Registry<>( );
+
+		final Injector injector = Guice.createInjector( new KiekerTraceDiagnosisModule( ) );
+		ivService = injector.getInstance( MonitoringLogService.class );
+	}
+
+	@Test
+	public void testEmptyDirectory( ) {
+		// Import the directory
+		final File directory = ivTemporaryFolder.getRoot( );
+		ivService.importMonitoringLog( directory );
+
+		// Make sure that nothing has been imported
+		assertThat( ivService.getMethods( ), is( empty( ) ) );
+		assertThat( ivService.getAggreatedMethods( ), is( empty( ) ) );
+		assertThat( ivService.getTraceRoots( ), is( empty( ) ) );
+		assertThat( ivService.getProcessedBytes( ), is( 0L ) );
+	}
+
+	@Test
+	public void testSingleTrace( ) throws Exception {
+		// Prepare the data
+		writeRecord( new TraceMetadata( 1L, 0L, "0", "host", 0L, 0 ) );
+		writeRecord( new BeforeOperationEvent( System.currentTimeMillis( ), 1L, 0, "op1", "class1" ) );
+		writeRecord( new BeforeOperationEvent( System.currentTimeMillis( ), 1L, 0, "op2", "class1" ) );
+		writeRecord( new AfterOperationEvent( System.currentTimeMillis( ), 1L, 0, "op2", "class1" ) );
+		writeRecord( new AfterOperationEvent( System.currentTimeMillis( ), 1L, 0, "op1", "class1" ) );
+		writeMappingFile( );
+		finishWriting( );
+
+		// Import the directory
+		final File directory = ivTemporaryFolder.getRoot( );
+		ivService.importMonitoringLog( directory );
+
+		// Make sure that the import worked as intended
+		assertThat( ivService.getMethods( ), hasSize( 2 ) );
+		assertThat( ivService.getAggreatedMethods( ), hasSize( 2 ) );
+		assertThat( ivService.getTraceRoots( ), hasSize( 1 ) );
+		assertThat( ivService.getProcessedBytes( ), is( greaterThan( 0L ) ) );
+	}
+
+	@Test
+	public void testTwoInterleavedTrace( ) throws Exception {
+		// Prepare the data
+		writeRecord( new TraceMetadata( 1L, 0L, "0", "host", 0L, 0 ) );
+		writeRecord( new BeforeOperationEvent( System.currentTimeMillis( ), 1L, 0, "op1", "class1" ) );
+		writeRecord( new BeforeOperationEvent( System.currentTimeMillis( ), 1L, 0, "op2", "class1" ) );
+		writeRecord( new TraceMetadata( 2L, 0L, "0", "host", 0L, 0 ) );
+		writeRecord( new BeforeOperationEvent( System.currentTimeMillis( ), 2L, 0, "op1", "class2" ) );
+		writeRecord( new AfterOperationEvent( System.currentTimeMillis( ), 1L, 0, "op2", "class1" ) );
+		writeRecord( new BeforeOperationEvent( System.currentTimeMillis( ), 2L, 0, "op2", "class2" ) );
+		writeRecord( new AfterOperationEvent( System.currentTimeMillis( ), 2L, 0, "op2", "class2" ) );
+		writeRecord( new AfterOperationEvent( System.currentTimeMillis( ), 1L, 0, "op1", "class1" ) );
+		writeRecord( new AfterOperationEvent( System.currentTimeMillis( ), 2L, 0, "op1", "class2" ) );
+		writeMappingFile( );
+		finishWriting( );
+
+		// Import the directory
+		final File directory = ivTemporaryFolder.getRoot( );
+		ivService.importMonitoringLog( directory );
+
+		// Make sure that the import worked as intended
+		assertThat( ivService.getMethods( ), hasSize( 4 ) );
+		assertThat( ivService.getAggreatedMethods( ), hasSize( 4 ) );
+		assertThat( ivService.getTraceRoots( ), hasSize( 2 ) );
+		assertThat( ivService.getProcessedBytes( ), is( greaterThan( 0L ) ) );
+	}
+
+	@Test
+	public void testFailedTrace( ) throws Exception {
+		// Prepare the data
+		writeRecord( new TraceMetadata( 1L, 0L, "0", "host", 0L, 0 ) );
+		writeRecord( new BeforeOperationEvent( System.currentTimeMillis( ), 1L, 0, "op1", "class1" ) );
+		writeRecord( new BeforeOperationEvent( System.currentTimeMillis( ), 1L, 0, "op2", "class1" ) );
+		writeRecord( new AfterOperationFailedEvent( System.currentTimeMillis( ), 1L, 0, "op2", "class1", "cause" ) );
+		writeRecord( new AfterOperationFailedEvent( System.currentTimeMillis( ), 1L, 0, "op1", "class1", "cause" ) );
+		writeMappingFile( );
+		finishWriting( );
+
+		// Import the directory
+		final File directory = ivTemporaryFolder.getRoot( );
+		ivService.importMonitoringLog( directory );
+
+		// Make sure that the import worked as intended
+		assertThat( ivService.getMethods( ), hasSize( 2 ) );
+		assertThat( ivService.getAggreatedMethods( ), hasSize( 2 ) );
+		assertThat( ivService.getTraceRoots( ), hasSize( 1 ) );
+		assertThat( ivService.getProcessedBytes( ), is( greaterThan( 0L ) ) );
+	}
+
+	@Test
+	public void testMethodAggregation( ) throws Exception {
+		// Prepare the data
+		writeRecord( new TraceMetadata( 1L, 0L, "0", "host", 0L, 0 ) );
+		writeRecord( new BeforeOperationEvent( System.currentTimeMillis( ), 1L, 0, "op1", "class1" ) );
+		writeRecord( new BeforeOperationEvent( System.currentTimeMillis( ), 1L, 0, "op1", "class1" ) );
+		writeRecord( new AfterOperationEvent( System.currentTimeMillis( ), 1L, 0, "op1", "class1" ) );
+		writeRecord( new BeforeOperationEvent( System.currentTimeMillis( ), 1L, 0, "op2", "class1" ) );
+		writeRecord( new AfterOperationEvent( System.currentTimeMillis( ), 1L, 0, "op2", "class1" ) );
+		writeRecord( new BeforeOperationEvent( System.currentTimeMillis( ), 1L, 0, "op1", "class2" ) );
+		writeRecord( new AfterOperationEvent( System.currentTimeMillis( ), 1L, 0, "op1", "class2" ) );
+		writeRecord( new AfterOperationEvent( System.currentTimeMillis( ), 1L, 0, "op1", "class1" ) );
+		writeMappingFile( );
+		finishWriting( );
+
+		// Import the directory
+		final File directory = ivTemporaryFolder.getRoot( );
+		ivService.importMonitoringLog( directory );
+
+		// Make sure that the import worked as intended
+		assertThat( ivService.getMethods( ), hasSize( 4 ) );
+		assertThat( ivService.getAggreatedMethods( ), hasSize( 3 ) );
+		assertThat( ivService.getTraceRoots( ), hasSize( 1 ) );
+		assertThat( ivService.getProcessedBytes( ), is( greaterThan( 0L ) ) );
+	}
+
+	@Test
+	public void testIncompleteTrace( ) throws Exception {
+		// Prepare the data
+		writeRecord( new TraceMetadata( 1L, 0L, "0", "host", 0L, 0 ) );
+		writeRecord( new BeforeOperationEvent( System.currentTimeMillis( ), 1L, 0, "op1", "class1" ) );
+		writeRecord( new BeforeOperationEvent( System.currentTimeMillis( ), 1L, 0, "op2", "class1" ) );
+		writeRecord( new AfterOperationEvent( System.currentTimeMillis( ), 1L, 0, "op2", "class1" ) );
+		writeMappingFile( );
+		finishWriting( );
+
+		// Import the directory
+		final File directory = ivTemporaryFolder.getRoot( );
+		ivService.importMonitoringLog( directory );
+
+		// Make sure that the import worked as intended
+		assertThat( ivService.getMethods( ), hasSize( 0 ) );
+		assertThat( ivService.getAggreatedMethods( ), hasSize( 0 ) );
+		assertThat( ivService.getTraceRoots( ), hasSize( 0 ) );
+		assertThat( ivService.getIncompleteTraces( ), is( 1 ) );
+		assertThat( ivService.getProcessedBytes( ), is( greaterThan( 0L ) ) );
+	}
+
+	@Test
+	public void testDanglingRecords( ) throws Exception {
+		// Prepare the data
+		writeRecord( new BeforeOperationEvent( System.currentTimeMillis( ), 1L, 0, "op1", "class1" ) );
+		writeRecord( new BeforeOperationEvent( System.currentTimeMillis( ), 1L, 0, "op2", "class1" ) );
+		writeRecord( new AfterOperationEvent( System.currentTimeMillis( ), 1L, 0, "op2", "class1" ) );
+		writeRecord( new AfterOperationEvent( System.currentTimeMillis( ), 1L, 0, "op1", "class1" ) );
+		writeMappingFile( );
+		finishWriting( );
+
+		// Import the directory
+		final File directory = ivTemporaryFolder.getRoot( );
+		ivService.importMonitoringLog( directory );
+
+		// Make sure that the import worked as intended
+		assertThat( ivService.getMethods( ), hasSize( 0 ) );
+		assertThat( ivService.getAggreatedMethods( ), hasSize( 0 ) );
+		assertThat( ivService.getTraceRoots( ), hasSize( 0 ) );
+		assertThat( ivService.getDanglingRecords( ), is( 4 ) );
+		assertThat( ivService.getProcessedBytes( ), is( greaterThan( 0L ) ) );
+	}
+
+	@Test
+	public void testDurationConversion( ) throws Exception {
+		// Prepare the data
+		writeRecord( new TraceMetadata( 1L, 0L, "0", "host", 0L, 0 ) );
+		writeRecord( new KiekerMetadataRecord( "0", "0", "0", 0, false, 0L, TimeUnit.SECONDS.name( ), 0 ) );
+		writeRecord( new BeforeOperationEvent( 10, 1L, 0, "op1", "class1" ) );
+		writeRecord( new AfterOperationFailedEvent( 20, 1L, 0, "op1", "class1", "cause" ) );
+		writeMappingFile( );
+		finishWriting( );
+
+		// Import the directory
+		final File directory = ivTemporaryFolder.getRoot( );
+		ivService.importMonitoringLog( directory );
+
+		// Make sure that the import worked as intended
+		final MethodCall methodCall = ivService.getMethods( ).get( 0 );
+		assertThat( methodCall.getDuration( ), is( 10000000000L ) );
+	}
+
+	@Test
+	public void testTimestampConversion( ) throws Exception {
+		// Prepare the data
+		writeRecord( new TraceMetadata( 1L, 0L, "0", "host", 0L, 0 ) );
+		writeRecord( new KiekerMetadataRecord( "0", "0", "0", 0, false, 0L, TimeUnit.SECONDS.name( ), 0 ) );
+		writeRecord( new BeforeOperationEvent( 10, 1L, 0, "op1", "class1" ) );
+		writeRecord( new AfterOperationFailedEvent( 20, 1L, 0, "op1", "class1", "cause" ) );
+		writeMappingFile( );
+		finishWriting( );
+
+		// Import the directory
+		final File directory = ivTemporaryFolder.getRoot( );
+		ivService.importMonitoringLog( directory );
+
+		// Make sure that the import worked as intended
+		final MethodCall methodCall = ivService.getMethods( ).get( 0 );
+		assertThat( methodCall.getTimestamp( ), is( 10000L ) );
+	}
+
+	@Test
+	public void testIgnoreRecord( ) throws Exception {
+		// Prepare the data
+		writeRecord( new CPUUtilizationRecord( 0L, "", "", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ) );
+		writeRecord( new CPUUtilizationRecord( 1L, "", "", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ) );
+
+		writeMappingFile( );
+		finishWriting( );
+
+		// Import the directory
+		final File directory = ivTemporaryFolder.getRoot( );
+		ivService.importMonitoringLog( directory );
+
+		// Make sure that the import worked as intended
+		assertThat( ivService.getMethods( ), hasSize( 0 ) );
+		assertThat( ivService.getIgnoredRecords( ), is( 2 ) );
+	}
+
+	@Test
+	public void testUnknownRecord( ) throws Exception {
+		// Prepare the data
+		writeRecord( new UnknownRecord( ) );
+
+		writeMappingFile( );
+		finishWriting( );
+
+		// The import should not work
+		ivExpectedException.expect( RuntimeException.class );
+
+		// Import the directory
+		final File directory = ivTemporaryFolder.getRoot( );
+		ivService.importMonitoringLog( directory );
+	}
+
+	private void writeRecord( final AbstractMonitoringRecord aRecord ) {
+		// Register the record name
+		final int recordKey = ivStringRegistry.get( aRecord.getClass( ).getName( ) );
+
+		// Register the record's strings
+		aRecord.registerStrings( ivStringRegistry );
+
+		// Now write the record into our buffer
+		final byte[] byteArray = new byte[aRecord.getSize( ) + 4 + 8];
+		final ByteBuffer byteBuffer = ByteBuffer.wrap( byteArray );
+		byteBuffer.putInt( recordKey );
+		byteBuffer.putLong( System.currentTimeMillis( ) );
+		aRecord.writeBytes( byteBuffer, ivStringRegistry );
+		byteBuffer.flip( );
+
+		ivByteList.add( byteArray );
+	}
+
+	private void writeMappingFile( ) throws IOException {
+		// Collect the mappings
+		final StringBuilder stringBuilder = new StringBuilder( );
+
+		final Object[] allStrings = ivStringRegistry.getAll( );
+		for ( final Object string : allStrings ) {
+			final int id = ivStringRegistry.get( (String) string );
+			stringBuilder.append( "$" ).append( id ).append( "=" ).append( string ).append( "\n" );
+		}
+
+		// Write the mapping file
+		final File mappingFile = new File( ivTemporaryFolder.getRoot( ), "kieker.map" );
+		Files.write( stringBuilder.toString( ), mappingFile, Charset.forName( "UTF-8" ) );
+	}
+
+	private void finishWriting( ) throws IOException {
+		final File binaryFile = new File( ivTemporaryFolder.getRoot( ), "kieker.bin" );
+		ivByteList.trimToSize( );
+		Files.write( ivByteList.buffer, binaryFile );
+	}
+
+	private static class UnknownRecord extends AbstractMonitoringRecord {
+
+		private static final long serialVersionUID = 1L;
+
+		@Override
+		public Object[] toArray( ) {
+			return null;
+		}
+
+		@Override
+		public void writeBytes( final ByteBuffer aBuffer, final IRegistry<String> aStringRegistry ) throws BufferOverflowException {
+		}
+
+		@Override
+		public void initFromBytes( final ByteBuffer aBuffer, final IRegistry<String> aStringRegistry ) throws BufferUnderflowException {
+		}
+
+		@Override
+		public void initFromArray( final Object[] aValues ) {
+		}
+
+		@Override
+		public Class<?>[] getValueTypes( ) {
+			return null;
+		}
+
+		@Override
+		public int getSize( ) {
+			return 0;
+		}
+
+	}
+
+}
diff --git a/kieker-trace-diagnosis-architecture/pom.xml b/kieker-trace-diagnosis-architecture/pom.xml
index 48832f34c97399ed3042dca05995d1d4d56a7d6a..679a86b405a0878f8ae25bf87905bd33f0413800 100644
--- a/kieker-trace-diagnosis-architecture/pom.xml
+++ b/kieker-trace-diagnosis-architecture/pom.xml
@@ -33,9 +33,9 @@
 			<artifactId>junit</artifactId>
 			<scope>test</scope>
 		</dependency>
-		<dependency>
+		<dependency> 
 			<groupId>org.hamcrest</groupId>
-			<artifactId>hamcrest-core</artifactId>
+			<artifactId>hamcrest-all</artifactId>
 			<scope>test</scope>
 		</dependency>
 	</dependencies>
diff --git a/kieker-trace-diagnosis-dependencies/pom.xml b/kieker-trace-diagnosis-dependencies/pom.xml
index 9fb90b9288b397b591190b5c797ffad13a297a4f..cb13c1a91779ab136d3b594686f68401f9de3375 100644
--- a/kieker-trace-diagnosis-dependencies/pom.xml
+++ b/kieker-trace-diagnosis-dependencies/pom.xml
@@ -66,7 +66,7 @@
 			</dependency>
 			<dependency>
 				<groupId>org.hamcrest</groupId>
-				<artifactId>hamcrest-core</artifactId>
+				<artifactId>hamcrest-all</artifactId>
 				<version>1.3</version>
 			</dependency>
 			<dependency>