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

com.netflix.spectator.atlas.AtlasDistributionSummary Maven / Gradle / Ivy

There is a newer version: 1.7.21
Show newest version
/*
 * Copyright 2014-2022 Netflix, Inc.
 *
 * 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.netflix.spectator.atlas;

import com.netflix.spectator.api.Clock;
import com.netflix.spectator.api.DistributionSummary;
import com.netflix.spectator.api.Id;
import com.netflix.spectator.api.Statistic;
import com.netflix.spectator.impl.StepDouble;
import com.netflix.spectator.impl.StepLong;
import com.netflix.spectator.impl.StepValue;

import java.util.concurrent.atomic.AtomicLong;

/**
 * Distribution summary that reports four measurements to Atlas:
 *
 * 
    *
  • count: counter incremented each time record is called
  • *
  • totalAmount: counter incremented by the recorded amount
  • *
  • totalOfSquares: counter incremented by the recorded amount2
  • *
  • max: maximum recorded amount
  • *
* *

Having an explicit {@code totalAmount} and {@code count} on the backend * can be used to calculate an accurate average for an arbitrary grouping. The * {@code totalOfSquares} is used for computing a standard deviation.

* *

Note that the {@link #count()} and {@link #totalAmount()} will report * the values since the last complete interval rather than the total for the * life of the process.

*/ class AtlasDistributionSummary extends AtlasMeter implements DistributionSummary { private final StepLong count; private final StepLong total; private final StepDouble totalOfSquares; private final StepLong max; private final Id[] stats; /** Create a new instance. */ AtlasDistributionSummary(Id id, Clock clock, long ttl, long step) { super(id, clock, ttl); this.count = new StepLong(0L, clock, step); this.total = new StepLong(0L, clock, step); this.totalOfSquares = new StepDouble(0.0, clock, step); this.max = new StepLong(0L, clock, step); this.stats = new Id[] { id.withTags(DsType.rate, Statistic.count), id.withTags(DsType.rate, Statistic.totalAmount), id.withTags(DsType.rate, Statistic.totalOfSquares), id.withTags(DsType.gauge, Statistic.max) }; } @Override void measure(long now, MeasurementConsumer consumer) { reportMeasurement(now, consumer, stats[0], count); reportMeasurement(now, consumer, stats[1], total); reportMeasurement(now, consumer, stats[2], totalOfSquares); reportMaxMeasurement(now, consumer, stats[3], max); } private void reportMeasurement(long now, MeasurementConsumer consumer, Id mid, StepValue v) { // poll needs to be called before accessing the timestamp to ensure // the counters have been rotated if there was no activity in the // current interval. double rate = v.pollAsRate(now); long timestamp = v.timestamp(); consumer.accept(mid, timestamp, rate); } private void reportMaxMeasurement(long now, MeasurementConsumer consumer, Id mid, StepLong v) { // poll needs to be called before accessing the timestamp to ensure // the counters have been rotated if there was no activity in the // current interval. double maxValue = v.poll(now); long timestamp = v.timestamp(); consumer.accept(mid, timestamp, maxValue); } @Override public void record(long amount) { long now = clock.wallTime(); count.getCurrent(now).incrementAndGet(); if (amount > 0) { total.getCurrent(now).addAndGet(amount); totalOfSquares.getCurrent(now).addAndGet((double) amount * amount); updateMax(max.getCurrent(now), amount); } updateLastModTime(now); } @Override public void record(long[] amounts, int n) { final int limit = Math.min(Math.max(0, n), amounts.length); long accumulatedTotal = 0; long accumulatedMax = Long.MIN_VALUE; double accumulatedTotalOfSquares = 0.0; // accumulate results for (int i = 0; i < limit; i++) { if (amounts[i] > 0) { accumulatedTotal += amounts[i]; accumulatedTotalOfSquares += ((double) amounts[i] * amounts[i]); accumulatedMax = Math.max(amounts[i], accumulatedMax); } } // issue updates as a batch final long now = clock.wallTime(); count.getCurrent(now).addAndGet(limit); total.getCurrent(now).addAndGet(accumulatedTotal); totalOfSquares.getCurrent(now).addAndGet(accumulatedTotalOfSquares); updateMax(max.getCurrent(now), accumulatedMax); updateLastModTime(now); } private void updateMax(AtomicLong maxValue, long v) { long p = maxValue.get(); while (v > p && !maxValue.compareAndSet(p, v)) { p = maxValue.get(); } } @Override public long count() { return count.poll(); } @Override public long totalAmount() { return total.poll(); } @Override public BatchUpdater batchUpdater(int batchSize) { AtlasDistSummaryBatchUpdater updater = new AtlasDistSummaryBatchUpdater(batchSize); updater.accept(() -> this); return updater; } /** * Helper to allow the batch updater to directly update the individual stats. */ void update(long count, long total, double totalOfSquares, long max) { long now = clock.wallTime(); this.count.getCurrent(now).addAndGet(count); this.total.getCurrent(now).addAndGet(total); this.totalOfSquares.getCurrent(now).addAndGet(totalOfSquares); updateMax(this.max.getCurrent(now), max); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy