package org.coderthoughts.service.spector.methodtimer;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.coderthoughts.service.spector.ServiceAspect;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ServiceScope;

@Component(scope=ServiceScope.PROTOTYPE)
public class MethodTimer implements ServiceAspect {
    Map<String, Queue<Long>> invocationDurations = new ConcurrentHashMap<>();
    ThreadLocal<Long> startNanoThreadLocal = new ThreadLocal<>();

    @Override
    public void preServiceInvoke(Object service, Method method, Object[] args) throws Exception {
        startNanoThreadLocal.set(System.nanoTime());
    }

    @Override
    public void postServiceInvoke(Object service, Method method, Object[] args, Object result) throws Exception {
        long endNanos = System.nanoTime();
        long startNanos = startNanoThreadLocal.get();
        long duration = endNanos - startNanos;
        startNanoThreadLocal.remove();

        Class<?> declaringClass = method.getDeclaringClass();
        String key = declaringClass.getSimpleName() + "#" + method.getName();
        invocationDurations.computeIfAbsent(key, k -> new ConcurrentLinkedQueue<>()).add(duration);
    }

    @Override
    public void report() {
        System.out.println("Invocation duration (nanoseconds)");
        System.out.println("=================================");
        for (Map.Entry<String, Queue<Long>> entry : invocationDurations.entrySet()) {
            long average = (long) entry.getValue().stream().mapToLong(Long::longValue).average().getAsDouble();
            System.out.println(entry.getKey() + ": " + average);
        }
        System.out.println();
    }
}

@@ -283,16 +283,60 @@
 Aspect;%0A
+import org.osgi.framework.ServiceReference;%0A
 import o
@@ -679,24 +679,137 @@
 Local%3C%3E();%0A%0A
+    @Override%0A    public String announce() %7B%0A        return %22Invocation Duration measurement started.%5Cn%22;%0A    %7D%0A%0A
     @Overrid
@@ -835,38 +835,51 @@
 reServiceInvoke(
-Object
+ServiceReference%3C?%3E
  service, Method
@@ -901,33 +901,16 @@
 %5B%5D args)
- throws Exception
  %7B%0A     
@@ -1012,22 +1012,35 @@
 eInvoke(
-Object
+ServiceReference%3C?%3E
  service
@@ -1089,25 +1089,8 @@
 ult)
- throws Exception
  %7B%0A 
@@ -1544,20 +1544,22 @@
  public 
-void
+String
  report(
@@ -1571,33 +1571,72 @@
        S
-ystem.out.println
+tringBuilder sb = new StringBuilder();%0A        sb.append
 (%22Invoca
@@ -1662,16 +1662,18 @@
 seconds)
+%5Cn
 %22);%0A    
@@ -1676,34 +1676,25 @@
         
-System.out.println
+sb.append
 (%22======
@@ -1720,16 +1720,18 @@
 ========
+%5Cn
 %22);%0A    
@@ -1936,34 +1936,25 @@
         
-System.out.println
+sb.append
 (entry.g
@@ -1977,16 +1977,23 @@
  average
+ + %22%5Cn%22
 );%0A     
@@ -2009,26 +2009,26 @@
     
-System.out.println
+return sb.toString
 ();%0A

Refactor ServiceAspect API.