/**
* 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 org.apache.aurora.scheduler.thrift.aop;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicLong;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.aurora.common.stats.SlidingStats;
import org.apache.aurora.common.stats.Stats;
import org.apache.aurora.gen.Response;
import org.apache.aurora.gen.ResponseCode;
import org.apache.aurora.scheduler.thrift.aop.ThriftWorkload.ThriftWorkloadCounter;
/**
* A method interceptor that exports counterStats about thrift calls.
*/
class ThriftStatsExporterInterceptor implements MethodInterceptor {
@VisibleForTesting
static final String TIMING_STATS_NAME_TEMPLATE = "scheduler_thrift_%s";
@VisibleForTesting
static final String WORKLOAD_STATS_NAME_TEMPLATE = "scheduler_thrift_workload_%s";
private final LoadingCache<Method, SlidingStats> timingStats =
CacheBuilder.newBuilder().build(new CacheLoader<Method, SlidingStats>() {
@Override
public SlidingStats load(Method method) {
return new SlidingStats(
Stats.normalizeName(String.format(TIMING_STATS_NAME_TEMPLATE, method.getName())),
"nanos");
}
});
private final LoadingCache<Method, AtomicLong> workloadStats =
CacheBuilder.newBuilder().build(new CacheLoader<Method, AtomicLong>() {
@Override
public AtomicLong load(Method method) {
return Stats.exportLong(
Stats.normalizeName(String.format(WORKLOAD_STATS_NAME_TEMPLATE, method.getName())));
}
});
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
SlidingStats stat = timingStats.getUnchecked(method);
long start = System.nanoTime();
Response response = null;
try {
response = (Response) invocation.proceed();
} finally {
stat.accumulate(System.nanoTime() - start);
if (response != null
&& response.getResponseCode() == ResponseCode.OK
&& method.isAnnotationPresent(ThriftWorkload.class)) {
ThriftWorkloadCounter counter = method.getAnnotation(ThriftWorkload.class)
.value()
.newInstance();
workloadStats.getUnchecked(method).addAndGet(counter.apply(response.getResult()));
}
}
return response;
}
}