blob: e3877e83502210c7b4320ce12d4ab2782fa83fb1 [file] [log] [blame]
/*
* Copyright 2016 Open Networking Laboratory
*
* 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.onosproject.utils;
import com.codahale.metrics.Counter;
import com.codahale.metrics.Timer;
import com.google.common.collect.Maps;
import org.onlab.metrics.MetricsComponent;
import org.onlab.metrics.MetricsFeature;
import org.onlab.metrics.MetricsService;
import org.onlab.osgi.DefaultServiceDirectory;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Agent that implements usage and performance monitoring via the metrics service.
*/
public class MeteringAgent {
private Counter exceptionCounter;
private Counter perObjExceptionCounter;
private MetricsService metricsService;
private MetricsComponent metricsComponent;
private MetricsFeature metricsFeature;
private final Map<String, Timer> perObjOpTimers = Maps.newConcurrentMap();
private final Map<String, Timer> perOpTimers = Maps.newConcurrentMap();
private Timer perPrimitiveTimer;
private Timer perObjTimer;
private MetricsFeature wildcard;
private final boolean activated;
private Context nullTimer;
/**
* Constructs a new MeteringAgent for a given distributed primitive.
* Instantiates the metrics service
* Initializes all the general metrics for that object
*
* @param primitiveName Type of primitive to be metered
* @param objName Global name of the primitive
* @param activated boolean flag for whether metering is enabled or not
*/
public MeteringAgent(String primitiveName, String objName, boolean activated) {
checkNotNull(objName, "Object name cannot be null");
this.activated = activated;
nullTimer = new Context(null, "");
if (this.activated) {
this.metricsService = DefaultServiceDirectory.getService(MetricsService.class);
this.metricsComponent = metricsService.registerComponent(primitiveName);
this.metricsFeature = metricsComponent.registerFeature(objName);
this.wildcard = metricsComponent.registerFeature("*");
this.perObjTimer = metricsService.createTimer(metricsComponent, metricsFeature, "*");
this.perPrimitiveTimer = metricsService.createTimer(metricsComponent, wildcard, "*");
this.perObjExceptionCounter = metricsService.createCounter(metricsComponent, metricsFeature, "exceptions");
this.exceptionCounter = metricsService.createCounter(metricsComponent, wildcard, "exceptions");
}
}
/**
* Initializes a specific timer for a given operation.
*
* @param op Specific operation being metered
* @return timer context
*/
public Context startTimer(String op) {
if (!activated) {
return nullTimer;
}
// Check if timer exists, if it doesn't creates it
final Timer currTimer = perObjOpTimers.computeIfAbsent(op, timer ->
metricsService.createTimer(metricsComponent, metricsFeature, op));
perOpTimers.computeIfAbsent(op, timer -> metricsService.createTimer(metricsComponent, wildcard, op));
// Starts timer
return new Context(currTimer.time(), op);
}
/**
* Timer.Context with a specific operation.
*/
public class Context {
private final Timer.Context context;
private final String operation;
/**
* Constructs Context.
*
* @param context context
* @param operation operation name
*/
public Context(Timer.Context context, String operation) {
this.context = context;
this.operation = operation;
}
/**
* Stops timer given a specific context and updates all related metrics.
* @param e throwable
*/
public void stop(Throwable e) {
if (!activated) {
return;
}
if (e == null) {
//Stop and updates timer with specific measurements per map, per operation
final long time = context.stop();
//updates timer with aggregated measurements per map
perOpTimers.get(operation).update(time, TimeUnit.NANOSECONDS);
//updates timer with aggregated measurements per map
perObjTimer.update(time, TimeUnit.NANOSECONDS);
//updates timer with aggregated measurements per all Consistent Maps
perPrimitiveTimer.update(time, TimeUnit.NANOSECONDS);
} else {
exceptionCounter.inc();
perObjExceptionCounter.inc();
}
}
}
}