/** * Copyright 2015 StreamSets Inc. * * Licensed under the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.streamsets.datacollector.metrics; import com.codahale.metrics.Clock; import com.codahale.metrics.EWMA; import com.codahale.metrics.Meter; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import static java.lang.Math.exp; public class ExtendedMeter extends Meter { private static final int INTERVAL = 5; private static final double SECONDS_PER_MINUTE = 60.0; private static final int THIRTY_MINUTES = 30; private static final int ONE_HOUR_MINUTES = 60; private static final int SIX_HOURS_MINUTES = 6 * 60; private static final int TWELVE_HOURS_MINUTES = 12 * 60; private static final int TWENTY_HOURS_MINUTES = 24 * 60; private static final double M30_ALPHA = 1 - exp(-INTERVAL / SECONDS_PER_MINUTE / THIRTY_MINUTES); private static final double H1_ALPHA = 1 - exp(-INTERVAL / SECONDS_PER_MINUTE / ONE_HOUR_MINUTES); private static final double H6_ALPHA = 1 - exp(-INTERVAL / SECONDS_PER_MINUTE / SIX_HOURS_MINUTES); private static final double H12_ALPHA = 1 - exp(-INTERVAL / SECONDS_PER_MINUTE / TWELVE_HOURS_MINUTES); private static final double H24_ALPHA = 1 - exp(-INTERVAL / SECONDS_PER_MINUTE / TWENTY_HOURS_MINUTES); private static final long TICK_INTERVAL = TimeUnit.SECONDS.toNanos(5); private final EWMA m30Rate; private final EWMA h1Rate; private final EWMA h6Rate; private final EWMA h12Rate; private final EWMA h24Rate; private final AtomicLong lastTick; private final Clock clock; public ExtendedMeter() { this(Clock.defaultClock()); } public ExtendedMeter(Clock clock) { super(clock); this.clock = clock; this.lastTick = new AtomicLong(this.clock.getTick()); m30Rate = new EWMA(M30_ALPHA, INTERVAL, TimeUnit.SECONDS); h1Rate = new EWMA(H1_ALPHA, INTERVAL, TimeUnit.SECONDS); h6Rate = new EWMA(H6_ALPHA, INTERVAL, TimeUnit.SECONDS); h12Rate = new EWMA(H12_ALPHA, INTERVAL, TimeUnit.SECONDS); h24Rate = new EWMA(H24_ALPHA, INTERVAL, TimeUnit.SECONDS); } @Override public void mark(long n) { super.mark(n); tickIfNecessary(); m30Rate.update(n); h1Rate.update(n); h6Rate.update(n); h12Rate.update(n); h24Rate.update(n); } private void tickIfNecessary() { final long oldTick = lastTick.get(); final long newTick = clock.getTick(); final long age = newTick - oldTick; if (age > TICK_INTERVAL) { final long newIntervalStartTick = newTick - age % TICK_INTERVAL; if (lastTick.compareAndSet(oldTick, newIntervalStartTick)) { final long requiredTicks = age / TICK_INTERVAL; for (long i = 0; i < requiredTicks; i++) { m30Rate.tick(); h1Rate.tick(); h6Rate.tick(); h12Rate.tick(); h24Rate.tick(); } } } } public double getThirtyMinuteRate() { tickIfNecessary(); return m30Rate.getRate(TimeUnit.SECONDS); } public double getOneHourRate() { tickIfNecessary(); return h1Rate.getRate(TimeUnit.SECONDS); } public double getSixHourRate() { tickIfNecessary(); return h6Rate.getRate(TimeUnit.SECONDS); } public double getTwelveHourRate() { tickIfNecessary(); return h12Rate.getRate(TimeUnit.SECONDS); } public double getTwentyFourHourRate() { tickIfNecessary(); return h24Rate.getRate(TimeUnit.SECONDS); } }