/**
 * Copyright 2017 Pivotal Software, Inc.
 * <p>
 * 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
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * 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 io.micrometer.core.samples;

import cern.jet.random.Normal;
import cern.jet.random.engine.MersenneTwister64;
import cern.jet.random.engine.RandomEngine;
import io.micrometer.core.instrument.FunctionTimer;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.samples.utils.SampleRegistries;
import reactor.core.publisher.Flux;

import java.time.Duration;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class FunctionTimerSample {
    public static void main(String[] args) {
        MeterRegistry registry = SampleRegistries.atlas();
        Timer timer = Timer.builder("timer")
            .publishPercentiles(0.5, 0.95)
            .register(registry);

        FunctionTimer.builder("ftimer", timer, Timer::count, t -> t.totalTime(TimeUnit.SECONDS), TimeUnit.SECONDS)
            .register(registry);

        RandomEngine r = new MersenneTwister64(0);
        Normal incomingRequests = new Normal(0, 1, r);
        Normal duration = new Normal(250, 50, r);

        AtomicInteger latencyForThisSecond = new AtomicInteger(duration.nextInt());
        Flux.interval(Duration.ofSeconds(1))
            .doOnEach(d -> latencyForThisSecond.set(duration.nextInt()))
            .subscribe();

        // the potential for an "incoming request" every 10 ms
        Flux.interval(Duration.ofMillis(10))
            .doOnEach(d -> {
                if (incomingRequests.nextDouble() + 0.4 > 0) {
                    // pretend the request took some amount of time, such that the time is
                    // distributed normally with a mean of 250ms
                    timer.record(latencyForThisSecond.get(), TimeUnit.MILLISECONDS);
                }
            })
            .blockLast();
    }
}

@@ -913,24 +913,77 @@
 ment.Timer;%0A
+import io.micrometer.core.instrument.util.TimeUtils;%0A
 import io.mi
@@ -1184,43 +1184,231 @@
 er;%0A
-%0Apublic class FunctionTimerSample %7B
+import java.util.concurrent.atomic.AtomicLong;%0A%0Apublic class FunctionTimerSample %7B%0A    /**%0A     * For Atlas: http://localhost:7101/api/v1/graph?q=name,ftimer,:eq,:dist-avg,name,timer,:eq,:dist-avg,1,:axis&s=e-5m&l=0%0A     */
 %0A   
@@ -1504,24 +1504,25 @@
 es.atlas();%0A
+%0A
         Time
@@ -1643,68 +1643,231 @@
     
-FunctionTimer.builder(%22ftimer%22, timer, Timer::count, t
+Object placeholder = new Object();%0A        AtomicLong totalTimeNanos = new AtomicLong(0);%0A        AtomicLong totalCount = new AtomicLong(0);%0A%0A        FunctionTimer.builder(%22ftimer%22, placeholder, p -%3E totalCount.get(), p
  -%3E 
-t.
 tota
@@ -1875,25 +1875,18 @@
 Time
-(TimeUnit.SECONDS
+Nanos.get(
 ), T
@@ -1893,16 +1893,20 @@
 imeUnit.
+NANO
 SECONDS)
@@ -2767,16 +2767,193 @@
 CONDS);%0A
+                    totalCount.incrementAndGet();%0A                    totalTimeNanos.addAndGet((long) TimeUtils.millisToUnit(latencyForThisSecond.get(), TimeUnit.NANOSECONDS));%0A
         

Update FunctionTimerSample (issue #275)