All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.joyqueue.toolkit.metric.Metric Maven / Gradle / Ivy

/**
 * Copyright 2019 The JoyQueue Authors.
 *
 * 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 org.joyqueue.toolkit.metric;

import org.joyqueue.toolkit.format.Format;
import org.joyqueue.toolkit.time.SystemClock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class Metric {
    private final List metricInstances;
    private final String name;
    private final String[] latencies, counters, traffics;
    private long resetTime = SystemClock.now();
    private static final Logger logger = LoggerFactory.getLogger(Metric.class);

    public Metric(String name, int instanceCount, String[] latencies, String[] counters, String[] traffics) {
        this.name = name;
        metricInstances = new ArrayList<>(instanceCount);
        IntStream.range(0, instanceCount).forEach(i -> metricInstances.add(new MetricInstance(latencies, counters, traffics)));
        this.latencies = latencies;
        this.counters = counters;
        this.traffics = traffics;
    }

    public List getMetricInstances() {
        return metricInstances;
    }

    public String getName() {
        return name;
    }


    public void reportAndReset() {
        long reportTime = SystemClock.now();
        int intervalMs = (int) (reportTime - resetTime);
        logger.info(System.lineSeparator() + "{}:{}", name, Stream.of(
                Arrays.stream(counters)
                        .map(name -> {
                            long cps = 0L;
                            if (intervalMs > 0) {
                                cps = metricInstances.stream()
                                        .mapToLong(instance -> instance.getAndResetCounter(name))
                                        .sum() * 1000L / intervalMs;
                            }
                            return String.format("%s: %d /S", name, cps);
                        }),

                Arrays.stream(traffics)
                        .map(name -> {
                            long cps = 0L;
                            if (intervalMs > 0) {
                                cps = metricInstances.stream()
                                        .mapToLong(instance -> instance.getAndResetTraffic(name))
                                        .sum() * 1000L / intervalMs;
                            }
                            return String.format("%s: %s/S", name, Format.formatSize(cps));
                        }),

                Arrays.stream(latencies)
                        .map(name -> {

                            // 算tp99, tp90
                            long[] sorted = metricInstances.stream()
                                    .map(instance -> instance.getAndResetLatencies(name))
                                    .flatMap(List::stream)
                                    .mapToLong(Long::longValue).sorted().toArray();
                            if (sorted.length > 0) {
                                double avg = Arrays.stream(sorted).average().orElse(0D) / 1000000;
                                double tp90 = sorted[(int) (sorted.length * 0.90)] / 1000000D;
                                double tp99 = sorted[(int) (sorted.length * 0.99)] / 1000000D;
                                double max = sorted[sorted.length - 1] / 1000000D;
                                return String.format("%s: %.4f/%.4f/%.4f/%.4f ms", name, avg, tp90, tp99, max);
                            } else {
                                return String.format("%s: 0/0/0/0 ms", name);
                            }
                        }))
                .reduce(Stream::concat).orElseGet(Stream::empty)
                .collect(Collectors.joining(", ")));
        resetTime = reportTime;

    }

    public static class Latency {
        private List latencies = Collections.synchronizedList(new LinkedList<>());

        void add(long latency) {
            latencies.add(latency);
        }

        List getAndReset() {
            List ret = new ArrayList<>(latencies);
            latencies.clear();
            return ret;
        }
    }

    public static class Counter {
        private final AtomicLong atomicLong = new AtomicLong(0L);

        void add(long count) {
            atomicLong.addAndGet(count);
        }

        long getAndReset() {
            return atomicLong.getAndSet(0L);
        }
    }


    public static class Traffic {
        private final AtomicLong atomicLong = new AtomicLong(0L);

        void add(long count) {
            atomicLong.addAndGet(count);
        }

        long getAndReset() {
            return atomicLong.getAndSet(0L);
        }
    }


    public static class MetricInstance {


        private Map latencies;
        private Map counters;
        private Map traffics;

        MetricInstance(String[] latencyNames, String[] counterNames, String[] trafficNames) {
            latencies = new HashMap<>(latencyNames.length);
            Arrays.stream(latencyNames).forEach(name -> latencies.put(name, new Latency()));
            counters = new HashMap<>(counterNames.length);
            Arrays.stream(counterNames).forEach(name -> counters.put(name, new Counter()));
            traffics = new HashMap<>(trafficNames.length);
            Arrays.stream(trafficNames).forEach(name -> traffics.put(name, new Traffic()));
        }

        public void addLatency(String name, long value) {
            latencies.get(name).add(value);
        }

        public void addCounter(String name, long value) {
            counters.get(name).add(value);
        }

        public void addTraffic(String name, long value) {
            traffics.get(name).add(value);
        }

        public List getAndResetLatencies(String name) {
            return latencies.get(name).getAndReset();
        }

        public long getAndResetCounter(String name) {
            return counters.get(name).getAndReset();
        }

        public long getAndResetTraffic(String name) {
            return traffics.get(name).getAndReset();
        }

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy