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

com.swirlds.common.metrics.extensions.CountPerSecond Maven / Gradle / Ivy

Go to download

Swirlds is a software platform designed to build fully-distributed applications that harness the power of the cloud without servers. Now you can develop applications with fairness in decision making, speed, trust and reliability, at a fraction of the cost of traditional server-based platforms.

There is a newer version: 0.56.6
Show newest version
/*
 * Copyright (C) 2016-2024 Hedera Hashgraph, LLC
 *
 * 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.swirlds.common.metrics.extensions;

import static com.swirlds.base.ArgumentUtils.throwArgBlank;

import com.swirlds.base.time.Time;
import com.swirlds.base.units.UnitConstants;
import com.swirlds.common.metrics.IntegerPairAccumulator;
import com.swirlds.common.time.IntegerEpochTime;
import com.swirlds.metrics.api.FloatFormats;
import com.swirlds.metrics.api.Metrics;
import java.util.Objects;

/**
 * Platform-implementation of {@link CountPerSecond}. The granularity of this metric is a millisecond. This metric needs
 * to be reset once every 25 days in order to remain accurate. If not reset at this interval, it will no longer provide
 * accurate data. Every time a snapshot is taken (which is way more frequent than 25 days) the value is reset, because
 * of this, it is highly unlikely to get inaccurate data.
 */
public class CountPerSecond {
    /** An instance that provides the current time */
    private final IntegerEpochTime time;

    /** Used to atomically update and reset the time and count */
    private final IntegerPairAccumulator accumulator;

    /**
     * The default constructor, uses the {@link Time#getCurrent()}
     *
     * @param config the configuration for this metric
     */
    public CountPerSecond(final Metrics metrics, final CountPerSecond.Config config) {
        this(metrics, config, new IntegerEpochTime(Time.getCurrent()));
    }

    /**
     * A constructor where a custom {@link Time} instance could be supplied
     *
     * @param config the configuration for this metric
     * @param time   provides the current time
     */
    public CountPerSecond(final Metrics metrics, final CountPerSecond.Config config, final IntegerEpochTime time) {
        this.time = time;
        this.accumulator = metrics.getOrCreate(new IntegerPairAccumulator.Config<>(
                        config.getCategory(), config.getName(), Double.class, this::perSecond)
                .withDescription(config.getDescription())
                .withUnit(config.getUnit())
                .withFormat(config.getFormat())
                .withLeftAccumulator(CountPerSecond::noChangeAccumulator)
                .withRightAccumulator(Integer::sum)
                .withLeftInitializer(this.time::getMilliTime)
                .withRightInitialValue(0));
    }

    /**
     * An implementation of a {@link com.swirlds.metrics.api.IntegerAccumulator} that does not change the value
     */
    public static int noChangeAccumulator(final int currentValue, final int ignored) {
        return currentValue;
    }

    /**
     * Increase the count by 1
     */
    public void count() {
        count(1);
    }

    /**
     * Increase the count by the value provided
     *
     * @param count the amount to increase the count by
     */
    public void count(final int count) {
        accumulator.update(0, count);
    }

    /**
     * Calculates the count per second from the time provided time until now
     *
     * @param startTime the time at which we started counting
     * @param count     the count
     * @return the count per second
     */
    private double perSecond(final int startTime, final int count) {
        int millisElapsed = time.millisElapsed(startTime);
        if (millisElapsed == 0) {
            // theoretically this is infinity, but we will say that 1 millisecond of time passed because some time has
            // to have passed
            millisElapsed = 1;
        }
        return count / (millisElapsed * UnitConstants.MILLISECONDS_TO_SECONDS);
    }

    /**
     * This method resets a {@code Metric}. It is for example called after startup to ensure that the startup time is
     * not taken into consideration.
     */
    public void reset() {
        accumulator.reset();
    }

    /**
     * @return the current count per second
     */
    public double get() {
        return accumulator.get();
    }

    /**
     * Configuration of a {@link com.swirlds.metrics.api.LongAccumulator}
     */
    public static final class Config {

        private final String category;
        private final String name;

        private final String description;
        private final String unit;
        private final String format;

        /**
         * Constructor of {@link CountPerSecond.Config}
         *
         * @param category the kind of metric (metrics are grouped or filtered by this)
         * @param name     a short name for the metric
         */
        public Config(final String category, final String name) {
            this(category, name, name, "Hz", FloatFormats.FORMAT_10_2);
        }

        private Config(
                final String category,
                final String name,
                final String description,
                final String unit,
                final String format) {
            this.category = throwArgBlank(category, "category");
            this.name = throwArgBlank(name, "name");
            this.description = throwArgBlank(description, "description");
            this.unit = Objects.requireNonNull(unit, "unit must not be null");
            this.format = throwArgBlank(format, "format");
        }

        /**
         * Getter of the {@link com.swirlds.metrics.api.Metric#getCategory() Metric.category}
         *
         * @return the {@code category}
         */
        public String getCategory() {
            return category;
        }

        /**
         * Getter of the {@link com.swirlds.metrics.api.Metric#getName() Metric.name}
         *
         * @return the {@code name}
         */
        public String getName() {
            return name;
        }

        /**
         * Getter of the {@link com.swirlds.metrics.api.Metric#getDescription() Metric.description}
         *
         * @return the {@code description}
         */
        public String getDescription() {
            return description;
        }

        /**
         * Sets the {@link com.swirlds.metrics.api.Metric#getDescription() Metric.description} in fluent style.
         *
         * @param description the description
         * @return a new configuration-object with updated {@code description}
         * @throws IllegalArgumentException if {@code description} is {@code null}, too long or consists only of
         *                                  whitespaces
         */
        public CountPerSecond.Config withDescription(final String description) {
            return new CountPerSecond.Config(getCategory(), getName(), description, getUnit(), getFormat());
        }

        /**
         * Getter of the {@link com.swirlds.metrics.api.Metric#getUnit() Metric.unit}
         *
         * @return the {@code unit}
         */
        public String getUnit() {
            return unit;
        }

        /**
         * Sets the {@link com.swirlds.metrics.api.Metric#getUnit() Metric.unit} in fluent style.
         *
         * @param unit the unit
         * @return a new configuration-object with updated {@code unit}
         * @throws IllegalArgumentException if {@code unit} is {@code null}
         */
        public CountPerSecond.Config withUnit(final String unit) {
            return new CountPerSecond.Config(getCategory(), getName(), getDescription(), unit, getFormat());
        }

        /**
         * Getter of the {@link com.swirlds.metrics.api.Metric#getFormat() Metric.format}
         *
         * @return the format-{@code String}
         */
        public String getFormat() {
            return format;
        }

        /**
         * Sets the {@link com.swirlds.metrics.api.Metric#getFormat() Metric.format} in fluent style.
         *
         * @param format the format-string
         * @return a new configuration-object with updated {@code format}
         * @throws IllegalArgumentException if {@code format} is {@code null} or consists only of whitespaces
         */
        public CountPerSecond.Config withFormat(final String format) {
            return new CountPerSecond.Config(getCategory(), getName(), getDescription(), getUnit(), format);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy