diff --git a/common/source/java/ch/systemsx/cisd/common/concurrent/MonitoringProxy.java b/common/source/java/ch/systemsx/cisd/common/concurrent/MonitoringProxy.java
index da17857d9df94540df612511bfa29cc8a9f1e6fa..9f5800482bc640c46a4c599cbf3840d4a2a7f70b 100644
--- a/common/source/java/ch/systemsx/cisd/common/concurrent/MonitoringProxy.java
+++ b/common/source/java/ch/systemsx/cisd/common/concurrent/MonitoringProxy.java
@@ -26,11 +26,13 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 
+import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
 import ch.systemsx.cisd.base.exceptions.InterruptedExceptionUnchecked;
 import ch.systemsx.cisd.base.exceptions.TimeoutExceptionUnchecked;
 import ch.systemsx.cisd.base.namedthread.NamedCallable;
@@ -106,6 +108,12 @@ public class MonitoringProxy<T>
 
     private final Map<Method, Object> errorMethodValueMap;
 
+    private final Map<Class<?>, Object> asyncOkTypeValueMap;
+
+    private final Map<Method, Object> asyncOkMethodValueMap;
+
+    private final Set<Method> asyncMethodSet;
+
     private final Set<Class<? extends Exception>> exceptionClassesSuitableForRetrying;
 
     private final MonitoringInvocationHandler handler;
@@ -122,10 +130,12 @@ public class MonitoringProxy<T>
 
     private ISimpleLogger loggerOrNull;
 
+    private LogLevel logLevelForSuccessfulCalls;
+
     private IMonitoringProxyLogger invocationLoggerOrNull;
 
     private IActivitySensor sensorOrNull;
-    
+
     private ExecutorService executorService = defaultExecutorService;
 
     private Set<MonitorCommunicator> currentOperations =
@@ -192,6 +202,22 @@ public class MonitoringProxy<T>
         result.put(Short.TYPE, (short) 0);
         result.put(Integer.TYPE, 0);
         result.put(Long.TYPE, 0L);
+        result.put(Float.TYPE, 0f);
+        result.put(Double.TYPE, 0.0);
+        return result;
+    }
+
+    private static Map<Class<?>, Object> createDefaultOKTypeValueMap()
+    {
+        final Map<Class<?>, Object> result = new HashMap<Class<?>, Object>();
+        result.put(Void.TYPE, Void.TYPE.cast(null));
+        result.put(Boolean.TYPE, true);
+        result.put(Byte.TYPE, (byte) 1);
+        result.put(Short.TYPE, (short) 1);
+        result.put(Integer.TYPE, 1);
+        result.put(Long.TYPE, 1L);
+        result.put(Float.TYPE, 1f);
+        result.put(Double.TYPE, 1.0);
         return result;
     }
 
@@ -227,42 +253,72 @@ public class MonitoringProxy<T>
         private ExecutionResult<Object> retryingExecuteInThread(final Object myProxy,
                 final Method method, final Object[] args)
         {
-            int counter = 0;
-            ExecutionResult<Object> result = null;
-            boolean willRetry;
-            do
+            final Callable<ExecutionResult<Object>> callable =
+                    new Callable<ExecutionResult<Object>>()
+                        {
+                            @Override
+                            public ExecutionResult<Object> call() throws Exception
+                            {
+                                int counter = 0;
+                                ExecutionResult<Object> result = null;
+                                boolean willRetry;
+                                do
+                                {
+                                    result = executeInThread(myProxy, method, args);
+                                    if (result.getStatus() == ExecutionStatus.COMPLETE
+                                            || result.getStatus() == ExecutionStatus.INTERRUPTED
+                                            || exceptionStatusUnsuitableForRetry(result))
+                                    {
+                                        willRetry = false;
+                                    } else
+                                    {
+                                        willRetry =
+                                                (counter++ < timingParameters
+                                                        .getMaxRetriesOnFailure());
+                                    }
+                                    if (invocationLoggerOrNull != null)
+                                    {
+                                        invocationLoggerOrNull.log(method, result, willRetry);
+                                    }
+                                    if (willRetry
+                                            && timingParameters
+                                                    .getIntervalToWaitAfterFailureMillis() > 0)
+                                    {
+                                        try
+                                        {
+                                            Thread.sleep(timingParameters
+                                                    .getIntervalToWaitAfterFailureMillis());
+                                        } catch (InterruptedException ex)
+                                        {
+                                            result = ExecutionResult.createInterrupted();
+                                            if (invocationLoggerOrNull != null)
+                                            {
+                                                invocationLoggerOrNull.log(method, result, false);
+                                            }
+                                            return result;
+                                        }
+                                    }
+                                } while (willRetry);
+                                return result;
+                            }
+                        };
+            try
             {
-                result = executeInThread(myProxy, method, args);
-                if (result.getStatus() == ExecutionStatus.COMPLETE
-                        || result.getStatus() == ExecutionStatus.INTERRUPTED
-                        || exceptionStatusUnsuitableForRetry(result))
+                if (asyncMethodSet.contains(method))
                 {
-                    willRetry = false;
+                    final Object returnValue =
+                            asyncOkMethodValueMap.containsKey(method) ? asyncOkMethodValueMap
+                                    .get(method) : asyncOkTypeValueMap.get(method.getReturnType());
+                    executorService.submit(callable);
+                    return ExecutionResult.create(returnValue);
                 } else
                 {
-                    willRetry = (counter++ < timingParameters.getMaxRetriesOnFailure());
-                }
-                if (invocationLoggerOrNull != null)
-                {
-                    invocationLoggerOrNull.log(method, result, willRetry);
-                }
-                if (willRetry && timingParameters.getIntervalToWaitAfterFailureMillis() > 0)
-                {
-                    try
-                    {
-                        Thread.sleep(timingParameters.getIntervalToWaitAfterFailureMillis());
-                    } catch (InterruptedException ex)
-                    {
-                        result = ExecutionResult.createInterrupted();
-                        if (invocationLoggerOrNull != null)
-                        {
-                            invocationLoggerOrNull.log(method, result, false);
-                        }
-                        return result;
-                    }
+                    return callable.call();
                 }
-            } while (willRetry);
-            return result;
+            } catch (Exception ex)
+            {
+                throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+            }
         }
 
         private boolean exceptionStatusUnsuitableForRetry(ExecutionResult<Object> result)
@@ -349,6 +405,12 @@ public class MonitoringProxy<T>
                                         return describe(method);
                                     }
                                 }
+
+                                @Override
+                                public LogLevel getLogLevelForSuccess()
+                                {
+                                    return logLevelForSuccessfulCalls;
+                                }
                             };
                 final ExecutionResult<Object> result =
                         ConcurrencyUtilities.getResult(future, timingParameters.getTimeoutMillis(),
@@ -387,7 +449,11 @@ public class MonitoringProxy<T>
         assert interfaceClass.isInterface();
 
         this.errorTypeValueMap = createDefaultErrorTypeValueMap();
+        this.asyncOkTypeValueMap = createDefaultOKTypeValueMap();
         this.errorMethodValueMap = new HashMap<Method, Object>();
+        this.asyncOkMethodValueMap = new HashMap<Method, Object>();
+        this.asyncMethodSet = new HashSet<Method>();
+        this.logLevelForSuccessfulCalls = LogLevel.OFF;
         this.exceptionClassesSuitableForRetrying = new HashSet<Class<? extends Exception>>();
         this.timingParameters = TimingParameters.getNoTimeoutNoRetriesParameters();
         this.delegate = new DelegatingInvocationHandler<T>(objectToProxyFor);
@@ -610,7 +676,7 @@ public class MonitoringProxy<T>
         this.loggerOrNull = newLogger;
         return this;
     }
-    
+
     /**
      * Set the <var>newExecutorService</var> to use calls to this monitoring proxy.
      * <p>
@@ -658,6 +724,45 @@ public class MonitoringProxy<T>
         return this;
     }
 
+    /**
+     * The monitoring proxy can call some methods in a simple asynchronous way. This method is to
+     * state that the given <var>method</var> should be called asynchronously.
+     * <p>
+     * <i>Note that asynchronously called methods cannot be monitored for success but will return a
+     * value signing "OK" to the caller.<i>
+     */
+    public MonitoringProxy<T> callAsynchronously(Method method)
+    {
+        asyncMethodSet.add(method);
+        return this;
+    }
+
+    /**
+     * Sets a return <var>value</var> that signals "OK" for the type <var>clazz</var>.
+     * <p>
+     * <i>A value set by this method is only relevant if the proxy is configured to run a method
+     * asynchronously.</i>
+     */
+    public <V> MonitoringProxy<T> asyncOkTypeValueMapping(Class<V> clazz, V value)
+    {
+        asyncOkTypeValueMap.put(clazz, value);
+        return this;
+    }
+
+    /**
+     * Sets a return <var>value</var> that signals "OK" for the given <var>method</var>. This
+     * <var>value</var> takes precedence over the ok type mapping for methods with the same return
+     * type.
+     * <p>
+     * <i>A value set by this method is only relevant if the proxy is configured to run a method
+     * asynchronously.</i>
+     */
+    public MonitoringProxy<T> asyncOkMethodValueMapping(Method method, Object value)
+    {
+        asyncOkMethodValueMap.put(method, value);
+        return this;
+    }
+
     /**
      * Add an {@link Exception} class that is suitable for retrying the operation.
      */
@@ -677,6 +782,17 @@ public class MonitoringProxy<T>
         return this;
     }
 
+    /**
+     * Sets a log level for successful calls to the proxy.
+     * <p>
+     * Default: {@link LogLevel#OFF}.
+     */
+    public MonitoringProxy<T> logLevelForSuccessfulCalls(LogLevel newLogLevelForSuccessfulCalls)
+    {
+        this.logLevelForSuccessfulCalls = newLogLevelForSuccessfulCalls;
+        return this;
+    }
+
     /**
      * Sets a sensor for detecting activity during a monitored method call. Activity on this sensor
      * can prevent the monitored method invocation from timing out.
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/concurrent/MonitoringProxyTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/concurrent/MonitoringProxyTest.java
index 931b3987886c536bb2a76cbac1435160f2767ddd..b448812726d99fd5e187cfcb584ef39e7c0f36f7 100644
--- a/common/sourceTest/java/ch/systemsx/cisd/common/concurrent/MonitoringProxyTest.java
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/concurrent/MonitoringProxyTest.java
@@ -42,8 +42,10 @@ import ch.systemsx.cisd.base.namedthread.NamingThreadPoolExecutor;
 import ch.systemsx.cisd.base.tests.Retry50;
 import ch.systemsx.cisd.common.TimingParameters;
 import ch.systemsx.cisd.common.concurrent.MonitoringProxy.IMonitorCommunicator;
+import ch.systemsx.cisd.common.logging.AssertingLogger;
 import ch.systemsx.cisd.common.logging.ConsoleLogger;
 import ch.systemsx.cisd.common.logging.ISimpleLogger;
+import ch.systemsx.cisd.common.logging.LogLevel;
 
 /**
  * Test cases for the {@link MonitoringProxy}.
@@ -74,10 +76,14 @@ public class MonitoringProxyTest
 
     private ITest exceptionThrowingProxy;
 
+    private AssertingLogger asyncLogger;
+
+    private ITest asynchronouslyExecutingProxy;
+
     private ITest retryingOnceExceptionThrowingProxy;
 
     private ITest retryingTwiceExceptionThrowingProxy;
-    
+
     private ITest nonDefaultExecutorServiceProxy;
 
     private static class SignalException extends RuntimeException
@@ -99,12 +105,14 @@ public class MonitoringProxyTest
     {
         void idle(boolean hang);
 
+        void idle(long[] idleTimes);
+
         void busyUpdatingActivity();
 
         void busyUpdatingActivity(IMonitorCommunicator communicator);
 
         String getString(boolean hang);
-        
+
         String getThreadName();
 
         boolean getBoolean(boolean hang);
@@ -139,9 +147,12 @@ public class MonitoringProxyTest
     {
         private final IActivityObserver observer;
 
-        TestImpl(IActivityObserver observer)
+        private final boolean checkThreadName;
+
+        TestImpl(IActivityObserver observer, boolean checkThreadName)
         {
             this.observer = observer;
+            this.checkThreadName = checkThreadName;
         }
 
         private void hang(boolean hang)
@@ -149,14 +160,24 @@ public class MonitoringProxyTest
             if (hang)
             {
                 threadToStop = Thread.currentThread();
-                while (true)
+                try
+                {
+                    while (true)
+                    {
+                    }
+                } finally
                 {
+                    threadToStop = null;
                 }
             }
         }
 
         private void checkThreadName()
         {
+            if (checkThreadName == false)
+            {
+                return;
+            }
             final String name = Thread.currentThread().getName();
             assertTrue(name, THREAD_NAME_PATTERN.matcher(name).matches());
         }
@@ -168,16 +189,31 @@ public class MonitoringProxyTest
             hang(hang);
         }
 
+        int invocationCount4 = 0;
+
+        @Override
+        public void idle(long[] idleTimes)
+        {
+            checkThreadName();
+            ConcurrencyUtilities.sleep(idleTimes[invocationCount4++]);
+        }
+
         @Override
         public void busyUpdatingActivity()
         {
             checkThreadName();
             threadToStop = Thread.currentThread();
-            final long timeToHangMillis = (long) (TIMEOUT_MILLIS * 1.5);
-            final long start = System.currentTimeMillis();
-            while (System.currentTimeMillis() - start < timeToHangMillis)
+            try
+            {
+                final long timeToHangMillis = (long) (TIMEOUT_MILLIS * 1.5);
+                final long start = System.currentTimeMillis();
+                while (System.currentTimeMillis() - start < timeToHangMillis)
+                {
+                    observer.update();
+                }
+            } finally
             {
-                observer.update();
+                threadToStop = null;
             }
         }
 
@@ -186,15 +222,21 @@ public class MonitoringProxyTest
         {
             checkThreadName();
             threadToStop = Thread.currentThread();
-            final long timeToHangMillis = (long) (TIMEOUT_MILLIS * 1.5);
-            final long start = System.currentTimeMillis();
-            while (System.currentTimeMillis() - start < timeToHangMillis)
+            try
             {
-                if (communicator.isCancelled())
+                final long timeToHangMillis = (long) (TIMEOUT_MILLIS * 1.5);
+                final long start = System.currentTimeMillis();
+                while (System.currentTimeMillis() - start < timeToHangMillis)
                 {
-                    return;
+                    if (communicator.isCancelled())
+                    {
+                        return;
+                    }
+                    communicator.update();
                 }
-                communicator.update();
+            } finally
+            {
+                threadToStop = null;
             }
         }
 
@@ -320,7 +362,7 @@ public class MonitoringProxyTest
         observerSensor = new RecordingActivityObserverSensor();
         defaultReturningProxy =
                 MonitoringProxy
-                        .create(ITest.class, new TestImpl(observerSensor))
+                        .create(ITest.class, new TestImpl(observerSensor, true))
                         .timing(TimingParameters.createNoRetries(TIMEOUT_MILLIS))
                         .errorValueOnTimeout()
                         .name(THREAD_NAME)
@@ -333,31 +375,48 @@ public class MonitoringProxyTest
                 new NamingThreadPoolExecutor("My Special Monitoring Proxy").corePoolSize(1)
                         .daemonize();
 
-        nonDefaultExecutorServiceProxy = 
+        nonDefaultExecutorServiceProxy =
                 MonitoringProxy
-                .create(ITest.class, new TestImpl(observerSensor))
-                .timing(TimingParameters.createNoRetries(TIMEOUT_MILLIS))
-                .errorValueOnTimeout()
-                .name(THREAD_NAME)
-                .errorTypeValueMapping(Status.class, Status.UUUPS)
-                .errorMethodValueMapping(
-                        ITest.class.getMethod("getSpecialStatus", new Class<?>[]
-                            { Boolean.TYPE }), Status.SPECIAL_UUUPS).sensor(observerSensor)
-                .errorLog(logger)
-                .executorService(executorService)
-                .get();
+                        .create(ITest.class, new TestImpl(observerSensor, true))
+                        .timing(TimingParameters.createNoRetries(TIMEOUT_MILLIS))
+                        .errorValueOnTimeout()
+                        .name(THREAD_NAME)
+                        .errorTypeValueMapping(Status.class, Status.UUUPS)
+                        .errorMethodValueMapping(
+                                ITest.class.getMethod("getSpecialStatus", new Class<?>[]
+                                    { Boolean.TYPE }), Status.SPECIAL_UUUPS).sensor(observerSensor)
+                        .errorLog(logger)
+                        .executorService(executorService)
+                        .get();
         exceptionThrowingProxy =
-                MonitoringProxy.create(ITest.class, new TestImpl(observerSensor))
+                MonitoringProxy.create(ITest.class, new TestImpl(observerSensor, true))
                         .timing(TimingParameters.createNoRetries(TIMEOUT_MILLIS)).name(THREAD_NAME)
-                        .sensor(observerSensor).errorLog(logger).get();
+                        .sensor(observerSensor).errorLog(logger)
+                        .get();
+        asyncLogger = new AssertingLogger();
+        asynchronouslyExecutingProxy =
+                MonitoringProxy.create(ITest.class, new TestImpl(observerSensor, false))
+                        .name(THREAD_NAME)
+                        .sensor(observerSensor)
+                        .errorLog(asyncLogger)
+                        .logLevelForSuccessfulCalls(LogLevel.INFO)
+                        .timing(TimingParameters.create(TIMEOUT_MILLIS, 1, 0L))
+                        .exceptionClassSuitableForRetrying(RetryItException.class)
+                        .callAsynchronously(ITest.class.getMethod("idle", new Class<?>[]
+                            { long[].class }))
+                        .callAsynchronously(ITest.class.getMethod("throwSignalException"))
+                        .callAsynchronously(ITest.class.getMethod("worksOnSecondInvocation"))
+                        .callAsynchronously(ITest.class.getMethod("getInteger", new Class<?>[]
+                            { Boolean.TYPE }))
+                        .get();
         retryingOnceExceptionThrowingProxy =
-                MonitoringProxy.create(ITest.class, new TestImpl(observerSensor))
+                MonitoringProxy.create(ITest.class, new TestImpl(observerSensor, true))
                         .timing(TimingParameters.create(TIMEOUT_MILLIS, 1, 0L)).name(THREAD_NAME)
                         .sensor(observerSensor)
                         .exceptionClassSuitableForRetrying(RetryItException.class).errorLog(logger)
                         .get();
         retryingTwiceExceptionThrowingProxy =
-                MonitoringProxy.create(ITest.class, new TestImpl(observerSensor))
+                MonitoringProxy.create(ITest.class, new TestImpl(observerSensor, true))
                         .timing(TimingParameters.create(TIMEOUT_MILLIS, 2, 0L)).name(THREAD_NAME)
                         .sensor(observerSensor)
                         .exceptionClassSuitableForRetrying(RetryItException.class).errorLog(logger)
@@ -400,32 +459,120 @@ public class MonitoringProxyTest
         final String threadName = nonDefaultExecutorServiceProxy.getThreadName();
         assertTrue(threadName, MY_SPECIAL_THREAD_NAME_PATTERN.matcher(threadName).matches());
     }
-    
+
     @Test(expectedExceptions = SignalException.class, retryAnalyzer = Retry50.class)
     public void testThrowExceptionNullReturningPolicy()
     {
         defaultReturningProxy.throwSignalException();
     }
 
-    @Test(expectedExceptions = SignalException.class, retryAnalyzer = Retry50.class)
+    @Test
+    public void testWorksOnSecondInvocationOnAsynchronouslyCalledMethod()
+    {
+        asyncLogger.reset();
+        asynchronouslyExecutingProxy.worksOnSecondInvocation();
+        for (int i = 0; i < 10; ++i)
+        {
+            if (asyncLogger.getNumberOfRecords() > 1)
+            {
+                break;
+            }
+            ConcurrencyUtilities.sleep(100L);
+        }
+        asyncLogger.assertNumberOfMessage(2);
+        asyncLogger
+                .assertEq(
+                        0,
+                        LogLevel.ERROR,
+                        "Call to method 'ITest.worksOnSecondInvocation()'[Some Flaky Stuff]: exception: <no message> [RetryItException].");
+        asyncLogger
+                .assertEq(
+                        1,
+                        LogLevel.INFO,
+                        "Call to method 'ITest.worksOnSecondInvocation()'[Some Flaky Stuff]: call returns null.");
+    }
+
+    @Test(retryAnalyzer = Retry50.class, successPercentage = 2)
+    public void testGetIntegerAsynchronouslyCalledMethod()
+    {
+        asyncLogger.reset();
+        assertEquals(1, asynchronouslyExecutingProxy.getInteger(false));
+        for (int i = 0; i < 20; ++i)
+        {
+            if (asyncLogger.getNumberOfRecords() > 0)
+            {
+                break;
+            }
+            ConcurrencyUtilities.sleep(100L);
+        }
+        asyncLogger.assertNumberOfMessage(1);
+        asyncLogger.assertEq(0, LogLevel.INFO,
+                "Call to method 'ITest.getInteger(boolean)'[Some Flaky Stuff]: call returns 17.");
+    }
+
+    @Test(groups = "slow", retryAnalyzer = Retry50.class, successPercentage = 2)
+    public void testTimeoutOnAsynchronouslyCalledMethod()
+    {
+        asyncLogger.reset();
+        final long start = System.currentTimeMillis();
+        asynchronouslyExecutingProxy.idle(new long[]
+            { 3000L, 0L });
+        final long stop = System.currentTimeMillis();
+        assertTrue(Long.toString(stop - start), (stop - start) < 20);
+        for (int i = 0; i < 30; ++i)
+        {
+            if (asyncLogger.getNumberOfRecords() > 1)
+            {
+                break;
+            }
+            ConcurrencyUtilities.sleep(100L);
+        }
+        asyncLogger.assertNumberOfMessage(2);
+        asyncLogger
+                .assertEq(0, LogLevel.ERROR,
+                        "Call to method 'ITest.idle(long[])'[Some Flaky Stuff]: timeout of 2.00 s exceeded, cancelled.");
+        asyncLogger.assertEq(1, LogLevel.INFO,
+                "Call to method 'ITest.idle(long[])'[Some Flaky Stuff]: call returns null.");
+    }
+
+    @Test(groups = "slow", retryAnalyzer = Retry50.class, successPercentage = 2)
+    public void testThrowExceptionOnAsynchronouslyCalledMethod()
+    {
+        asyncLogger.reset();
+        asynchronouslyExecutingProxy.throwSignalException();
+        for (int i = 0; i < 30; ++i)
+        {
+            if (asyncLogger.getNumberOfRecords() > 0)
+            {
+                break;
+            }
+            ConcurrencyUtilities.sleep(100L);
+        }
+        asyncLogger.assertNumberOfMessage(1);
+        asyncLogger.assertEq(0, LogLevel.ERROR,
+                "Call to method 'ITest.throwSignalException()'[Some Flaky Stuff]:" +
+                        " exception: <no message> [SignalException].");
+    }
+
+    @Test(expectedExceptions = SignalException.class, retryAnalyzer = Retry50.class, successPercentage = 2)
     public void testThrowExceptionExceptionThrowsPolicy()
     {
         exceptionThrowingProxy.throwSignalException();
     }
 
-    @Test(groups = "slow", expectedExceptions = TimeoutExceptionUnchecked.class, retryAnalyzer = Retry50.class)
+    @Test(groups = "slow", expectedExceptions = TimeoutExceptionUnchecked.class, retryAnalyzer = Retry50.class, successPercentage = 2)
     public void testVoidTimeoutWithException()
     {
         exceptionThrowingProxy.idle(true);
     }
 
-    @Test(groups = "slow", retryAnalyzer = Retry50.class)
+    @Test(groups = "slow", retryAnalyzer = Retry50.class, successPercentage = 2)
     public void testNoTimeoutDueToSensorUpdate()
     {
         exceptionThrowingProxy.busyUpdatingActivity();
     }
 
-    @Test(groups = "slow", retryAnalyzer = Retry50.class)
+    @Test(groups = "slow", retryAnalyzer = Retry50.class, successPercentage = 2)
     public void testNoTimeoutDueToCommunicatorUpdate()
     {
         exceptionThrowingProxy.busyUpdatingActivity(null);
@@ -449,65 +596,65 @@ public class MonitoringProxyTest
         assertNull(defaultReturningProxy.getString(true));
     }
 
-    @Test(groups = "slow", expectedExceptions = TimeoutExceptionUnchecked.class, retryAnalyzer = Retry50.class)
+    @Test(groups = "slow", expectedExceptions = TimeoutExceptionUnchecked.class, retryAnalyzer = Retry50.class, successPercentage = 2)
     public void testGetStringTimeoutWithException()
     {
         exceptionThrowingProxy.getString(true);
     }
 
-    @Test(retryAnalyzer = Retry50.class)
+    @Test(retryAnalyzer = Retry50.class, successPercentage = 2)
     public void testGetIntNullReturningPolicy()
     {
         assertEquals(THE_INTEGER, defaultReturningProxy.getInteger(false));
     }
 
-    @Test(retryAnalyzer = Retry50.class)
+    @Test(retryAnalyzer = Retry50.class, successPercentage = 2)
     public void testGetIntExceptionThrowingPolicy()
     {
         assertEquals(THE_INTEGER, exceptionThrowingProxy.getInteger(false));
     }
 
-    @Test(groups = "slow", retryAnalyzer = Retry50.class)
+    @Test(groups = "slow", retryAnalyzer = Retry50.class, successPercentage = 2)
     public void testGetBoolTimeoutReturnsDefault()
     {
         assertEquals(false, defaultReturningProxy.getBoolean(true));
     }
 
-    @Test(retryAnalyzer = Retry50.class)
+    @Test(retryAnalyzer = Retry50.class, successPercentage = 2)
     public void testGetStatus()
     {
         assertEquals(THE_STATUS, defaultReturningProxy.getStatus(false));
     }
 
-    @Test(groups = "slow", retryAnalyzer = Retry50.class)
+    @Test(groups = "slow", retryAnalyzer = Retry50.class, successPercentage = 2)
     public void testGetStatusTimeoutReturnsDefault()
     {
         assertEquals(Status.UUUPS, defaultReturningProxy.getStatus(true));
     }
 
-    @Test(groups = "slow", retryAnalyzer = Retry50.class)
+    @Test(groups = "slow", retryAnalyzer = Retry50.class, successPercentage = 2)
     public void testGetSpecialStatusTimeoutReturnsMethodDefault()
     {
         assertEquals(Status.SPECIAL_UUUPS, defaultReturningProxy.getSpecialStatus(true));
     }
 
-    @Test(groups = "slow", retryAnalyzer = Retry50.class)
+    @Test(groups = "slow", retryAnalyzer = Retry50.class, successPercentage = 2)
     public void testGetIntTimeoutReturnsDefault()
     {
         assertEquals(0, defaultReturningProxy.getInteger(true));
     }
 
-    @Test(groups = "slow", expectedExceptions = TimeoutExceptionUnchecked.class, retryAnalyzer = Retry50.class)
+    @Test(groups = "slow", expectedExceptions = TimeoutExceptionUnchecked.class, retryAnalyzer = Retry50.class, successPercentage = 2)
     public void testGetIntTimeoutWithException()
     {
         exceptionThrowingProxy.getInteger(true);
     }
 
-    @Test(groups = "slow", expectedExceptions = InterruptedExceptionUnchecked.class, retryAnalyzer = Retry50.class)
+    @Test(groups = "slow", expectedExceptions = InterruptedExceptionUnchecked.class, retryAnalyzer = Retry50.class, successPercentage = 2)
     public void testInterruptTheUninterruptableThrowsException()
     {
         final ITest proxy =
-                MonitoringProxy.create(ITest.class, new TestImpl(observerSensor))
+                MonitoringProxy.create(ITest.class, new TestImpl(observerSensor, true))
                         .timing(TimingParameters.create(1000L)).name(THREAD_NAME).get();
         final Thread currentThread = Thread.currentThread();
         final Timer timer = new Timer();
@@ -525,12 +672,12 @@ public class MonitoringProxyTest
         timer.cancel();
     }
 
-    @Test(groups = "slow", retryAnalyzer = Retry50.class)
+    @Test(groups = "slow", retryAnalyzer = Retry50.class, successPercentage = 2)
     public void testInterruptTheUninterruptableReturnsDefaultValue()
     {
         final String defaultReturnValue = "That's the default return value.";
         final ITest proxy =
-                MonitoringProxy.create(ITest.class, new TestImpl(observerSensor))
+                MonitoringProxy.create(ITest.class, new TestImpl(observerSensor, true))
                         .timing(TimingParameters.create(1000L)).name(THREAD_NAME)
                         .errorValueOnInterrupt()
                         .errorTypeValueMapping(String.class, defaultReturnValue).get();
@@ -556,14 +703,14 @@ public class MonitoringProxyTest
         exceptionThrowingProxy.worksOnSecondInvocation();
     }
 
-    @Test(retryAnalyzer = Retry50.class)
+    @Test(retryAnalyzer = Retry50.class, successPercentage = 2)
     public void testRetryOnceFailOnce()
     {
         retryingOnceExceptionThrowingProxy.worksOnSecondInvocation();
     }
 
     @Test(groups =
-        { "slow" }, retryAnalyzer = Retry50.class)
+        { "slow" }, retryAnalyzer = Retry50.class, successPercentage = 2)
     public void testRetryOnceFailOnceWithCommunicator()
     {
         retryingOnceExceptionThrowingProxy.resetInvocationsCancelled();
@@ -579,19 +726,19 @@ public class MonitoringProxyTest
         retryingOnceExceptionThrowingProxy.worksOnThirdInvocation();
     }
 
-    @Test(groups = "slow", retryAnalyzer = Retry50.class)
+    @Test(groups = "slow", retryAnalyzer = Retry50.class, successPercentage = 2)
     public void testRetryTwiceFailTwice()
     {
         retryingTwiceExceptionThrowingProxy.worksOnThirdInvocation();
     }
 
-    @Test(retryAnalyzer = Retry50.class)
+    @Test(retryAnalyzer = Retry50.class, successPercentage = 2)
     public void testInvocationLog()
     {
         final List<ExecutionResult<Object>> results = new ArrayList<ExecutionResult<Object>>();
         final List<Boolean> retryFlags = new ArrayList<Boolean>();
         final ITest proxy =
-                MonitoringProxy.create(ITest.class, new TestImpl(observerSensor))
+                MonitoringProxy.create(ITest.class, new TestImpl(observerSensor, true))
                         .timing(TimingParameters.create(TIMEOUT_MILLIS, 2, 0L)).name(THREAD_NAME)
                         .sensor(observerSensor)
                         .exceptionClassSuitableForRetrying(RetryItException.class)
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/logging/AssertingLogger.java b/common/sourceTest/java/ch/systemsx/cisd/common/logging/AssertingLogger.java
index 3896220960a29691c253df1a62b2a33acea6596e..525227879dba85dc81d244507eb2ea1c97c2a3ea 100644
--- a/common/sourceTest/java/ch/systemsx/cisd/common/logging/AssertingLogger.java
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/logging/AssertingLogger.java
@@ -20,6 +20,7 @@ import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertTrue;
 
+import java.io.PrintStream;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -44,6 +45,11 @@ public class AssertingLogger implements ISimpleLogger
         records.add(new LogRecord(level, message, throwableOrNull));
     }
 
+    public void reset()
+    {
+        records.clear();
+    }
+    
     public void assertNumberOfMessage(final int expectedNumberOfMessages)
     {
         assertEquals(expectedNumberOfMessages, records.size());
@@ -79,6 +85,19 @@ public class AssertingLogger implements ISimpleLogger
         assertTrue(assertError, message.matches(throwableMessagePattern));
     }
 
+    public int getNumberOfRecords()
+    {
+        return records.size();
+    }
+    
+    public void print(PrintStream out)
+    {
+        for (LogRecord record : records)
+        {
+            out.println(record);
+        }
+    }
+    
     private static class LogRecord
     {
         final LogLevel level;
@@ -93,5 +112,19 @@ public class AssertingLogger implements ISimpleLogger
             this.message = message;
             this.throwableOrNull = throwableOrNull;
         }
+
+        @Override
+        public String toString()
+        {
+            if (throwableOrNull != null)
+            {
+                return "LogRecord [level=" + level + ", message=" + message + ", throwable="
+                        + throwableOrNull + "]";
+                
+            } else
+            {
+                return "LogRecord [level=" + level + ", message=" + message + "]";
+            }
+        }
     }
 }
\ No newline at end of file