mirror of
https://github.com/wahyd4/pinpoint.git
synced 2026-08-20 10:16:13 +10:00
Merge pull request #20 from naver/dev-translation
comment cleanup and English translation
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
+4
-3
@@ -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();
|
||||
|
||||
+1
@@ -17,6 +17,7 @@
|
||||
package com.navercorp.pinpoint.bootstrap.instrument;
|
||||
|
||||
// TODO 추후 별도 계층구조가 필요하면 분화 필요.
|
||||
// TODO Separate this class when hierarchical layers are needed
|
||||
/**
|
||||
* @author emeroad
|
||||
*/
|
||||
|
||||
+2
-1
@@ -17,7 +17,8 @@
|
||||
package com.navercorp.pinpoint.bootstrap.interceptor;
|
||||
|
||||
/**
|
||||
* precompile level의 methodDescriptor를 setting 받을수 있게 한다.
|
||||
* this enables assigning "precompiled" methodDescriptor
|
||||
*
|
||||
* @author emeroad
|
||||
*/
|
||||
public interface ByteCodeMethodDescriptorSupport {
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
+1
-1
@@ -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 {
|
||||
|
||||
+2
-2
@@ -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;
|
||||
}
|
||||
|
||||
+3
-3
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-4
@@ -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,
|
||||
|
||||
+15
-15
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+14
-14
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+12
-12
@@ -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;
|
||||
}
|
||||
|
||||
+4
-4
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -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 {
|
||||
|
||||
+3
-3
@@ -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>();
|
||||
|
||||
+2
-2
@@ -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) {
|
||||
|
||||
+3
-3
@@ -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;
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
+3
-3
@@ -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();
|
||||
|
||||
+2
-1
@@ -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() {
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ import com.navercorp.pinpoint.web.vo.LinkKey;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 호출관계의 양방향 데이터를 표현
|
||||
* representation of caller/callee relationship
|
||||
* @author emeroad
|
||||
*/
|
||||
public class LinkCallData {
|
||||
|
||||
+3
-2
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
+3
-3
@@ -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();
|
||||
|
||||
+18
-19
@@ -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) {
|
||||
|
||||
+49
-50
@@ -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);
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+6
-6
@@ -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());
|
||||
|
||||
|
||||
+12
-11
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
+39
-35
@@ -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;
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user