/*
* Copyright (c) 2010-2012 Grid Dynamics Consulting Services, Inc, All Rights Reserved
* http://www.griddynamics.com
*
* This library is free software; you can redistribute it and/or modify it under the terms of
* the Apache License; either
* version 2.0 of the License, or any later version.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.griddynamics.jagger.agent.impl;
import com.google.common.base.Throwables;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.Uninterruptibles;
import com.griddynamics.jagger.agent.model.AgentContext;
import com.griddynamics.jagger.agent.model.CpuData;
import com.griddynamics.jagger.agent.model.DisksData;
import com.griddynamics.jagger.agent.model.MonitoringInfoService;
import com.griddynamics.jagger.agent.model.SystemInfo;
import com.griddynamics.jagger.agent.model.SystemInfoCollector;
import com.griddynamics.jagger.agent.model.SystemUnderTestInfo;
import com.griddynamics.jagger.agent.model.SystemUnderTestService;
import com.griddynamics.jagger.agent.model.TcpData;
import com.griddynamics.jagger.dbapi.parameter.DefaultMonitoringParameters;
import com.griddynamics.jagger.dbapi.parameter.MonitoringParameter;
import com.griddynamics.jagger.util.TimeUtils;
import com.griddynamics.jagger.util.Timeout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static com.griddynamics.jagger.util.Units.bytesToKiB;
import static com.griddynamics.jagger.util.Units.bytesToMiB;
/**
* User: vshulga
* Date: 7/5/11
* Time: 5:35 PM
* <p/>
* Service aggregates logic for general system monitoring and specific JVM monitoring.
*/
public class MonitoringInfoServiceImpl implements MonitoringInfoService {
private static final Logger log = LoggerFactory.getLogger(MonitoringInfoServiceImpl.class);
private Timeout jmxTimeout = new Timeout(300,"");
private SystemInfoCollector systemInfoService;
private SystemUnderTestService systemUnderTestService;
private ThreadPoolExecutor jmxThreadPoolExecutor =
new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
public void setSystemInfoService(SystemInfoCollector systemInfoService) {
this.systemInfoService = systemInfoService;
}
public void setSystemUnderTestService(SystemUnderTestService systemUnderTestService) {
this.systemUnderTestService = systemUnderTestService;
}
public void setJmxTimeout(Timeout jmxTimeout) {
this.jmxTimeout = jmxTimeout;
}
@Override
public SystemInfo getSystemInfo() {
long startTime = System.currentTimeMillis(), startTimeLog = startTime;
log.debug("start collecting box info through sigar on agent");
Map<MonitoringParameter, Double> sysInfoStringMap = Maps.newHashMap();
Map<String, String> memInfo = this.systemInfoService.getMemInfo();
DisksData disksData = systemInfoService.getDisksData();
CpuData cpuData = systemInfoService.getCpuData();
TcpData tcpData = systemInfoService.getTcpData();
sysInfoStringMap.put(DefaultMonitoringParameters.MEM_RAM, Double.parseDouble(memInfo.get("Ram")));
sysInfoStringMap.put(DefaultMonitoringParameters.MEM_TOTAL, bytesToMiB(memInfo.get("Total")));
sysInfoStringMap.put(DefaultMonitoringParameters.MEM_USED, bytesToMiB(memInfo.get("Used")));
sysInfoStringMap.put(DefaultMonitoringParameters.MEM_ACTUAL_USED, bytesToMiB(memInfo.get("ActualUsed")));
sysInfoStringMap.put(DefaultMonitoringParameters.MEM_ACTUAL_FREE, bytesToMiB(memInfo.get("ActualFree")));
sysInfoStringMap.put(DefaultMonitoringParameters.MEM_FREE, bytesToMiB(memInfo.get("Free")));
sysInfoStringMap.put(DefaultMonitoringParameters.MEM_FREE_PERCENT, Double.valueOf(memInfo.get("FreePercent")));
sysInfoStringMap.put(DefaultMonitoringParameters.TCP_ESTABLISHED, tcpData.getTcpEstablished());
sysInfoStringMap.put(DefaultMonitoringParameters.TCP_LISTEN, tcpData.getTcpListen());
sysInfoStringMap.put(DefaultMonitoringParameters.TCP_SYNCHRONIZED_RECEIVED, tcpData.getTcpSynchronizedReceived());
sysInfoStringMap.put(DefaultMonitoringParameters.TCP_INBOUND_TOTAL, bytesToKiB(tcpData.getTcpInboundTotal()));
sysInfoStringMap.put(DefaultMonitoringParameters.TCP_OUTBOUND_TOTAL, bytesToKiB(tcpData.getTcpOutboundTotal()));
sysInfoStringMap.put(DefaultMonitoringParameters.DISKS_READ_BYTES_TOTAL, bytesToKiB(disksData.getDisksReadBytesTotal()));
sysInfoStringMap.put(DefaultMonitoringParameters.DISKS_WRITE_BYTES_TOTAL, bytesToKiB(disksData.getDisksWriteBytesTotal()));
sysInfoStringMap.put(DefaultMonitoringParameters.DISKS_AVERAGE_QUEUE_SIZE_TOTAL, disksData.getDisksQueueTotal());
sysInfoStringMap.put(DefaultMonitoringParameters.DISKS_SERVICE_TIME_TOTAL, disksData.getDisksSvcTimeTotal());
sysInfoStringMap.put(DefaultMonitoringParameters.CPU_STATE_USER_PERC, cpuData.getCpuStateUser() * 100);
sysInfoStringMap.put(DefaultMonitoringParameters.CPU_STATE_SYSTEM_PERC, cpuData.getCpuStateSys() * 100);
sysInfoStringMap.put(DefaultMonitoringParameters.CPU_STATE_IDLE_PERC, cpuData.getCpuStateIdle() * 100);
sysInfoStringMap.put(DefaultMonitoringParameters.CPU_STATE_IDLE_WAIT, cpuData.getCpuStateWait() * 100);
sysInfoStringMap.put(DefaultMonitoringParameters.CPU_STATE_COMBINED, cpuData.getCpuStateCombined() * 100);
log.debug("finish collecting box info through sigar on agent: time {} ms", System.currentTimeMillis() - startTimeLog);
startTimeLog = System.currentTimeMillis();
log.debug("start collecting LoadAverage info on agent");
double[] loadAverage = systemInfoService.getLoadAverage();
log.debug("finish collecting LoadAverage info on agent: time {} ms", System.currentTimeMillis() - startTimeLog);
sysInfoStringMap.put(DefaultMonitoringParameters.CPU_LOAD_AVERAGE_1, loadAverage[0]);
sysInfoStringMap.put(DefaultMonitoringParameters.CPU_LOAD_AVERAGE_5, loadAverage[1]);
sysInfoStringMap.put(DefaultMonitoringParameters.CPU_LOAD_AVERAGE_15, loadAverage[2]);
SystemInfo systemInfo = new SystemInfo();
systemInfo.setTime(startTime);
systemInfo.setSysInfo(sysInfoStringMap);
startTimeLog = System.currentTimeMillis();
log.debug("start collecting SuT info through jmx on agent");
Map<String, SystemUnderTestInfo> jmxInfo = getResponseFromSut(new Callable<Map<String, SystemUnderTestInfo>>() {
@Override
public Map<String, SystemUnderTestInfo> call() throws Exception {
return systemUnderTestService.getInfo();
}
});
systemInfo.setSysUnderTest(jmxInfo);
log.debug("finish collecting SuT info through jmx on agent: time {} ms", System.currentTimeMillis() - startTimeLog);
return systemInfo;
}
@Override
public Map<String, Map<String, String>> getSystemProperties() {
Map<String, Map<String, String>> result = getResponseFromSut(new Callable<Map<String, Map<String, String>>>() {
@Override
public Map<String, Map<String, String>> call() throws Exception {
return systemUnderTestService.getSystemProperties();
}
});
if (result == null){
return Collections.EMPTY_MAP;
}
return result;
}
private <T>T getResponseFromSut(Callable<T> response){
T result = null;
if (jmxThreadPoolExecutor.getActiveCount() == 0) {
Future<T> future = jmxThreadPoolExecutor.submit(response);
try {
result = Uninterruptibles.getUninterruptibly(future, jmxTimeout.getValue(), TimeUnit.MILLISECONDS);
} catch (ExecutionException e) {
log.error("Execution failed {}", e);
throw Throwables.propagate(e);
} catch (TimeoutException e) {
log.warn("Timeout. Collection of jmx data was not finished in {}. Pass out without jmx data",
jmxTimeout.toString());
TimeUtils.sleepMillis(jmxTimeout.getValue());
}
} else {
log.warn("jmxThread is busy. Pass out without jmx data");
}
return result;
}
@Override
public void setContext(AgentContext context) {
systemUnderTestService.setContext(context);
}
}