001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.rest.stats; 018 019import java.lang.reflect.*; 020import java.util.*; 021import java.util.concurrent.atomic.*; 022 023import org.apache.juneau.*; 024import org.apache.juneau.cp.*; 025import org.apache.juneau.internal.*; 026import org.apache.juneau.marshaller.*; 027 028/** 029 * Method execution statistics. 030 * 031 * Keeps track of number of starts/finishes on tasks and keeps an average run time. 032 * 033 * <h5 class='section'>See Also:</h5><ul> 034 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/ExecutionStatistics">REST method execution statistics</a> 035 * </ul> 036 */ 037public class MethodExecStats { 038 039 //----------------------------------------------------------------------------------------------------------------- 040 // Static 041 //----------------------------------------------------------------------------------------------------------------- 042 043 /** 044 * Static creator. 045 * 046 * @param beanStore The bean store to use for creating beans. 047 * @return A new builder for this object. 048 */ 049 public static Builder create(BeanStore beanStore) { 050 return new Builder(beanStore); 051 } 052 053 //----------------------------------------------------------------------------------------------------------------- 054 // Builder 055 //----------------------------------------------------------------------------------------------------------------- 056 057 /** 058 * Builder class. 059 */ 060 public static class Builder extends BeanBuilder<MethodExecStats> { 061 062 Method method; 063 ThrownStore thrownStore; 064 065 /** 066 * Constructor. 067 * 068 * @param beanStore The bean store to use for creating beans. 069 */ 070 protected Builder(BeanStore beanStore) { 071 super(MethodExecStats.class, beanStore); 072 } 073 074 @Override /* BeanBuilder */ 075 protected MethodExecStats buildDefault() { 076 return new MethodExecStats(this); 077 } 078 079 //------------------------------------------------------------------------------------------------------------- 080 // Properties 081 //------------------------------------------------------------------------------------------------------------- 082 083 /** 084 * Specifies the Java method. 085 * 086 * @param value The new value for this setting. 087 * @return This object. 088 */ 089 public Builder method(Method value) { 090 method = value; 091 return this; 092 } 093 094 /** 095 * Specifies the thrown store for tracking exceptions. 096 * 097 * @param value The new value for this setting. 098 * @return This object. 099 */ 100 public Builder thrownStore(ThrownStore value) { 101 thrownStore = value; 102 return this; 103 } 104 @Override /* Overridden from BeanBuilder */ 105 public Builder impl(Object value) { 106 super.impl(value); 107 return this; 108 } 109 110 @Override /* Overridden from BeanBuilder */ 111 public Builder type(Class<?> value) { 112 super.type(value); 113 return this; 114 } 115 } 116 117 //----------------------------------------------------------------------------------------------------------------- 118 // Instance 119 //----------------------------------------------------------------------------------------------------------------- 120 121 private final long guid; 122 private final Method method; 123 private final ThrownStore thrownStore; 124 125 private volatile int minTime = -1, maxTime; 126 127 private AtomicInteger 128 starts = new AtomicInteger(), 129 finishes = new AtomicInteger(), 130 errors = new AtomicInteger(); 131 132 private AtomicLong 133 totalTime = new AtomicLong(); 134 135 /** 136 * Constructor. 137 * 138 * @param builder The builder for this object. 139 */ 140 protected MethodExecStats(Builder builder) { 141 this.guid = new Random().nextLong(); 142 this.method = builder.method; 143 this.thrownStore = builder.thrownStore != null ? builder.thrownStore : new ThrownStore(); 144 } 145 146 147 /** 148 * Call when task is started. 149 * 150 * @return This object. 151 */ 152 public MethodExecStats started() { 153 starts.incrementAndGet(); 154 return this; 155 } 156 157 /** 158 * Call when task is finished. 159 * 160 * @param nanoTime The execution time of the task in nanoseconds. 161 * @return This object. 162 */ 163 public MethodExecStats finished(long nanoTime) { 164 finishes.incrementAndGet(); 165 int milliTime = (int)(nanoTime/1_000_000); 166 totalTime.addAndGet(nanoTime); 167 minTime = minTime == -1 ? milliTime : Math.min(minTime, milliTime); 168 maxTime = Math.max(maxTime, milliTime); 169 return this; 170 } 171 172 /** 173 * Call when an error occurs. 174 * 175 * @param e The exception thrown. Can be <jk>null</jk>. 176 * @return This object. 177 */ 178 public MethodExecStats error(Throwable e) { 179 errors.incrementAndGet(); 180 thrownStore.add(e); 181 return this; 182 } 183 184 /** 185 * Returns a globally unique ID for this object. 186 * 187 * <p> 188 * A random long generated during the creation of this object. 189 * Allows this object to be differentiated from other similar objects in multi-node environments so that 190 * statistics can be reliably stored in a centralized location. 191 * 192 * @return The globally unique ID for this object. 193 */ 194 public long getGuid() { 195 return guid; 196 } 197 198 /** 199 * Returns the method name of these stats. 200 * 201 * @return The method name of these stats. 202 */ 203 public Method getMethod() { 204 return method; 205 } 206 207 /** 208 * Returns the number of times the {@link #started()} method was called. 209 * 210 * @return The number of times the {@link #started()} method was called. 211 */ 212 public int getRuns() { 213 return starts.get(); 214 } 215 216 /** 217 * Returns the number currently running method invocations. 218 * 219 * @return The number of currently running method invocations. 220 */ 221 public int getRunning() { 222 return starts.get() - finishes.get(); 223 } 224 225 /** 226 * Returns the number of times the {@link #error(Throwable)} method was called. 227 * 228 * @return The number of times the {@link #error(Throwable)} method was called. 229 */ 230 public int getErrors() { 231 return errors.get(); 232 } 233 234 /** 235 * Returns the max execution time. 236 * 237 * @return The average execution time in milliseconds. 238 */ 239 public int getMinTime() { 240 return minTime == -1 ? 0 : minTime; 241 } 242 243 /** 244 * Returns the max execution time. 245 * 246 * @return The average execution time in milliseconds. 247 */ 248 public int getMaxTime() { 249 return maxTime; 250 } 251 252 /** 253 * Returns the average execution time. 254 * 255 * @return The average execution time in milliseconds. 256 */ 257 public int getAvgTime() { 258 int runs = finishes.get(); 259 return runs == 0 ? 0 : (int)(getTotalTime() / runs); 260 } 261 262 /** 263 * Returns the total execution time. 264 * 265 * @return The total execution time in milliseconds. 266 */ 267 public long getTotalTime() { 268 return totalTime.get() / 1_000_000; 269 } 270 271 /** 272 * Returns information on all stack traces of all exceptions encountered. 273 * 274 * @return Information on all stack traces of all exceptions encountered. 275 */ 276 public ThrownStore getThrownStore() { 277 return thrownStore; 278 } 279 280 @Override /* Object */ 281 public String toString() { 282 return Json5.of(this); 283 } 284}