Merge branch 'hyungil.jeong/pinpoint-profiler/issue-73' of hyungil.jeong/pinpoint-web

from pull-request 3

* refs/heads/hyungil.jeong/pinpoint-profiler/issue-73:
  [Pinpoint/pinpoint-profiler#73] Added support for AgentStats batch.

Reviewed-by: 정현길 <hyungil.jeong@navercorp.com>
This commit is contained in:
Hyun Jeong
2014-08-27 10:57:18 +09:00
15 changed files with 507 additions and 331 deletions
@@ -3,13 +3,13 @@ package com.nhn.pinpoint.web.controller;
import java.util.List;
import java.util.SortedMap;
import com.nhn.pinpoint.web.vo.AgentStat;
import com.nhn.pinpoint.web.vo.Range;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@@ -17,7 +17,6 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.nhn.pinpoint.common.bo.AgentInfoBo;
import com.nhn.pinpoint.thrift.dto.TAgentStat;
import com.nhn.pinpoint.web.service.AgentInfoService;
import com.nhn.pinpoint.web.service.AgentStatService;
import com.nhn.pinpoint.web.vo.linechart.agentstat.AgentStatChartGroup;
@@ -25,53 +24,51 @@ import com.nhn.pinpoint.web.vo.linechart.agentstat.AgentStatChartGroup;
@Controller
public class AgentStatController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private AgentStatService agentStatService;
@Autowired
private AgentInfoService agentInfoService;
@RequestMapping(value = "/getAgentStat", method = RequestMethod.GET)
@Autowired
private AgentStatService agentStatService;
@Autowired
private AgentInfoService agentInfoService;
@RequestMapping(value = "/getAgentStat", method = RequestMethod.GET)
@ResponseBody
public AgentStatChartGroup getAgentStat(
@RequestParam("agentId") String agentId,
@RequestParam("from") long from,
@RequestParam("to") long to,
@RequestParam(value = "sampleRate", required = false) Integer sampleRate) throws Exception {
StopWatch watch = new StopWatch();
watch.start("agentStatService.selectAgentStatList");
public AgentStatChartGroup getAgentStat(
@RequestParam("agentId") String agentId,
@RequestParam("from") long from,
@RequestParam("to") long to,
@RequestParam(value = "sampleRate", required = false) Integer sampleRate) throws Exception {
StopWatch watch = new StopWatch();
watch.start("agentStatService.selectAgentStatList");
Range range = new Range(from, to);
List<TAgentStat> agentStatList = agentStatService.selectAgentStatList(agentId, range);
watch.stop();
if (logger.isInfoEnabled()) {
logger.info("getAgentStat(agentId={}, from={}, to={}) : {}ms", agentId, from, to, watch.getLastTaskTimeMillis());
}
List<AgentStat> agentStatList = agentStatService.selectAgentStatList(agentId, range);
watch.stop();
// FIXME dummy
int nPoints = (int) (to - from) / 5000;
if (sampleRate == null) {
sampleRate = nPoints < 300 ? 1 : nPoints / 300;
}
AgentStatChartGroup chart = new AgentStatChartGroup();
for (TAgentStat each : agentStatList) {
chart.addData(each, sampleRate);
}
if (logger.isInfoEnabled()) {
logger.info("getAgentStat(agentId={}, from={}, to={}) : {}ms", agentId, from, to, watch.getLastTaskTimeMillis());
}
return chart;
}
// FIXME dummy
int nPoints = (int) (to - from) / 5000;
if (sampleRate == null) {
sampleRate = nPoints < 300 ? 1 : nPoints / 300;
}
@RequestMapping(value = "/getAgentList", method = RequestMethod.GET)
AgentStatChartGroup chart = new AgentStatChartGroup(sampleRate);
chart.addAgentStats(agentStatList);
return chart;
}
@RequestMapping(value = "/getAgentList", method = RequestMethod.GET)
@ResponseBody
public SortedMap<String, List<AgentInfoBo>> getApplicationAgentList(
@RequestParam("application") String applicationName,
@RequestParam("from") long from,
@RequestParam("to") long to) {
@RequestParam("application") String applicationName,
@RequestParam("from") long from,
@RequestParam("to") long to) {
Range range = new Range(from, to);
SortedMap<String, List<AgentInfoBo>> applicationAgentList = agentInfoService.getApplicationAgentList(applicationName, range);
return applicationAgentList;
}
SortedMap<String, List<AgentInfoBo>> applicationAgentList = agentInfoService.getApplicationAgentList(applicationName, range);
return applicationAgentList;
}
}
@@ -2,12 +2,14 @@ package com.nhn.pinpoint.web.dao;
import java.util.List;
import com.nhn.pinpoint.thrift.dto.TAgentStat;
import com.nhn.pinpoint.web.vo.AgentStat;
import com.nhn.pinpoint.web.vo.Range;
/**
* @author hyungil.jeong
*/
public interface AgentStatDao {
List<TAgentStat> scanAgentStatList(String agentId, Range range);
// List<AgentStat> scanAgentStatList(String agentId, long start, long end, final int limit);
List<AgentStat> scanAgentStatList(String agentId, Range range);
}
@@ -5,8 +5,9 @@ import static com.nhn.pinpoint.common.hbase.HBaseTables.AGENT_NAME_MAX_LEN;
import java.util.ArrayList;
import java.util.List;
import com.nhn.pinpoint.thrift.dto.TAgentStat;
import com.nhn.pinpoint.web.vo.AgentStat;
import com.nhn.pinpoint.web.vo.Range;
import org.apache.hadoop.hbase.client.Scan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -25,30 +26,31 @@ import com.sematext.hbase.wd.AbstractRowKeyDistributor;
/**
* @author emeroad
* @author hyungil.jeong
*/
@Repository
public class HbaseAgentStatDao implements AgentStatDao {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private HbaseOperations2 hbaseOperations2;
@Autowired
private HbaseOperations2 hbaseOperations2;
@Autowired
@Qualifier("agentStatMapper")
private RowMapper<List<AgentStat>> agentStatMapper;
@Autowired
@Qualifier("agentStatMapper")
private RowMapper<List<TAgentStat>> agentStatMapper;
@Autowired
@Qualifier("agentStatRowKeyDistributor")
private AbstractRowKeyDistributor rowKeyDistributor;
private int scanCacheSize = 256;
private int scanCacheSize = 256;
public void setScanCacheSize(int scanCacheSize) {
this.scanCacheSize = scanCacheSize;
}
public List<TAgentStat> scanAgentStatList(String agentId, Range range) {
public void setScanCacheSize(int scanCacheSize) {
this.scanCacheSize = scanCacheSize;
}
public List<AgentStat> scanAgentStatList(String agentId, Range range) {
if (agentId == null) {
throw new NullPointerException("agentId must not be null");
}
@@ -57,85 +59,86 @@ public class HbaseAgentStatDao implements AgentStatDao {
}
if (logger.isDebugEnabled()) {
logger.debug("scanAgentStat : agentId={}, {}", agentId, range);
}
logger.debug("scanAgentStat : agentId={}, {}", agentId, range);
}
Scan scan = createScan(agentId, range);
List<List<TAgentStat>> intermediate = hbaseOperations2.find(HBaseTables.AGENT_STAT, scan, rowKeyDistributor, agentStatMapper);
int expectedSize = (int)(range.getRange() / 5000); // 5초간 데이터
List<TAgentStat> merged = new ArrayList<TAgentStat>(expectedSize);
for(List<TAgentStat> each : intermediate) {
Scan scan = createScan(agentId, range);
List<List<AgentStat>> intermediate = hbaseOperations2.find(HBaseTables.AGENT_STAT, scan, rowKeyDistributor, agentStatMapper);
int expectedSize = (int)(range.getRange() / 5000); // 5초간 데이터
List<AgentStat> merged = new ArrayList<AgentStat>(expectedSize);
for(List<AgentStat> each : intermediate) {
merged.addAll(each);
}
return merged;
}
/**
* timestamp 기반의 row key를 만든다.
* FIXME collector에 있는 DAO에도 동일한 코드가 중복되어 있으니 참고.
*/
private byte[] getRowKey(String agentId, long timestamp) {
if (agentId == null) {
throw new IllegalArgumentException("agentId must not null");
}
byte[] bAgentId = BytesUtils.toBytes(agentId);
return RowKeyUtils.concatFixedByteAndLong(bAgentId, AGENT_NAME_MAX_LEN, TimeUtils.reverseTimeMillis(timestamp));
}
}
private Scan createScan(String agentId, Range range) {
Scan scan = new Scan();
scan.setCaching(this.scanCacheSize);
/**
* timestamp 기반의 row key를 만든다.
* FIXME collector에 있는 DAO에도 동일한 코드가 중복되어 있으니 참고.
*/
private byte[] getRowKey(String agentId, long timestamp) {
if (agentId == null) {
throw new IllegalArgumentException("agentId must not null");
}
byte[] bAgentId = BytesUtils.toBytes(agentId);
return RowKeyUtils.concatFixedByteAndLong(bAgentId, AGENT_NAME_MAX_LEN, TimeUtils.reverseTimeMillis(timestamp));
}
byte[] startKey = getRowKey(agentId, range.getFrom());
byte[] endKey = getRowKey(agentId, range.getTo());
private Scan createScan(String agentId, Range range) {
Scan scan = new Scan();
scan.setCaching(this.scanCacheSize);
// key가 reverse되었기 떄문에 start, end가 뒤바뀌게 된다.
scan.setStartRow(endKey);
scan.setStopRow(startKey);
byte[] startKey = getRowKey(agentId, range.getFrom());
byte[] endKey = getRowKey(agentId, range.getTo());
scan.addColumn(HBaseTables.AGENT_STAT_CF_STATISTICS, HBaseTables.AGENT_STAT_CF_STATISTICS_V1);
scan.setId("AgentStatScan");
// key가 reverse되었기 떄문에 start, end가 뒤바뀌게 된다.
scan.setStartRow(endKey);
scan.setStopRow(startKey);
// json으로 변화해서 로그를 찍어서. 최초 변환 속도가 느림.
logger.debug("create scan:{}", scan);
return scan;
}
// scan.addColumn(HBaseTables.AGENT_STAT_CF_STATISTICS, HBaseTables.AGENT_STAT_CF_STATISTICS_V1);
scan.addFamily(HBaseTables.AGENT_STAT_CF_STATISTICS);
scan.setId("AgentStatScan");
// json으로 변화해서 로그를 찍어서. 최초 변환 속도가 느림.
logger.debug("create scan:{}", scan);
return scan;
}
// public List<AgentStat> scanAgentStatList(String agentId, long start, long end, final int limit) {
// if (logger.isDebugEnabled()) {
// logger.debug("scanAgentStatList");
// }
// Scan scan = createScan(agentId, start, end);
//
// List<AgentStat> list = hbaseOperations2.find(HBaseTables.AGENT_STAT, scan, rowKeyDistributor, new ResultsExtractor<List<AgentStat>>() {
// @Override
// public List<AgentStat> extractData(ResultScanner results) throws Exception {
// TDeserializer deserializer = new TDeserializer();
// List<AgentStat> list = new ArrayList<AgentStat>();
// for (Result result : results) {
// if (result == null) {
// continue;
// }
//
// if (list.size() >= limit) {
// break;
// }
//
// for (KeyValue kv : result.raw()) {
// AgentStat agentStat = new AgentStat();
// deserializer.deserialize(agentStat, kv.getBuffer());
// list.add(agentStat);
// }
// }
// return list;
// }
// });
// return list;
// }
// public List<AgentStat> scanAgentStatList(String agentId, long start, long end, final int limit) {
// if (logger.isDebugEnabled()) {
// logger.debug("scanAgentStatList");
// }
// Scan scan = createScan(agentId, start, end);
//
// List<AgentStat> list = hbaseOperations2.find(HBaseTables.AGENT_STAT, scan, rowKeyDistributor, new ResultsExtractor<List<AgentStat>>() {
// @Override
// public List<AgentStat> extractData(ResultScanner results) throws Exception {
// TDeserializer deserializer = new TDeserializer();
// List<AgentStat> list = new ArrayList<AgentStat>();
// for (Result result : results) {
// if (result == null) {
// continue;
// }
//
// if (list.size() >= limit) {
// break;
// }
//
// for (KeyValue kv : result.raw()) {
// AgentStat agentStat = new AgentStat();
// deserializer.deserialize(agentStat, kv.getBuffer());
// list.add(agentStat);
// }
// }
// return list;
// }
// });
// return list;
// }
}
@@ -1,13 +1,24 @@
package com.nhn.pinpoint.web.mapper;
import static com.nhn.pinpoint.common.hbase.HBaseTables.AGENT_STAT_CF_STATISTICS;
import static com.nhn.pinpoint.common.hbase.HBaseTables.AGENT_STAT_CF_STATISTICS_V1;
import static com.nhn.pinpoint.common.hbase.HBaseTables.AGENT_STAT_CF_STATISTICS_MEMORY_GC;
import static com.nhn.pinpoint.common.hbase.HBaseTables.AGENT_STAT_CF_STATISTICS_CPU_LOAD;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.nhn.pinpoint.common.bo.AgentStatCpuLoadBo;
import com.nhn.pinpoint.common.bo.AgentStatMemoryGcBo;
import com.nhn.pinpoint.thrift.dto.TAgentStat;
import org.apache.hadoop.hbase.KeyValue;
import com.nhn.pinpoint.thrift.dto.TJvmGc;
import com.nhn.pinpoint.web.vo.AgentStat;
import org.apache.hadoop.hbase.client.Result;
import org.apache.thrift.TDeserializer;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TProtocolFactory;
import org.springframework.data.hadoop.hbase.RowMapper;
@@ -15,30 +26,55 @@ import org.springframework.stereotype.Component;
/**
* @author harebox
* @author hyungil.jeong
*/
@Component
public class AgentStatMapper implements RowMapper<List<TAgentStat>> {
public class AgentStatMapper implements RowMapper<List<AgentStat>> {
private TProtocolFactory factory = new TCompactProtocol.Factory();
public List<TAgentStat> mapRow(Result result, int rowNum) throws Exception {
if (result.isEmpty()) {
return Collections.emptyList();
}
KeyValue[] raw = result.raw();
List<TAgentStat> list = new ArrayList<TAgentStat>(raw.length);
// CompactProtocol을 사용하고 있음.
TDeserializer deserializer = new TDeserializer(factory);
private TProtocolFactory factory = new TCompactProtocol.Factory();
for (KeyValue kv : raw) {
TAgentStat each = new TAgentStat();
deserializer.deserialize(each, kv.getValue());
list.add(each);
}
public List<AgentStat> mapRow(Result result, int rowNum) throws Exception {
if (result.isEmpty()) {
return Collections.emptyList();
}
return list;
}
Map<byte[], byte[]> qualifierMap = result.getFamilyMap(AGENT_STAT_CF_STATISTICS);
// FIXME (2014.08) Legacy support for TAgentStat Thrift DTO stored directly into hbase.
if (qualifierMap.containsKey(AGENT_STAT_CF_STATISTICS_V1)) {
return readAgentStatThriftDto(qualifierMap.get(AGENT_STAT_CF_STATISTICS_V1));
}
AgentStat agentStat = new AgentStat();
if (qualifierMap.containsKey(AGENT_STAT_CF_STATISTICS_MEMORY_GC)) {
agentStat.setMemoryGc(new AgentStatMemoryGcBo.Builder(qualifierMap.get(AGENT_STAT_CF_STATISTICS_MEMORY_GC)).build());
}
if (qualifierMap.containsKey(AGENT_STAT_CF_STATISTICS_CPU_LOAD)) {
agentStat.setCpuLoad(new AgentStatCpuLoadBo.Builder(qualifierMap.get(AGENT_STAT_CF_STATISTICS_CPU_LOAD)).build());
}
List<AgentStat> agentStats = new ArrayList<AgentStat>();
agentStats.add(agentStat);
return agentStats;
}
// FIXME (2014.08) Legacy support for TAgentStat Thrift DTO stored directly into hbase.
private List<AgentStat> readAgentStatThriftDto(byte[] tAgentStatByteArray) throws TException {
// CompactProtocol을 사용하고 있음.
TDeserializer deserializer = new TDeserializer(factory);
TAgentStat tAgentStat = new TAgentStat();
deserializer.deserialize(tAgentStat, tAgentStatByteArray);
TJvmGc gc = tAgentStat.getGc();
AgentStatMemoryGcBo.Builder memoryGcBoBuilder = new AgentStatMemoryGcBo.Builder(tAgentStat.getAgentId(), tAgentStat.getStartTimestamp(), tAgentStat.getTimestamp());
memoryGcBoBuilder.gcType(gc.getType().name());
memoryGcBoBuilder.jvmMemoryHeapUsed(gc.getJvmMemoryHeapUsed()).jvmMemoryHeapMax(gc.getJvmMemoryHeapMax());
memoryGcBoBuilder.jvmMemoryNonHeapUsed(gc.getJvmMemoryNonHeapUsed()).jvmMemoryNonHeapMax(gc.getJvmMemoryNonHeapMax());
memoryGcBoBuilder.jvmGcOldCount(gc.getJvmGcOldCount()).jvmGcOldTime(gc.getJvmGcOldTime());
AgentStat agentStat = new AgentStat();
agentStat.setMemoryGc(memoryGcBoBuilder.build());
List<AgentStat> result = new ArrayList<AgentStat>(1);
result.add(agentStat);
return result;
}
}
@@ -2,17 +2,20 @@ package com.nhn.pinpoint.web.service;
import java.util.List;
import com.nhn.pinpoint.thrift.dto.TAgentStat;
import com.nhn.pinpoint.web.vo.AgentStat;
import com.nhn.pinpoint.web.vo.Range;
/**
* @author hyungil.jeong
*/
public interface AgentStatService {
/**
* 주어진 시간 범위에 따라 특정 agentId에 해당하는 시스템 통계 정보를 조회한다.
* @param agentId
* @param range
* @return
*/
List<TAgentStat> selectAgentStatList(String agentId, Range range);
/**
* 주어진 시간 범위에 따라 특정 agentId에 해당하는 시스템 통계 정보를 조회한다.
* @param agentId
* @param range
* @return
*/
List<AgentStat> selectAgentStatList(String agentId, Range range);
}
@@ -2,8 +2,9 @@ package com.nhn.pinpoint.web.service;
import java.util.List;
import com.nhn.pinpoint.thrift.dto.TAgentStat;
import com.nhn.pinpoint.web.vo.AgentStat;
import com.nhn.pinpoint.web.vo.Range;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -11,18 +12,19 @@ import com.nhn.pinpoint.web.dao.AgentStatDao;
/**
* @author harebox
* @author hyungil.jeong
*/
@Service
public class AgentStatServiceImpl implements AgentStatService {
@Autowired
private AgentStatDao agentStatDao;
public List<TAgentStat> selectAgentStatList(String agentId, Range range) {
@Autowired
private AgentStatDao agentStatDao;
public List<AgentStat> selectAgentStatList(String agentId, Range range) {
if (agentId == null) {
throw new NullPointerException("agentId must not be null");
}
return agentStatDao.scanAgentStatList(agentId, range);
}
}
}
@@ -0,0 +1,29 @@
package com.nhn.pinpoint.web.vo;
import com.nhn.pinpoint.common.bo.AgentStatCpuLoadBo;
import com.nhn.pinpoint.common.bo.AgentStatMemoryGcBo;
/**
* @author hyungil.jeong
*/
public class AgentStat {
private AgentStatMemoryGcBo memoryGc;
private AgentStatCpuLoadBo cpuLoad;
public AgentStatMemoryGcBo getMemoryGc() {
return memoryGc;
}
public void setMemoryGc(AgentStatMemoryGcBo memoryGc) {
this.memoryGc = memoryGc;
}
public AgentStatCpuLoadBo getCpuLoad() {
return cpuLoad;
}
public void setCpuLoad(AgentStatCpuLoadBo cpuLoad) {
this.cpuLoad = cpuLoad;
}
}
@@ -5,53 +5,53 @@ import java.util.List;
public abstract class Chart {
private String title;
private String xAxisName;
private String yAxisName;
private String title;
private String xAxisName;
private String yAxisName;
public String getTitle() {
return title;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public void setTitle(String title) {
this.title = title;
}
public void setXAxisName(String name) {
this.xAxisName = name;
}
public void setXAxisName(String name) {
this.xAxisName = name;
}
public void setYAxisName(String name) {
this.yAxisName = name;
}
public void setYAxisName(String name) {
this.yAxisName = name;
}
public String getxAxisName() {
return xAxisName;
}
public String getxAxisName() {
return xAxisName;
}
public void setxAxisName(String xAxisName) {
this.xAxisName = xAxisName;
}
public void setxAxisName(String xAxisName) {
this.xAxisName = xAxisName;
}
public String getyAxisName() {
return yAxisName;
}
public String getyAxisName() {
return yAxisName;
}
public void setyAxisName(String yAxisName) {
this.yAxisName = yAxisName;
}
public static final class Points {
private List<Long[]> points = new LinkedList<Long[]>();
public void setyAxisName(String yAxisName) {
this.yAxisName = yAxisName;
}
public Points() {
}
public static final class Points {
public List<Long[]> getPoints() {
return points;
}
private List<Number[]> points = new LinkedList<Number[]>();
}
public Points() {
}
public List<Number[]> getPoints() {
return points;
}
}
}
@@ -2,24 +2,22 @@ package com.nhn.pinpoint.web.vo.linechart;
import java.util.List;
public class LineChart extends Chart {
public abstract class LineChart<X extends Number, Y extends Number> extends Chart {
protected Chart.Points points;
protected Chart.Points points;
public LineChart() {
this.points = new Points();
}
public void addPoint(Long[] point) {
points.getPoints().add(point);
}
public LineChart() {
this.points = new Points();
}
public void setPoints(Points points) {
this.points = points;
}
public List<Long[]> getPoints() {
return this.points.getPoints();
}
public abstract void addPoint(X xVal, Y yVal);
public void setPoints(Points points) {
this.points = points;
}
public List<Number[]> getPoints() {
return this.points.getPoints();
}
}
@@ -0,0 +1,37 @@
package com.nhn.pinpoint.web.vo.linechart;
/**
* @author hyungil.jeong
*/
public class SampledDoubleLineChart extends LineChart<Long, Double> {
int sampleRate;
int sampleIndex;
Double[] sampleBuffer;
public SampledDoubleLineChart(int sampleRate) {
this.sampleRate = sampleRate;
this.sampleBuffer = new Double[sampleRate];
this.sampleIndex = 0;
}
@Override
public void addPoint(Long xVal, Double yVal) {
sampleBuffer[sampleIndex++] = yVal;
// FIXME 선택 가능하게. 모두 다 하는 경우에는 그냥 메소드 한번으로 끝낼 수도 있지만 일단...
if (sampleIndex == sampleRate) {
// point[x, minY, maxY, avgY]
Number[] samplePoint = new Number[4];
samplePoint[0] = xVal;
samplePoint[1] = DownSamplers.MIN.sampleDouble(sampleBuffer);
samplePoint[2] = DownSamplers.MAX.sampleDouble(sampleBuffer);
samplePoint[3] = DownSamplers.AVG.sampleDouble(sampleBuffer);
getPoints().add(samplePoint);
sampleIndex = 0;
}
}
}
@@ -1,40 +0,0 @@
package com.nhn.pinpoint.web.vo.linechart;
import java.security.InvalidParameterException;
public final class SampledLineChart extends LineChart {
int sampleRate;
int sampleIndex;
Long[] sampleBuffer;
public SampledLineChart(int sampleRate) {
this.sampleRate = sampleRate;
this.sampleBuffer = new Long[sampleRate];
this.sampleIndex = 0;
}
@Override
public void addPoint(Long[] point) {
if (point == null || point.length != 2) {
throw new InvalidParameterException("point array should be Number[2]");
}
sampleBuffer[sampleIndex++] = point[1];
// FIXME 선택 가능하게. 모두 다 하는 경우에는 그냥 메소드 한번으로 끝낼 수도 있지만 일단...
if (sampleIndex == sampleRate) {
// point[x, minY, maxY, avgY]
Long[] samplePoint = new Long[4];
samplePoint[0] = point[0];
samplePoint[1] = DownSamplers.MIN.sampleLong(sampleBuffer);
samplePoint[2] = DownSamplers.MAX.sampleLong(sampleBuffer);
samplePoint[3] = DownSamplers.AVG.sampleLong(sampleBuffer);
getPoints().add(samplePoint);
sampleIndex = 0;
}
}
}
@@ -0,0 +1,36 @@
package com.nhn.pinpoint.web.vo.linechart;
/**
* @author hyungil.jeong
*/
public final class SampledLongLineChart extends LineChart<Long, Long> {
int sampleRate;
int sampleIndex;
Long[] sampleBuffer;
public SampledLongLineChart(int sampleRate) {
this.sampleRate = sampleRate;
this.sampleBuffer = new Long[sampleRate];
this.sampleIndex = 0;
}
@Override
public void addPoint(Long xVal, Long yVal) {
sampleBuffer[sampleIndex++] = yVal;
// FIXME 선택 가능하게. 모두 다 하는 경우에는 그냥 메소드 한번으로 끝낼 수도 있지만 일단...
if (sampleIndex == sampleRate) {
// point[x, minY, maxY, avgY]
Number[] samplePoint = new Number[4];
samplePoint[0] = xVal;
samplePoint[1] = DownSamplers.MIN.sampleLong(sampleBuffer);
samplePoint[2] = DownSamplers.MAX.sampleLong(sampleBuffer);
samplePoint[3] = DownSamplers.AVG.sampleLong(sampleBuffer);
getPoints().add(samplePoint);
sampleIndex = 0;
}
}
}
@@ -1,60 +1,109 @@
package com.nhn.pinpoint.web.vo.linechart.agentstat;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.nhn.pinpoint.thrift.dto.TAgentStat;
import com.nhn.pinpoint.thrift.dto.TJvmGc;
import org.springframework.util.CollectionUtils;
import com.nhn.pinpoint.common.bo.AgentStatCpuLoadBo;
import com.nhn.pinpoint.common.bo.AgentStatMemoryGcBo;
import com.nhn.pinpoint.web.vo.AgentStat;
import com.nhn.pinpoint.web.vo.linechart.LineChart;
import com.nhn.pinpoint.web.vo.linechart.SampledLineChart;
import com.nhn.pinpoint.web.vo.linechart.SampledDoubleLineChart;
import com.nhn.pinpoint.web.vo.linechart.SampledLongLineChart;
/**
* @author harebox
* @author hyungil.jeong
*/
public class AgentStatChartGroup {
private String type;
private Map<String, LineChart> charts = new HashMap<String, LineChart>();
public void addData(TAgentStat data, int sampleRate) {
if (data == null) {
return;
}
private static final String JVM_MEMORY_HEAP_USED_KEY = "jvmMemoryHeapUsed";
private static final String JVM_MEMORY_HEAP_MAX_KEY = "jvmMemoryHeapMax";
private static final String JVM_MEMORY_NON_HEAP_USED_KEY = "jvmMemoryNonHeapUsed";
private static final String JVM_MEMORY_NON_HEAP_MAX_KEY = "jvmMemoryNonHeapMax";
private static final String JVM_GC_OLD_COUNT_KEY = "jvmGcOldCount";
private static final String JVM_GC_OLD_TIME_KEY = "jvmGcOldTime";
// 먼저 메시지에 포함된 데이터 타입을 알아낸다.
TJvmGc gc = data.getGc();
for (TJvmGc._Fields each : TJvmGc.metaDataMap.keySet()) {
Object fieldValue = gc.getFieldValue(each);
if (! (fieldValue instanceof Long)) {
continue;
}
if (! charts.containsKey(each.getFieldName())) {
charts.put(each.getFieldName(), new SampledLineChart(sampleRate));
}
LineChart chart = charts.get(each.getFieldName());
chart.addPoint(new Long[]{ data.getTimestamp(), (Long) fieldValue });
}
this.type = gc.getType().name();
}
private static final String CPU_LOAD_JVM_KEY = "jvmCpuLoad";
private static final String CPU_LOAD_SYSTEM_KEY = "systemCpuLoad";
public String getType() {
return type;
}
private String type;
private Map<String, LineChart<?, ?>> charts = new HashMap<String, LineChart<? extends Number, ? extends Number>>();
public void setType(String type) {
this.type = type;
}
public AgentStatChartGroup(int sampleRate) {
charts.put(JVM_MEMORY_HEAP_USED_KEY, new SampledLongLineChart(sampleRate));
charts.put(JVM_MEMORY_HEAP_MAX_KEY, new SampledLongLineChart(sampleRate));
charts.put(JVM_MEMORY_NON_HEAP_USED_KEY, new SampledLongLineChart(sampleRate));
charts.put(JVM_MEMORY_NON_HEAP_MAX_KEY, new SampledLongLineChart(sampleRate));
charts.put(JVM_GC_OLD_COUNT_KEY, new SampledLongLineChart(sampleRate));
charts.put(JVM_GC_OLD_TIME_KEY, new SampledLongLineChart(sampleRate));
charts.put(CPU_LOAD_JVM_KEY, new SampledDoubleLineChart(sampleRate));
charts.put(CPU_LOAD_SYSTEM_KEY, new SampledDoubleLineChart(sampleRate));
}
public Map<String, LineChart> getCharts() {
return charts;
}
public void addAgentStats(List<AgentStat> agentStats) {
for (AgentStat agentStat : agentStats) {
addMemoryGcData(agentStat.getMemoryGc());
addCpuLoadData(agentStat.getCpuLoad());
}
removeUncollectedCharts();
}
public void setCharts(Map<String, LineChart> charts) {
this.charts = charts;
}
private void addMemoryGcData(AgentStatMemoryGcBo data) {
if (data == null) {
return;
}
this.type = data.getGcType();
long timestamp = data.getTimestamp();
((SampledLongLineChart)charts.get(JVM_MEMORY_HEAP_USED_KEY)).addPoint(timestamp, data.getJvmMemoryHeapUsed());
((SampledLongLineChart)charts.get(JVM_MEMORY_HEAP_MAX_KEY)).addPoint(timestamp, data.getJvmMemoryHeapMax());
((SampledLongLineChart)charts.get(JVM_MEMORY_NON_HEAP_USED_KEY)).addPoint(timestamp, data.getJvmMemoryNonHeapUsed());
((SampledLongLineChart)charts.get(JVM_MEMORY_NON_HEAP_MAX_KEY)).addPoint(timestamp, data.getJvmMemoryNonHeapMax());
((SampledLongLineChart)charts.get(JVM_GC_OLD_COUNT_KEY)).addPoint(timestamp, data.getJvmGcOldCount());
((SampledLongLineChart)charts.get(JVM_GC_OLD_TIME_KEY)).addPoint(timestamp, data.getJvmGcOldTime());
}
private void addCpuLoadData(AgentStatCpuLoadBo data) {
if (data == null) {
return;
}
long timestamp = data.getTimestamp();
double jvmCpuLoadPercentage = data.getJvmCpuLoad() * 100;
double systemCpuLoadPercentage = data.getSystemCpuLoad() * 100;
if (!(jvmCpuLoadPercentage < 0)) {
((SampledDoubleLineChart)charts.get(CPU_LOAD_JVM_KEY)).addPoint(timestamp, jvmCpuLoadPercentage);
}
if (!(systemCpuLoadPercentage < 0)) {
((SampledDoubleLineChart)charts.get(CPU_LOAD_SYSTEM_KEY)).addPoint(timestamp, systemCpuLoadPercentage);
}
}
private void removeUncollectedCharts() {
for (Iterator<Map.Entry<String, LineChart<?, ?>>> iter = charts.entrySet().iterator(); iter.hasNext();) {
Map.Entry<String, LineChart<?, ?>> chartEntry = iter.next();
if (CollectionUtils.isEmpty(chartEntry.getValue().getPoints())) {
iter.remove();
}
}
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Map<String, LineChart<?, ?>> getCharts() {
return charts;
}
public void setCharts(Map<String, LineChart<?, ?>> charts) {
this.charts = charts;
}
}
@@ -2,8 +2,9 @@ package com.nhn.pinpoint.web.dao.hbase;
import java.util.List;
import com.nhn.pinpoint.thrift.dto.TAgentStat;
import com.nhn.pinpoint.web.vo.AgentStat;
import com.nhn.pinpoint.web.vo.Range;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
@@ -12,20 +13,21 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author harebox
* @author hyungil.jeong
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class HbaseAgentStatDaoTest {
@Autowired
private HbaseAgentStatDao dao;
@Test
public void selectAgentStat() {
long timestamp = System.currentTimeMillis();
@Autowired
private HbaseAgentStatDao dao;
@Test
public void selectAgentStat() {
long timestamp = System.currentTimeMillis();
Range range = new Range(timestamp - 100000, timestamp);
List<TAgentStat> result = dao.scanAgentStatList("FRONT-WEB1", range);
System.out.println(result);
}
List<AgentStat> result = dao.scanAgentStatList("FRONT-WEB1", range);
System.out.println(result);
}
}
@@ -4,25 +4,47 @@ import static org.junit.Assert.assertTrue;
import org.codehaus.jackson.map.ObjectMapper;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SampledLineChartTest {
@Test
public void tdd() throws Exception {
int sampleRate = 60;
int totalPoints = 10000;
LineChart lineChart = new SampledLineChart(sampleRate);
for (long i = 0; i < totalPoints; i++) {
lineChart.addPoint(new Long[]{i, i});
}
assertTrue(lineChart.getPoints().size() == totalPoints / sampleRate);
ObjectMapper mapper = new ObjectMapper();
String result = mapper.writeValueAsString(lineChart);
System.out.println(result);
}
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Test
public void testSampledLongLineChart() throws Exception {
int sampleRate = 60;
int totalPoints = 10000;
SampledLongLineChart lineChart = new SampledLongLineChart(sampleRate);
for (long i = 0; i < totalPoints; i++) {
lineChart.addPoint(i, i);
}
assertTrue(lineChart.getPoints().size() == totalPoints / sampleRate);
ObjectMapper mapper = new ObjectMapper();
String result = mapper.writeValueAsString(lineChart);
logger.debug(result);
}
@Test
public void testSampledDoubleLineChart() throws Exception {
int sampleRate = 60;
int totalPoints = 10000;
SampledDoubleLineChart lineChart = new SampledDoubleLineChart(sampleRate);
for (long i = 0; i < totalPoints; i++) {
lineChart.addPoint(i, (double)i);
}
assertTrue(lineChart.getPoints().size() == totalPoints / sampleRate);
ObjectMapper mapper = new ObjectMapper();
String result = mapper.writeValueAsString(lineChart);
logger.debug(result);
}
}