// Copyright 2017 JanusGraph Authors // // 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.janusgraph.graphdb.query; import java.util.Iterator; import com.codahale.metrics.Timer; import com.google.common.base.Function; import com.google.common.base.Preconditions; import org.janusgraph.core.JanusGraphElement; import org.janusgraph.graphdb.query.profile.QueryProfiler; import org.janusgraph.util.stats.MetricManager; /** * Wraps a {@link QueryExecutor} to gather metrics on the query execution and forward them to METRICS. * * @author Dan LaRocque (dan@thinkaurelius.com) */ public class MetricsQueryExecutor<Q extends ElementQuery,R extends JanusGraphElement,B extends BackendQuery> implements QueryExecutor<Q,R,B> { private final QueryExecutor<Q,R,B> qe; private final String metricsPrefix; private static final String M_CALLS = "calls"; private static final String M_TIME = "time"; private static final String M_EXCEPTIONS = "exceptions"; public MetricsQueryExecutor(String prefix, String name, QueryExecutor<Q, R, B> qe) { super(); this.qe = qe; this.metricsPrefix = prefix + ".query." + name; } @Override public Iterator<R> getNew(final Q query) { return runWithMetrics("getNew", new Function<Void, Iterator<R>>() { @Override public Iterator<R> apply(Void v) { return qe.getNew(query); } }); } @Override public boolean hasDeletions(final Q query) { return runWithMetrics("hasDeletions", new Function<Void, Boolean>() { @Override public Boolean apply(Void v) { return qe.hasDeletions(query); } }); } @Override public boolean isDeleted(final Q query, final R result) { return runWithMetrics("isDeleted", new Function<Void, Boolean>() { @Override public Boolean apply(Void v) { return qe.isDeleted(query, result); } }); } @Override public Iterator<R> execute(final Q query, final B subquery, final Object executionInfo, final QueryProfiler profiler) { return runWithMetrics("execute", new Function<Void, Iterator<R>>() { @Override public Iterator<R> apply(Void v) { return qe.execute(query, subquery, executionInfo, profiler); } }); } private <T> T runWithMetrics(String opName, Function<Void,T> impl) { Preconditions.checkNotNull(opName); Preconditions.checkNotNull(impl); final MetricManager mgr = MetricManager.INSTANCE; mgr.getCounter(metricsPrefix, opName, M_CALLS).inc(); final Timer.Context tc = mgr.getTimer(metricsPrefix, opName, M_TIME).time(); try { return impl.apply(null); } catch (RuntimeException e) { mgr.getCounter(metricsPrefix, opName, M_EXCEPTIONS).inc(); throw e; } finally { tc.stop(); } } }