/**
* Copyright 2017 Netflix, Inc.
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 com.netflix.raigad.monitoring;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.netflix.raigad.configuration.IConfiguration;
import com.netflix.raigad.scheduler.SimpleTimer;
import com.netflix.raigad.scheduler.Task;
import com.netflix.raigad.scheduler.TaskTimer;
import com.netflix.raigad.utils.ElasticsearchProcessMonitor;
import com.netflix.raigad.utils.ElasticsearchTransportClient;
import com.netflix.servo.annotations.DataSourceType;
import com.netflix.servo.annotations.Monitor;
import com.netflix.servo.monitor.Monitors;
import org.elasticsearch.action.admin.cluster.node.stats.NodeStats;
import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse;
import org.elasticsearch.monitor.jvm.JvmStats;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
@Singleton
public class JvmStatsMonitor extends Task {
private static final Logger logger = LoggerFactory.getLogger(JvmStatsMonitor.class);
public static final String METRIC_NAME = "Elasticsearch_JvmStatsMonitor";
public static final String GC_YOUNG_TAG = "young";
public static final String GC_OLD_TAG = "old";
public static final String GC_SURVIVOR_TAG = "survivor";
private final Elasticsearch_JvmStatsReporter jvmStatsReporter;
@Inject
public JvmStatsMonitor(IConfiguration config) {
super(config);
jvmStatsReporter = new Elasticsearch_JvmStatsReporter();
Monitors.registerObject(jvmStatsReporter);
}
@Override
public void execute() throws Exception {
// Only start monitoring if Elasticsearch is started
if (!ElasticsearchProcessMonitor.isElasticsearchRunning()) {
String exceptionMsg = "Elasticsearch is not yet started, check back again later";
logger.info(exceptionMsg);
return;
}
JvmStatsBean jvmStatsBean = new JvmStatsBean();
try {
NodesStatsResponse nodesStatsResponse = ElasticsearchTransportClient.getNodesStatsResponse(config);
NodeStats nodeStats = null;
List<NodeStats> nodeStatsList = nodesStatsResponse.getNodes();
if (nodeStatsList.size() > 0) {
nodeStats = nodeStatsList.get(0);
}
if (nodeStats == null) {
logger.info("JVM stats is not available (node stats is not available)");
return;
}
JvmStats jvmStats = nodeStats.getJvm();
if (jvmStats == null) {
logger.info("JVM stats is not available");
return;
}
//Heap
jvmStatsBean.heapCommittedInBytes = jvmStats.getMem().getHeapCommitted().getMb();
jvmStatsBean.heapMaxInBytes = jvmStats.getMem().getHeapMax().getMb();
jvmStatsBean.heapUsedInBytes = jvmStats.getMem().getHeapUsed().getMb();
jvmStatsBean.heapUsedPercent = jvmStats.getMem().getHeapUsedPercent();
jvmStatsBean.nonHeapCommittedInBytes = jvmStats.getMem().getNonHeapCommitted().getMb();
jvmStatsBean.nonHeapUsedInBytes = jvmStats.getMem().getNonHeapUsed().getMb();
Iterator<JvmStats.MemoryPool> memoryPoolIterator = jvmStats.getMem().iterator();
while (memoryPoolIterator.hasNext()) {
JvmStats.MemoryPool memoryPoolStats = memoryPoolIterator.next();
if (memoryPoolStats.getName().equalsIgnoreCase(GC_YOUNG_TAG)) {
jvmStatsBean.youngMaxInBytes = memoryPoolStats.getMax().getBytes();
jvmStatsBean.youngUsedInBytes = memoryPoolStats.getUsed().getBytes();
jvmStatsBean.youngPeakUsedInBytes = memoryPoolStats.getPeakUsed().getBytes();
jvmStatsBean.youngPeakMaxInBytes = memoryPoolStats.getPeakMax().getBytes();
} else if (memoryPoolStats.getName().equalsIgnoreCase(GC_SURVIVOR_TAG)) {
jvmStatsBean.survivorMaxInBytes = memoryPoolStats.getMax().getBytes();
jvmStatsBean.survivorUsedInBytes = memoryPoolStats.getUsed().getBytes();
jvmStatsBean.survivorPeakUsedInBytes = memoryPoolStats.getPeakUsed().getBytes();
jvmStatsBean.survivorPeakMaxInBytes = memoryPoolStats.getPeakMax().getBytes();
} else if (memoryPoolStats.getName().equalsIgnoreCase(GC_OLD_TAG)) {
jvmStatsBean.oldMaxInBytes = memoryPoolStats.getMax().getBytes();
jvmStatsBean.oldUsedInBytes = memoryPoolStats.getUsed().getBytes();
jvmStatsBean.oldPeakUsedInBytes = memoryPoolStats.getPeakUsed().getBytes();
jvmStatsBean.oldPeakMaxInBytes = memoryPoolStats.getPeakMax().getBytes();
}
}
//Threads
jvmStatsBean.threadCount = jvmStats.getThreads().getCount();
jvmStatsBean.threadPeakCount = jvmStats.getThreads().getPeakCount();
jvmStatsBean.uptimeHours = jvmStats.getUptime().getHours();
//GC
for (JvmStats.GarbageCollector garbageCollector : jvmStats.getGc().getCollectors()) {
if (garbageCollector.getName().equalsIgnoreCase(GC_YOUNG_TAG)) {
jvmStatsBean.youngCollectionCount = garbageCollector.getCollectionCount();
jvmStatsBean.youngCollectionTimeInMillis = garbageCollector.getCollectionTime().getMillis();
} else if (garbageCollector.getName().equalsIgnoreCase(GC_OLD_TAG)) {
jvmStatsBean.oldCollectionCount = garbageCollector.getCollectionCount();
jvmStatsBean.oldCollectionTimeInMillis = garbageCollector.getCollectionTime().getMillis();
}
}
} catch (Exception e) {
logger.warn("Failed to load JVM stats data", e);
}
jvmStatsReporter.jvmStatsBean.set(jvmStatsBean);
}
public class Elasticsearch_JvmStatsReporter {
private final AtomicReference<JvmStatsBean> jvmStatsBean;
public Elasticsearch_JvmStatsReporter() {
jvmStatsBean = new AtomicReference<JvmStatsBean>(new JvmStatsBean());
}
@Monitor(name = "heap_committed_in_bytes", type = DataSourceType.GAUGE)
public long getHeapCommitedInBytes() {
return jvmStatsBean.get().heapCommittedInBytes;
}
@Monitor(name = "heap_max_in_bytes", type = DataSourceType.GAUGE)
public long getHeapMaxInBytes() {
return jvmStatsBean.get().heapMaxInBytes;
}
@Monitor(name = "heap_used_in_bytes", type = DataSourceType.GAUGE)
public long getHeapUsedInBytes() {
return jvmStatsBean.get().heapUsedInBytes;
}
@Monitor(name = "non_heap_committed_in_bytes", type = DataSourceType.GAUGE)
public long getNonHeapCommittedInBytes() {
return jvmStatsBean.get().nonHeapCommittedInBytes;
}
@Monitor(name = "non_heap_used_in_bytes", type = DataSourceType.GAUGE)
public long getNonHeapUsedInBytes() {
return jvmStatsBean.get().nonHeapUsedInBytes;
}
@Monitor(name = "heap_used_percent", type = DataSourceType.GAUGE)
public short getHeapUsedPercent() {
return jvmStatsBean.get().heapUsedPercent;
}
@Monitor(name = "threads_count", type = DataSourceType.GAUGE)
public long getThreadsCount() {
return jvmStatsBean.get().threadCount;
}
@Monitor(name = "threads_peak_count", type = DataSourceType.GAUGE)
public long getThreadsPeakCount() {
return jvmStatsBean.get().threadPeakCount;
}
@Monitor(name = "uptime_hours", type = DataSourceType.GAUGE)
public double getUptimeHours() {
return jvmStatsBean.get().uptimeHours;
}
@Monitor(name = "young_collection_count", type = DataSourceType.GAUGE)
public long getYoungCollectionCount() {
return jvmStatsBean.get().youngCollectionCount;
}
@Monitor(name = "young_collection_time_in_millis", type = DataSourceType.GAUGE)
public long getYoungCollectionTimeInMillis() {
return jvmStatsBean.get().youngCollectionTimeInMillis;
}
@Monitor(name = "old_collection_count", type = DataSourceType.GAUGE)
public long getOldCollectionCount() {
return jvmStatsBean.get().oldCollectionCount;
}
@Monitor(name = "old_collection_time_in_millis", type = DataSourceType.GAUGE)
public long getOldCollectionTimeInMillis() {
return jvmStatsBean.get().oldCollectionTimeInMillis;
}
@Monitor(name = "young_used_in_bytes", type = DataSourceType.GAUGE)
public long getYoungUsedInBytes() {
return jvmStatsBean.get().youngUsedInBytes;
}
@Monitor(name = "young_max_in_bytes", type = DataSourceType.GAUGE)
public long getYoungMaxInBytes() {
return jvmStatsBean.get().youngMaxInBytes;
}
@Monitor(name = "young_peak_used_in_bytes", type = DataSourceType.GAUGE)
public long getYoungPeakUsedInBytes() {
return jvmStatsBean.get().youngPeakUsedInBytes;
}
@Monitor(name = "young_peak_max_in_bytes", type = DataSourceType.GAUGE)
public long getYoungPeakMaxInBytes() {
return jvmStatsBean.get().youngPeakMaxInBytes;
}
@Monitor(name = "survivor_used_in_bytes", type = DataSourceType.GAUGE)
public long getSurvivorUsedInBytes() {
return jvmStatsBean.get().survivorUsedInBytes;
}
@Monitor(name = "survivor_max_in_bytes", type = DataSourceType.GAUGE)
public long getSurvivorMaxInBytes() {
return jvmStatsBean.get().survivorMaxInBytes;
}
@Monitor(name = "survivor_peak_used_in_bytes", type = DataSourceType.GAUGE)
public long getSurvivorPeakUsedInBytes() {
return jvmStatsBean.get().survivorPeakUsedInBytes;
}
@Monitor(name = "survivor_peak_max_in_bytes", type = DataSourceType.GAUGE)
public long getSurvivorPeakMaxInBytes() {
return jvmStatsBean.get().survivorPeakMaxInBytes;
}
@Monitor(name = "old_used_in_bytes", type = DataSourceType.GAUGE)
public long getOldUsedInBytes() {
return jvmStatsBean.get().oldUsedInBytes;
}
@Monitor(name = "old_max_in_bytes", type = DataSourceType.GAUGE)
public long getOldMaxInBytes() {
return jvmStatsBean.get().oldMaxInBytes;
}
@Monitor(name = "old_peak_used_in_bytes", type = DataSourceType.GAUGE)
public long getOldPeakUsedInBytes() {
return jvmStatsBean.get().oldPeakUsedInBytes;
}
@Monitor(name = "old_peak_max_in_bytes", type = DataSourceType.GAUGE)
public long getOldPeakMaxInBytes() {
return jvmStatsBean.get().oldPeakMaxInBytes;
}
@Monitor(name = "young_last_gc_start_time", type = DataSourceType.GAUGE)
public long getYoungLastGcStartTime() {
return jvmStatsBean.get().youngLastGcStartTime;
}
@Monitor(name = "young_last_gc_end_time", type = DataSourceType.GAUGE)
public long getYoungLastGcEndTime() {
return jvmStatsBean.get().youngLastGcEndTime;
}
@Monitor(name = "young_last_gc_max_in_bytes", type = DataSourceType.GAUGE)
public long getYoungLastGcMaxInBytes() {
return jvmStatsBean.get().youngLastGcMaxInBytes;
}
@Monitor(name = "young_last_gc_before_used_in_bytes", type = DataSourceType.GAUGE)
public long getYoungLastGcBeforeUsedInBytes() {
return jvmStatsBean.get().youngLastGcBeforeUsedInBytes;
}
@Monitor(name = "young_last_gc_after_used_in_bytes", type = DataSourceType.GAUGE)
public long getYoungLastGcAfterUsedInBytes() {
return jvmStatsBean.get().youngLastGcAfterUsedInBytes;
}
@Monitor(name = "young_last_gc_duration", type = DataSourceType.GAUGE)
public long getYoungLastGcDuration() {
return jvmStatsBean.get().youngLastGcDuration;
}
@Monitor(name = "old_last_gc_start_time", type = DataSourceType.GAUGE)
public long getOldLastGcStartTime() {
return jvmStatsBean.get().oldLastGcStartTime;
}
@Monitor(name = "old_last_gc_end_time", type = DataSourceType.GAUGE)
public long getOldLastGcEndTime() {
return jvmStatsBean.get().oldLastGcEndTime;
}
@Monitor(name = "old_last_gc_max_in_bytes", type = DataSourceType.GAUGE)
public long getOldLastGcMaxInBytes() {
return jvmStatsBean.get().oldLastGcMaxInBytes;
}
@Monitor(name = "old_last_gc_before_used_in_bytes", type = DataSourceType.GAUGE)
public long getOldLastGcBeforeUsedInBytes() {
return jvmStatsBean.get().oldLastGcBeforeUsedInBytes;
}
@Monitor(name = "old_last_gc_after_used_in_bytes", type = DataSourceType.GAUGE)
public long getOldLastGcAfterUsedInBytes() {
return jvmStatsBean.get().oldLastGcAfterUsedInBytes;
}
@Monitor(name = "old_last_gc_duration", type = DataSourceType.GAUGE)
public long getOldLastGcDuration() {
return jvmStatsBean.get().oldLastGcDuration;
}
}
private static class JvmStatsBean {
private long heapCommittedInBytes;
private long heapMaxInBytes;
private long heapUsedInBytes;
private long nonHeapCommittedInBytes;
private long nonHeapUsedInBytes;
private short heapUsedPercent;
private int threadCount;
private int threadPeakCount;
private long uptimeHours;
private long youngCollectionCount;
private long youngCollectionTimeInMillis;
private long oldCollectionCount;
private long oldCollectionTimeInMillis;
private long youngUsedInBytes;
private long youngMaxInBytes;
private long youngPeakUsedInBytes;
private long youngPeakMaxInBytes;
private long survivorUsedInBytes;
private long survivorMaxInBytes;
private long survivorPeakUsedInBytes;
private long survivorPeakMaxInBytes;
private long oldUsedInBytes;
private long oldMaxInBytes;
private long oldPeakUsedInBytes;
private long oldPeakMaxInBytes;
private long youngLastGcStartTime;
private long youngLastGcEndTime;
private long youngLastGcMaxInBytes;
private long youngLastGcBeforeUsedInBytes;
private long youngLastGcAfterUsedInBytes;
private long youngLastGcDuration;
private long oldLastGcStartTime;
private long oldLastGcEndTime;
private long oldLastGcMaxInBytes;
private long oldLastGcBeforeUsedInBytes;
private long oldLastGcAfterUsedInBytes;
private long oldLastGcDuration;
}
public static TaskTimer getTimer(String name) {
return new SimpleTimer(name, 60 * 1000);
}
@Override
public String getName() {
return METRIC_NAME;
}
}