001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.mstat;
014
015import java.lang.reflect.*;
016import java.util.*;
017import java.util.concurrent.atomic.*;
018
019import org.apache.juneau.annotation.*;
020import org.apache.juneau.marshall.*;
021import org.apache.juneau.utils.*;
022
023/**
024 * Basic timing information.
025 *
026 * Keeps track of number of starts/finishes on tasks and keeps an average run time.
027 */
028@Bean(bpi="method,runs,running,errors,minTime,maxTime,avgTime,totalTime,exceptions")
029public class MethodExecStats implements Comparable<MethodExecStats> {
030
031   private String method;
032   private volatile int minTime = -1, maxTime;
033
034   private AtomicInteger
035      starts = new AtomicInteger(),
036      finishes = new AtomicInteger(),
037      errors = new AtomicInteger();
038
039   private AtomicLong
040      totalTime = new AtomicLong();
041
042   private ExceptionStore stackTraceDb;
043
044   /**
045    * Constructor.
046    *
047    * @param method Arbitrary label.  Should be kept to less than 50 characters.
048    * @param stackTraceStopClass Don't calculate stack traces when this class is encountered.
049    */
050   public MethodExecStats(Method method, Class<?> stackTraceStopClass) {
051      this.method = method.getDeclaringClass().getSimpleName() + "." + method.getName();
052      this.stackTraceDb = new ExceptionStore(-1, stackTraceStopClass);
053   }
054
055   /**
056    * Constructor.
057    *
058    * @param method Arbitrary label.  Should be kept to less than 50 characters.
059    */
060   public MethodExecStats(Method method) {
061      this(method, MethodInvoker.class);
062   }
063
064   /**
065    * Call when task is started.
066    */
067   public void started() {
068      starts.incrementAndGet();
069   }
070
071   /**
072    * Call when task is finished.
073    * @param nanoTime The execution time of the task in nanoseconds.
074    */
075   public void finished(long nanoTime) {
076      finishes.incrementAndGet();
077      int milliTime = (int)(nanoTime/1_000_000);
078      totalTime.addAndGet(nanoTime);
079      minTime = minTime == -1 ? milliTime : Math.min(minTime, milliTime);
080      maxTime = Math.max(maxTime, milliTime);
081   }
082
083   /**
084    * Call when an error occurs.
085    * @param e The exception thrown.  Can be <jk>null</jk>.
086    */
087   public void error(Throwable e) {
088      errors.incrementAndGet();
089      stackTraceDb.add(e);
090   }
091
092   /**
093    * Returns the method name of these stats.
094    *
095    * @return The method name of these stats.
096    */
097   public String getMethod() {
098      return method;
099   }
100
101   /**
102    * Returns the number of times the {@link #started()} method was called.
103    *
104    * @return The number of times the {@link #started()} method was called.
105    */
106   public int getRuns() {
107      return starts.get();
108   }
109
110   /**
111    * Returns the number currently running method invocations.
112    *
113    * @return The number of currently running method invocations.
114    */
115   public int getRunning() {
116      return starts.get() - finishes.get();
117   }
118
119   /**
120    * Returns the number of times the {@link #error(Throwable)} method was called.
121    *
122    * @return The number of times the {@link #error(Throwable)} method was called.
123    */
124   public int getErrors() {
125      return errors.get();
126   }
127
128   /**
129    * Returns the max execution time.
130    *
131    * @return The average execution time in milliseconds.
132    */
133   public int getMinTime() {
134      return minTime == -1 ? 0 : minTime;
135   }
136
137   /**
138    * Returns the max execution time.
139    *
140    * @return The average execution time in milliseconds.
141    */
142   public int getMaxTime() {
143      return maxTime;
144   }
145
146   /**
147    * Returns the average execution time.
148    *
149    * @return The average execution time in milliseconds.
150    */
151   public int getAvgTime() {
152      int runs = getRuns();
153      return runs == 0 ? 0 : (int)(getTotalTime() / runs);
154   }
155
156   /**
157    * Returns the total execution time.
158    *
159    * @return The total execution time in milliseconds.
160    */
161   public long getTotalTime() {
162      return totalTime.get() / 1_000_000;
163   }
164
165   /**
166    * Returns information on all stack traces of all exceptions encountered.
167    *
168    * @return Information on all stack traces of all exceptions encountered.
169    */
170   public List<ExceptionStats> getExceptions() {
171      return stackTraceDb.getClonedStats();
172   }
173
174   @Override /* Object */
175   public String toString() {
176      return SimpleJson.DEFAULT.toString(this);
177   }
178
179   @Override /* Comparable */
180   public int compareTo(MethodExecStats o) {
181      return Long.compare(o.getTotalTime(), getTotalTime());
182   }
183}