/** * Copyright 2013 Netflix, 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 com.netflix.servo.monitor; import com.netflix.servo.stats.StatsConfig; import com.netflix.servo.tag.Tags; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** * A {@link Timer} that provides statistics. * <p/> * The statistics are collected periodically and are published according to the configuration * specified by the user using a {@link com.netflix.servo.stats.StatsConfig} object. Please * make sure that the sampleSize corresponds to roughly the number of samples expected in * a reporting interval. While the statistics collected are accurate for this machine they will not * be correct if they are aggregated across groups of machines. * If that is an expected use-case a better * approach is to use buckets that correspond to different times. * For example you might have a counter * that tracks how many calls took < 20ms, one for [ 20ms, 500ms ], and one for > 500ms. * This bucketing approach can be easily aggregated. * See {@link com.netflix.servo.monitor.BucketTimer} */ public class StatsTimer extends StatsMonitor implements Timer { private final TimeUnit timeUnit; private static final String UNIT = "unit"; /** * Creates a new instance of the timer with a unit of milliseconds, using the default executor. */ public StatsTimer(MonitorConfig baseConfig, StatsConfig statsConfig) { this(baseConfig, statsConfig, TimeUnit.MILLISECONDS, DEFAULT_EXECUTOR); } /** * Creates a new instance of the timer with a given unit, using the default executor. */ public StatsTimer(MonitorConfig baseConfig, StatsConfig statsConfig, TimeUnit unit) { this(baseConfig, statsConfig, unit, DEFAULT_EXECUTOR); } /** * Creates a new instance of the timer with a unit of milliseconds, * using the {@link ScheduledExecutorService} provided by * the user. * To avoid memory leaks the ScheduledExecutorService * should have the policy to remove tasks from the work queue. * See {@link java.util.concurrent.ScheduledThreadPoolExecutor#setRemoveOnCancelPolicy(boolean)} */ public StatsTimer(MonitorConfig config, StatsConfig statsConfig, TimeUnit unit, ScheduledExecutorService executor) { super(config, statsConfig, executor, "totalTime", false, Tags.newTag(UNIT, unit.name())); this.timeUnit = unit; startComputingStats(); } /** * {@inheritDoc} */ @Override public Stopwatch start() { Stopwatch s = new TimedStopwatch(this); s.start(); return s; } /** * {@inheritDoc} */ @Override public TimeUnit getTimeUnit() { return timeUnit; } /** * {@inheritDoc} */ @Override public void record(long duration, TimeUnit timeUnit) { record(this.timeUnit.convert(duration, timeUnit)); } /** * {@inheritDoc} */ @Override public String toString() { return "StatsTimer{StatsMonitor=" + super.toString() + ", timeUnit=" + timeUnit + '}'; } /** * {@inheritDoc} */ @Override public boolean equals(Object obj) { if (!(obj instanceof StatsTimer)) { return false; } final StatsTimer m = (StatsTimer) obj; return super.equals(obj) && timeUnit.equals(m.timeUnit); } /** * {@inheritDoc} */ @Override public int hashCode() { int result = super.hashCode(); result = 31 * result + timeUnit.hashCode(); return result; } /** * Get the number of times this timer has been updated. */ public long getCount() { return count.getValue().longValue(); } /** * Get the total time recorded for this timer. */ public long getTotalTime() { return getTotalMeasurement(); } }