Merge pull request #20 from naver/dev-translation

comment cleanup and English translation
This commit is contained in:
Jongho Moon
2014-12-29 10:46:21 +09:00
56 changed files with 378 additions and 363 deletions
@@ -80,9 +80,9 @@ public class AgentClassLoader {
Constructor<?> constructor = bootStrapClazz.getConstructor(String.class, String.class, Instrumentation.class, ProfilerConfig.class);
return constructor.newInstance(agentPath, agentArgs, instrumentation, profilerConfig);
} catch (InstantiationException e) {
throw new BootStrapException("boot create fail. Caused:" + e.getMessage(), e);
throw new BootStrapException("boot create failed. Error:" + e.getMessage(), e);
} catch (IllegalAccessException e) {
throw new BootStrapException("boot method invoke fail. Caused:" + e.getMessage(), e);
throw new BootStrapException("boot method invoke failed. Error:" + e.getMessage(), e);
}
}
});
@@ -96,7 +96,7 @@ public class AgentClassLoader {
} else {
agentClassName = agent.getClass().getName();
}
throw new BootStrapException("Invalid AgentType. boot fail. AgentClass:" + agentClassName);
throw new BootStrapException("Invalid AgentType. boot failed. AgentClass:" + agentClassName);
}
}
@@ -105,7 +105,7 @@ public class AgentClassLoader {
try {
return this.classLoader.loadClass(bootClass);
} catch (ClassNotFoundException e) {
throw new BootStrapException("boot class not found. bootClass:" + bootClass + " Caused:" + e.getMessage(), e);
throw new BootStrapException("boot class not found. bootClass:" + bootClass + " Error:" + e.getMessage(), e);
}
}
@@ -125,9 +125,9 @@ public class AgentClassLoader {
try {
return findMethod.invoke(agentBootStrap, args);
} catch (InvocationTargetException e) {
throw new BootStrapException(findMethod.getName() + "() fail. Caused:" + e.getMessage(), e);
throw new BootStrapException(findMethod.getName() + "() failed. Error:" + e.getMessage(), e);
} catch (IllegalAccessException e) {
throw new BootStrapException("boot method invoke fail. Caused:" + e.getMessage(), e);
throw new BootStrapException("boot method invoke failed. Error:" + e.getMessage(), e);
}
}
});
@@ -138,7 +138,7 @@ public class AgentClassLoader {
try {
return clazz.getDeclaredMethod(method, type);
} catch (NoSuchMethodException e) {
throw new BootStrapException("(" + method + ") boot method not found. Caused:" + e.getMessage(), e);
throw new BootStrapException("(" + method + ") boot method not found. Error:" + e.getMessage(), e);
}
}
@@ -170,7 +170,7 @@ public class ClassPathResolver {
try {
return uri.toURL();
} catch (MalformedURLException e) {
logger.log(Level.WARNING, file.getName() + ".toURL() fail. Caused:" + e.getMessage(), e);
logger.log(Level.WARNING, file.getName() + ".toURL() failed. Error:" + e.getMessage(), e);
return null;
}
}
@@ -95,13 +95,13 @@ public class PinpointBootStrap {
List<URL> libUrlList = resolveLib(classPathResolver);
AgentClassLoader agentClassLoader = new AgentClassLoader(libUrlList.toArray(new URL[libUrlList.size()]));
agentClassLoader.setBootClass(BOOT_CLASS);
logger.info("pinpoint agent start.");
logger.info("pinpoint agent starting...");
agentClassLoader.boot(classPathResolver.getAgentDirPath(), agentArgs, instrumentation, profilerConfig);
logger.info("pinpoint agent start success.");
logger.info("pinpoint agent started normally.");
changeLoadState(BOOT_STRAP_LOAD_STATE_COMPLETE);
} catch (Exception e) {
// unexpected exception that did not be checked above
logger.log(Level.SEVERE, ProductInfo.CAMEL_NAME + " start fail. Caused:" + e.getMessage(), e);
logger.log(Level.SEVERE, ProductInfo.CAMEL_NAME + " start failed. Error:" + e.getMessage(), e);
changeLoadState(BOOT_STRAP_LOAD_STATE_ERROR);
logPinpointAgentLoadFail();
}
@@ -115,7 +115,7 @@ public class PinpointBootStrap {
private static void logPinpointAgentLoadFail() {
final String errorLog =
"*****************************************************************************\n" +
"* PinpointAgent load fail\n" +
"* Pinpoint Agent load failure\n" +
"*****************************************************************************";
System.err.println(errorLog);
}
@@ -126,7 +126,7 @@ public class PinpointBootStrap {
changeLoadState(BOOT_STRAP_LOAD_STATE_LOADING);
} else {
if (logger.isLoggable(Level.SEVERE)) {
logger.severe("pinpoint-bootstrap already started. skip agent loading. loadState:" + exist);
logger.severe("pinpoint-bootstrap already started. skipping agent loading. loadState:" + exist);
}
return true;
}
@@ -67,12 +67,12 @@ public class ProfilerConfig {
return new ProfilerConfig(properties);
} catch (FileNotFoundException fe) {
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING, pinpointConfigFileName + " file is not exists. Please check configuration.");
logger.log(Level.WARNING, pinpointConfigFileName + " file does not exist. Please check your configuration.");
}
throw fe;
} catch (IOException e) {
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING, pinpointConfigFileName + " file read error. Cause:" + e.getMessage(), e);
logger.log(Level.WARNING, pinpointConfigFileName + " file I/O error. Error:" + e.getMessage(), e);
}
throw e;
}
@@ -562,7 +562,7 @@ public class ProfilerConfig {
// for test
void readPropertyValues() {
// TODO : use Properties's defaultvalue instead of using temp variable.
// TODO : use Properties's default value instead of using a temp variable.
final ValueResolver placeHolderResolver = new PlaceHolderResolver();
this.profileEnable = readBoolean("profiler.enable", true);
@@ -69,6 +69,6 @@ public interface AsyncTrace {
void recordDestinationId(String destinationId);
// TODO: final String... endPoint로 받으면 합치는데 비용이 들어가 그냥 한번에 받는게 나을것 같음.
// TODO: final String... an aggregated input needed so we don't have to sum up endPoints
void recordEndPoint(String endPoint);
}
@@ -80,10 +80,11 @@ public interface RecordableTrace {
void recordParentApplication(String parentApplicationName, short parentApplicationType);
/**
* WAS_A -> WAS_B 호출 관계일 때 WAS_B에서 WAS_A가 보내준 호출 정보를 통해 자기 자신의 정보를 추출하여 저장
* 이 데이터는 서버맵에서 WAS끼리 호출관계를 알아낼 떄 필요하다.
*
* @param host host 값은 WAS를 호출한 URL상의 host를 가져와야 한다.
* when WAS_A sends a request to WAS_B, WAS_A stores its own data through parameters sent by WAS_B.
* This data is needed to extract caller/callee relationship.
*
* @param host (we need to extract hostname from the request URL)
*
*
*/
@@ -30,7 +30,7 @@ public interface TraceContext {
Trace currentTraceObject();
/**
* sampling rate를 추가적으로 확인해야 되는 trace를 리턴한다.
* return a trace whose sampling rate should be further verified
* @return
*/
Trace currentRawTraceObject();
@@ -17,6 +17,7 @@
package com.navercorp.pinpoint.bootstrap.instrument;
// TODO 추후 별도 계층구조가 필요하면 분화 필요.
// TODO Separate this class when hierarchical layers are needed
/**
* @author emeroad
*/
@@ -17,7 +17,8 @@
package com.navercorp.pinpoint.bootstrap.interceptor;
/**
* precompile level의 methodDescriptor를 setting 받을수 있게 한다.
* this enables assigning "precompiled" methodDescriptor
*
* @author emeroad
*/
public interface ByteCodeMethodDescriptorSupport {
@@ -93,7 +93,7 @@ public class InterceptorRegistry {
SimpleAroundInterceptor getSimpleInterceptor0(int key) {
SimpleAroundInterceptor interceptor = simpleIndex[key];
if (interceptor == null) {
// 로직이 잘못되었을경우 에러가 발생하지 않도록 더미를 리턴.
// return DUMMY upon wrong logic
return DUMMY;
}
return interceptor;
@@ -102,7 +102,7 @@ public class InterceptorRegistry {
// SimpleAroundInterceptor getInterceptor0(int key) {
// StaticAfterInterceptor interceptor = index[key];
// if (interceptor == null) {
// // 로직이 잘못되었을 경우 에러가 발생하지 않도록 더미를 리턴.
// // return DUMMY upon wrong logic
// return DUMMY;
// }
// return interceptor;
@@ -17,7 +17,7 @@
package com.navercorp.pinpoint.bootstrap.interceptor;
/**
* 객체 생성을 줄이기 위해서 객체를 리턴하지 않고 c 스타일 api로 디자인함.
* C-style API (doesn't return an object) in order to reduce the number of object instantiating
* @author emeroad
*/
public interface ParameterExtractor {
@@ -49,7 +49,7 @@ public abstract class SpanSimpleAroundInterceptor implements SimpleAroundInterce
if (trace == null) {
return;
}
// TODO STATDISABLE 일단 통계 저장기능을 disable하기 위해 아래 로직을 추가함.
// TODO STATDISABLE this logic was added to disable statstics tracing
if (!trace.canSampled()) {
return;
}
@@ -77,7 +77,7 @@ public abstract class SpanSimpleAroundInterceptor implements SimpleAroundInterce
return;
}
traceContext.detachTraceObject();
// TODO STATDISABLE 일단 통계 저장기능을 disable하기 위해 아래 로직을 추가함.
// TODO STATDISABLE this logic was added to disable statstics tracing
if (!trace.canSampled()) {
return;
}
@@ -35,8 +35,8 @@ public final class PLoggerFactory {
}
public static void unregister(PLoggerBinder loggerBinder) {
// 등록한 놈만 제거 가능하도록 제한
// testcase 작성시 가능한 logger를 등록했다가 삭제하는 로직은 beforeClass, afterClass에 넣어야 한다.
// Limited to remove only the ones already registered
// when writing a test case, logger register/unregister logic must be located in beforeClass and afterClass
if (loggerBinder == PLoggerFactory.loggerBinder) {
PLoggerFactory.loggerBinder = null;
}
@@ -44,7 +44,7 @@ public final class PLoggerFactory {
public static PLogger getLogger(String name) {
if (loggerBinder == null) {
// 바인딩 되지 않은 상태에서 getLogger를 호출시 null ex가 발생하므로 dummy logger를 리턴하도록 함.
// this prevents null exception: need to return Dummy until a Binder is assigned
return DummyPLogger.INSTANCE;
}
return loggerBinder.getLogger(name);
@@ -17,8 +17,8 @@
package com.navercorp.pinpoint.bootstrap.pair;
/**
* classLoading구조에서 interceptor가 parent에 위치하면서 멀티 value access 데이터 전달이 필요할 경우의 공통 자료구조로 사용한다.
* value가 int type일때 사용
* need to use common data structure when classLoading intercepter is in parent and, at the same time, multiple "value access" data are needed.
* Use this when value is "int" type.
* @author emeroad
*/
public class NameIntValuePair<T> {
@@ -17,7 +17,7 @@
package com.navercorp.pinpoint.bootstrap.pair;
/**
* classLoading구조에서 interceptor가 parent에 위치하면서 멀티 value access 데이터 전달이 필요할 경우의 공통 자료구조로 사용한다.
* need to use common data structure when classLoading intercepter is in parent and, at the same time, multiple "value access" data are needed.
* @author emeroad
*/
public class NameValuePair<T, V> {
@@ -39,10 +39,10 @@ public final class BytecodeUtils {
return method;
} catch (NoSuchMethodException e) {
// link error
throw new RuntimeException("defineClass not found. Caused:" + e.getMessage(), e);
throw new RuntimeException("defineClass not found. Error:" + e.getMessage(), e);
} catch (SecurityException e) {
// link error
throw new RuntimeException("defineClass error. Caused:" + e.getMessage(), e);
throw new RuntimeException("defineClass error. Error:" + e.getMessage(), e);
}
}
@@ -21,8 +21,7 @@ package com.navercorp.pinpoint.bootstrap.sampler;
*/
public final class SamplingFlagUtils {
// 향후 다른 샘플링 스펙이 추가될수 있으므로
// 일부러 1개 byte를 소비하여 sampling마크 한다.
// 1 byte dummy mark for further expansion of sampling specs
public static final String SAMPLING_RATE_PREFIX = "s";
@@ -36,8 +35,8 @@ public final class SamplingFlagUtils {
if (samplingFlag == null) {
return true;
}
// 정확하게 하지 말란 flag가 세팅되었을 경우만 샘플링을 하지 않는다.
// prefix를 보고 뭔가 더 정확하게 동작되어야 필요성이 있음.
// we turn off sampling only when a specific flag was given
// XXX needs better detection mechanism through prefix parsing
if (samplingFlag.startsWith(SAMPLING_RATE_PREFIX)) {
return !SAMPLING_RATE_FALSE.equals(samplingFlag);
}
@@ -36,40 +36,40 @@ public class AlarmPartitioner implements Partitioner {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
public static final int APP_COUNT = 5;
public static final String PARTITION_NUMBER = "partition_number";
@Autowired
private ApplicationIndexDao applicationIndexDao;
public AlarmPartitioner() {
}
protected AlarmPartitioner(ApplicationIndexDao applicationIndexDao) {
this.applicationIndexDao = applicationIndexDao;
}
@Override
public Map<String, ExecutionContext> partition(int gridSize) {
int partitionCount = calculateGroupCount();
Map<String, ExecutionContext> mapContext = new HashMap<String, ExecutionContext>();
for (int i = 1; i <= partitionCount; i++) {
ExecutionContext executionContext = new ExecutionContext();
executionContext.put(PARTITION_NUMBER, i);
mapContext.put(PARTITION_NUMBER + "_" + i, executionContext);
}
return mapContext;
}
}
public int calculateGroupCount() {
List<Application> applicationList = applicationIndexDao.selectAllApplicationNames();
int partitionCount = applicationList.size() / APP_COUNT;
if (applicationList.size() % APP_COUNT != 0) {
partitionCount++;
}
logger.info("application count is {}. patition count is {}", applicationList.size(), partitionCount);
logger.info("application count is {}. partition count is {}", applicationList.size(), partitionCount);
return partitionCount;
}
}
@@ -34,23 +34,23 @@ import com.navercorp.pinpoint.web.vo.Application;
*/
@Component
public class DataCollectorFactory {
public final static long SLOT_INTERVAL_FIVE_MIN = 300000;
public final static long SLOT_INTERVAL_THREE_MIN = 180000;
@Autowired
private HbaseMapResponseTimeDao hbaseMapResponseTimeDao;
@Autowired
private HbaseAgentStatDao hbaseAgentStatDao;
@Autowired
private HbaseApplicationIndexDao hbaseApplicationIndexDao;
@Autowired
private HbaseMapStatisticsCallerDao mapStatisticsCallerDao;
public DataCollector createDataCollector(CheckerCategory checker, Application application, long timeSlotEndTime) {
switch (checker.getDataCollectorCategory()) {
case RESPONSE_TIME:
@@ -60,11 +60,11 @@ public class DataCollectorFactory {
case CALLER_STAT:
return new MapStatisticsCallerDataCollector(DataCollectorCategory.CALLER_STAT, application, mapStatisticsCallerDao, timeSlotEndTime, SLOT_INTERVAL_FIVE_MIN);
}
throw new IllegalArgumentException("not create DataCollector : " + checker.getName());
throw new IllegalArgumentException("unable to create DataCollector : " + checker.getName());
}
public enum DataCollectorCategory {
RESPONSE_TIME,
AGENT_STAT,
@@ -38,19 +38,19 @@ public class AgentStatDataCollector extends DataCollector {
private final ApplicationIndexDao applicationIndexDao;
private final long timeSlotEndTime;
private final long slotInterval;
private final AtomicBoolean init = new AtomicBoolean(false); // need to consider the concurrency situation when checkers start simultaneously.
private final AtomicBoolean init = new AtomicBoolean(false); // need to consider a race condition when checkers start simultaneously.
private final Map<String, Long> agentHeapUsageRate = new HashMap<String, Long>();
private final Map<String, Long> agentGcCount = new HashMap<String, Long>();
private final Map<String, Long> agentJvmCpuUsageRate = new HashMap<String, Long>();
public AgentStatDataCollector(DataCollectorCategory category, Application application, AgentStatDao agentStatDao, ApplicationIndexDao applicationIndexDao, long timeSlotEndTime, long slotInterval) {
super(category);
this.application = application;
this.agentStatDao = agentStatDao;
this.applicationIndexDao = applicationIndexDao;
this.timeSlotEndTime = timeSlotEndTime;
this.slotInterval = slotInterval;
this.slotInterval = slotInterval;
}
@Override
@@ -58,40 +58,40 @@ public class AgentStatDataCollector extends DataCollector {
if (init.get()) {
return;
}
Range range = Range.createUncheckedRange(timeSlotEndTime - slotInterval, timeSlotEndTime);
List<String> agentIds = applicationIndexDao.selectAgentIds(application.getName());
for(String agentId : agentIds) {
List<AgentStat> scanAgentStatList = agentStatDao.scanAgentStatList(agentId, range);
int listSize = scanAgentStatList.size();
long totalHeapSize = 0;
long usedHeapSize = 0;
long jvmCpuUsaged = 0;
for (AgentStat agentStat : scanAgentStatList) {
totalHeapSize += agentStat.getMemoryGc().getJvmMemoryHeapMax();
usedHeapSize += agentStat.getMemoryGc().getJvmMemoryHeapUsed();
jvmCpuUsaged += agentStat.getCpuLoad().getJvmCpuLoad() * 100;
}
if(listSize > 0) {
long percent = calculatePercent(usedHeapSize, totalHeapSize);
agentHeapUsageRate.put(agentId, percent);
percent = calculatePercent(jvmCpuUsaged, 100*scanAgentStatList.size());
agentJvmCpuUsageRate.put(agentId, percent);
long accruedLastGCcount = scanAgentStatList.get(0).getMemoryGc().getJvmGcOldCount();
long accruedFirstGCcount= scanAgentStatList.get(listSize - 1).getMemoryGc().getJvmGcOldCount();
agentGcCount.put(agentId, accruedLastGCcount - accruedFirstGCcount);
agentGcCount.put(agentId, accruedLastGCcount - accruedFirstGCcount);
}
}
init.set(true);
}
private long calculatePercent(long used, long total) {
@@ -113,5 +113,5 @@ public class AgentStatDataCollector extends DataCollector {
public Map<String, Long> getJvmCpuUsageRate() {
return agentJvmCpuUsageRate;
}
}
@@ -36,18 +36,18 @@ import com.navercorp.pinpoint.web.vo.Range;
public class MapStatisticsCallerDataCollector extends DataCollector {
private Application application;
private MapStatisticsCallerDao mapStatisticsCallerDao;
private MapStatisticsCallerDao mapStatisticsCallerDao;
private long timeSlotEndTime;
private long slotInterval;
private Map<String, LinkCallData> calleStatMap = new HashMap<String, LinkCallData>();
private final AtomicBoolean init =new AtomicBoolean(false); // need to consider the concurrency situation when checkers start simultaneously.
private final AtomicBoolean init =new AtomicBoolean(false); // need to consider a trace condition when checkers start simultaneously.
public MapStatisticsCallerDataCollector(DataCollectorCategory category, Application application, MapStatisticsCallerDao mapStatisticsCallerDao, long timeSlotEndTime, long slotInterval) {
super(category);
this.application = application;
this.mapStatisticsCallerDao = mapStatisticsCallerDao;
this.timeSlotEndTime = timeSlotEndTime;
this.slotInterval = slotInterval;
this.slotInterval = slotInterval;
}
@Override
@@ -55,24 +55,24 @@ public class MapStatisticsCallerDataCollector extends DataCollector {
if (init.get()) {
return;
}
LinkDataMap callerDataMap = mapStatisticsCallerDao.selectCaller(application, new Range(timeSlotEndTime - slotInterval, timeSlotEndTime));
for (LinkData linkData : callerDataMap.getLinkDataList()) {
LinkCallDataMap linkCallDataMap = linkData.getLinkCallDataMap();
for (LinkCallData linkCallData : linkCallDataMap.getLinkDataList()) {
calleStatMap.put(linkCallData.getTarget(), linkCallData);
}
}
init.set(true);
}
public long getCount(String calleName, DataCategory dataCategory) {
LinkCallData linkCallData = calleStatMap.get(calleName);
long count = 0;
if (linkCallData != null) {
switch (dataCategory) {
case SLOW_COUNT:
@@ -94,18 +94,18 @@ public class MapStatisticsCallerDataCollector extends DataCollector {
default :
throw new IllegalArgumentException("Can't count for " + dataCategory.toString());
}
return count;
}
return 0;
}
public long getCountRate(String calleName, DataCategory dataCategory) {
LinkCallData linkCallData = calleStatMap.get(calleName);
long count = 0;
long totalCount = 0;
if (linkCallData != null) {
switch (dataCategory) {
case SLOW_RATE:
@@ -124,10 +124,10 @@ public class MapStatisticsCallerDataCollector extends DataCollector {
default :
throw new IllegalArgumentException("Can't calculate rate for " + dataCategory.toString());
}
return calculatePercent(count, totalCount);
}
return 0;
}
@@ -36,20 +36,20 @@ public class ResponseTimeDataCollector extends DataCollector {
private final MapResponseDao responseDao;
private final long timeSlotEndTime;
private final long slotInterval;
private final AtomicBoolean init =new AtomicBoolean(false); // need to consider the concurrency situation when checkers start simultaneously.
private final AtomicBoolean init =new AtomicBoolean(false); // need to consider a race condition when checkers start simultaneously.
private long slowCount = 0;
private long errorCount = 0;
private long totalCount = 0;
private long slowRate = 0;
private long errorRate = 0;
public ResponseTimeDataCollector(DataCollectorCategory category, Application application, MapResponseDao responseDAO, long timeSlotEndTime, long slotInterval) {
super(category);
this.application = application;
this.responseDao = responseDAO;
this.timeSlotEndTime = timeSlotEndTime;
this.slotInterval = slotInterval;
this.slotInterval = slotInterval;
}
@Override
@@ -57,14 +57,14 @@ public class ResponseTimeDataCollector extends DataCollector {
if (init.get()) {
return;
}
Range range = Range.createUncheckedRange(timeSlotEndTime - slotInterval, timeSlotEndTime);
List<ResponseTime> responseTimes = responseDao.selectResponseTime(application, range);
for (ResponseTime responseTime : responseTimes) {
sum(responseTime.getAgentResponseHistogramList());
}
setSlowRate();
setErrorRate();
@@ -74,11 +74,11 @@ public class ResponseTimeDataCollector extends DataCollector {
private void setSlowRate() {
slowRate = calculatePercent(slowCount);
}
private void setErrorRate() {
errorRate = calculatePercent(errorCount);
}
private long calculatePercent(long value) {
if (totalCount == 0 || value == 0) {
return 0;
@@ -95,15 +95,15 @@ public class ResponseTimeDataCollector extends DataCollector {
totalCount += timeHistogram.getTotalCount();
}
}
public long getSlowCount() {
return slowCount;
}
public long getErrorCount() {
return errorCount;
}
public long getTotalCount() {
return totalCount;
}
@@ -39,9 +39,9 @@ public class ApplicationMapBuilder {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final Range range;
private MatcherGroup matcherGroup;
public ApplicationMapBuilder(Range range, MatcherGroup matcherGroup) {
if (range == null) {
throw new NullPointerException("range must not be null");
@@ -115,8 +115,8 @@ public class ApplicationMapBuilder {
for (LinkData linkData : linkDataMap.getLinkDataList()) {
final Application fromApplication = linkData.getFromApplication();
// FROM -> TO에서 FROM이 CLIENT가 아니면 FROM은 node
// rpc가 나올수가 없음. 이미 unknown으로 치환을 하기 때문에. 만약 rpc가 나온다면 이상한 케이스임
// FROM is either a CLIENT or a node
// cannot be RPC. Already converted to unknown.
if (!fromApplication.getServiceType().isRpcClient()) {
final boolean success = addNode(nodeList, fromApplication);
if (success) {
@@ -17,7 +17,8 @@
package com.navercorp.pinpoint.web.applicationmap;
/**
* 호출한 정보에 의해서 생성된거면 Source, 호출당한 정보에 의해서 생성되면 Target
* Source if created with caller information
* Target if created with callee information
* @author emeroad
*/
public enum CreateType {
@@ -37,8 +37,8 @@ import java.util.List;
import java.util.Set;
/**
* application map에서 application간의 관계를 담은 클래스
*
* A class that describes relationship between apps in application map
*
* @author netspider
* @author emeroad
*/
@@ -48,8 +48,8 @@ public class Link {
public static final String LINK_DELIMITER = "~";
// 링크를 생성한 데이터의 주체가 누구인가를 나타냄
// source에 의해서 먼저 생성된것인지, target에 의해서 수동적으로 생성된것인지 나타낸다.
// specified who created a link.
// indicates whether created by a source or manually created by a target
private final CreateType createType;
private final Node fromNode;
private final Node toNode;
@@ -92,8 +92,8 @@ public class Link {
}
public Application getFilterApplication() {
// User 링크일 경우 from을 보면 안되고 was를 봐야 한다.
// User는 가상의 링크이기 때문에, User로 필터링을 칠수 없음.
// User link: need to look at WAS, not from
// Since User is a virtual link, we cannot filter by User
if (fromNode.getServiceType() == ServiceType.USER) {
return toNode.getApplication();
}
@@ -147,8 +147,8 @@ public class Link {
}
private Histogram createHistogram0() {
// 내가 호출하는 대상의 serviceType을 가져와야 한다.
// tomcat -> arcus를 호출한다고 하였을 경우 arcus의 타입을 가져와야함.
// need serviceType of target (callee)
// ie. Tomcat -> Arcus: we need arcus type
final LinkCallDataMap findMap = getLinkCallDataMap();
AgentHistogramList targetList = findMap.getTargetList();
return targetList.mergeHistogram(toNode.getServiceType());
@@ -174,8 +174,8 @@ public class Link {
}
public Histogram getTargetHistogram() {
// 내가 호출하는 대상의 serviceType을 가져와야 한다.
// tomcat -> arcus를 호출한다고 하였을 경우 arcus의 타입을 가져와야함.
// need serviceType of target (callee)
// ie. Tomcat -> Arcus: we need Arcus type
AgentHistogramList targetList = targetLinkCallDataMap.getTargetList();
return targetList.mergeHistogram(toNode.getServiceType());
@@ -201,20 +201,20 @@ public class Link {
}
private ApplicationTimeHistogram getSourceApplicationTimeSeriesHistogramData() {
// form인것 같지만 link의 시간은 rpc를 기준으로 삼아야 하기 때문에. to를 기준으로 삼아야 한다.
// we need Target (to)'s time since time in link is RPC-based
ApplicationTimeHistogramBuilder builder = new ApplicationTimeHistogramBuilder(toNode.getApplication(), range);
return builder.build(sourceLinkCallDataMap.getLinkDataList());
}
public ApplicationTimeHistogram getTargetApplicationTimeSeriesHistogramData() {
// form인것 같지만 link의 시간은 rpc를 기준으로 삼아야 하기 때문에. to를 기준으로 삼아야 한다.
// we need Target (to)'s time since time in link is RPC-based
ApplicationTimeHistogramBuilder builder = new ApplicationTimeHistogramBuilder(toNode.getApplication(), range);
return builder.build(targetLinkCallDataMap.getLinkDataList());
}
public AgentResponseTimeViewModelList getSourceAgentTimeSeriesHistogram() {
// form인것 같지만 link의 시간은 rpc를 기준으로 삼아야 하기 때문에. to를 기준으로 삼아야 한다.
// we need Target (to)'s time since time in link is RPC-based
AgentTimeHistogramBuilder builder = new AgentTimeHistogramBuilder(toNode.getApplication(), range);
AgentTimeHistogram applicationTimeSeriesHistogram = builder.buildSource(sourceLinkCallDataMap);
AgentResponseTimeViewModelList agentResponseTimeViewModelList = new AgentResponseTimeViewModelList(applicationTimeSeriesHistogram.createViewModel());
@@ -43,7 +43,7 @@ public class LinkList {
}
/**
* toApplication을 가리키는(호출당하는) 모든 link를 찾음.
* find all callers of toApplication
* @param toApplication
* @return
*/
@@ -55,7 +55,7 @@ public class LinkList {
List<Link> findList = new ArrayList<Link>();
for (Link link : linkMap.values()) {
Node toNode = link.getTo();
// destnation이 자신을 가리키는 모든 Link를 찾음.
// find all the callers of toApplication/destination
if (toNode.getApplication().equals(toApplication)) {
findList.add(link);
}
@@ -64,7 +64,7 @@ public class LinkList {
}
/**
* fromApplication 에서 나가는(호출하는) link를 모두 찾음.
* find all callees of fromApplication
* @param fromApplication
* @return
*/
@@ -29,7 +29,8 @@ public class LinkStateResolver {
if (link == null) {
throw new NullPointerException("link must not be null");
}
// Histogram이 중복으로 생성되고 있어 그냥 인자로 받음 수정 요망.
// since Histogram dup gets created, we simply accepts as a parameter
// XXX need to fix this
final long error = getErrorRate(link.getHistogram());
if (error * 100 > 10) {
return BAD;
@@ -30,8 +30,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* node map에서 application을 나타낸다.
*
* class for application in node map
*
* @author netspider
* @author emeroad
*/
@@ -47,7 +47,8 @@ public class Node {
private ServerInstanceList serverInstanceList;
private NodeHistogram nodeHistogram;
// 임시로 생성.
// temporary
private static final ObjectMapper MAPPER = new ObjectMapper();
@@ -79,7 +79,7 @@ public class ServerBuilder {
}
/**
* 어플리케이션에 속한 물리서버와 서버 인스턴스 정보를 채운다.
* filled with application information of physical server and service instance
*
* @param hostHistogram
*/
@@ -110,11 +110,11 @@ public class ServerBuilder {
public ServerInstanceList build() {
if (!agentSet.isEmpty()) {
// agent이름이 존재할 경우. 실제 리얼 서버가 존재할 경우
// only when agent name exists or real server exists
this.logger.debug("buildPhysicalServer:{}", agentSet);
return buildPhysicalServer(agentSet);
} else {
// 논리 이름으로 구성.
// otherwise, logical name
this.logger.debug("buildLogicalServer");
return buildLogicalServer(agentHistogramList);
}
@@ -24,7 +24,7 @@ import com.navercorp.pinpoint.web.applicationmap.link.MatcherGroup;
import com.navercorp.pinpoint.web.applicationmap.link.ServerMatcher;
/**
*
*
* @author netspider
* @author emeroad
*/
@@ -40,7 +40,8 @@ public class ServerInstance {
private final AgentInfoBo agentInfo;
// 모양세는 어디선가 inject받던지 하는게 좋은데. 일단 그냥 한다. 로직에서 new하는 부분이라. 이걸 inject받을려니 힘듬.
// it is better for something else to inject this.
// it's difficult to do that since it is new'ed within logic
private static final MatcherGroup MATCHER_GROUP = new MatcherGroup();
private ServerMatcher match;
@@ -56,7 +57,7 @@ public class ServerInstance {
this.serverType = ServerType.Physical;
this.match = MATCHER_GROUP.match(hostName);
}
public ServerInstance(String hostName, String physicalName, ServiceType serviceType) {
if (hostName == null) {
throw new NullPointerException("hostName must not be null");
@@ -41,12 +41,12 @@ public class ServerInstanceList {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final Map<String, List<ServerInstance>> serverInstanceList = new TreeMap<String, List<ServerInstance>>();
private MatcherGroup matcherGroup = new MatcherGroup();
public ServerInstanceList() {
}
public ServerInstanceList(MatcherGroup matcherGroup) {
if (matcherGroup != null) {
this.matcherGroup.addMatcherGroup(matcherGroup);
@@ -54,7 +54,7 @@ public class ServerInstanceList {
}
public Map<String, List<ServerInstance>> getServerInstanceList() {
// list의 소트가 안되 있는 문제가 있음.
// XXX list sorting problem exist
return serverInstanceList;
}
@@ -89,14 +89,14 @@ public class ServerInstanceList {
List<ServerInstance> find = getServerInstanceList(serverInstance.getHostName());
addServerInstance(find, serverInstance);
}
public Map<String, String> getLink(String serverName) {
ServerMatcher serverMatcher = matcherGroup.match(serverName);
Map<String, String> linkInfo = new HashMap<String, String>();
linkInfo.put("linkName", serverMatcher.getLinkName());
linkInfo.put("linkURL", serverMatcher.getLink(serverName));
return linkInfo;
}
@@ -34,8 +34,8 @@ import org.slf4j.LoggerFactory;
import java.util.*;
/**
* 리팩토링하면서 AgentHistogramList에 기능이 거의 위임되었음.
* viewCreate정도로 기능이 한정되서 추후 삭제하거나. 이름을 변경해야 될듯하다.
* most of the features have been delegated to AgentHistorgramList upon refactoring
* TODO: limited to viewCreate. need to be renamed or removed
* @author emeroad
*/
public class AgentTimeHistogram {
@@ -87,9 +87,9 @@ public class AgentTimeHistogramBuilder {
return new AgentHistogramList();
}
// window 공간생성. AgentHistogramList 사용이전에는 그냥 생짜 자료구조를 사용함.
// list로 할수도 있으나, filter일 경우 range를 초과하는 경우가 발생할 가능성이 있어 map으로 생성한다.
// 좀더 나은 방인이 있으면 변경하는게 좋을듯.
// window space. before AgentHistogramList, we used a raw data structure.
// could've been a list, but a map is more suitable since range overflow occurs in case of filter.
// TODO: find better structure
final AgentHistogramList resultAgentHistogramList = new AgentHistogramList();
for (AgentHistogram agentHistogram : agentHistogramList.getAgentHistogramList()) {
List<TimeHistogram> timeHistogramList = new ArrayList<TimeHistogram>();
@@ -66,7 +66,7 @@ public class ApplicationTimeHistogramBuilder {
timeHistogram = new TimeHistogram(application.getServiceType(), timeStamp);
applicationLevelHistogram.put(timeStamp, timeHistogram);
}
// 개별 agent 레벨 데이터를 합친다.
// add each agent's level data
Histogram applicationResponseHistogram = responseTime.getApplicationResponseHistogram();
timeHistogram.add(applicationResponseHistogram);
}
@@ -109,7 +109,7 @@ public class ApplicationTimeHistogramBuilder {
}
private List<TimeHistogram> interpolation(Collection<TimeHistogram> histogramList) {
// span에 대한 개별 조회시 window time만 가지고 보간하는것에 한계가 있을수 있음.
// upon individual span query, "window time" alone may not be enough
//
Map<Long, TimeHistogram> resultMap = new HashMap<Long, TimeHistogram>();
for (Long time : window) {
@@ -31,7 +31,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize;
*/
@JsonSerialize(using=HistogramSerializer.class)
public class Histogram {
private final HistogramSchema schema;
private long fastCount;
@@ -67,7 +67,7 @@ public class Histogram {
this(ServiceType.findServiceType(serviceType));
}
// TODO slot번호를 이 클래스에서 추출해야 할 것 같긴 함.
// TODO one may extract slot number from this class
public void addCallCount(final short slotTime, final long count) {
final HistogramSchema schema = this.schema;
if (slotTime == schema.getVerySlowSlot().getSlotTime()) { // 0 is slow slotTime
@@ -78,7 +78,7 @@ public class Histogram {
this.errorCount += count;
return;
}
// TODO slotTime 은 <= 아니고 ==으로 수정되어야함.
// TODO if clause condition should be "==", not "<="
if (slotTime <= schema.getFastSlot().getSlotTime()) {
this.fastCount += count;
return;
@@ -26,11 +26,11 @@ import org.slf4j.LoggerFactory;
import java.util.*;
/**
* this class is a collection of
* applicationHistogram
* agentHistogram
* applicationTimeHistogram
* agentTimeHistogram
* 의 집합
* @author emeroad
*/
public class NodeHistogram {
@@ -44,7 +44,7 @@ public class NodeHistogram {
// ApplicationLevelHistogram
private Histogram applicationHistogram;
// key agentId이다.
// key is agentId
private Map<String, Histogram> agentHistogramMap;
private ApplicationTimeHistogram applicationTimeHistogram;
@@ -28,14 +28,14 @@ import java.util.HashMap;
import java.util.Map;
/**
*
*
* @author netspider
* @author emeroad
*/
public class AgentHistogram {
/**
* UI에서 호스트를 구분하기 위한 목적으로 hostname, agentid, endpoint등 구분할 수 있는 아무거나 넣으면 됨.
* to uniquely identify a host from UI, we can use things like hostname, agentId, endpoint, etc
*/
private final Application agentId;
@@ -115,7 +115,7 @@ public class AgentHistogram {
final StringBuilder sb = new StringBuilder("AgentHistogram{");
sb.append("agent='").append(agentId.getName()).append('\'');
sb.append(", serviceType=").append(agentId.getServiceType());
// 자료 구조가 변경되어 잠시 땜빵.
// temporarily hard-coded due to a change in the data structure
sb.append(", ").append(timeHistogramMap);
sb.append('}');
return sb.toString();
@@ -33,7 +33,8 @@ import java.util.*;
public class AgentHistogramList {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
// agent별 Time 시리즈 데이터를 가지고 있음.
// stores times series data per agent
private final Map<Application, AgentHistogram> agentHistogramMap = new HashMap<Application, AgentHistogram>();
public AgentHistogramList() {
@@ -24,7 +24,7 @@ import com.navercorp.pinpoint.web.vo.LinkKey;
import java.util.*;
/**
* 호출관계의 양방향 데이터를 표현
* representation of caller/callee relationship
* @author emeroad
*/
public class LinkCallData {
@@ -106,8 +106,9 @@ public class LinkCallDataMap {
for (Map.Entry<LinkKey, LinkCallData> linkKeyRawCallDataEntry : linkDataMap.entrySet()) {
final LinkKey key = linkKeyRawCallDataEntry.getKey();
final LinkCallData linkCallData = linkKeyRawCallDataEntry.getValue();
// to ServiceType이 들어가야 한다.
// 여기서 source란 source의 입장에서 target 호출시의 데이터를 의미하는 것이기 때문에. ServiceType자체는 To의 ServiceType이 들어가야한다.
// need target (to) ServiceType
// the definition of source is data from the source when the source sends a request to a target.
// Thus ServiceType is the target's ServiceType
sourceList.addAgentHistogram(key.getFromApplication(), key.getToServiceType(), linkCallData.getTimeHistogram());
}
return sourceList;
@@ -23,8 +23,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* DB에서 조회한 application호출 관계 정보.
*
* application caller/callee relationship stored in DB
*
* @author netspider
* @author emeroad
*/
@@ -50,7 +50,7 @@ public class LinkData {
this.linkCallDataMap = new LinkCallDataMap();
}
// 이건 일부러 복사 생성자로 구현안함.
// deliberaly didn't implement copy constructor
public LinkData(Application fromApplication, Application toApplication, LinkCallDataMap linkCallDataMap) {
if (fromApplication == null) {
throw new NullPointerException("fromApplication must not be null");
@@ -65,9 +65,9 @@ public class LinkData {
}
/**
*
*
* @param hostname
* host이름 또는 endpoint
* host name or endpoint
* @param slot
* @param count
*/
@@ -25,18 +25,18 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
*
* @author netspider
* @author emeroad
*/
public class SpanAligner2 {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
// 매치가 안됨.
// not matched
public static final int FAIL_MATCH = 0;
// transaction이 완벽하게 끝남.
// transaction completed succesfully
public static final int BEST_MATCH = 1;
// transaction이 진행중이거나. 일부 분실된 데이터가 있음.
// transaction in-flight or missing data
public static final int START_TIME_MATCH = 2;
@@ -61,33 +61,33 @@ public class SpanAligner2 {
root.add(span);
}
}
// 최상 조건의 best매치. 완벽 조건의 매치.
// perfect match condition
final int rootSpanBoSize = root.size();
if (rootSpanBoSize == 1) {
final SpanBo spanBo = root.get(0);
logger.debug("root span found. best match:{}", spanBo);
matchType = BEST_MATCH;
// 틈세가 추가로 있음. root는 있으나 조회한 span이 없을 경우 추가처리가 있어야함.
// XXX in case where root exist but no span queried. additional logic needed
return spanBo.getSpanId();
}
// 버그 rootspan이 2개 이상인 경우는 로직 버그이다. 아무거나 잡아서 데이터를 뿌려줘야 되나?
// XXX: a bug in the logic if rootspan is more than 2. should we display randomly?
if (rootSpanBoSize > 1) {
logger.warn("parentSpanId(-1) collision. size:{} root span:{} allSpan:{}", rootSpanBoSize, root, spanList);
throw new IllegalStateException("parentSpanId(-1) collision. size:" + rootSpanBoSize);
}
// root 분실. 혹은 아직 도착하지 않아 root가 완성 되지 않음. 즉 진행중인 process일 수 있음.
// 차선책으로 자신이 조회한 span의 시작 시간을 기준으로 span을 조회한다.
// span에서 데이터를 추출하는 것이기 때문에, 왠간하면 데이터는 존재함. hbase insert시 data insert를 실패할 경우 없을수 있음.
// missing root or incomplete root (not arrived yet): meaning on-going process
// next best thing is to lookup span based on the beginning of time of span it looked up
// most likely data exist since the data gets extracted from span. non-existent data possible due to hbase insertion failure
final List<SpanBo> collectorAcceptTimeMatcher = new ArrayList<SpanBo>();
for(SpanBo span : spanList) {
// collectorTime이 힌트로 들어온다.
// collectorTime is a hint
if (span.getCollectorAcceptTime() == collectorAcceptTime) {
collectorAcceptTimeMatcher.add(span);
}
}
// startTime 기반 match. 아래 추가 정보가 제공 되면 더 정확하게 매치가 가능하다.
// 이중에서 어느 정보를 얻으면 가장 쉽고 정확하게 매치가 가능한가? agentId가 제일 무난하지 않나 함.
// a match based on startTime. a further accurate match when additional informations (below) are given
// which one of these leads to a best match? possibly agentId.
// "applicationName" : "/httpclient4/post.pinpoint",
// "transactionId" : "emeroad-pc^1382955966412^16",
// "agentId" : "emeroad-pc",
@@ -105,7 +105,8 @@ public class SpanAligner2 {
logger.warn("collectorAcceptTime match collision. size:{} collectorAcceptTime:{} allSpan:{}", startMatchSize, collectorAcceptTime, spanList);
throw new IllegalStateException("startTime match collision size:" + startMatchSize + " collectorAcceptTime:" + collectorAcceptTime);
}
// 여기서 다음상황으로 더 정확하게 매치가 가능한가? 마땅히 call stack을 랜더링 할수 있는 방법 없음
// can we do better match like below?
// there is no definitive answer for do call stack rendering
logger.warn("collectorAcceptTime match not found. size:{} collectorAcceptTime:{} allSpan:{}", startMatchSize, collectorAcceptTime, spanList);
throw new IllegalStateException("startTime match not found startTime size:" + startMatchSize + " collectorAcceptTime:" + collectorAcceptTime);
}
@@ -151,7 +152,7 @@ public class SpanAligner2 {
if (logger.isDebugEnabled()) {
logger.debug("span type:{} depth:{} spanDepth:{} ", currentDepth, span.getServiceType(), spanDepth);
}
SpanAlign spanAlign = new SpanAlign(currentDepth, span);
container.add(spanAlign);
@@ -159,9 +160,9 @@ public class SpanAligner2 {
if (spanEventBoList == null) {
return;
}
spanAlign.setHasChild(true);
for (SpanEventBo spanEventBo : spanEventBoList) {
if (spanEventBo. getDepth() != -1) {
currentDepth = spanDepth + spanEventBo.getDepth();
@@ -189,7 +190,7 @@ public class SpanAligner2 {
logger.debug("populate end");
}
// nextSpan의 충돌 까지 해결한다.
// fix nextSpan collision problem
private SpanBo getNextSpan(SpanBo span, SpanEventBo beforeSpanEventBo, List<SpanBo> nextSpanBoList) {
if (logger.isDebugEnabled()) {
logger.debug("beforeSpanEvent:{}, nextSpanBoList:{}", beforeSpanEventBo, nextSpanBoList);
@@ -197,15 +198,16 @@ public class SpanAligner2 {
if (nextSpanBoList.size() == 1) {
return nextSpanBoList.get(0);
} else if(nextSpanBoList.size() > 1) {
// 최대한 비슷한 매칭을 시도한다.
// try best similar match
// return spanBos.get(0);
long spanEventBoStartTime = span.getStartTime() + beforeSpanEventBo.getStartElapsed();
SpanIdMatcher spanIdMatcher = new SpanIdMatcher(nextSpanBoList);
// 전체를 보지 않고 일부만 보고 유사도를 측정하므로, 패킷 lost등에 매우 취약함. 전체를 보고 근사도를 추가 분석하는 방법이 강구되어야 될것 같음.
// very susceptible to things like packet loss due to similarilty match based on restricted set of data
// TODO: need to find a better way to calc similarity based on entire data
SpanBo matched = spanIdMatcher.approximateMatch(spanEventBoStartTime);
if (matched == null) {
// match되는 span을 찾을수 없음.
// no matching span
return null;
}
List<SpanBo> other = spanIdMatcher.other();
@@ -39,7 +39,7 @@ public class SpanIdMatcher {
}
public SpanBo approximateMatch(long spanEventBoStartTime) {
// 매칭 알고리즘이 있어야 함.
// TODO: we need mathing algorithm
List<WeightSpanBo> weightSpanList = computeWeight(spanEventBoStartTime);
if (weightSpanList.size() == 0) {
return null;
@@ -82,8 +82,9 @@ public class SpanIdMatcher {
if (minValue.size() == 1) {
return minValue.get(0);
}
// 2개 이상일 경우일단 그냥 앞선 데이터를 던짐.
// 뭔가 로그 필요.
// returns the first data when more than one
// TODO: we probably log this
return minValue.get(0);
}
@@ -94,7 +95,7 @@ public class SpanIdMatcher {
long distance = startTime - spanEventBoStartTime;
long weightDistance = getWeightDistance(distance);
if (weightDistance > MAX_EXCLUDE_WEIGHT) {
// MAX WEIGHT보다 가중치가 높을 경우. 분실된 케이스 일수 있으므로 그냥 버린다.
// if higher than MAX WEIGHT, most likely missing case. just drop it
continue;
}
weightSpanList.add(new WeightSpanBo(weightDistance, next));
@@ -104,12 +105,13 @@ public class SpanIdMatcher {
private long getWeightDistance(long distance) {
if (distance >= 0) {
// 양수일 경우
// positive number
return distance;
} else {
// 음수일 경우 패널티를 둔다. 네트워크 타임 동기화 시간이 길지 않을 경우 음수가 매치될 확율은 매우 적어야 한다.
// 차라리 jvm gc등으로 인해 양수 값이 많이 차이 날수 있지. 음수값이 매치될 가능성은 매우낮다고 봐야 한다.
// 네트워크 싱크 시간?? 오차 등을 추가로 더하면 될거 같은데. 모르니깐 대충 더하자. 패널티는 1초
// give a penalty when negative
// if time skew due to network time sync problem is not big, it is highly unlikely to match a negative number
// it actually is more likely to get higher positive number diff due to JVM GC.
// TODO: need to adjust for network sync time diff. penalty is just set to 1 second
distance = Math.abs(distance);
return (distance * 2) + 1000;
}
@@ -26,7 +26,7 @@ public interface ClusterManager {
boolean registerWebCluster(String zNodeName, byte[] contents);
void close();
List<String> getRegisteredAgentList(String applicationName, String agentId, long startTimeStamp);
}
@@ -35,7 +35,7 @@ public class CollectorClusterInfoRepository {
private final Map<String, Map<String, String>> repository = new HashMap<String, Map<String, String>>();
private final Object lock = new Object();
public void put(String id, byte[] data) {
synchronized (lock) {
Map<String, String> newMap = new HashMap<String, String>();
@@ -49,7 +49,7 @@ public class CollectorClusterInfoRepository {
newMap.put(profilerInfo, id);
}
repository.put(id, newMap);
}
}
@@ -93,7 +93,7 @@ public class CollectorClusterInfoRepository {
return key.toString();
}
@Override
public String toString() {
return repository.toString();
@@ -46,23 +46,23 @@ public class ZookeeperClient {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
// 쥬키퍼 클라이언트는 스레드 세이프함
// ZK client is thread-safe
private final ZookeeperClusterManager manager;
private final ZooKeeper zookeeper;
private final AtomicBoolean clientState = new AtomicBoolean(true);
// 데이터를 이친구가 다가지고 있어야 할 거 같은데;
// hmm this structure should contain all necessary information
public ZookeeperClient(String hostPort, int sessionTimeout, ZookeeperClusterManager manager) throws KeeperException, IOException, InterruptedException {
this.manager = manager;
zookeeper = new ZooKeeper(hostPort, sessionTimeout, this.manager); // server
}
/**
* path의 가장마지막에 있는 node는 생성하지 않는다.
*
* @throws PinpointZookeeperException
* @throws InterruptedException
* do not create node in path suffix
*
* @throws PinpointZookeeperException
* @throws InterruptedException
*/
public void createPath(String path) throws PinpointZookeeperException, InterruptedException {
checkState();
@@ -86,14 +86,13 @@ public class ZookeeperClient {
} catch (KeeperException exception) {
if (exception.code() != Code.NODEEXISTS) {
handleException(exception);
}
}
}
} while (pos < path.length());
}
// 정확히 동일한 노드가 생성되어 있는지 확인하려면
// 내부의 컨텐츠 검사도 해야됨
// we need deep node inspection for verification purpose (node content)
public String createNode(String znodePath, byte[] data, CreateMode createMode) throws PinpointZookeeperException, InterruptedException {
checkState();
@@ -107,11 +106,11 @@ public class ZookeeperClient {
} catch (KeeperException exception) {
if (exception.code() != Code.NODEEXISTS) {
handleException(exception);
}
}
}
return znodePath;
}
public List<String> getChildren(String path, boolean watch) throws PinpointZookeeperException, InterruptedException {
checkState();
@@ -122,10 +121,10 @@ public class ZookeeperClient {
handleException(exception);
}
}
return Collections.emptyList();
}
public byte[] getData(String path) throws PinpointZookeeperException, InterruptedException {
return getData(path, false);
}
@@ -138,11 +137,11 @@ public class ZookeeperClient {
} catch (KeeperException exception) {
handleException(exception);
}
throw new UnknownException("UnknownException.");
}
public void delete(String path) throws PinpointZookeeperException, InterruptedException {
checkState();
@@ -151,7 +150,7 @@ public class ZookeeperClient {
} catch (KeeperException exception) {
if (exception.code() != Code.NONODE) {
handleException(exception);
}
}
}
}
@@ -166,7 +165,7 @@ public class ZookeeperClient {
} catch (KeeperException exception) {
if (exception.code() != Code.NODEEXISTS) {
handleException(exception);
}
}
}
return true;
}
@@ -200,7 +199,7 @@ public class ZookeeperClient {
throw new UnknownException(keeperException.getMessage(), keeperException);
}
}
public void close() {
if (clientState.compareAndSet(true, false)) {
if (zookeeper != null) {
@@ -61,23 +61,22 @@ public class ZookeeperClusterManager implements ClusterManager, Watcher {
private final ZookeeperClient client;
private final int retryInterval;
private final Timer timer;
private final AtomicReference<PushWebClusterJob> job = new AtomicReference<ZookeeperClusterManager.PushWebClusterJob>();
private final CollectorClusterInfoRepository collectorClusterInfo = new CollectorClusterInfoRepository();
public ZookeeperClusterManager(String zookeeperAddress, int sessionTimeout, int retryInterval) throws KeeperException, IOException, InterruptedException {
this.client = new ZookeeperClient(zookeeperAddress, sessionTimeout, this);
this.retryInterval = retryInterval;
// 등록이 실패하였을때 생성하게 하는게 나을수도 있음
// it could be better to create upon failure
this.timer = createTimer();
}
// 등록이 실패해도 계속 시도 (주기는 기본 1분)
// 크게 부하가 가는 작업이 아니며,
// 실패할 경우 계속 로그를 출력
// Retry upon failure (1 min retry period)
// not too much overhead, just logging
@Override
public boolean registerWebCluster(String zNodeName, byte[] contents) {
String zNodePath = bindingPathAndZnode(PINPOINT_WEB_CLUSTER_PATh, zNodeName);
@@ -90,12 +89,12 @@ public class ZookeeperClusterManager implements ClusterManager, Watcher {
return false;
}
// 스케쥴로 라도 등록하면 성공
// successful even for schedular registration completion
if (!isConnected()) {
logger.info("Zookeeper is Disconnected.");
return true;
}
if (!syncWebCluster(job)) {
timer.newTimeout(job, job.getRetryInterval(), TimeUnit.MILLISECONDS);
}
@@ -106,15 +105,15 @@ public class ZookeeperClusterManager implements ClusterManager, Watcher {
@Override
public void process(WatchedEvent event) {
logger.info("Zookeepr Event({}) ocurred.", event);
KeeperState state = event.getState();
EventType eventType = event.getType();
String path = event.getPath();
boolean result = false;
// 상태가 되면 ephemeral 노드가 사라짐
// 문서에 따라 자동으로 연결이 되고, 연결되는 이벤트는 process에서 감지가 됨
// when this happens, ephemeral node disappears
// reconnects automatically, and process gets notified for all events
if (state == KeeperState.Disconnected || state == KeeperState.Expired) {
result = handleDisconnected();
} else if ((state == KeeperState.SyncConnected || state == KeeperState.NoSyncConnected) && eventType == EventType.None) {
@@ -126,24 +125,24 @@ public class ZookeeperClusterManager implements ClusterManager, Watcher {
} else if ((state == KeeperState.SyncConnected || state == KeeperState.NoSyncConnected) && eventType == EventType.NodeDataChanged) {
result = handleNodeDataChanged(path);
}
if (result) {
logger.info("Zookeeper Event({}) successed.", event);
logger.info("Zookeeper Event({}) successed.", event);
} else {
logger.info("Zookeeper Event({}) failed.", event);
logger.info("Zookeeper Event({}) failed.", event);
}
}
private boolean handleDisconnected() {
connected.compareAndSet(true, false);
collectorClusterInfo.clear();
return true;
}
private boolean handleConnected() {
boolean result = true;
// 이전상태가 RUN일수 있기 때문에 유지해도 됨
// is it ok to keep this since previous condition was possibly RUN
boolean changed = connected.compareAndSet(false, true);
if (changed) {
PushWebClusterJob job = this.job.get();
@@ -153,7 +152,7 @@ public class ZookeeperClusterManager implements ClusterManager, Watcher {
result = false;
}
}
if (!syncCollectorCluster()) {
timer.newTimeout(new FetchCollectorClusterJob(), SYNC_INTERVAL_TIME_MILLIS, TimeUnit.MILLISECONDS);
result = false;
@@ -161,10 +160,10 @@ public class ZookeeperClusterManager implements ClusterManager, Watcher {
} else {
result = false;
}
return result;
}
private boolean handleNodeChildrenChanged(String path) {
if (PINPOINT_COLLECTOR_CLUSTER_PATH.equals(path)) {
if (syncCollectorCluster()) {
@@ -172,10 +171,10 @@ public class ZookeeperClusterManager implements ClusterManager, Watcher {
}
timer.newTimeout(new FetchCollectorClusterJob(), SYNC_INTERVAL_TIME_MILLIS, TimeUnit.MILLISECONDS);
}
return false;
}
private boolean handleNodeDeleted(String path) {
if (path != null) {
String id = extractCollectorClusterId(path);
@@ -186,18 +185,18 @@ public class ZookeeperClusterManager implements ClusterManager, Watcher {
}
return false;
}
private boolean handleNodeDataChanged(String path) {
if (path != null) {
String id = extractCollectorClusterId(path);
if (id != null) {
if (syncCollectorCluster(id)) {
return true;
}
}
timer.newTimeout(new FetchCollectorClusterJob(), SYNC_INTERVAL_TIME_MILLIS, TimeUnit.MILLISECONDS);
}
}
return false;
}
@@ -216,7 +215,7 @@ public class ZookeeperClusterManager implements ClusterManager, Watcher {
public List<String> getRegisteredAgentList(String applicationName, String agentId, long startTimeStamp) {
return collectorClusterInfo.get(applicationName, agentId, startTimeStamp);
}
private Timer createTimer() {
HashedWheelTimer timer = TimerFactory.createHashedWheelTimer("Pinpoint-Web-Cluster-Timer", 100, TimeUnit.MILLISECONDS, 512);
timer.start();
@@ -232,7 +231,7 @@ public class ZookeeperClusterManager implements ClusterManager, Watcher {
client.createPath(zNodePath);
}
// 쥬키퍼의 zNode는 ip:port 형태의 이름으로 만들수 있음
// ip:port zNode naming scheme
String nodeName = client.createNode(zNodePath, contents, CreateMode.EPHEMERAL);
logger.info("Register Web Cluster Zookeeper UniqPath = {}.", zNodePath);
return true;
@@ -257,12 +256,12 @@ public class ZookeeperClusterManager implements ClusterManager, Watcher {
return fullPath.toString();
}
private String extractCollectorClusterId(String path) {
int index = path.indexOf(PINPOINT_COLLECTOR_CLUSTER_PATH);
int startPosition = index + PINPOINT_COLLECTOR_CLUSTER_PATH.length() + 1;
if (path.length() > startPosition) {
String id = path.substring(startPosition);
return id;
@@ -270,11 +269,11 @@ public class ZookeeperClusterManager implements ClusterManager, Watcher {
return null;
}
private boolean syncCollectorCluster() {
synchronized (this) {
Map<String, byte[]> map = getCollectorData();
if (map == null) {
return false;
}
@@ -282,7 +281,7 @@ public class ZookeeperClusterManager implements ClusterManager, Watcher {
for (Map.Entry<String, byte[]> entry : map.entrySet()) {
String key = entry.getKey();
byte[] value = entry.getValue();
String id = extractCollectorClusterId(key);
if (id == null) {
logger.error("Illegal Collector Path({}) finded.", key);
@@ -290,17 +289,17 @@ public class ZookeeperClusterManager implements ClusterManager, Watcher {
}
collectorClusterInfo.put(id, value);
}
return true;
}
}
private boolean syncCollectorCluster(String id) {
String path = bindingPathAndZnode(PINPOINT_COLLECTOR_CLUSTER_PATH, id);
synchronized (this) {
try {
byte[] data = client.getData(path, true);
collectorClusterInfo.put(id, data);
return true;
} catch(NoNodeException e) {
@@ -309,7 +308,7 @@ public class ZookeeperClusterManager implements ClusterManager, Watcher {
} catch (Exception e) {
logger.warn(e.getMessage(), e);
}
return false;
}
}
@@ -319,19 +318,19 @@ public class ZookeeperClusterManager implements ClusterManager, Watcher {
List<String> collectorList = client.getChildren(PINPOINT_COLLECTOR_CLUSTER_PATH, true);
Map<String, byte[]> map = new HashMap<String, byte[]>();
for (String collector : collectorList) {
String node = bindingPathAndZnode(PINPOINT_COLLECTOR_CLUSTER_PATH, collector);
byte[] data = client.getData(node, true);
map.put(node, data);
}
return map;
} catch (Exception e) {
logger.warn(e.getMessage(), e);
}
return null;
}
@@ -340,7 +339,7 @@ public class ZookeeperClusterManager implements ClusterManager, Watcher {
private final String znodeName;
private final byte[] contents;
private final int retryInterval;
public PushWebClusterJob(String znodeName, byte[] contents, int retryInterval) {
this.znodeName = znodeName;
this.contents = contents;
@@ -358,7 +357,7 @@ public class ZookeeperClusterManager implements ClusterManager, Watcher {
public int getRetryInterval() {
return retryInterval;
}
@Override
public String toString() {
StringBuilder toString = new StringBuilder();
@@ -371,19 +370,19 @@ public class ZookeeperClusterManager implements ClusterManager, Watcher {
@Override
public void run(Timeout timeout) throws Exception {
logger.info("Reservation Job({}) started.", this.getClass().getSimpleName());
if (!isConnected()) {
return;
}
if (!syncWebCluster(this)) {
timer.newTimeout(this, getRetryInterval(), TimeUnit.MILLISECONDS);
}
}
}
class FetchCollectorClusterJob implements TimerTask {
@Override
public void run(Timeout timeout) throws Exception {
logger.info("Reservation Job({}) started.", this.getClass().getSimpleName());
@@ -391,7 +390,7 @@ public class ZookeeperClusterManager implements ClusterManager, Watcher {
if (!isConnected()) {
return;
}
if (!syncCollectorCluster()) {
timer.newTimeout(new FetchCollectorClusterJob(), SYNC_INTERVAL_TIME_MILLIS, TimeUnit.MILLISECONDS);
}
@@ -20,7 +20,7 @@ package com.navercorp.pinpoint.web.cluster.zookeeper.exception;
* @author koo.taejin
*/
public class PinpointZookeeperException extends Exception {
public PinpointZookeeperException() {
}
@@ -29,10 +29,10 @@ import org.springframework.beans.factory.annotation.Value;
public class WebConfig {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Value("#{pinpointWebProps['cluster.enable'] ?: false}")
private boolean clusterEnable;
@Value("#{pinpointWebProps['cluster.web.tcp.port'] ?: 0}")
private int clusterTcpPort;
@@ -44,7 +44,7 @@ public class WebConfig {
@Value("#{pinpointWebProps['cluster.zookeeper.retry.interval'] ?: 60000}")
private int clusterZookeeperRetryInterval;
@PostConstruct
public void validation() {
if (isClusterEnable()) {
@@ -55,7 +55,7 @@ public class WebConfig {
assertPositiveNumber(clusterZookeeperSessionTimeout);
assertPositiveNumber(clusterZookeeperRetryInterval);
}
logger.info("{}", toString());
}
@@ -63,15 +63,15 @@ public class WebConfig {
if (port > 0 && 65535 > port) {
return true;
}
throw new IllegalArgumentException("Invalid Port =" + port);
}
private boolean assertPositiveNumber(int number) {
if (number >= 0) {
return true;
}
throw new IllegalArgumentException("Invalid Positive Number =" + number);
}
@@ -90,7 +90,7 @@ public class WebConfig {
public int getClusterZookeeperSessionTimeout() {
return clusterZookeeperSessionTimeout;
}
@Override
public String toString() {
return "WebConfig [clusterEnable=" + clusterEnable
@@ -70,8 +70,8 @@ public class BusinessTransactionController {
private FilterBuilder filterBuilder;
/**
* applicationname에서 from ~ to 시간대에 수행된 URL을 조회한다.
*
* executed URLs in applicationname query within from ~ to timeframe
*
* @param model
* @param applicationName
* @param from
@@ -83,13 +83,13 @@ public class BusinessTransactionController {
@ResponseBody
public Model getBusinessTransactionsData(Model model,
@RequestParam("application") String applicationName,
@RequestParam("from") long from,
@RequestParam("from") long from,
@RequestParam("to") long to,
@RequestParam(value = "filter", required = false) String filterText,
@RequestParam(value = "limit", required = false, defaultValue = "10000") int limit) {
limit = LimitUtils.checkRange(limit);
Range range = new Range(from, to);
// TOOD 구조개선을 위해 server map조회 로직 분리함, 임시로 분리한 상태이고 개선이 필요하다.
// TODO more refactoring needed: partially separated out server map lookup logic.
LimitedScanResult<List<TransactionId>> traceIdList = filteredMapService.selectTraceIdsFromApplicationTraceIndex(applicationName, range, limit);
Filter filter = filterBuilder.build(filterText);
@@ -114,7 +114,7 @@ public class BusinessTransactionController {
@RequestMapping(value = "/lastTransactionList", method = RequestMethod.GET)
@ResponseBody
public Model getLastBusinessTransactionsData(Model model, HttpServletResponse response,
@RequestParam("application") String applicationName,
@RequestParam("application") String applicationName,
@RequestParam("period") long period,
@RequestParam(value = "filter", required = false) String filterText,
@RequestParam(value = "limit", required = false, defaultValue = "10000") int limit) {
@@ -125,7 +125,7 @@ public class BusinessTransactionController {
}
/**
* 선택한 하나의 Transaction 정보 조회.
* info lookup for a selected transaction
*
* @param traceIdParam
* @param focusTimestamp
@@ -54,8 +54,8 @@ import com.navercorp.pinpoint.web.server.PinpointSocketManager;
@RequestMapping("/command")
public class CommandController {
// FIX ME: 단순히 연동 테스트를 위해서 만든것
// 나중에 api같은게 정해지면 그때 이를 이용해서 정상적으로 api를 만들면 될듯
// FIX ME: created for a simple ping/pong test for now
// need a formal set of APIs and proper code
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@@ -56,8 +56,8 @@ public class FilteredMapController {
private FilterBuilder filterBuilder;
/**
* 필터가 적용된 서버맵의 FROM ~ TO기간의 데이터 조회
*
* filtered server map data query within from ~ to timeframe
*
* @param applicationName
* @param serviceTypeCode
* @param from
@@ -79,18 +79,17 @@ public class FilteredMapController {
@RequestParam(value = "limit", required = false, defaultValue = "10000") int limit) {
limit = LimitUtils.checkRange(limit);
final Filter filter = filterBuilder.build(filterText, filterHint);
// scan을 해야 될 토탈 범위
final Range range = new Range(from, to);
final LimitedScanResult<List<TransactionId>> limitedScanResult = filteredMapService.selectTraceIdsFromApplicationTraceIndex(applicationName, range, limit);
final long lastScanTime = limitedScanResult.getLimitedTime();
// 원본 범위, 시계열 차트의 sampling을 하려면 필요함.
// original range: needed for visual chart data sampling
final Range originalRange = new Range(from, originTo);
// 정확히 스캔된 범위가 어디까지 인지 알기 위해서 필요함.
// needed to figure out already scanned ranged
final Range scannerRange = new Range(lastScanTime, to);
logger.debug("originalRange:{} scannerRange:{} ", originalRange, scannerRange);
ApplicationMap map = filteredMapService.selectApplicationMap(limitedScanResult.getScanData(), originalRange, scannerRange, filter);
if (logger.isDebugEnabled()) {
logger.debug("getFilteredServerMapData range scan(limit:{}) range:{} lastFetchedTimestamp:{}", limit, range.prettyToString(), DateUtils.longToDateStr(lastScanTime));
}
@@ -99,10 +98,11 @@ public class FilteredMapController {
mapWrap.setLastFetchedTimestamp(lastScanTime);
return mapWrap;
}
/**
* 필터가 적용된 서버맵의 Period before 부터 현재시간까지의 데이터 조회.
*
* filtered server map data query for the last "Period" up to now
*
*
* @param applicationName
* @param serviceTypeCode
* @param filterText
@@ -122,9 +122,10 @@ public class FilteredMapController {
long to = TimeUtils.getDelayLastTime();
long from = to - period;
// TODO 실시간 조회가 현재 disable이므로 to to로 수정하였음. 이것도 추가적으로 @RequestParam("originTo")가 필요할수 있음.
// TODO: since realtime query is enabled for now, calling parameters are fixed as "..., to, to, ..."
// may need additional @RequestParam("originTo")
return getFilteredServerMapData(applicationName, serviceTypeCode, from, to, to, filterText, filterHint, limit);
}
}
}
@@ -57,4 +57,4 @@ public class MainController {
public ServerTime getServerTime() {
return new ServerTime();
}
}
}
@@ -59,7 +59,7 @@ public class MapController {
private Limiter dateLimit;
/**
* FROM ~ TO기간의 서버 맵 데이터 조회
* Server map data query within from ~ to timeframe
*
* @param applicationName
* @param serviceTypeCode
@@ -85,8 +85,8 @@ public class MapController {
}
/**
* Period before 부터 현재시간까지의 서버맵 조회.
*
* Server map data query for the last "Period" timeframe
*
* @param applicationName
* @param serviceTypeCode
* @param period
@@ -98,16 +98,16 @@ public class MapController {
@RequestParam("applicationName") String applicationName,
@RequestParam("serviceTypeCode") short serviceTypeCode,
@RequestParam("period") long period) {
long to = TimeUtils.getDelayLastTime();
long from = to - period;
return getServerMapData(applicationName, serviceTypeCode, from, to);
}
/**
* 맵에서 직접 찍어오는걸로 변경시 잘 사용하지 않는 API가 될것임.
* 필터가 사용되지 않은 서버맵의 연결선을 통과하는 요청의 통계정보 조회
*
* Possible deprecation expected when UI change push forward to pick a map first from UI
* Unfiltered server map request data query
*
* @param model
* @param from
* @param to
@@ -127,32 +127,32 @@ public class MapController {
@RequestParam("targetApplicationName") String targetApplicationName,
@RequestParam("targetServiceType") short targetServiceType) {
final Application sourceApplication = new Application(sourceApplicationName, sourceServiceType);
final Application destinationApplication = new Application(targetApplicationName, targetServiceType);
final Range range = new Range(from, to);
final Application sourceApplication = new Application(sourceApplicationName, sourceServiceType);
final Application destinationApplication = new Application(targetApplicationName, targetServiceType);
final Range range = new Range(from, to);
NodeHistogram nodeHistogram = mapService.linkStatistics(sourceApplication, destinationApplication, range);
NodeHistogram nodeHistogram = mapService.linkStatistics(sourceApplication, destinationApplication, range);
model.addAttribute("range", range);
model.addAttribute("sourceApplication", sourceApplication);
model.addAttribute("sourceApplication", sourceApplication);
model.addAttribute("targetApplication", destinationApplication);
model.addAttribute("targetApplication", destinationApplication);
Histogram applicationHistogram = nodeHistogram.getApplicationHistogram();
Histogram applicationHistogram = nodeHistogram.getApplicationHistogram();
model.addAttribute("linkStatistics", applicationHistogram);
List<ResponseTimeViewModel> applicationTimeSeriesHistogram = nodeHistogram.getApplicationTimeHistogram();
String applicationTimeSeriesHistogramJson = null;
try {
applicationTimeSeriesHistogramJson = MAPPER.writeValueAsString(applicationTimeSeriesHistogram);
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
model.addAttribute("timeSeriesHistogram", applicationTimeSeriesHistogramJson);
List<ResponseTimeViewModel> applicationTimeSeriesHistogram = nodeHistogram.getApplicationTimeHistogram();
String applicationTimeSeriesHistogramJson = null;
try {
applicationTimeSeriesHistogramJson = MAPPER.writeValueAsString(applicationTimeSeriesHistogram);
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
model.addAttribute("timeSeriesHistogram", applicationTimeSeriesHistogramJson);
// 결과의 from, to를 다시 명시해야 되는듯 한데. 현재는 그냥 요청 데이터를 그냥 주는것으로 보임.
// looks like we need to specify "from, to" to the result. but data got passed thru as it is.
model.addAttribute("resultFrom", from);
model.addAttribute("resultTo", to);
@@ -161,4 +161,4 @@ public class MapController {
}
private final static ObjectMapper MAPPER = new ObjectMapper();
}
}
@@ -47,7 +47,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
/**
*
*
* @author netspider
* @author emeroad
*/
@@ -58,7 +58,7 @@ public class ScatterChartController {
@Autowired
private ScatterChartService scatter;
@Autowired
private FilteredMapService flow;
@@ -73,9 +73,9 @@ public class ScatterChartController {
@RequestMapping(value = "/scatterpopup", method = RequestMethod.GET)
public String scatterPopup(Model model,
@RequestParam("application") String applicationName,
@RequestParam("from") long from,
@RequestParam("to") long to,
@RequestParam("period") long period,
@RequestParam("from") long from,
@RequestParam("to") long to,
@RequestParam("period") long period,
@RequestParam("usePeriod") boolean usePeriod,
@RequestParam(value = "filter", required = false) String filterText) {
model.addAttribute("applicationName", applicationName);
@@ -88,21 +88,21 @@ public class ScatterChartController {
}
/**
*
*
* @param applicationName
* @param from
* @param to
* @param limit
* 한번에 조회 할 데이터의 크기, 조회 결과가 이 크기를 넘어가면 limit개만 반환한다. 나머지는 다시 요청해서
* 조회해야 한다.
* max number of data return. if the requested data exceed this limit, we need additional calls to
* fetch the rest of the data
* @return
*/
@RequestMapping(value = "/getScatterData", method = RequestMethod.GET)
public ModelAndView getScatterData(
@RequestParam("application") String applicationName,
@RequestParam("from") long from,
@RequestParam("from") long from,
@RequestParam("to") long to,
@RequestParam("limit") int limit,
@RequestParam("limit") int limit,
@RequestParam(value = "filter", required = false) String filterText,
@RequestParam(value = "_callback", required = false) String jsonpCallback,
@RequestParam(value = "v", required = false, defaultValue = "2") int version) {
@@ -111,7 +111,7 @@ public class ScatterChartController {
StopWatch watch = new StopWatch();
watch.start("selectScatterData");
// TODO 레인지 체크 확인 exception 발생, from값이 to 보다 더 큼.
// TODO range check verification exception occurs. "from" is bigger than "to"
final Range range = Range.createUncheckedRange(from, to);
logger.debug("fetch scatter data. {}, LIMIT={}, FILTER={}", range, limit, filterText);
@@ -135,7 +135,8 @@ public class ScatterChartController {
final List<TransactionId> traceIdList = limitedScanResult.getScanData();
logger.trace("submitted transactionId count={}", traceIdList.size());
// TODO sorted만 하는가? tree기반으로 레인지 체크하도록 하고 삭제하도록 하자.
// TODO just need sorted? we need range check with tree-based structure.
SortedSet<TransactionId> traceIdSet = new TreeSet<TransactionId>(traceIdList);
logger.debug("unified traceIdSet size={}", traceIdSet.size());
@@ -182,8 +183,8 @@ public class ScatterChartController {
}
/**
* NOW 버튼을 눌렀을 때 scatter 데이터 조회.
*
* scatter chart data query for "NOW" button
*
* @param applicationName
* @param limit
* @return
@@ -200,13 +201,14 @@ public class ScatterChartController {
long to = TimeUtils.getDelayLastTime();
long from = to - period;
// TODO version은 임시로 사용됨. template변경과 서버개발을 동시에 하려고..
// TODO versioning is temporary. to sync template change and server dev
return getScatterData(applicationName, from, to, limit, filterText, jsonpCallback, version);
}
/**
* scatter에서 점 여러개를 선택했을 때 점에 대한 정보를 조회한다.
*
* selected points from scatter chart data query
*
* @param model
* @param request
* @param response
@@ -242,14 +244,14 @@ public class ScatterChartController {
logger.debug("query:{}", query);
return query;
}
/**
* scatter chart에서 선택한 범위에 속하는 트랜잭션 목록을 조회
*
* trasaction list query for selected points in scatter chart
*
* <pre>
* TEST URL = http://localhost:7080/transactionmetadata2.pinpoint?application=FRONT-WEB&from=1394432299032&to=1394433498269&responseFrom=100&responseTo=200&responseOffset=100&limit=10
* </pre>
*
*
* @param model
* @param request
* @param response
@@ -258,38 +260,40 @@ public class ScatterChartController {
@RequestMapping(value = "/transactionmetadata2", method = RequestMethod.GET)
public String getTransaction(Model model,
@RequestParam("application") String applicationName,
@RequestParam("from") long from,
@RequestParam("from") long from,
@RequestParam("to") long to,
@RequestParam("responseFrom") int responseFrom,
@RequestParam("responseFrom") int responseFrom,
@RequestParam("responseTo") int responseTo,
@RequestParam("limit") int limit,
@RequestParam("limit") int limit,
@RequestParam(value = "offsetTime", required = false, defaultValue = "-1") long offsetTime,
@RequestParam(value = "offsetTransactionId", required = false) String offsetTransactionId,
@RequestParam(value = "offsetTransactionElapsed", required = false, defaultValue = "-1") int offsetTransactionElapsed,
@RequestParam(value = "filter", required = false) String filterText) {
limit = LimitUtils.checkRange(limit);
StopWatch watch = new StopWatch();
watch.start("selectScatterData");
watch.start("selectScatterData");
final SelectedScatterArea area = SelectedScatterArea.createUncheckedArea(from, to, responseFrom, responseTo);
logger.debug("fetch scatter data. {}, LIMIT={}, FILTER={}", area, limit, filterText);
if (filterText == null) {
// limit에 걸려서 조회되지 않은 부분 우선 조회
// query data above "limit" first
TransactionId offsetId = null;
List<SpanBo> extraMetadata = null;
if (offsetTransactionId != null) {
offsetId = new TransactionId(offsetTransactionId);
SelectedScatterArea extraArea = SelectedScatterArea.createUncheckedArea(offsetTime, offsetTime, responseFrom, responseTo);
List<Dot> extraAreaDotList = scatter.selectScatterData(applicationName, extraArea, offsetId, offsetTransactionElapsed, limit);
extraMetadata = scatter.selectTransactionMetadata(parseSelectTransaction(extraAreaDotList));
model.addAttribute("extraMetadata", extraMetadata);
}
// limit에 걸려서 조회되지 않은 부분 조회 결과가 limit에 미치지 못하면 나머지 영역 추가 조회
// query data up to limit
// XXX extraMetadata.size() <= limit????
if (extraMetadata == null || extraMetadata.size() < limit) {
int newlimit = limit - ((extraMetadata == null) ? 0 : extraMetadata.size());
List<Dot> selectedDotList = scatter.selectScatterData(applicationName, area, null, -1, newlimit);
@@ -300,8 +304,8 @@ public class ScatterChartController {
final LimitedScanResult<List<TransactionId>> limitedScanResult = flow.selectTraceIdsFromApplicationTraceIndex(applicationName, area, limit);
final List<TransactionId> traceIdList = limitedScanResult.getScanData();
logger.trace("submitted transactionId count={}", traceIdList.size());
// TODO sorted만 하는가? tree기반으로 레인지 체크하도록 하고 삭제하도록 하자.
// TODO: just sorted? we need range check based on tree structure
SortedSet<TransactionId> traceIdSet = new TreeSet<TransactionId>(traceIdList);
logger.debug("unified traceIdSet size={}", traceIdSet.size());
@@ -310,10 +314,10 @@ public class ScatterChartController {
watch.stop();
logger.info("Fetch scatterData time : {}ms", watch.getLastTaskTimeMillis());
return "transactionmetadata2";
}
private TransactionMetadataQuery parseSelectTransaction(List<Dot> dotList) {
TransactionMetadataQuery query = new TransactionMetadataQuery();
if (dotList == null) {
@@ -325,4 +329,4 @@ public class ScatterChartController {
logger.debug("query:{}", query);
return query;
}
}
}
@@ -65,10 +65,10 @@ public class HbaseAgentInfoDao implements AgentInfoDao {
logger.debug("get agentInfo with, agentId={}, {}", agentId, range);
Scan scan = new Scan();
scan.setCaching(20);
long fromTime = TimeUtils.reverseTimeMillis(range.getTo());
long toTime = TimeUtils.reverseTimeMillis(1);
@@ -92,9 +92,9 @@ public class HbaseAgentInfoDao implements AgentInfoDao {
long startTime = TimeUtils.recoveryTimeMillis(reverseStartTime);
byte[] serializedAgentInfo = next.getValue(HBaseTables.AGENTINFO_CF_INFO, HBaseTables.AGENTINFO_CF_INFO_IDENTIFIER);
byte[] serializedServerMetaData = next.getValue(HBaseTables.AGENTINFO_CF_INFO, HBaseTables.AGENTINFO_CF_INFO_SERVER_META_DATA);
logger.debug("found={}, {}, start={}", found, range, startTime);
if (found > 1 && startTime <= range.getFrom()) {
logger.debug("stop finding agentInfo.");
break;
@@ -108,7 +108,7 @@ public class HbaseAgentInfoDao implements AgentInfoDao {
agentInfoBoBuilder.serverMetaData(new ServerMetaDataBo.Builder(serializedServerMetaData).build());
}
final AgentInfoBo agentInfoBo = agentInfoBoBuilder.build();
logger.debug("found agentInfoBo {}", agentInfoBo);
result.add(agentInfoBo);
}
@@ -116,9 +116,9 @@ public class HbaseAgentInfoDao implements AgentInfoDao {
return result;
}
});
logger.debug("get agentInfo result, {}", found);
return found;
}
@@ -158,15 +158,15 @@ public class HbaseAgentInfoDao implements AgentInfoDao {
agentInfoBoBuilder.serverMetaData(new ServerMetaDataBo.Builder(serializedServerMetaData).build());
}
final AgentInfoBo agentInfoBo = agentInfoBoBuilder.build();
logger.debug("agent:{} startTime find {}", agentId, startTime);
return agentInfoBo;
}
}
logger.warn("agentInfo not found. agentId={}, time={}", agentId, currentTime);
return null;
}
});