/*******************************************************************************
* Copyright (c) 2014 Imperial College London
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Raul Castro Fernandez - initial API and implementation
******************************************************************************/
package uk.ac.imperial.lsds.seep.infrastructure.monitor.slave.reader;
import com.codahale.metrics.Counter;
import com.codahale.metrics.Gauge;
import com.codahale.metrics.Metric;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.SharedMetricRegistries;
import com.codahale.metrics.Timer;
import com.codahale.metrics.jvm.MemoryUsageGaugeSet;
import com.sun.management.OperatingSystemMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import uk.ac.imperial.lsds.seep.infrastructure.monitor.policy.metric.MetricName;
import uk.ac.imperial.lsds.seep.infrastructure.monitor.policy.metric.MetricValue;
/**
* Default concrete implementation of a metric reader for slaves. There might
* be other readers that provide more detailed or application specific metrics.
* A single slave node can read values from multiple readers.
*
* @author mrouaux
*/
public class DefaultMetricsReader implements MetricsReader {
private final static MetricRegistry metricRegistry
= SharedMetricRegistries.getOrCreate("uk.ac.imperial.lsds.seep.infrastructure.monitor");
static {
metricRegistry.register(MetricName.QUEUE_LENGTH.getName(), new Counter());
metricRegistry.register(MetricName.OPERATOR_LATENCY.getName(), new Timer());
}
private static final String MEMORY_HEAP_SIZE_KEY = "heap.used";
private static final String MEMORY_HEAP_UTIL_KEY = "heap.usage";
// Initially, we will only support CPU utilisation on slave nodes and grow
// from there. Typically, other metrics we might be interested on are heap
// side/utilisation, processing delay and input queue length for an operator.
private MetricName[] readableNames = new MetricName[]{
MetricName.CPU_UTILIZATION,
MetricName.HEAP_SIZE,
MetricName.HEAP_UTILIZATION,
MetricName.QUEUE_LENGTH,
MetricName.OPERATOR_LATENCY
};
private OperatingSystemMXBean operatingSystemMXBean;
private RuntimeMXBean runtimeMXBean;
private MemoryUsageGaugeSet memoryMetricSet;
/**
* Default constructor
*/
public DefaultMetricsReader() {
// Get management beans to obtain JVM and OS runtime details
this.runtimeMXBean = ManagementFactory.getRuntimeMXBean();
this.operatingSystemMXBean = (com.sun.management.OperatingSystemMXBean)
ManagementFactory.getOperatingSystemMXBean();
this.memoryMetricSet = new MemoryUsageGaugeSet();
}
/**
* @return List of metric names returned by this reader.
*/
@Override
public List<MetricName> readableNames() {
return Arrays.asList(readableNames);
}
/**
* Read a metric value for a given name.
* @param name Name of the metric to read.
* @return Metric value.
*/
@Override
public MetricValue readValue(MetricName name) {
MetricValue value = null;
switch (name) {
case CPU_UTILIZATION:
value = readCpuUtilization();
break;
case HEAP_SIZE:
value = readHeapSize();
break;
case HEAP_UTILIZATION:
value = readHeapUtilization();
break;
case QUEUE_LENGTH:
value = readQueueLength();
break;
case OPERATOR_LATENCY:
value = readOperatorLatency();
break;
}
return value;
}
/**
* Calculate CPU utilisation and return as MetricValue (percentage).
*/
private MetricValue readCpuUtilization() {
int availableProcessors = operatingSystemMXBean.getAvailableProcessors();
long stUpTime = runtimeMXBean.getUptime();
long stProcessCpuTime = operatingSystemMXBean.getProcessCpuTime();
try {
Thread.sleep(100);
} catch (Exception ex) {
}
long edUpTime = runtimeMXBean.getUptime();
long edProcessCpuTime = operatingSystemMXBean.getProcessCpuTime();
long elapsedCpu = edProcessCpuTime - stProcessCpuTime;
long elapsedTime = edUpTime - stUpTime;
double cpuUsage = Math.min(100F, elapsedCpu / (elapsedTime * 10000F * availableProcessors));
return MetricValue.percent(cpuUsage);
}
/**
* Obtain heap used size and return as MetricValue (bytes).
*/
private MetricValue readHeapSize() {
Map<String, Metric> metrics = memoryMetricSet.getMetrics();
MetricValue value = null;
if (metrics.containsKey(MEMORY_HEAP_SIZE_KEY)) {
value = MetricValue.bytes(
((Long) ((Gauge) metrics.get(MEMORY_HEAP_SIZE_KEY)).getValue()).intValue());
}
return value;
}
/**
* Obtain heap utilisation and return as MetricValue (percentage).
*/
private MetricValue readHeapUtilization() {
Map<String, Metric> metrics = memoryMetricSet.getMetrics();
MetricValue value = null;
if (metrics.containsKey(MEMORY_HEAP_UTIL_KEY)) {
value = MetricValue.percent(
(Double) ((Gauge) metrics.get(MEMORY_HEAP_UTIL_KEY)).getValue());
}
return value;
}
/**
* Obtain operator latency and return as MetricValue (milliseconds)
*/
private MetricValue readOperatorLatency() {
MetricValue value = null;
Timer operatorLatency = metricRegistry
.timer(MetricName.OPERATOR_LATENCY.getName());
if (operatorLatency != null) {
value = MetricValue.millis(Double.valueOf(
operatorLatency.getSnapshot().getMean() / 1000000).intValue());
}
return value;
}
/**
* Obtain operator queue length and return as MetricValue (tuples)
*/
private MetricValue readQueueLength() {
MetricValue value = null;
Counter queueLength = metricRegistry
.counter(MetricName.QUEUE_LENGTH.getName());
if (queueLength != null) {
value = MetricValue.tuples(Long.valueOf(
queueLength.getCount()).intValue());
}
return value;
}
}