/*
 * 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 com.codahale.gprcproxy;

import io.grpc.Metadata;
import io.grpc.ServerStreamTracer;
import io.grpc.Status;
import java.time.Instant;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.LongAdder;
import org.HdrHistogram.Histogram;
import org.HdrHistogram.Recorder;

class StatsTracerFactory extends ServerStreamTracer.Factory {

  private final LongAdder requests = new LongAdder();
  private final LongAdder responseTime = new LongAdder();
  private final Recorder latency = new Recorder(3);
  private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

  @Override
  public ServerStreamTracer newServerStreamTracer(String fullMethodName, Metadata headers) {
    requests.increment();

    return new ServerStreamTracer() {
      final long start = System.nanoTime();

      @Override
      public void streamClosed(Status status) {
        final long duration = TimeUnit.NANOSECONDS.toMicros(System.nanoTime() - start);
        responseTime.add(duration);
        latency.recordValue(duration);
      }
    };
  }

  void start() {
    executor.scheduleAtFixedRate(() -> {
      final Histogram h = latency.getIntervalHistogram();
      final long n = requests.sumThenReset();
      System.out.printf("Stats at %s ==============\n", Instant.now());
      System.out.printf("  Throughput: %d req/sec\n", n);
      System.out.printf("  Avg Response Time: %2.4fs\n",
          (double) responseTime.sumThenReset() / n * 1e-6);
      System.out.printf("  p50:  %2.2fms\n", h.getValueAtPercentile(50) * 1e-3);
      System.out.printf("  p75:  %2.2fms\n", h.getValueAtPercentile(75) * 1e-3);
      System.out.printf("  p95:  %2.2fms\n", h.getValueAtPercentile(95) * 1e-3);
      System.out.printf("  p99:  %2.2fms\n", h.getValueAtPercentile(99) * 1e-3);
      System.out.printf("  p999: %2.2fms\n", h.getValueAtPercentile(99.9) * 1e-3);
    }, 1, 1, TimeUnit.SECONDS);
  }

  void stop() {
    executor.shutdown();
  }
}

@@ -830,16 +830,63 @@
 meUnit;%0A
+import java.util.concurrent.atomic.AtomicLong;%0A
 import j
@@ -1160,32 +1160,89 @@
 ew LongAdder();%0A
+  private final AtomicLong timestamp = new AtomicLong();%0A
   private final 
@@ -1863,151 +1863,540 @@
     
-executor.scheduleAtFixedRate(() -%3E %7B%0A      final Histogram h = latency.getIntervalHistogram();%0A      final long n = requests.sumThenReset();%0A  
+timestamp.set(System.nanoTime());%0A    executor.scheduleAtFixedRate(this::report, 1, 1, TimeUnit.SECONDS);%0A  %7D%0A%0A  void stop() %7B%0A    executor.shutdown();%0A  %7D%0A%0A  private void report() %7B%0A    final double t = (System.nanoTime() - timestamp.getAndSet(System.nanoTime())) * 1e-9;%0A    final Histogram h = latency.getIntervalHistogram();%0A    final double x = requests.sumThenReset() / t;%0A    final double r, n;%0A    if (x == 0) %7B%0A      r = n = 0;%0A    %7D else %7B%0A      r = (double) responseTime.sumThenReset() / x * 1e-6;%0A      n = x * r;%0A    %7D%0A
     
@@ -2461,26 +2461,24 @@
 now());%0A    
- 
- 
 System.out.p
@@ -2499,17 +2499,20 @@
 ghput: %25
-d
+2.2f
  req/sec
@@ -2516,26 +2516,24 @@
 sec%5Cn%22, 
-n
+x
 );%0A    
- 
- 
 System.o
@@ -2578,71 +2578,77 @@
 %5Cn%22,
+ r);
 %0A    
-      (double) responseTime.sumThenReset() / n * 1e-6
+System.out.printf(%22  Avg Concurrent Clients: %252.4fs%5Cn%22, n
 );%0A
-  
     
@@ -2718,34 +2718,32 @@
 0) * 1e-3);%0A    
-  
 System.out.print
@@ -2793,34 +2793,32 @@
 le(75) * 1e-3);%0A
-  
     System.out.p
@@ -2876,34 +2876,32 @@
 5) * 1e-3);%0A    
-  
 System.out.print
@@ -2963,18 +2963,16 @@
 3);%0A    
-  
 System.o
@@ -3044,86 +3044,8 @@
 3);%0A
-    %7D, 1, 1, TimeUnit.SECONDS);%0A  %7D%0A%0A  void stop() %7B%0A    executor.shutdown();%0A
   %7D%0A

Improve reporting.