mirror of
https://github.com/wahyd4/pinpoint.git
synced 2026-08-15 07:46:19 +10:00
Merge branch 'master' of https://github.com/naver/pinpoint into #117_refactoring_plugin_api
This commit is contained in:
+24
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright 2014 NAVER Corp.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.navercorp.pinpoint.bootstrap.interceptor;
|
||||
|
||||
/**
|
||||
* @author Jongho Moon
|
||||
*
|
||||
*/
|
||||
public interface ApiIdAwareAroundInterceptor extends Interceptor {
|
||||
void before(Object target, int apiId, Object[] args);
|
||||
void after(Object target, int apiId, Object[] args, Object result, Throwable throwable);
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2014 NAVER Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.navercorp.pinpoint.bootstrap.interceptor.group;
|
||||
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.ApiIdAwareAroundInterceptor;
|
||||
import com.navercorp.pinpoint.bootstrap.logging.PLogger;
|
||||
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
|
||||
|
||||
/**
|
||||
* @author emeroad
|
||||
*/
|
||||
public class GroupedApiIdAwareAroundInterceptor implements ApiIdAwareAroundInterceptor {
|
||||
private final PLogger logger = PLoggerFactory.getLogger(getClass());
|
||||
private final boolean debugEnabled = logger.isDebugEnabled();
|
||||
|
||||
private final ApiIdAwareAroundInterceptor delegate;
|
||||
private final InterceptorGroup group;
|
||||
private final ExecutionPolicy policy;
|
||||
|
||||
public GroupedApiIdAwareAroundInterceptor(ApiIdAwareAroundInterceptor delegate, InterceptorGroup group, ExecutionPolicy policy) {
|
||||
this.delegate = delegate;
|
||||
this.group = group;
|
||||
this.policy = policy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void before(Object target, int apiId, Object[] args) {
|
||||
InterceptorGroupInvocation transaction = group.getCurrentInvocation();
|
||||
|
||||
if (transaction.tryEnter(policy)) {
|
||||
this.delegate.before(target, apiId, args);
|
||||
} else {
|
||||
if (debugEnabled) {
|
||||
logger.debug("tryBefore() returns false: interceptorGroupTransaction: {}, executionPoint: {}. Skip interceptor {}", new Object[] {transaction, policy, delegate.getClass()} );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void after(Object target, int apiId, Object[] args, Object result, Throwable throwable) {
|
||||
InterceptorGroupInvocation transaction = group.getCurrentInvocation();
|
||||
|
||||
if (transaction.canLeave(policy)) {
|
||||
this.delegate.after(target, apiId, args, result, throwable);
|
||||
transaction.leave(policy);
|
||||
} else {
|
||||
if (debugEnabled) {
|
||||
logger.debug("tryAfter() returns false: interceptorGroupTransaction: {}, executionPoint: {}. Skip interceptor {}", new Object[] {transaction, policy, delegate.getClass()} );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -101,7 +101,6 @@ public class ClusterPointRouter implements MessageListener, ServerStreamChannelM
|
||||
} else {
|
||||
handleRouteRequestFail("Unknown error.", requestPacket, pinpointSocket);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -157,7 +156,7 @@ public class ClusterPointRouter implements MessageListener, ServerStreamChannelM
|
||||
return StreamCode.ROUTE_ERROR;
|
||||
}
|
||||
|
||||
return StreamCode.SUCCESS;
|
||||
return StreamCode.OK;
|
||||
}
|
||||
|
||||
public ClusterPointRepository<TargetClusterPoint> getTargetClusterPointRepository() {
|
||||
|
||||
+23
-1
@@ -22,6 +22,7 @@ import com.navercorp.pinpoint.collector.cluster.TargetClusterPoint;
|
||||
import com.navercorp.pinpoint.collector.cluster.route.filter.RouteFilter;
|
||||
import com.navercorp.pinpoint.rpc.ResponseMessage;
|
||||
import com.navercorp.pinpoint.rpc.packet.stream.StreamClosePacket;
|
||||
import com.navercorp.pinpoint.rpc.packet.stream.StreamCode;
|
||||
import com.navercorp.pinpoint.rpc.packet.stream.StreamResponsePacket;
|
||||
import com.navercorp.pinpoint.rpc.server.PinpointServer;
|
||||
import com.navercorp.pinpoint.rpc.stream.*;
|
||||
@@ -111,6 +112,7 @@ public class StreamRouteHandler extends AbstractRouteHandler<StreamEvent> {
|
||||
ClientStreamChannelContext producerContext = createStreamChannel((PinpointServerClusterPoint) clusterPoint, event.getDeliveryCommand().getPayload(), routeManager);
|
||||
if (producerContext.getCreateFailPacket() == null) {
|
||||
routeManager.setProducer(producerContext.getStreamChannel());
|
||||
producerContext.getStreamChannel().addStateChangeEventHandler(routeManager);
|
||||
return createResponse(TRouteResult.OK);
|
||||
}
|
||||
} else {
|
||||
@@ -139,7 +141,7 @@ public class StreamRouteHandler extends AbstractRouteHandler<StreamEvent> {
|
||||
}
|
||||
|
||||
// fix me : StreamRouteManager will change worker thread pattern.
|
||||
private class StreamRouteManager implements ClientStreamChannelMessageListener {
|
||||
private class StreamRouteManager implements ClientStreamChannelMessageListener,StreamChannelStateChangeEventHandler<ClientStreamChannel> {
|
||||
|
||||
private final StreamEvent streamEvent;
|
||||
private final ServerStreamChannel consumer;
|
||||
@@ -187,6 +189,26 @@ public class StreamRouteHandler extends AbstractRouteHandler<StreamEvent> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eventPerformed(ClientStreamChannel streamChannel, StreamChannelStateCode updatedStateCode) throws Exception {
|
||||
logger.info("eventPerformed streamChannel:{}, stateCode:{}", streamChannel, updatedStateCode);
|
||||
|
||||
switch (updatedStateCode) {
|
||||
case CLOSED:
|
||||
case ILLEGAL_STATE:
|
||||
if (consumer != null) {
|
||||
consumer.close();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ClientStreamChannel streamChannel, StreamChannelStateCode updatedStateCode, Throwable e) {
|
||||
logger.warn("exceptionCaught message:{}, streamChannel:{}, stateCode:{}", e.getMessage(), streamChannel, updatedStateCode, e);
|
||||
}
|
||||
|
||||
public ClientStreamChannel getProducer() {
|
||||
return producer;
|
||||
}
|
||||
|
||||
+26
-8
@@ -18,20 +18,18 @@ import java.lang.reflect.Modifier;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentException;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.Instrumentor;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.MethodFilter;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.MethodFilters;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.Instrumentor;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.transformer.PinpointClassFileTransformer;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.BasicMethodInterceptor;
|
||||
import com.navercorp.pinpoint.bootstrap.logging.PLogger;
|
||||
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
|
||||
|
||||
import static com.navercorp.pinpoint.common.util.VarArgs.va;
|
||||
|
||||
/**
|
||||
* @author Jongho Moon
|
||||
*
|
||||
@@ -43,10 +41,9 @@ public class BeanMethodTransformer implements PinpointClassFileTransformer {
|
||||
|
||||
private final PLogger logger = PLoggerFactory.getLogger(getClass());
|
||||
|
||||
private AtomicInteger interceptorId = new AtomicInteger(-1);
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.navercorp.pinpoint.bootstrap.plugin.transformer.PinpointClassFileTransformer#transform(com.navercorp.pinpoint.bootstrap.plugin.PinpointInstrument, java.lang.ClassLoader, java.lang.String, java.lang.Class, java.security.ProtectionDomain, byte[])
|
||||
*/
|
||||
@Override
|
||||
public byte[] transform(Instrumentor instrumentContext, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException {
|
||||
if (logger.isInfoEnabled()) {
|
||||
@@ -66,7 +63,7 @@ public class BeanMethodTransformer implements PinpointClassFileTransformer {
|
||||
logger.trace("### c={}, m={}, params={}", new Object[] {className, method.getName(), Arrays.toString(method.getParameterTypes())});
|
||||
}
|
||||
|
||||
method.addInterceptor(BasicMethodInterceptor.class.getName(), va(SpringBeansConstants.SERVICE_TYPE));
|
||||
addInterceptor(method);
|
||||
}
|
||||
|
||||
return target.toBytecode();
|
||||
@@ -75,4 +72,25 @@ public class BeanMethodTransformer implements PinpointClassFileTransformer {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void addInterceptor(InstrumentMethod targetMethod) throws InstrumentException {
|
||||
int id = interceptorId.get();
|
||||
|
||||
if (id != -1) {
|
||||
targetMethod.addInterceptor(id);
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (interceptorId) {
|
||||
id = interceptorId.get();
|
||||
|
||||
if (id != -1) {
|
||||
targetMethod.addInterceptor(id);
|
||||
return;
|
||||
}
|
||||
|
||||
id = targetMethod.addInterceptor("com.navercorp.pinpoint.plugin.spring.beans.interceptor.BeanMethodInterceptor");
|
||||
interceptorId.set(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-1
@@ -18,7 +18,6 @@ package com.navercorp.pinpoint.plugin.spring.beans.interceptor;
|
||||
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.Instrumentor;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.transformer.PinpointClassFileTransformer;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.Interceptor;
|
||||
import com.navercorp.pinpoint.bootstrap.logging.PLogger;
|
||||
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
|
||||
|
||||
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2014 NAVER Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.navercorp.pinpoint.plugin.spring.beans.interceptor;
|
||||
|
||||
import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder;
|
||||
import com.navercorp.pinpoint.bootstrap.context.Trace;
|
||||
import com.navercorp.pinpoint.bootstrap.context.TraceContext;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.ApiIdAwareAroundInterceptor;
|
||||
import com.navercorp.pinpoint.bootstrap.logging.PLogger;
|
||||
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
|
||||
import com.navercorp.pinpoint.plugin.spring.beans.SpringBeansConstants;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author netspider
|
||||
* @author emeroad
|
||||
*/
|
||||
public class BeanMethodInterceptor implements ApiIdAwareAroundInterceptor {
|
||||
|
||||
private final PLogger logger = PLoggerFactory.getLogger(BeanMethodInterceptor.class);
|
||||
private final boolean isDebug = logger.isDebugEnabled();
|
||||
|
||||
private final TraceContext traceContext;
|
||||
|
||||
public BeanMethodInterceptor(TraceContext traceContext) {
|
||||
this.traceContext = traceContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void before(Object target, int apiId, Object[] args) {
|
||||
if (isDebug) {
|
||||
logger.beforeInterceptor(target, args);
|
||||
}
|
||||
|
||||
Trace trace = traceContext.currentTraceObject();
|
||||
if (trace == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final SpanEventRecorder recorder = trace.traceBlockBegin();
|
||||
recorder.recordServiceType(SpringBeansConstants.SERVICE_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void after(Object target, int apiId, Object[] args, Object result, Throwable throwable) {
|
||||
if (isDebug) {
|
||||
logger.afterInterceptor(target, args);
|
||||
}
|
||||
|
||||
Trace trace = traceContext.currentTraceObject();
|
||||
if (trace == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final SpanEventRecorder recorder = trace.currentSpanEventRecorder();
|
||||
recorder.recordApi(new DummyMethodDescriptor(apiId));
|
||||
recorder.recordException(throwable);
|
||||
} finally {
|
||||
trace.traceBlockEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Copyright 2014 NAVER Corp.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.navercorp.pinpoint.plugin.spring.beans.interceptor;
|
||||
|
||||
import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor;
|
||||
|
||||
/**
|
||||
* @author Jongho Moon
|
||||
*
|
||||
*/
|
||||
public class DummyMethodDescriptor implements MethodDescriptor {
|
||||
private final int apiId;
|
||||
|
||||
public DummyMethodDescriptor(int apiId) {
|
||||
this.apiId = apiId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getParameterTypes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getParameterVariableName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParameterDescriptor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLineNumber() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFullName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApiId(int apiId) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getApiId() {
|
||||
return apiId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getApiDescriptor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import com.navercorp.pinpoint.profiler.receiver.service.ActiveThreadCountService;
|
||||
import com.navercorp.pinpoint.rpc.client.PinpointClient;
|
||||
import com.navercorp.pinpoint.rpc.util.ClientFactoryUtils;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
+5
-5
@@ -18,7 +18,6 @@ package com.navercorp.pinpoint.profiler.instrument;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import com.navercorp.pinpoint.common.util.Asserts;
|
||||
import javassist.CannotCompileException;
|
||||
import javassist.CtBehavior;
|
||||
import javassist.CtClass;
|
||||
@@ -48,6 +47,7 @@ import com.navercorp.pinpoint.bootstrap.interceptor.annotation.Group;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.group.ExecutionPolicy;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.group.InterceptorGroup;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.registry.InterceptorRegistry;
|
||||
import com.navercorp.pinpoint.common.util.Asserts;
|
||||
import com.navercorp.pinpoint.profiler.context.DefaultMethodDescriptor;
|
||||
import com.navercorp.pinpoint.profiler.instrument.interceptor.InvokeAfterCodeGenerator;
|
||||
import com.navercorp.pinpoint.profiler.instrument.interceptor.InvokeBeforeCodeGenerator;
|
||||
@@ -72,7 +72,7 @@ public class JavassistMethod implements InstrumentMethod {
|
||||
this.interceptorRegistryBinder = interceptorRegistryBinder;
|
||||
this.behavior = behavior;
|
||||
this.declaringClass = declaringClass;
|
||||
|
||||
|
||||
String[] parameterVariableNames = JavaAssistUtils.getParameterVariableName(behavior);
|
||||
int lineNumber = JavaAssistUtils.getLineNumber(behavior);
|
||||
|
||||
@@ -329,7 +329,7 @@ public class JavassistMethod implements InstrumentMethod {
|
||||
}
|
||||
|
||||
|
||||
InvokeAfterCodeGenerator catchGenerator = new InvokeAfterCodeGenerator(interceptorId, interceptorClass, interceptorMethod, declaringClass, this, localVarsInitialized, true);
|
||||
InvokeAfterCodeGenerator catchGenerator = new InvokeAfterCodeGenerator(interceptorId, interceptorClass, interceptorMethod, declaringClass, this, pluginContext.getTraceContext(), localVarsInitialized, true);
|
||||
String catchCode = catchGenerator.generate();
|
||||
|
||||
if (isDebug) {
|
||||
@@ -340,7 +340,7 @@ public class JavassistMethod implements InstrumentMethod {
|
||||
insertCatch(originalCodeOffset, catchCode, throwable, "$e");
|
||||
|
||||
|
||||
InvokeAfterCodeGenerator afterGenerator = new InvokeAfterCodeGenerator(interceptorId, interceptorClass, interceptorMethod, declaringClass, this, localVarsInitialized, false);
|
||||
InvokeAfterCodeGenerator afterGenerator = new InvokeAfterCodeGenerator(interceptorId, interceptorClass, interceptorMethod, declaringClass, this, pluginContext.getTraceContext(), localVarsInitialized, false);
|
||||
final String afterCode = afterGenerator.generate();
|
||||
|
||||
if (isDebug) {
|
||||
@@ -361,7 +361,7 @@ public class JavassistMethod implements InstrumentMethod {
|
||||
return -1;
|
||||
}
|
||||
|
||||
InvokeBeforeCodeGenerator generator = new InvokeBeforeCodeGenerator(interceptorId, interceptorClass, interceptorMethod, declaringClass, this);
|
||||
InvokeBeforeCodeGenerator generator = new InvokeBeforeCodeGenerator(interceptorId, interceptorClass, interceptorMethod, declaringClass, this, pluginContext.getTraceContext());
|
||||
String beforeCode = generator.generate();
|
||||
|
||||
if (isDebug) {
|
||||
|
||||
+12
-4
@@ -16,6 +16,7 @@ package com.navercorp.pinpoint.profiler.instrument.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import com.navercorp.pinpoint.bootstrap.context.TraceContext;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod;
|
||||
|
||||
@@ -33,8 +34,8 @@ public class InvokeAfterCodeGenerator extends InvokeCodeGenerator {
|
||||
private final boolean localVarsInitialized;
|
||||
private final boolean catchClause;
|
||||
|
||||
public InvokeAfterCodeGenerator(int interceptorId, Class<?> interceptorClass, Method interceptorMethod, InstrumentClass targetClass, InstrumentMethod targetMethod, boolean localVarsInitialized, boolean catchClause) {
|
||||
super(interceptorId, interceptorClass, targetMethod);
|
||||
public InvokeAfterCodeGenerator(int interceptorId, Class<?> interceptorClass, Method interceptorMethod, InstrumentClass targetClass, InstrumentMethod targetMethod, TraceContext traceContext, boolean localVarsInitialized, boolean catchClause) {
|
||||
super(interceptorId, interceptorClass, targetMethod, traceContext);
|
||||
|
||||
this.interceptorId = interceptorId;
|
||||
this.interceptorMethod = interceptorMethod;
|
||||
@@ -110,7 +111,10 @@ public class InvokeAfterCodeGenerator extends InvokeCodeGenerator {
|
||||
case STATIC:
|
||||
appendStaticAfterArguments(builder);
|
||||
break;
|
||||
case CUSTOM:
|
||||
case API_ID_AWARE:
|
||||
appendApiIdAwareAfterArguments(builder);
|
||||
break;
|
||||
case BASIC:
|
||||
appendCustomAfterArguments(builder);
|
||||
break;
|
||||
}
|
||||
@@ -123,7 +127,11 @@ public class InvokeAfterCodeGenerator extends InvokeCodeGenerator {
|
||||
private void appendStaticAfterArguments(CodeBuilder builder) {
|
||||
builder.format("%1$s, \"%2$s\", \"%3$s\", \"%4$s\", %5$s, %6$s, %7$s", getTarget(), targetClass.getName(), targetMethod.getName(), getParameterTypes(), getArguments(), getReturnValue(), getException());
|
||||
}
|
||||
|
||||
|
||||
private void appendApiIdAwareAfterArguments(CodeBuilder builder) {
|
||||
builder.format("%1$s, %2$d, %3$s, %4$s, %5$s", getTarget(), getApiId(), getArguments(), getReturnValue(), getException());
|
||||
}
|
||||
|
||||
private void appendCustomAfterArguments(CodeBuilder builder) {
|
||||
final Class<?>[] interceptorParamTypes = interceptorMethod.getParameterTypes();
|
||||
|
||||
|
||||
+11
-3
@@ -16,6 +16,7 @@ package com.navercorp.pinpoint.profiler.instrument.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import com.navercorp.pinpoint.bootstrap.context.TraceContext;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod;
|
||||
|
||||
@@ -28,8 +29,8 @@ public class InvokeBeforeCodeGenerator extends InvokeCodeGenerator {
|
||||
private final Method interceptorMethod;
|
||||
private final InstrumentClass targetClass;
|
||||
|
||||
public InvokeBeforeCodeGenerator(int interceptorId, Class<?> interceptorClass, Method interceptorMethod, InstrumentClass targetClass, InstrumentMethod targetMethod) {
|
||||
super(interceptorId, interceptorClass, targetMethod);
|
||||
public InvokeBeforeCodeGenerator(int interceptorId, Class<?> interceptorClass, Method interceptorMethod, InstrumentClass targetClass, InstrumentMethod targetMethod, TraceContext traceContext) {
|
||||
super(interceptorId, interceptorClass, targetMethod, traceContext);
|
||||
|
||||
this.interceptorId = interceptorId;
|
||||
this.interceptorMethod = interceptorMethod;
|
||||
@@ -72,7 +73,10 @@ public class InvokeBeforeCodeGenerator extends InvokeCodeGenerator {
|
||||
case STATIC:
|
||||
appendStaticBeforeArguments(builder);
|
||||
break;
|
||||
case CUSTOM:
|
||||
case API_ID_AWARE:
|
||||
appendApiIdAwareBeforeArguments(builder);
|
||||
break;
|
||||
case BASIC:
|
||||
appendCustomBeforeArguments(builder);
|
||||
break;
|
||||
}
|
||||
@@ -86,6 +90,10 @@ public class InvokeBeforeCodeGenerator extends InvokeCodeGenerator {
|
||||
builder.format("%1$s, \"%2$s\", \"%3$s\", \"%4$s\", %5$s", getTarget(), targetClass.getName(), targetMethod.getName(), getParameterTypes(), getArguments());
|
||||
}
|
||||
|
||||
private void appendApiIdAwareBeforeArguments(CodeBuilder builder) {
|
||||
builder.format("%1$s, %2$d, %3$s", getTarget(), getApiId(), getArguments());
|
||||
}
|
||||
|
||||
private void appendCustomBeforeArguments(CodeBuilder builder) {
|
||||
Class<?>[] paramTypes = interceptorMethod.getParameterTypes();
|
||||
|
||||
|
||||
+16
-3
@@ -16,8 +16,11 @@ package com.navercorp.pinpoint.profiler.instrument.interceptor;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor;
|
||||
import com.navercorp.pinpoint.bootstrap.context.TraceContext;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.AfterInterceptor;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.ApiIdAwareAroundInterceptor;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.BeforeInterceptor;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.InterceptorInvokerHelper;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.StaticAroundInterceptor;
|
||||
@@ -29,27 +32,31 @@ import com.navercorp.pinpoint.profiler.util.JavaAssistUtils;
|
||||
*
|
||||
*/
|
||||
public class InvokeCodeGenerator {
|
||||
private final TraceContext traceContext;
|
||||
protected final Class<?> interceptorClass;
|
||||
protected final InstrumentMethod targetMethod;
|
||||
protected final int interceptorId;
|
||||
protected final Type type;
|
||||
|
||||
public InvokeCodeGenerator(int interceptorId, Class<?> interceptorClass, InstrumentMethod targetMethod) {
|
||||
public InvokeCodeGenerator(int interceptorId, Class<?> interceptorClass, InstrumentMethod targetMethod, TraceContext traceContext) {
|
||||
this.interceptorClass = interceptorClass;
|
||||
this.targetMethod = targetMethod;
|
||||
this.interceptorId = interceptorId;
|
||||
this.traceContext = traceContext;
|
||||
|
||||
if (BeforeInterceptor.class.isAssignableFrom(interceptorClass) || AfterInterceptor.class.isAssignableFrom(interceptorClass)) {
|
||||
type = Type.ARRAY_ARGS;
|
||||
} else if (StaticAroundInterceptor.class.isAssignableFrom(interceptorClass)) {
|
||||
type = Type.STATIC;
|
||||
} else if (ApiIdAwareAroundInterceptor.class.isAssignableFrom(interceptorClass)) {
|
||||
type = Type.API_ID_AWARE;
|
||||
} else {
|
||||
type = Type.CUSTOM;
|
||||
type = Type.BASIC;
|
||||
}
|
||||
}
|
||||
|
||||
protected enum Type {
|
||||
ARRAY_ARGS, STATIC, CUSTOM
|
||||
ARRAY_ARGS, STATIC, BASIC, API_ID_AWARE
|
||||
}
|
||||
|
||||
protected String getInterceptorType() {
|
||||
@@ -73,6 +80,12 @@ public class InvokeCodeGenerator {
|
||||
return "$args";
|
||||
}
|
||||
|
||||
protected int getApiId() {
|
||||
MethodDescriptor descriptor = targetMethod.getDescriptor();
|
||||
int apiId = traceContext.cacheApi(descriptor);
|
||||
return apiId;
|
||||
}
|
||||
|
||||
protected String getInterceptorInvokerHelperClassName() {
|
||||
return InterceptorInvokerHelper.class.getName();
|
||||
}
|
||||
|
||||
+4
@@ -26,6 +26,7 @@ import com.navercorp.pinpoint.bootstrap.interceptor.AfterInterceptor2;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.AfterInterceptor3;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.AfterInterceptor4;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.AfterInterceptor5;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.ApiIdAwareAroundInterceptor;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor0;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor1;
|
||||
@@ -44,6 +45,7 @@ import com.navercorp.pinpoint.bootstrap.interceptor.Interceptor;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.StaticAroundInterceptor;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.annotation.Group;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.group.ExecutionPolicy;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.group.GroupedApiIdAwareAroundInterceptor;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.group.GroupedInterceptor;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.group.GroupedInterceptor0;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.group.GroupedInterceptor1;
|
||||
@@ -136,6 +138,8 @@ public class AnnotatedInterceptorFactory implements InterceptorFactory {
|
||||
return new GroupedInterceptor((BeforeInterceptor)interceptor, null, group, policy);
|
||||
} else if (interceptor instanceof AfterInterceptor) {
|
||||
return new GroupedInterceptor(null, (AfterInterceptor)interceptor, group, policy);
|
||||
} else if (interceptor instanceof ApiIdAwareAroundInterceptor) {
|
||||
return new GroupedApiIdAwareAroundInterceptor((ApiIdAwareAroundInterceptor)interceptor, group, policy);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unexpected interceptor type: " + interceptor.getClass());
|
||||
|
||||
+4
-31
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.navercorp.pinpoint.profiler.receiver;
|
||||
|
||||
import com.navercorp.pinpoint.common.Version;
|
||||
import com.navercorp.pinpoint.rpc.MessageListener;
|
||||
import com.navercorp.pinpoint.rpc.PinpointSocket;
|
||||
import com.navercorp.pinpoint.rpc.packet.RequestPacket;
|
||||
@@ -26,13 +25,10 @@ import com.navercorp.pinpoint.rpc.packet.stream.StreamCode;
|
||||
import com.navercorp.pinpoint.rpc.packet.stream.StreamCreatePacket;
|
||||
import com.navercorp.pinpoint.rpc.stream.ServerStreamChannelContext;
|
||||
import com.navercorp.pinpoint.rpc.stream.ServerStreamChannelMessageListener;
|
||||
import com.navercorp.pinpoint.rpc.util.AssertUtils;
|
||||
import com.navercorp.pinpoint.thrift.dto.TResult;
|
||||
import com.navercorp.pinpoint.thrift.io.*;
|
||||
import com.navercorp.pinpoint.thrift.util.SerializationUtils;
|
||||
import org.apache.thrift.TBase;
|
||||
import org.apache.thrift.protocol.TCompactProtocol;
|
||||
import org.apache.thrift.protocol.TProtocolFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -44,29 +40,8 @@ public class CommandDispatcher implements MessageListener, ServerStreamChannelMe
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private final ProfilerCommandServiceRegistry commandServiceRegistry = new ProfilerCommandServiceRegistry();
|
||||
|
||||
private final SerializerFactory<HeaderTBaseSerializer> serializerFactory;
|
||||
private final DeserializerFactory<HeaderTBaseDeserializer> deserializerFactory;
|
||||
|
||||
public CommandDispatcher() {
|
||||
this(Version.VERSION);
|
||||
}
|
||||
|
||||
public CommandDispatcher(String pinpointVersion) {
|
||||
this(pinpointVersion, HeaderTBaseSerializerFactory.DEFAULT_UDP_STREAM_MAX_SIZE);
|
||||
}
|
||||
|
||||
public CommandDispatcher(String pinpointVersion, int serializationMaxSize) {
|
||||
TProtocolFactory protocolFactory = new TCompactProtocol.Factory();
|
||||
TCommandRegistry commandTbaseRegistry = new TCommandRegistry(TCommandTypeVersion.getVersion(pinpointVersion));
|
||||
|
||||
SerializerFactory<HeaderTBaseSerializer> serializerFactory = new HeaderTBaseSerializerFactory(true, serializationMaxSize, protocolFactory, commandTbaseRegistry);
|
||||
this.serializerFactory = wrappedThreadLocalSerializerFactory(serializerFactory);
|
||||
AssertUtils.assertNotNull(this.serializerFactory);
|
||||
|
||||
DeserializerFactory<HeaderTBaseDeserializer> deserializerFactory = new HeaderTBaseDeserializerFactory(protocolFactory, commandTbaseRegistry);
|
||||
this.deserializerFactory = wrappedThreadLocalDeserializerFactory(deserializerFactory);
|
||||
AssertUtils.assertNotNull(this.deserializerFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -78,7 +53,7 @@ public class CommandDispatcher implements MessageListener, ServerStreamChannelMe
|
||||
public void handleRequest(RequestPacket requestPacket, PinpointSocket pinpointSocket) {
|
||||
logger.info("handleRequest packet:{}, remote:{}", requestPacket, pinpointSocket.getRemoteAddress());
|
||||
|
||||
final TBase<?, ?> request = SerializationUtils.deserialize(requestPacket.getPayload(), deserializerFactory, null);
|
||||
final TBase<?, ?> request = SerializationUtils.deserialize(requestPacket.getPayload(), CommandSerializer.DESERIALIZER_FACTORY, null);
|
||||
logger.debug("handleRequest request:{}, remote:{}", request, pinpointSocket.getRemoteAddress());
|
||||
|
||||
TBase response;
|
||||
@@ -99,7 +74,7 @@ public class CommandDispatcher implements MessageListener, ServerStreamChannelMe
|
||||
}
|
||||
}
|
||||
|
||||
final byte[] payload = SerializationUtils.serialize(response, serializerFactory, null);
|
||||
final byte[] payload = SerializationUtils.serialize(response, CommandSerializer.SERIALIZER_FACTORY, null);
|
||||
if (payload != null) {
|
||||
pinpointSocket.response(requestPacket, payload);
|
||||
}
|
||||
@@ -109,7 +84,7 @@ public class CommandDispatcher implements MessageListener, ServerStreamChannelMe
|
||||
public StreamCode handleStreamCreate(ServerStreamChannelContext streamChannelContext, StreamCreatePacket packet) {
|
||||
logger.info("MessageReceived handleStreamCreate {} {}", packet, streamChannelContext);
|
||||
|
||||
final TBase<?, ?> request = SerializationUtils.deserialize(packet.getPayload(), deserializerFactory, null);
|
||||
final TBase<?, ?> request = SerializationUtils.deserialize(packet.getPayload(), CommandSerializer.DESERIALIZER_FACTORY, null);
|
||||
if (request == null) {
|
||||
return StreamCode.TYPE_UNKNOWN;
|
||||
}
|
||||
@@ -119,9 +94,7 @@ public class CommandDispatcher implements MessageListener, ServerStreamChannelMe
|
||||
return StreamCode.TYPE_UNSUPPORT;
|
||||
}
|
||||
|
||||
service.streamCommandService(request, streamChannelContext);
|
||||
|
||||
return StreamCode.SUCCESS;
|
||||
return service.streamCommandService(request, streamChannelContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2014 NAVER Corp.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navercorp.pinpoint.profiler.receiver;
|
||||
|
||||
import com.navercorp.pinpoint.common.Version;
|
||||
import com.navercorp.pinpoint.thrift.io.*;
|
||||
import org.apache.thrift.protocol.TCompactProtocol;
|
||||
import org.apache.thrift.protocol.TProtocolFactory;
|
||||
|
||||
/**
|
||||
* @Author Taejin Koo
|
||||
*/
|
||||
public class CommandSerializer {
|
||||
|
||||
public static final SerializerFactory<HeaderTBaseSerializer> SERIALIZER_FACTORY;
|
||||
public static final DeserializerFactory<HeaderTBaseDeserializer> DESERIALIZER_FACTORY;
|
||||
|
||||
static {
|
||||
TProtocolFactory protocolFactory = new TCompactProtocol.Factory();
|
||||
TCommandRegistry commandTbaseRegistry = new TCommandRegistry(TCommandTypeVersion.getVersion(Version.VERSION));
|
||||
|
||||
SerializerFactory<HeaderTBaseSerializer> serializerFactory = new HeaderTBaseSerializerFactory(true, HeaderTBaseSerializerFactory.DEFAULT_UDP_STREAM_MAX_SIZE, protocolFactory, commandTbaseRegistry);
|
||||
SERIALIZER_FACTORY = wrappedThreadLocalSerializerFactory(serializerFactory);
|
||||
|
||||
DeserializerFactory<HeaderTBaseDeserializer> deserializerFactory = new HeaderTBaseDeserializerFactory(protocolFactory, commandTbaseRegistry);
|
||||
DESERIALIZER_FACTORY = wrappedThreadLocalDeserializerFactory(deserializerFactory);
|
||||
}
|
||||
|
||||
private static SerializerFactory<HeaderTBaseSerializer> wrappedThreadLocalSerializerFactory(SerializerFactory<HeaderTBaseSerializer> serializerFactory) {
|
||||
return new ThreadLocalHeaderTBaseSerializerFactory<HeaderTBaseSerializer>(serializerFactory);
|
||||
}
|
||||
|
||||
private static DeserializerFactory<HeaderTBaseDeserializer> wrappedThreadLocalDeserializerFactory(DeserializerFactory<HeaderTBaseDeserializer> deserializerFactory) {
|
||||
return new ThreadLocalHeaderTBaseDeserializerFactory<HeaderTBaseDeserializer>(deserializerFactory);
|
||||
}
|
||||
|
||||
}
|
||||
+3
-3
@@ -84,7 +84,7 @@ public class ProfilerCommandServiceRegistry implements ProfilerCommandServiceLoc
|
||||
}
|
||||
|
||||
final ProfilerCommandService service = profilerCommandServiceRepository.get(tBase.getClass());
|
||||
if (service instanceof ProfilerSimpleCommandService) {
|
||||
if (service != null && (service instanceof ProfilerSimpleCommandService)) {
|
||||
return (ProfilerSimpleCommandService) service;
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ public class ProfilerCommandServiceRegistry implements ProfilerCommandServiceLoc
|
||||
}
|
||||
|
||||
final ProfilerCommandService service = profilerCommandServiceRepository.get(tBase.getClass());
|
||||
if (service instanceof ProfilerRequestCommandService) {
|
||||
if (service != null && (service instanceof ProfilerRequestCommandService)) {
|
||||
return (ProfilerRequestCommandService) service;
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ public class ProfilerCommandServiceRegistry implements ProfilerCommandServiceLoc
|
||||
}
|
||||
|
||||
final ProfilerCommandService service = profilerCommandServiceRepository.get(tBase.getClass());
|
||||
if (service instanceof ProfilerStreamCommandService) {
|
||||
if (service != null && (service instanceof ProfilerStreamCommandService)) {
|
||||
return (ProfilerStreamCommandService) service;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -16,12 +16,13 @@
|
||||
|
||||
package com.navercorp.pinpoint.profiler.receiver;
|
||||
|
||||
import com.navercorp.pinpoint.rpc.packet.stream.StreamCode;
|
||||
import org.apache.thrift.TBase;
|
||||
|
||||
import com.navercorp.pinpoint.rpc.stream.ServerStreamChannelContext;
|
||||
|
||||
public interface ProfilerStreamCommandService extends ProfilerCommandService {
|
||||
|
||||
short streamCommandService(TBase tBase, ServerStreamChannelContext streamChannelContext);
|
||||
StreamCode streamCommandService(TBase tBase, ServerStreamChannelContext streamChannelContext);
|
||||
|
||||
}
|
||||
|
||||
+111
-7
@@ -24,17 +24,47 @@ import com.navercorp.pinpoint.common.trace.HistogramSlot;
|
||||
import com.navercorp.pinpoint.common.trace.SlotType;
|
||||
import com.navercorp.pinpoint.profiler.context.active.ActiveTraceInfo;
|
||||
import com.navercorp.pinpoint.profiler.context.active.ActiveTraceLocator;
|
||||
import com.navercorp.pinpoint.profiler.receiver.CommandSerializer;
|
||||
import com.navercorp.pinpoint.profiler.receiver.ProfilerRequestCommandService;
|
||||
import com.navercorp.pinpoint.profiler.receiver.ProfilerStreamCommandService;
|
||||
import com.navercorp.pinpoint.rpc.packet.stream.StreamCode;
|
||||
import com.navercorp.pinpoint.rpc.stream.*;
|
||||
import com.navercorp.pinpoint.rpc.util.TimerFactory;
|
||||
import com.navercorp.pinpoint.thrift.dto.command.TCmdActiveThreadCount;
|
||||
import com.navercorp.pinpoint.thrift.dto.command.TCmdActiveThreadCountRes;
|
||||
import com.navercorp.pinpoint.thrift.util.SerializationUtils;
|
||||
import org.apache.thrift.TBase;
|
||||
import org.jboss.netty.util.HashedWheelTimer;
|
||||
import org.jboss.netty.util.Timeout;
|
||||
import org.jboss.netty.util.TimerTask;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* @author Taejin Koo
|
||||
*/
|
||||
public class ActiveThreadCountService implements ProfilerRequestCommandService {
|
||||
public class ActiveThreadCountService implements ProfilerRequestCommandService, ProfilerStreamCommandService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private final Object lock = new Object();
|
||||
|
||||
// it will be changed.
|
||||
private final StreamChannelStateChangeEventHandler stateChangeEventHandler = new ActiveThreadCountStreamChannelStateChangeEventHandler();
|
||||
private final HashedWheelTimer timer = TimerFactory.createHashedWheelTimer("ActiveThreadCountService-Timer", 100, TimeUnit.MILLISECONDS, 512);
|
||||
private final long time = 1000;
|
||||
private final AtomicBoolean onTimerTask = new AtomicBoolean(false);
|
||||
|
||||
private final List<ServerStreamChannel> streamChannelRepository = new CopyOnWriteArrayList<ServerStreamChannel>();
|
||||
|
||||
|
||||
private static final List<SlotType> ACTIVE_THREAD_SLOTS_ORDER = new ArrayList<SlotType>();
|
||||
static {
|
||||
@@ -57,8 +87,29 @@ public class ActiveThreadCountService implements ProfilerRequestCommandService {
|
||||
this.activeThreadSlotsCount = ACTIVE_THREAD_SLOTS_ORDER.size();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TBase<?, ?> requestCommandService(TBase tBase) {
|
||||
public Class<? extends TBase> getCommandClazz() {
|
||||
return TCmdActiveThreadCount.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TBase<?, ?> requestCommandService(TBase activeThreadCountObject) {
|
||||
if (activeThreadCountObject == null) {
|
||||
throw new NullPointerException("activeThreadCountObject may not be null.");
|
||||
}
|
||||
|
||||
return getActiveThreadCountResponse();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamCode streamCommandService(TBase tBase, ServerStreamChannelContext streamChannelContext) {
|
||||
logger.info("streamCommandService object:{}, streamChannelContext:{}", tBase, streamChannelContext);
|
||||
streamChannelContext.getStreamChannel().addStateChangeEventHandler(stateChangeEventHandler);
|
||||
return StreamCode.OK;
|
||||
}
|
||||
|
||||
private TCmdActiveThreadCountRes getActiveThreadCountResponse() {
|
||||
Map<SlotType, IntAdder> mappedSlot = new LinkedHashMap<SlotType, IntAdder>(activeThreadSlotsCount);
|
||||
for (SlotType slotType : ACTIVE_THREAD_SLOTS_ORDER) {
|
||||
mappedSlot.put(slotType, new IntAdder(0));
|
||||
@@ -85,10 +136,6 @@ public class ActiveThreadCountService implements ProfilerRequestCommandService {
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends TBase> getCommandClazz() {
|
||||
return TCmdActiveThreadCount.class;
|
||||
}
|
||||
|
||||
private static class IntAdder {
|
||||
private int value = 0;
|
||||
@@ -106,4 +153,61 @@ public class ActiveThreadCountService implements ProfilerRequestCommandService {
|
||||
}
|
||||
}
|
||||
|
||||
private class ActiveThreadCountStreamChannelStateChangeEventHandler implements StreamChannelStateChangeEventHandler<ServerStreamChannel> {
|
||||
|
||||
private final LoggingStreamChannelStateChangeEventHandler loggingStateChangeEventListener = new LoggingStreamChannelStateChangeEventHandler();
|
||||
|
||||
@Override
|
||||
public void eventPerformed(ServerStreamChannel streamChannel, StreamChannelStateCode updatedStateCode) throws Exception {
|
||||
synchronized (lock) {
|
||||
switch (updatedStateCode) {
|
||||
case CONNECTED:
|
||||
streamChannelRepository.add(streamChannel);
|
||||
boolean turnOn = onTimerTask.compareAndSet(false, true);
|
||||
if (turnOn) {
|
||||
timer.newTimeout(new ActiveThreadCountTimerTask(), time, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
break;
|
||||
case CLOSED:
|
||||
case ILLEGAL_STATE:
|
||||
boolean removed = streamChannelRepository.remove(streamChannel);
|
||||
if (removed) {
|
||||
if (streamChannelRepository.size() == 0) {
|
||||
boolean turnOff = onTimerTask.compareAndSet(true, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ServerStreamChannel streamChannel, StreamChannelStateCode updatedStateCode, Throwable e) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ActiveThreadCountTimerTask implements TimerTask {
|
||||
|
||||
@Override
|
||||
public void run(Timeout timeout) throws Exception {
|
||||
logger.info("ActiveThreadCountService timer started.");
|
||||
|
||||
try {
|
||||
TCmdActiveThreadCountRes activeThreadCountResponse = getActiveThreadCountResponse();
|
||||
for (ServerStreamChannel serverStreamChannel : streamChannelRepository) {
|
||||
byte[] payload = SerializationUtils.serialize(activeThreadCountResponse, CommandSerializer.SERIALIZER_FACTORY, null);
|
||||
if (payload != null) {
|
||||
serverStreamChannel.sendData(payload);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (timer != null && onTimerTask.get()) {
|
||||
timer.newTimeout(this, time, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+21
-12
@@ -16,19 +16,21 @@
|
||||
|
||||
package com.navercorp.pinpoint.profiler.instrument.interceptor;
|
||||
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor0;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor3;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import com.navercorp.pinpoint.bootstrap.context.TraceContext;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor0;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor3;
|
||||
|
||||
/**
|
||||
* @author emeroad
|
||||
@@ -50,9 +52,11 @@ public class InvokeAfterCodeGeneratorTest {
|
||||
Mockito.when(mockMethod.getName()).thenReturn("TestMethod");
|
||||
Mockito.when(mockMethod.getParameterTypes()).thenReturn(new String[]{"java.lang.Object", "java.lang.Object", "java.lang.Object"});
|
||||
Mockito.when(mockMethod.getReturnType()).thenReturn("java.lang.Object");
|
||||
|
||||
TraceContext context = mock(TraceContext.class);
|
||||
|
||||
|
||||
final InvokeAfterCodeGenerator invokeAfterCodeGenerator = new InvokeAfterCodeGenerator(100, aroundInterceptor3Class, interceptorAfter, mockClass, mockMethod, false, true);
|
||||
final InvokeAfterCodeGenerator invokeAfterCodeGenerator = new InvokeAfterCodeGenerator(100, aroundInterceptor3Class, interceptorAfter, mockClass, mockMethod, context, false, true);
|
||||
final String generate = invokeAfterCodeGenerator.generate();
|
||||
|
||||
logger.debug("testGenerate_AroundInterceptor3_catchClause:{}", generate);
|
||||
@@ -78,8 +82,9 @@ public class InvokeAfterCodeGeneratorTest {
|
||||
Mockito.when(mockMethod.getParameterTypes()).thenReturn(new String[]{"java.lang.Object", "java.lang.Object", "java.lang.Object"});
|
||||
Mockito.when(mockMethod.getReturnType()).thenReturn("java.lang.Object");
|
||||
|
||||
TraceContext context = mock(TraceContext.class);
|
||||
|
||||
final InvokeAfterCodeGenerator invokeAfterCodeGenerator = new InvokeAfterCodeGenerator(100, aroundInterceptor3Class, interceptorAfter, mockClass, mockMethod, false, false);
|
||||
final InvokeAfterCodeGenerator invokeAfterCodeGenerator = new InvokeAfterCodeGenerator(100, aroundInterceptor3Class, interceptorAfter, mockClass, mockMethod, context, false, false);
|
||||
final String generate = invokeAfterCodeGenerator.generate();
|
||||
|
||||
logger.debug("testGenerate_AroundInterceptor3_NoCatchClause:{}", generate);
|
||||
@@ -104,9 +109,11 @@ public class InvokeAfterCodeGeneratorTest {
|
||||
Mockito.when(mockMethod.getName()).thenReturn("TestMethod");
|
||||
Mockito.when(mockMethod.getParameterTypes()).thenReturn(new String[]{"java.lang.Object", "java.lang.Object"});
|
||||
Mockito.when(mockMethod.getReturnType()).thenReturn("java.lang.Object");
|
||||
|
||||
TraceContext context = mock(TraceContext.class);
|
||||
|
||||
|
||||
final InvokeAfterCodeGenerator invokeAfterCodeGenerator = new InvokeAfterCodeGenerator(100, aroundInterceptor3Class, interceptorAfter, mockClass, mockMethod, false, true);
|
||||
final InvokeAfterCodeGenerator invokeAfterCodeGenerator = new InvokeAfterCodeGenerator(100, aroundInterceptor3Class, interceptorAfter, mockClass, mockMethod, context, false, true);
|
||||
final String generate = invokeAfterCodeGenerator.generate();
|
||||
|
||||
logger.debug("testGenerate_AroundInterceptor3_methodParam2:{}", generate);
|
||||
@@ -132,8 +139,9 @@ public class InvokeAfterCodeGeneratorTest {
|
||||
Mockito.when(mockMethod.getParameterTypes()).thenReturn(new String[]{"java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object"});
|
||||
Mockito.when(mockMethod.getReturnType()).thenReturn("java.lang.Object");
|
||||
|
||||
TraceContext context = mock(TraceContext.class);
|
||||
|
||||
final InvokeAfterCodeGenerator invokeAfterCodeGenerator = new InvokeAfterCodeGenerator(100, aroundInterceptor3Class, interceptorAfter, mockClass, mockMethod, false, true);
|
||||
final InvokeAfterCodeGenerator invokeAfterCodeGenerator = new InvokeAfterCodeGenerator(100, aroundInterceptor3Class, interceptorAfter, mockClass, mockMethod, context, false, true);
|
||||
final String generate = invokeAfterCodeGenerator.generate();
|
||||
|
||||
logger.debug("testGenerate_AroundInterceptor3_methodParam4:{}", generate);
|
||||
@@ -161,8 +169,9 @@ public class InvokeAfterCodeGeneratorTest {
|
||||
Mockito.when(mockMethod.getParameterTypes()).thenReturn(new String[]{});
|
||||
Mockito.when(mockMethod.getReturnType()).thenReturn("java.lang.Object");
|
||||
|
||||
TraceContext context = mock(TraceContext.class);
|
||||
|
||||
final InvokeAfterCodeGenerator invokeAfterCodeGenerator = new InvokeAfterCodeGenerator(100, aroundInterceptor3Class, interceptorAfter, mockClass, mockMethod, false, true);
|
||||
final InvokeAfterCodeGenerator invokeAfterCodeGenerator = new InvokeAfterCodeGenerator(100, aroundInterceptor3Class, interceptorAfter, mockClass, mockMethod, context, false, true);
|
||||
final String generate = invokeAfterCodeGenerator.generate();
|
||||
|
||||
logger.debug("testGenerate_AroundInterceptor0:{}", generate);
|
||||
|
||||
@@ -29,7 +29,7 @@ import java.util.Map;
|
||||
public enum StreamCode {
|
||||
|
||||
// Status Code
|
||||
SUCCESS((short) 0),
|
||||
OK((short) 0),
|
||||
|
||||
UNKNWON_ERROR((short) 100),
|
||||
|
||||
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2014 NAVER Corp.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navercorp.pinpoint.rpc.stream;
|
||||
|
||||
import com.navercorp.pinpoint.rpc.util.StringUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @Author Taejin Koo
|
||||
*/
|
||||
public class ClientStreamChannelMessageListenerRepository<V extends ClientStreamChannelMessageListener> {
|
||||
|
||||
private final ConcurrentHashMap<String, V> repository = new ConcurrentHashMap<String, V>();
|
||||
|
||||
public void put(String key, V messageListener) {
|
||||
if (StringUtils.isEmpty(key)) {
|
||||
throw new IllegalArgumentException("key is empty.");
|
||||
}
|
||||
|
||||
if (messageListener == null) {
|
||||
throw new IllegalArgumentException("messageListener is null.");
|
||||
}
|
||||
|
||||
repository.put(key, messageListener);
|
||||
}
|
||||
|
||||
public void get(String key) {
|
||||
repository.get(key);
|
||||
}
|
||||
|
||||
public void remove(String key) {
|
||||
if (StringUtils.isEmpty(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
repository.remove(key);
|
||||
}
|
||||
|
||||
public void remove(V messageListener) {
|
||||
if (messageListener == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String key = getKey(messageListener);
|
||||
repository.remove(key);
|
||||
}
|
||||
|
||||
public boolean contains(String key) {
|
||||
if (StringUtils.isEmpty(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return repository.containsKey(key);
|
||||
}
|
||||
|
||||
public boolean contains(V value) {
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return repository.contains(value);
|
||||
}
|
||||
|
||||
private String getKey(V messageListener) {
|
||||
for (Map.Entry<String, V> entry : repository.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
V value = entry.getValue();
|
||||
|
||||
if (messageListener == value) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Collection<V> values() {
|
||||
return repository.values();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return repository.size();
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -38,7 +38,7 @@ public class LoggingStreamChannelMessageListener {
|
||||
@Override
|
||||
public StreamCode handleStreamCreate(ServerStreamChannelContext streamChannelContext, StreamCreatePacket packet) {
|
||||
LOGGER.info("handleStreamCreate StreamChannel:{}, Packet:{}", streamChannelContext, packet);
|
||||
return StreamCode.SUCCESS;
|
||||
return StreamCode.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,20 +16,19 @@
|
||||
|
||||
package com.navercorp.pinpoint.rpc.stream;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import com.navercorp.pinpoint.rpc.PinpointSocketException;
|
||||
import com.navercorp.pinpoint.rpc.packet.PacketType;
|
||||
import com.navercorp.pinpoint.rpc.packet.stream.*;
|
||||
import com.navercorp.pinpoint.rpc.util.AssertUtils;
|
||||
import com.navercorp.pinpoint.rpc.util.IDGenerator;
|
||||
import org.jboss.netty.channel.Channel;
|
||||
import org.jboss.netty.channel.ChannelFuture;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.navercorp.pinpoint.rpc.PinpointSocketException;
|
||||
import com.navercorp.pinpoint.rpc.packet.PacketType;
|
||||
import com.navercorp.pinpoint.rpc.util.AssertUtils;
|
||||
import com.navercorp.pinpoint.rpc.util.IDGenerator;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* @author koo.taejin
|
||||
@@ -178,22 +177,22 @@ public class StreamChannelManager {
|
||||
private void handleCreate(StreamCreatePacket packet) {
|
||||
final int streamChannelId = packet.getStreamChannelId();
|
||||
|
||||
StreamCode code = StreamCode.SUCCESS;
|
||||
StreamCode code = StreamCode.OK;
|
||||
ServerStreamChannel streamChannel = new ServerStreamChannel(this.channel, streamChannelId, this);
|
||||
ServerStreamChannelContext streamChannelContext = new ServerStreamChannelContext(streamChannel);
|
||||
|
||||
code = registerStreamChannel(streamChannelContext);
|
||||
|
||||
if (code == StreamCode.SUCCESS) {
|
||||
if (code == StreamCode.OK) {
|
||||
code = streamChannelMessageListener.handleStreamCreate(streamChannelContext, (StreamCreatePacket) packet);
|
||||
|
||||
if (code == StreamCode.SUCCESS) {
|
||||
if (code == StreamCode.OK) {
|
||||
streamChannel.changeStateConnected();
|
||||
streamChannel.sendCreateSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
if (code != StreamCode.SUCCESS) {
|
||||
if (code != StreamCode.OK) {
|
||||
clearResourceAndSendCreateFail(streamChannelId, code);
|
||||
}
|
||||
}
|
||||
@@ -215,7 +214,7 @@ public class StreamChannelManager {
|
||||
return StreamCode.STATE_ERROR;
|
||||
}
|
||||
|
||||
return StreamCode.SUCCESS;
|
||||
return StreamCode.OK;
|
||||
}
|
||||
|
||||
private void handleCreateSuccess(ClientStreamChannelContext streamChannelContext, StreamCreateSuccessPacket packet) {
|
||||
|
||||
+3
-3
@@ -22,10 +22,10 @@ package com.navercorp.pinpoint.rpc.stream;
|
||||
/**
|
||||
* @Author Taejin Koo
|
||||
*/
|
||||
public interface StreamChannelStateChangeEventHandler {
|
||||
public interface StreamChannelStateChangeEventHandler <S extends StreamChannel> {
|
||||
|
||||
void eventPerformed(StreamChannel streamChannel, StreamChannelStateCode updatedStateCode) throws Exception;
|
||||
void eventPerformed(S streamChannel, StreamChannelStateCode updatedStateCode) throws Exception;
|
||||
|
||||
void exceptionCaught(StreamChannel streamChannel, StreamChannelStateCode updatedStateCode, Throwable e);
|
||||
void exceptionCaught(S streamChannel, StreamChannelStateCode updatedStateCode, Throwable e);
|
||||
|
||||
}
|
||||
|
||||
@@ -335,7 +335,7 @@ public class StreamChannelManagerTest {
|
||||
@Override
|
||||
public StreamCode handleStreamCreate(ServerStreamChannelContext streamChannelContext, StreamCreatePacket packet) {
|
||||
bo.addServerStreamChannelContext(streamChannelContext);
|
||||
return StreamCode.SUCCESS;
|
||||
return StreamCode.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -56,4 +56,10 @@ public interface AgentService {
|
||||
AgentActiveThreadCountList getActiveThreadCount(List<AgentInfo> agentInfoList) throws TException;
|
||||
AgentActiveThreadCountList getActiveThreadCount(List<AgentInfo> agentInfoList, byte[] payload) throws TException;
|
||||
|
||||
byte[] serializeRequest(TBase<?, ?> tBase) throws TException;
|
||||
byte[] serializeRequest(TBase<?, ?> tBase, byte[] defaultValue);
|
||||
|
||||
TBase<?, ?> deserializeResponse(byte[] objectData) throws TException;
|
||||
TBase<?, ?> deserializeResponse(byte[] objectData, TBase<?, ?> defaultValue);
|
||||
|
||||
}
|
||||
|
||||
@@ -236,8 +236,13 @@ public class AgentServiceImpl implements AgentService {
|
||||
AgentInfo agentInfo = entry.getKey();
|
||||
PinpointRouteResponse response = entry.getValue();
|
||||
|
||||
AgentActiveThreadCount agentActiveThreadStatus = new AgentActiveThreadCount(agentInfo.getAgentId(),
|
||||
response.getRouteResult(), response.getResponse(TCmdActiveThreadCountRes.class, null));
|
||||
AgentActiveThreadCount agentActiveThreadStatus = new AgentActiveThreadCount(agentInfo.getAgentId());
|
||||
TRouteResult routeResult = response.getRouteResult();
|
||||
if (routeResult == TRouteResult.OK) {
|
||||
agentActiveThreadStatus.setResult(response.getResponse(TCmdActiveThreadCountRes.class, null));
|
||||
} else {
|
||||
agentActiveThreadStatus.setFail(routeResult.name());
|
||||
}
|
||||
agentActiveThreadStatusList.add(agentActiveThreadStatus);
|
||||
}
|
||||
|
||||
@@ -285,4 +290,25 @@ public class AgentServiceImpl implements AgentService {
|
||||
return Math.max(startTime + timeout - System.currentTimeMillis(), 100L);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public byte[] serializeRequest(TBase<?, ?> tBase) throws TException {
|
||||
return SerializationUtils.serialize(tBase, commandSerializerFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] serializeRequest(TBase<?, ?> tBase, byte[] defaultValue) {
|
||||
return SerializationUtils.serialize(tBase, commandSerializerFactory, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TBase<?, ?> deserializeResponse(byte[] objectData) throws TException {
|
||||
return SerializationUtils.deserialize(objectData, commandDeserializerFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TBase<?, ?> deserializeResponse(byte[] objectData, TBase<?, ?> defaultValue) {
|
||||
return SerializationUtils.deserialize(objectData, commandDeserializerFactory, defaultValue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,47 +27,59 @@ import com.navercorp.pinpoint.thrift.dto.command.TRouteResult;
|
||||
*/
|
||||
public class AgentActiveThreadCount {
|
||||
|
||||
private final String agentId;
|
||||
private final TRouteResult routeResult;
|
||||
private final TCmdActiveThreadCountRes activeThreadCount;
|
||||
private final short OK_CODE = 0;
|
||||
private final String OK_CODE_MESSAGE = "OK";
|
||||
|
||||
public AgentActiveThreadCount(String agentId, TRouteResult routeResult, TCmdActiveThreadCountRes activeThreadCount) {
|
||||
private final String agentId;
|
||||
|
||||
private short code = -1;
|
||||
private String codeMessage = "UNKNOWN";
|
||||
|
||||
private TCmdActiveThreadCountRes activeThreadCount;
|
||||
|
||||
public AgentActiveThreadCount(String agentId) {
|
||||
this.agentId = agentId;
|
||||
this.routeResult = routeResult;
|
||||
this.activeThreadCount = activeThreadCount;
|
||||
}
|
||||
|
||||
public void setResult(TCmdActiveThreadCountRes activeThreadCount) {
|
||||
if (activeThreadCount != null) {
|
||||
this.activeThreadCount = activeThreadCount;
|
||||
this.code = OK_CODE;
|
||||
this.codeMessage = OK_CODE_MESSAGE;
|
||||
}
|
||||
}
|
||||
|
||||
public void setFail(String codeMessage) {
|
||||
setFail((short) -1, codeMessage);
|
||||
}
|
||||
|
||||
public void setFail(short code, String codeMessage) {
|
||||
this.code = code;
|
||||
this.codeMessage = codeMessage;
|
||||
}
|
||||
|
||||
public String getAgentId() {
|
||||
return agentId;
|
||||
}
|
||||
|
||||
public TRouteResult getRouteResult() {
|
||||
return routeResult;
|
||||
public short getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public TRouteResult getRouteResult(TRouteResult defaultValue) {
|
||||
if (routeResult == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return routeResult;
|
||||
public String getCodeMessage() {
|
||||
return codeMessage;
|
||||
}
|
||||
|
||||
public TCmdActiveThreadCountRes getActiveThreadCount() {
|
||||
return activeThreadCount;
|
||||
}
|
||||
|
||||
public TCmdActiveThreadCountRes getActiveThreadStatus(TCmdActiveThreadCountRes defaultValue) {
|
||||
if (activeThreadCount == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return activeThreadCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AgentActiveThreadCount{" +
|
||||
"agentId='" + agentId + '\'' +
|
||||
", routeResult=" + routeResult +
|
||||
", code=" + getCode() +
|
||||
", codeMessage=" + getCodeMessage() +
|
||||
", activeThreadCount=" + activeThreadCount +
|
||||
'}';
|
||||
}
|
||||
|
||||
@@ -39,6 +39,10 @@ public class AgentActiveThreadCountList {
|
||||
|
||||
private final List<AgentActiveThreadCount> agentActiveThreadRepository;
|
||||
|
||||
public AgentActiveThreadCountList() {
|
||||
agentActiveThreadRepository = new ArrayList<AgentActiveThreadCount>();
|
||||
}
|
||||
|
||||
public AgentActiveThreadCountList(int initialCapacity) {
|
||||
agentActiveThreadRepository = new ArrayList<AgentActiveThreadCount>(initialCapacity);
|
||||
}
|
||||
@@ -72,9 +76,8 @@ class AgentActiveThreadCountListSerializer extends JsonSerializer<AgentActiveThr
|
||||
jgen.writeFieldName(agentActiveThread.getAgentId());
|
||||
jgen.writeStartObject();
|
||||
|
||||
TRouteResult routeResult = agentActiveThread.getRouteResult(TRouteResult.UNKNOWN);
|
||||
jgen.writeNumberField("code", routeResult.getValue());
|
||||
jgen.writeStringField("message", routeResult.name());
|
||||
jgen.writeNumberField("code", agentActiveThread.getCode());
|
||||
jgen.writeStringField("message", agentActiveThread.getCodeMessage());
|
||||
|
||||
TCmdActiveThreadCountRes activeThreadCount = agentActiveThread.getActiveThreadCount();
|
||||
long timeStamp = System.currentTimeMillis();
|
||||
@@ -93,7 +96,6 @@ class AgentActiveThreadCountListSerializer extends JsonSerializer<AgentActiveThr
|
||||
jgen.writeEndArray();
|
||||
}
|
||||
}
|
||||
jgen.writeNumberField("timeStamp", timeStamp);
|
||||
|
||||
jgen.writeEndObject();
|
||||
}
|
||||
|
||||
+75
-105
@@ -19,13 +19,11 @@
|
||||
|
||||
package com.navercorp.pinpoint.web.websocket;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.navercorp.pinpoint.rpc.stream.ClientStreamChannelMessageListenerRepository;
|
||||
import com.navercorp.pinpoint.rpc.util.StringUtils;
|
||||
import com.navercorp.pinpoint.web.service.AgentService;
|
||||
import com.navercorp.pinpoint.web.vo.AgentActiveThreadCountList;
|
||||
import com.navercorp.pinpoint.web.vo.AgentInfo;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.thrift.TException;
|
||||
import org.jboss.netty.util.Timeout;
|
||||
import org.jboss.netty.util.Timer;
|
||||
import org.jboss.netty.util.TimerTask;
|
||||
@@ -36,7 +34,6 @@ import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -48,23 +45,24 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
public class ActiveThreadCountHandler extends TextWebSocketHandler implements PinpointWebSocketHandler {
|
||||
|
||||
private static final String APPLICATION_NAME_KEY = "applicationName";
|
||||
private static final String DEFAULT_REQUEST_MAPPING = "/agent/activeThread";
|
||||
|
||||
static final String DEFAULT_REQUEST_MAPPING = "/agent/activeThread";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
private final Object lock = new Object();
|
||||
|
||||
private final String requestMapping;
|
||||
private final AgentService agentSerivce;
|
||||
|
||||
private final Timer timer;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private final Object lock = new Object();
|
||||
|
||||
// it will be changed.
|
||||
private final long time = 1000;
|
||||
private final AtomicBoolean onTimerTask = new AtomicBoolean(false);
|
||||
|
||||
private final List<WebSocketSession> sessionRepository = new CopyOnWriteArrayList<WebSocketSession>();
|
||||
|
||||
private final Map<String, WebSocketResponseAggregator> aggregatorRepository = new HashMap<String, WebSocketResponseAggregator>();
|
||||
|
||||
private final ObjectMapper jsonConverter = new ObjectMapper();
|
||||
|
||||
public ActiveThreadCountHandler(WebSocketHandlerRegister register, AgentService agentSerivce) {
|
||||
@@ -90,8 +88,6 @@ public class ActiveThreadCountHandler extends TextWebSocketHandler implements Pi
|
||||
|
||||
synchronized (lock) {
|
||||
sessionRepository.add(newSession);
|
||||
Timeout timeout = timer.newTimeout(new ActiveThreadTimerTask(), time, TimeUnit.MILLISECONDS);
|
||||
|
||||
boolean turnOn = onTimerTask.compareAndSet(false, true);
|
||||
if (turnOn) {
|
||||
timer.newTimeout(new ActiveThreadTimerTask(), time, TimeUnit.MILLISECONDS);
|
||||
@@ -106,6 +102,8 @@ public class ActiveThreadCountHandler extends TextWebSocketHandler implements Pi
|
||||
logger.info("ConnectionClosed : {}, caused : {}", closeSession, status);
|
||||
|
||||
synchronized (lock) {
|
||||
closeAggregator(closeSession);
|
||||
|
||||
sessionRepository.remove(closeSession);
|
||||
if (sessionRepository.size() == 0) {
|
||||
boolean turnOff = onTimerTask.compareAndSet(true, false);
|
||||
@@ -116,17 +114,70 @@ public class ActiveThreadCountHandler extends TextWebSocketHandler implements Pi
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
|
||||
logger.info("handleTextMessage. session : {}, message : {}.", session, message.getPayload());
|
||||
protected void handleTextMessage(WebSocketSession webSocketSession, TextMessage message) throws Exception {
|
||||
logger.info("handleTextMessage. session : {}, message : {}.", webSocketSession, message.getPayload());
|
||||
|
||||
String request = message.getPayload();
|
||||
if (request != null && request.startsWith(APPLICATION_NAME_KEY + "=")) {
|
||||
String applicationName = request.substring(APPLICATION_NAME_KEY.length() + 1);
|
||||
session.getAttributes().put(APPLICATION_NAME_KEY, applicationName);
|
||||
synchronized (lock) {
|
||||
closeAggregator(webSocketSession);
|
||||
if (!StringUtils.isEmpty(applicationName)) {
|
||||
webSocketSession.getAttributes().put(APPLICATION_NAME_KEY, applicationName);
|
||||
openAggregator(webSocketSession);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this method will be checked socket status.
|
||||
super.handleTextMessage(session, message);
|
||||
super.handleTextMessage(webSocketSession, message);
|
||||
}
|
||||
|
||||
private void openAggregator(WebSocketSession webSocketSession) {
|
||||
String applicationName = (String) webSocketSession.getAttributes().get(APPLICATION_NAME_KEY);
|
||||
if (StringUtils.isEmpty(applicationName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
WebSocketResponseAggregator aggregator = aggregatorRepository.get(applicationName);
|
||||
if (aggregator == null) {
|
||||
aggregator = new WebSocketResponseAggregator(applicationName);
|
||||
aggregatorRepository.put(applicationName, aggregator);
|
||||
}
|
||||
|
||||
ClientStreamChannelMessageListenerRepository<ActiveThreadCountStreamListener> streamMessageListenerRepository = aggregator.getStreamMessageListenerRepository();
|
||||
List<AgentInfo> agentInfoList = agentSerivce.getAgentInfoList(applicationName);
|
||||
|
||||
for (AgentInfo agentInfo : agentInfoList) {
|
||||
String agentId = agentInfo.getAgentId();
|
||||
if (!streamMessageListenerRepository.contains(agentId)) {
|
||||
ActiveThreadCountStreamListener streamListener = new ActiveThreadCountStreamListener(agentSerivce, agentInfo, aggregator);
|
||||
streamListener.start();
|
||||
}
|
||||
}
|
||||
|
||||
aggregator.registerWebSocketSession(webSocketSession);
|
||||
}
|
||||
|
||||
private void closeAggregator(WebSocketSession webSocketSession) {
|
||||
String applicationName = (String) webSocketSession.getAttributes().get(APPLICATION_NAME_KEY);
|
||||
if (StringUtils.isEmpty(applicationName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
WebSocketResponseAggregator aggregator = aggregatorRepository.get(applicationName);
|
||||
if (aggregator == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
aggregator.unregisterWebSocketSession(webSocketSession);
|
||||
if (aggregator.registeredWebSocketSessionCount() == 0) {
|
||||
for (ActiveThreadCountStreamListener r : aggregator.getStreamMessageListenerRepository().values()) {
|
||||
r.stop();
|
||||
}
|
||||
|
||||
aggregatorRepository.remove(applicationName);
|
||||
}
|
||||
}
|
||||
|
||||
private class ActiveThreadTimerTask implements TimerTask {
|
||||
@@ -136,14 +187,13 @@ public class ActiveThreadCountHandler extends TextWebSocketHandler implements Pi
|
||||
try {
|
||||
logger.info("ActiveThreadTimerTask started.");
|
||||
|
||||
Map<String, List<WebSocketSession>> applicationGroup = createApplicationGroup(sessionRepository);
|
||||
|
||||
for (Map.Entry<String, List<WebSocketSession>> applicationEntry : applicationGroup.entrySet()) {
|
||||
String applicationName = applicationEntry.getKey();
|
||||
|
||||
List<AgentInfo> agentInfoList = getAgentInfoList(applicationName);
|
||||
AgentActiveThreadCountList agentActiveThreadCountList = getAgentActiveThreadCount(agentInfoList);
|
||||
doResponse(applicationEntry.getValue(), applicationName, agentActiveThreadCountList);
|
||||
Collection<WebSocketResponseAggregator> values = aggregatorRepository.values();
|
||||
for (WebSocketResponseAggregator aggregator : values) {
|
||||
try {
|
||||
aggregator.flush();
|
||||
} catch (Exception e) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (timer != null && onTimerTask.get()) {
|
||||
@@ -153,84 +203,4 @@ public class ActiveThreadCountHandler extends TextWebSocketHandler implements Pi
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, List<WebSocketSession>> createApplicationGroup(List<WebSocketSession> sessionRepository) {
|
||||
Map<String, List<WebSocketSession>> applicationGroup = new HashMap<String, List<WebSocketSession>>();
|
||||
for (WebSocketSession session : sessionRepository) {
|
||||
String applicationName = (String) session.getAttributes().get(APPLICATION_NAME_KEY);
|
||||
|
||||
if (applicationName == null || applicationName.length() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!applicationGroup.containsKey(applicationName)) {
|
||||
applicationGroup.put(applicationName, new ArrayList<WebSocketSession>());
|
||||
}
|
||||
|
||||
applicationGroup.get(applicationName).add(session);
|
||||
}
|
||||
|
||||
return applicationGroup;
|
||||
}
|
||||
|
||||
private List<AgentInfo> getAgentInfoList(String applicationName) {
|
||||
try {
|
||||
List<AgentInfo> agentInfoList = agentSerivce.getAgentInfoList(applicationName);
|
||||
return agentInfoList;
|
||||
} catch (Exception e) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private AgentActiveThreadCountList getAgentActiveThreadCount(List<AgentInfo> agentInfoList) {
|
||||
try {
|
||||
AgentActiveThreadCountList agentActiveThreadCountList = agentSerivce.getActiveThreadCount(agentInfoList);
|
||||
return agentActiveThreadCountList;
|
||||
} catch (TException e) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
}
|
||||
|
||||
return new AgentActiveThreadCountList(0);
|
||||
}
|
||||
|
||||
private void doResponse(List<WebSocketSession> webSocketSessions, String applicationName, AgentActiveThreadCountList activeThreadCount) {
|
||||
if (webSocketSessions == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String textMessage = makeResponseMessage(applicationName, activeThreadCount);
|
||||
|
||||
for (WebSocketSession session : webSocketSessions) {
|
||||
try {
|
||||
session.sendMessage(new TextMessage(textMessage));
|
||||
} catch (IOException e) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String makeResponseMessage(String applicationName, AgentActiveThreadCountList activeThreadCount) {
|
||||
Map<String, AgentActiveThreadCountList> response = new HashMap<String, AgentActiveThreadCountList>();
|
||||
response.put(applicationName, activeThreadCount);
|
||||
|
||||
try {
|
||||
return jsonConverter.writeValueAsString(response);
|
||||
} catch (JsonProcessingException e) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
}
|
||||
|
||||
return createEmptyJsonMessage(applicationName);
|
||||
}
|
||||
|
||||
private String createEmptyJsonMessage(String applicationName) {
|
||||
StringBuilder emptyJsonMessage = new StringBuilder();
|
||||
emptyJsonMessage.append("{");
|
||||
emptyJsonMessage.append("\"").append(applicationName).append("\"");
|
||||
emptyJsonMessage.append(":");
|
||||
emptyJsonMessage.append("{}");
|
||||
emptyJsonMessage.append("}");
|
||||
|
||||
return emptyJsonMessage.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2014 NAVER Corp.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navercorp.pinpoint.web.websocket;
|
||||
|
||||
import com.navercorp.pinpoint.rpc.packet.stream.StreamClosePacket;
|
||||
import com.navercorp.pinpoint.rpc.packet.stream.StreamCode;
|
||||
import com.navercorp.pinpoint.rpc.packet.stream.StreamCreateFailPacket;
|
||||
import com.navercorp.pinpoint.rpc.packet.stream.StreamResponsePacket;
|
||||
import com.navercorp.pinpoint.rpc.stream.*;
|
||||
import com.navercorp.pinpoint.thrift.dto.command.TCmdActiveThreadCount;
|
||||
import com.navercorp.pinpoint.thrift.dto.command.TCmdActiveThreadCountRes;
|
||||
import com.navercorp.pinpoint.thrift.dto.command.TCommandTransferResponse;
|
||||
import com.navercorp.pinpoint.thrift.dto.command.TRouteResult;
|
||||
import com.navercorp.pinpoint.web.service.AgentService;
|
||||
import com.navercorp.pinpoint.web.vo.AgentActiveThreadCount;
|
||||
import com.navercorp.pinpoint.web.vo.AgentInfo;
|
||||
import org.apache.thrift.TBase;
|
||||
import org.apache.thrift.TException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @Author Taejin Koo
|
||||
*/
|
||||
public class ActiveThreadCountStreamListener implements ClientStreamChannelMessageListener, StreamChannelStateChangeEventHandler<ClientStreamChannel> {
|
||||
|
||||
private static final ClientStreamChannelMessageListener LOGGING = LoggingStreamChannelMessageListener.CLIENT_LISTENER;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private final AgentService agentService;
|
||||
private final AgentInfo agentInfo;
|
||||
private final WebSocketResponseAggregator responseAggregator;
|
||||
private final AgentActiveThreadCount defaultFailedResponse;
|
||||
private StreamChannel streamchannel;
|
||||
|
||||
public ActiveThreadCountStreamListener(AgentService agentService, AgentInfo agentInfo, WebSocketResponseAggregator webSocketResponseAggregator) {
|
||||
this.agentService = agentService;
|
||||
this.agentInfo = agentInfo;
|
||||
this.responseAggregator = webSocketResponseAggregator;
|
||||
|
||||
this.defaultFailedResponse = new AgentActiveThreadCount(agentInfo.getAgentId());
|
||||
}
|
||||
|
||||
public void start() {
|
||||
try {
|
||||
ClientStreamChannelContext clientStreamChannelContext = agentService.openStream(agentInfo, new TCmdActiveThreadCount(), this);
|
||||
|
||||
if (clientStreamChannelContext.getCreateFailPacket() == null) {
|
||||
this.streamchannel = clientStreamChannelContext.getStreamChannel();
|
||||
this.streamchannel.addStateChangeEventHandler(this);
|
||||
defaultFailedResponse.setFail(TRouteResult.TIMEOUT.name());
|
||||
} else {
|
||||
StreamCreateFailPacket createFailPacket = clientStreamChannelContext.getCreateFailPacket();
|
||||
defaultFailedResponse.setFail(createFailPacket.getCode().name());
|
||||
}
|
||||
} catch (TException exception) {
|
||||
defaultFailedResponse.setFail(TRouteResult.NOT_SUPPORTED_REQUEST.name());
|
||||
} finally {
|
||||
this.responseAggregator.getStreamMessageListenerRepository().put(agentInfo.getAgentId(), this);
|
||||
}
|
||||
}
|
||||
|
||||
// fixed 결과값을 지정할수 있게 해야함
|
||||
public void stop() {
|
||||
try {
|
||||
if (streamchannel != null) {
|
||||
streamchannel.close();
|
||||
}
|
||||
defaultFailedResponse.setFail(StreamCode.STATE_CLOSED.name());
|
||||
} finally {
|
||||
this.responseAggregator.getStreamMessageListenerRepository().remove(agentInfo.getAgentId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleStreamData(ClientStreamChannelContext streamChannelContext, StreamResponsePacket packet) {
|
||||
LOGGING.handleStreamData(streamChannelContext, packet);
|
||||
|
||||
TBase response = agentService.deserializeResponse(packet.getPayload(), null);
|
||||
AgentActiveThreadCount activeThreadCount = getAgentActiveThreadCount(response);
|
||||
responseAggregator.response(activeThreadCount);
|
||||
}
|
||||
|
||||
private AgentActiveThreadCount getAgentActiveThreadCount(TBase routeResponse) {
|
||||
AgentActiveThreadCount agentActiveThreadCount = new AgentActiveThreadCount(agentInfo.getAgentId());
|
||||
|
||||
if (routeResponse != null && (routeResponse instanceof TCommandTransferResponse)) {
|
||||
byte[] payload = ((TCommandTransferResponse) routeResponse).getPayload();
|
||||
TBase<?, ?> activeThreadCountResponse = agentService.deserializeResponse(payload, null);
|
||||
|
||||
if (activeThreadCountResponse != null && (activeThreadCountResponse instanceof TCmdActiveThreadCountRes)) {
|
||||
agentActiveThreadCount.setResult((TCmdActiveThreadCountRes) activeThreadCountResponse);
|
||||
} else {
|
||||
agentActiveThreadCount.setFail("ROUTE_ERROR:" + TRouteResult.NOT_SUPPORTED_RESPONSE.name());
|
||||
}
|
||||
} else {
|
||||
agentActiveThreadCount.setFail("ROUTE_ERROR:" + TRouteResult.BAD_RESPONSE.name());
|
||||
}
|
||||
|
||||
return agentActiveThreadCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleStreamClose(ClientStreamChannelContext streamChannelContext, StreamClosePacket packet) {
|
||||
LOGGING.handleStreamClose(streamChannelContext, packet);
|
||||
|
||||
defaultFailedResponse.setFail(StreamCode.STATE_CLOSED.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eventPerformed(ClientStreamChannel streamChannel, StreamChannelStateCode updatedStateCode) throws Exception {
|
||||
logger.info("eventPerformed streamChannel:{}, stateCode:{}", streamChannel, updatedStateCode);
|
||||
|
||||
switch (updatedStateCode) {
|
||||
case CLOSED:
|
||||
case ILLEGAL_STATE:
|
||||
defaultFailedResponse.setFail(StreamCode.STATE_CLOSED.name());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ClientStreamChannel streamChannel, StreamChannelStateCode updatedStateCode, Throwable e) {
|
||||
logger.warn("exceptionCaught message:{}, streamChannel:{}, stateCode:{}", e.getMessage(), streamChannel, updatedStateCode, e);
|
||||
}
|
||||
|
||||
public AgentInfo getAgentInfo() {
|
||||
return agentInfo;
|
||||
}
|
||||
|
||||
public AgentActiveThreadCount getDefaultFailedResponse() {
|
||||
return defaultFailedResponse;
|
||||
}
|
||||
|
||||
}
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2014 NAVER Corp.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navercorp.pinpoint.web.websocket;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.navercorp.pinpoint.rpc.stream.ClientStreamChannelMessageListenerRepository;
|
||||
import com.navercorp.pinpoint.web.vo.AgentActiveThreadCount;
|
||||
import com.navercorp.pinpoint.web.vo.AgentActiveThreadCountList;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
* @Author Taejin Koo
|
||||
*/
|
||||
public class WebSocketResponseAggregator {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private final Object lock = new Object();
|
||||
private final ObjectMapper jsonConverter = new ObjectMapper();
|
||||
|
||||
private final String applicationName;
|
||||
private final List<WebSocketSession> webSocketSessions = new CopyOnWriteArrayList<>();
|
||||
private final ClientStreamChannelMessageListenerRepository<ActiveThreadCountStreamListener> streamMessageListenerRepository;
|
||||
|
||||
private Map<String, AgentActiveThreadCount> activeThreadCountMap;
|
||||
|
||||
public WebSocketResponseAggregator(String applicationName) {
|
||||
this.applicationName = applicationName;
|
||||
this.streamMessageListenerRepository = new ClientStreamChannelMessageListenerRepository<ActiveThreadCountStreamListener>();
|
||||
|
||||
this.activeThreadCountMap = new HashMap<String, AgentActiveThreadCount>(streamMessageListenerRepository.size());
|
||||
}
|
||||
|
||||
public void registerWebSocketSession(WebSocketSession webSocketSession) {
|
||||
if (webSocketSession == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("registerWebSocketSession webSocketSession:{}");
|
||||
synchronized (lock) {
|
||||
this.webSocketSessions.add(webSocketSession);
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterWebSocketSession(WebSocketSession webSocketSession) {
|
||||
if (webSocketSession == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("unregisterWebSocketSession webSocketSession:{}");
|
||||
synchronized (lock) {
|
||||
this.webSocketSessions.remove(webSocketSession);
|
||||
}
|
||||
}
|
||||
|
||||
public int registeredWebSocketSessionCount() {
|
||||
synchronized (lock) {
|
||||
return this.webSocketSessions.size();
|
||||
}
|
||||
}
|
||||
|
||||
public ClientStreamChannelMessageListenerRepository<ActiveThreadCountStreamListener> getStreamMessageListenerRepository() {
|
||||
return streamMessageListenerRepository;
|
||||
}
|
||||
|
||||
public void response(AgentActiveThreadCount activeThreadCount) {
|
||||
if (activeThreadCount == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (lock) {
|
||||
this.activeThreadCountMap.put(activeThreadCount.getAgentId(), activeThreadCount);
|
||||
}
|
||||
}
|
||||
|
||||
public void flush() throws Exception {
|
||||
logger.info("flush");
|
||||
|
||||
AgentActiveThreadCountList response = new AgentActiveThreadCountList();
|
||||
synchronized (lock) {
|
||||
for (ActiveThreadCountStreamListener threadCountStreamListener : streamMessageListenerRepository.values()) {
|
||||
String agentId = threadCountStreamListener.getAgentInfo().getAgentId();
|
||||
|
||||
AgentActiveThreadCount agentActiveThreadCount = activeThreadCountMap.get(agentId);
|
||||
if (agentActiveThreadCount != null) {
|
||||
response.add(agentActiveThreadCount);
|
||||
} else {
|
||||
response.add(threadCountStreamListener.getDefaultFailedResponse());
|
||||
}
|
||||
}
|
||||
activeThreadCountMap = new HashMap<String, AgentActiveThreadCount>(streamMessageListenerRepository.size());
|
||||
}
|
||||
|
||||
flush0(response);
|
||||
}
|
||||
|
||||
private void flush0(AgentActiveThreadCountList activeThreadCountList) {
|
||||
String response = makeResponseMessage(applicationName, activeThreadCountList);
|
||||
|
||||
for (WebSocketSession webSocketSession : webSocketSessions) {
|
||||
try {
|
||||
logger.debug("flush webSocket:{}, response:{}", webSocketSession, response);
|
||||
webSocketSession.sendMessage(new TextMessage(response));
|
||||
} catch (IOException e) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String makeResponseMessage(String applicationName, AgentActiveThreadCountList activeThreadCount) {
|
||||
Map<String, Object> response = new HashMap<String, Object>();
|
||||
|
||||
response.put("applicationName", applicationName);
|
||||
response.put("activeThreadCounts", activeThreadCount);
|
||||
response.put("timeStamp", System.currentTimeMillis());
|
||||
|
||||
try {
|
||||
return jsonConverter.writeValueAsString(response);
|
||||
} catch (JsonProcessingException e) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
}
|
||||
|
||||
return createEmptyJsonMessage(applicationName);
|
||||
}
|
||||
|
||||
private String createEmptyJsonMessage(String applicationName) {
|
||||
StringBuilder emptyJsonMessage = new StringBuilder();
|
||||
emptyJsonMessage.append("{");
|
||||
emptyJsonMessage.append("\"").append(applicationName).append("\"");
|
||||
emptyJsonMessage.append(":");
|
||||
emptyJsonMessage.append("{}");
|
||||
emptyJsonMessage.append("}");
|
||||
|
||||
return emptyJsonMessage.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
* @name NavbarVoService
|
||||
* @class
|
||||
*/
|
||||
pinpointApp.factory('NavbarVoService', function () {
|
||||
pinpointApp.factory('NavbarVoService', [ 'PreferenceService', function (preferenceService) {
|
||||
return function () {
|
||||
// define and initialize private variables;
|
||||
var self = this;
|
||||
@@ -22,9 +22,9 @@
|
||||
|
||||
this._sReadablePeriod = false;
|
||||
this._sQueryEndDateTime = false;
|
||||
|
||||
this._nCallerRange = 2;
|
||||
this._nCalleeRange = 2;
|
||||
|
||||
this._nCallerRange = preferenceService.getDepth();
|
||||
this._nCalleeRange = preferenceService.getDepth();
|
||||
|
||||
this._sHint = false;
|
||||
|
||||
@@ -206,5 +206,5 @@
|
||||
return self;
|
||||
};
|
||||
};
|
||||
});
|
||||
}]);
|
||||
})();
|
||||
@@ -0,0 +1,57 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
/**
|
||||
* (en)PreferenceService
|
||||
* @ko PreferenceService
|
||||
* @group Service
|
||||
* @name PreferenceService
|
||||
* @class
|
||||
*/
|
||||
pinpointApp.constant('PreferenceServiceConfig', {
|
||||
name : {
|
||||
depth: "preference.depth"
|
||||
},
|
||||
DEFAULT_DEPTH: 1
|
||||
});
|
||||
|
||||
pinpointApp.service('PreferenceService', [ 'PreferenceServiceConfig', function(cfg) {
|
||||
var oDefault = {};
|
||||
var bAddedFavorite = false;
|
||||
var aFavoriteApplicatName = [];
|
||||
|
||||
loadPreference();
|
||||
|
||||
|
||||
this.setDepth = function( d ) {
|
||||
localStorage.setItem(cfg.name.depth, d);
|
||||
oDefault.depth = d;
|
||||
}
|
||||
this.getDepth = function() {
|
||||
// @TODO
|
||||
return oDefault.depth;
|
||||
};
|
||||
this.setUsedApplicationName = function( applicationName ) {
|
||||
bAdded = true;
|
||||
var oFavoriate = JSON.parse( localStorage.getItem("favoriate") || "{}" );
|
||||
if ( angular.isDefined( oFavoriate[applicationName] ) ) {
|
||||
oFavoriate[applicationName] += 1;
|
||||
} else {
|
||||
oFavoriate[applicationName] = 1;
|
||||
}
|
||||
localStorage.setItem("favoriate", JSON.string(oFavoriate) );
|
||||
};
|
||||
this.getFavoriteApplicationName = function() {
|
||||
if ( bAddedFavorite ) {
|
||||
// 반환 값 계산 ( 상위 5개 추리기 )
|
||||
}
|
||||
return aFavoriteApplicationName;
|
||||
|
||||
};
|
||||
|
||||
function loadPreference() {
|
||||
oDefault.depth = parseInt( localStorage.getItem( cfg.name.depth ) || cfg.DEFAULT_DEPTH );
|
||||
//oDefault.favoriate = JSON.parse( localStorage.getItem("favoriate") || "{}" );
|
||||
};
|
||||
|
||||
}]);
|
||||
})();
|
||||
@@ -18,7 +18,7 @@
|
||||
FILTER_FETCH_LIMIT: 5000
|
||||
});
|
||||
|
||||
pinpointApp.service('ServerMapDaoService', [ 'serverMapDaoServiceConfig', function ServerMapDao(cfg) {
|
||||
pinpointApp.service('ServerMapDaoService', [ 'serverMapDaoServiceConfig', 'PreferenceService', function ServerMapDao(cfg, preferenceService) {
|
||||
|
||||
var self = this;
|
||||
|
||||
|
||||
@@ -13,15 +13,15 @@
|
||||
periodTypePrefix: '.navbar.periodType'
|
||||
});
|
||||
|
||||
pinpointApp.directive('navbarDirective', [ 'cfg', '$rootScope', '$http','$document', '$timeout', '$window', 'webStorage', 'helpContentTemplate', 'helpContentService', 'AnalyticsService',
|
||||
function (cfg, $rootScope, $http, $document, $timeout, $window, webStorage, helpContentTemplate, helpContentService, analyticsService) {
|
||||
pinpointApp.directive('navbarDirective', [ 'cfg', '$rootScope', '$http','$document', '$timeout', '$window', 'webStorage', 'helpContentTemplate', 'helpContentService', 'AnalyticsService', 'PreferenceService',
|
||||
function (cfg, $rootScope, $http, $document, $timeout, $window, webStorage, helpContentTemplate, helpContentService, analyticsService, preferenceService) {
|
||||
return {
|
||||
restrict: 'EA',
|
||||
replace: true,
|
||||
templateUrl: 'features/navbar/navbar.html',
|
||||
link: function (scope, element) {
|
||||
|
||||
var DEFAULT_RANGE = 2;
|
||||
var DEFAULT_RANGE = preferenceService.getDepth();
|
||||
var MAX_RANGE = 8;
|
||||
// define private variables
|
||||
var $application, $fromPicker, $toPicker, oNavbarVoService, aReadablePeriodList;
|
||||
|
||||
@@ -9,29 +9,31 @@
|
||||
*/
|
||||
pinpointApp.constant('RealtimeChartCtrlConfig', {
|
||||
wsUrl: "/agent/activeThread.pinpointws",
|
||||
agentChartTemplate: '<div class="agent-chart"><div></div></div>'
|
||||
agentChartTemplate: '<div class="agent-chart"><div></div></div>',
|
||||
chartDirectiveTemplate: Handlebars.compile( '<realtime-chart-directive chart-color="{{chartColor}}" xcount="{{xAxisCount}}" show-extra-info="{{showExtraInfo}}" request-label="requestLabelNames" namespace="{{namespace}}" width="{{width}}" height="{{height}}"></realtime-chart-directive>' )
|
||||
});
|
||||
|
||||
pinpointApp.controller('RealtimeChartCtrl', ['RealtimeChartCtrlConfig', '$scope', '$element', '$rootScope', '$compile', 'globalConfig',
|
||||
function (cfg, $scope, $element, $rootScope, $compile, globalConfig) {
|
||||
pinpointApp.controller('RealtimeChartCtrl', ['RealtimeChartCtrlConfig', '$scope', '$element', '$rootScope', '$compile', '$window', 'globalConfig',
|
||||
function (cfg, $scope, $element, $rootScope, $compile, $window, globalConfig) {
|
||||
|
||||
$scope.useRealTime = globalConfig.useRealTime || true;
|
||||
$scope.showRealtime = false;
|
||||
$scope.currentApplicationName = "";
|
||||
$scope.agentCount = 0;
|
||||
$scope.sumChartColor = ["rgba(44, 160, 44, 1)", "rgba(60, 129, 250, 1)", "rgba(248, 199, 49, 1)", "rgba(246, 145, 36, 1)" ];
|
||||
$scope.agentChartColor = ["rgba(44, 160, 44, 0.5)", "rgba(60, 129, 250, 0.5)", "rgba(248, 199, 49, 0.5)", "rgba(246, 145, 36, 0.5)" ];
|
||||
var DEFAULT_Y_MAX = 50;
|
||||
var aSumChartData = getInitChartData(10);
|
||||
var $elementSumChartWrapper = $element.find("div.agent-sum-chart");
|
||||
var $elementAgentChartList = $element.find("div.agent-chart-list");
|
||||
var aAgentChartList = [];
|
||||
var oAgentChartNamespace = {};
|
||||
|
||||
var wsOpened = false;
|
||||
var wsocket = null;
|
||||
var X_AXIS_COUNT = 10;
|
||||
var RECEIVE_SUCCESS = 0;
|
||||
|
||||
var $elSumChartWrapper = $element.find("div.agent-sum-chart");
|
||||
var $elAgentChartListWrapper = $element.find("div.agent-chart-list");
|
||||
var bWebsocketOpened = false;
|
||||
var websocket = null;
|
||||
var aSumChartData = [0];
|
||||
var aAgentChartElementList = [];
|
||||
var oNamespaceToIndexMap = {};
|
||||
var screenState = "small";
|
||||
|
||||
$scope.showRealtimeChart = false;
|
||||
$scope.sumChartColor = ["rgba(44, 160, 44, 1)", "rgba(60, 129, 250, 1)", "rgba(248, 199, 49, 1)", "rgba(246, 145, 36, 1)" ];
|
||||
$scope.agentChartColor = ["rgba(44, 160, 44, .8)", "rgba(60, 129, 250, .8)", "rgba(248, 199, 49, .8)", "rgba(246, 145, 36, .8)"];
|
||||
$scope.requestLabelNames= [ "Fast", "Normal", "Slow", "Very Slow"];
|
||||
$scope.currentAgentCount = 0;
|
||||
$scope.currentApplicationName = "";
|
||||
|
||||
function getInitChartData( len ) {
|
||||
var a = [];
|
||||
@@ -41,121 +43,157 @@
|
||||
return a;
|
||||
}
|
||||
function initChartDirective() {
|
||||
var el = $compile('<realtime-chart-directive chart-color="sumChartColor" use-label="true" namespace="sum" width="260" height="120"></realtime-chart-directive>')($scope);
|
||||
$elementSumChartWrapper.append( el );
|
||||
$elSumChartWrapper.append( $compile( cfg.chartDirectiveTemplate({
|
||||
"chartColor": "sumChartColor",
|
||||
"xAxisCount": X_AXIS_COUNT,
|
||||
"namespace": "sum",
|
||||
"showExtraInfo": "true",
|
||||
"height": 120,
|
||||
"width": 260
|
||||
}))($scope) );
|
||||
}
|
||||
function hasAgentChart( agentName ) {
|
||||
return angular.isDefined( oNamespaceToIndexMap[agentName] );
|
||||
}
|
||||
function addAgentChart( agentName ) {
|
||||
var $newAgentChart = $( cfg.agentChartTemplate ).find("div").html(agentName).end();
|
||||
var el = $compile('<realtime-chart-directive chart-color="agentChartColor" use-label="false" namespace="' + aAgentChartList.length + '" width="120" height="60"></realtime-chart-directive>')($scope);
|
||||
var $newAgentChart = $( cfg.agentChartTemplate ).append( $compile( cfg.chartDirectiveTemplate({
|
||||
"chartColor": "agentChartColor",
|
||||
"xAxisCount": X_AXIS_COUNT,
|
||||
"namespace": aAgentChartElementList.length,
|
||||
"showExtraInfo": "false",
|
||||
"height": 60,
|
||||
"width": 120
|
||||
}))($scope) );
|
||||
$elAgentChartListWrapper.append( $newAgentChart );
|
||||
|
||||
$newAgentChart.append( el );
|
||||
$elementAgentChartList.append( $newAgentChart );
|
||||
|
||||
aAgentChartList.push( $newAgentChart );
|
||||
oAgentChartNamespace[agentName] = aAgentChartList.length - 1;
|
||||
linkNamespaceToIndex( agentName, aAgentChartElementList.length );
|
||||
aAgentChartElementList.push( $newAgentChart );
|
||||
}
|
||||
function initWS() {
|
||||
wsocket = null;
|
||||
wsocket = new WebSocket("ws://" + location.host + cfg.wsUrl);
|
||||
wsocket.onopen = function(event) {
|
||||
wsOpened = true;
|
||||
console.log( "ws open : ", event );
|
||||
send();
|
||||
};
|
||||
wsocket.onmessage = function(event) {
|
||||
var data = JSON.parse( event.data );
|
||||
receive( data );
|
||||
};
|
||||
wsocket.onclose = function(event) {
|
||||
// retry connection
|
||||
wsOpened = false;
|
||||
wsocket = null;
|
||||
console.log( "ws close :", event );
|
||||
};
|
||||
|
||||
initChartDirective();
|
||||
websocket = null;
|
||||
if ( angular.isDefined( WebSocket ) ) {
|
||||
websocket = new WebSocket("ws://" + location.host + cfg.wsUrl);
|
||||
websocket.onopen = function(event) {
|
||||
console.log( "onOpen websocket", event);
|
||||
bWebsocketOpened = true;
|
||||
send();
|
||||
};
|
||||
websocket.onmessage = function(event) {
|
||||
receive( JSON.parse( event.data ) );
|
||||
};
|
||||
websocket.onclose = function(event) {
|
||||
console.log( "onClose websocket", event);
|
||||
bWebsocketOpened = false;
|
||||
websocket = null;
|
||||
// @TODO
|
||||
// if ( $scope.showRealtimeChart === true ) {
|
||||
// //reinit
|
||||
// }
|
||||
};
|
||||
initChartDirective();
|
||||
}
|
||||
}
|
||||
function receive( data ) {
|
||||
if ( angular.isUndefined( data[$scope.currentApplicationName] ) ) return;
|
||||
|
||||
var applicationData = data[$scope.currentApplicationName];
|
||||
//@Test-Code
|
||||
// for( var i = 0 ; i < 7 ; i++ ) {
|
||||
// applicationData["Naver-agent-" + i] = {
|
||||
// code: 0,
|
||||
// message: "OK",
|
||||
// status: [0, 0, 0, 0],
|
||||
// timeStamp: Date.now()
|
||||
// };
|
||||
// }
|
||||
var agentCount = 0;
|
||||
var aRequestSum = [0, 0, 0, 0];
|
||||
var timeStamp;
|
||||
|
||||
for( var p in applicationData ) {
|
||||
if ( applicationData[p].code === RECEIVE_SUCCESS ) {
|
||||
var aRequestCount = applicationData[p].status;
|
||||
for( var i = 0 ; i < aRequestCount.length ; i++ ) {
|
||||
aRequestSum[i] += aRequestCount[i];
|
||||
}
|
||||
timeStamp = applicationData[p].timeStamp;
|
||||
}
|
||||
}
|
||||
for (var i = 0 ; i < aSumChartData.length ; i++ ) {
|
||||
aSumChartData[i].push( aRequestSum[i] );
|
||||
aSumChartData[i].shift();
|
||||
}
|
||||
var sumOfMaxY = sumOfMax( aSumChartData );
|
||||
|
||||
for( var p in applicationData ) {
|
||||
if ( aAgentChartList.length <= agentCount ) {
|
||||
addAgentChart(p);
|
||||
}
|
||||
aAgentChartList[agentCount].show();
|
||||
|
||||
if ( applicationData[p].code === RECEIVE_SUCCESS ) {
|
||||
$rootScope.$broadcast('realtimeChartDirective.onData.' + oAgentChartNamespace[p], applicationData[p].status, applicationData[p].timeStamp, sumOfMaxY );
|
||||
} else {
|
||||
//show message
|
||||
}
|
||||
agentCount++;
|
||||
}
|
||||
var aRequestSum = getSumOfRequestType( applicationData );
|
||||
addSumYValue( aRequestSum );
|
||||
|
||||
$rootScope.$broadcast('realtimeChartDirective.onData.sum', aRequestSum, timeStamp, sumOfMaxY );
|
||||
$scope.$apply(function() {
|
||||
$scope.agentCount = agentCount;
|
||||
broadcastData( applicationData, aRequestSum );
|
||||
|
||||
}
|
||||
function broadcastData( applicationData, aRequestSum ) {
|
||||
var maxY = getMaxOfYValue();
|
||||
var agentIndexAndCount = 0;
|
||||
var timeStamp;
|
||||
|
||||
for( var agentName in applicationData ) {
|
||||
checkAgentChart( agentName, agentIndexAndCount );
|
||||
|
||||
timeStamp = applicationData[agentName].timeStamp;
|
||||
if ( applicationData[agentName].code === RECEIVE_SUCCESS ) {
|
||||
$rootScope.$broadcast('realtimeChartDirective.onData.' + oNamespaceToIndexMap[agentName], applicationData[agentName].status, timeStamp, maxY );
|
||||
} else {
|
||||
$rootScope.$broadcast('realtimeChartDirective.onError.' + oNamespaceToIndexMap[agentName], applicationData[agentName].message, timeStamp, maxY );
|
||||
}
|
||||
|
||||
showAgentChart( agentIndexAndCount );
|
||||
agentIndexAndCount++;
|
||||
}
|
||||
$rootScope.$broadcast('realtimeChartDirective.onData.sum', aRequestSum, timeStamp, maxY );
|
||||
|
||||
$scope.$apply(function() {
|
||||
$scope.currentAgentCount = agentIndexAndCount;
|
||||
});
|
||||
}
|
||||
function sumOfMax(datum) {
|
||||
var sum = 0;
|
||||
for (var i = 0 ; i < datum.length ; i++ ) {
|
||||
sum += Math.ceil( d3.max( datum[i], function( d ) {
|
||||
return d;
|
||||
}) );
|
||||
}
|
||||
return sum === 0 ? DEFAULT_Y_MAX : sum;
|
||||
function checkAgentChart( agentName, agentIndexAndCount ) {
|
||||
if ( hasAgentChart( agentName ) == false ) {
|
||||
if ( hasNotUseChart( agentIndexAndCount ) ) {
|
||||
linkNamespaceToIndex(agentName, agentIndexAndCount);
|
||||
} else {
|
||||
addAgentChart(agentName);
|
||||
}
|
||||
}
|
||||
setAgentName( agentIndexAndCount, agentName );
|
||||
}
|
||||
function linkNamespaceToIndex( name, index ) {
|
||||
oNamespaceToIndexMap[name] = index;
|
||||
}
|
||||
function hasNotUseChart( index ) {
|
||||
return aAgentChartElementList.length > index;
|
||||
}
|
||||
function showAgentChart( index ) {
|
||||
aAgentChartElementList[index].show();
|
||||
}
|
||||
function setAgentName( index, name ) {
|
||||
aAgentChartElementList[index].find("div").html(name);
|
||||
}
|
||||
function getSumOfRequestType( datum ) {
|
||||
var aRequestSum = [0, 0, 0, 0];
|
||||
for( var p in datum ) {
|
||||
if ( datum[p].code === RECEIVE_SUCCESS ) {
|
||||
jQuery.each(datum[p].status, function( i, v ) {
|
||||
aRequestSum[i] += v;
|
||||
});
|
||||
}
|
||||
}
|
||||
return aRequestSum;
|
||||
}
|
||||
function addSumYValue( data ) {
|
||||
aSumChartData.push( data.reduce(function(pre, cur) {
|
||||
return pre + cur;
|
||||
}));
|
||||
if ( aSumChartData.legnth > X_AXIS_COUNT ) {
|
||||
aSumChartData.shift();
|
||||
}
|
||||
}
|
||||
function getMaxOfYValue() {
|
||||
return d3.max( aSumChartData, function( d ) {
|
||||
return d;
|
||||
});
|
||||
}
|
||||
function send() {
|
||||
wsocket.send("applicationName=" + $scope.currentApplicationName);
|
||||
websocket.send("applicationName=" + $scope.currentApplicationName);
|
||||
}
|
||||
function startWS( applicationName ) {
|
||||
$scope.currentApplicationName = applicationName;
|
||||
if ( wsOpened === false || wsocket == null) {
|
||||
if ( bWebsocketOpened === false || websocket == null) {
|
||||
initWS();
|
||||
} else {
|
||||
send();
|
||||
}
|
||||
$scope.$apply(function() {
|
||||
$scope.showRealtime = true;
|
||||
$scope.showRealtimeChart = true;
|
||||
});
|
||||
}
|
||||
function stopWS() {
|
||||
$scope.showRealtime = false;
|
||||
wsocket.send("applicationName=");
|
||||
$scope.showRealtimeChart = false;
|
||||
websocket.send("applicationName=");
|
||||
}
|
||||
function stopChart() {
|
||||
$rootScope.$broadcast('realtimeChartDirective.clear.sum');
|
||||
$.each( aAgentChartList, function(index, el) {
|
||||
$.each( aAgentChartElementList, function(index, el) {
|
||||
$rootScope.$broadcast('realtimeChartDirective.clear.' + index);
|
||||
el.hide();
|
||||
});
|
||||
@@ -163,19 +201,44 @@
|
||||
}
|
||||
|
||||
$scope.$on('realtimeChartController.initialize', function (event, isWas, applicationName) {
|
||||
if ( $scope.useRealTime === false ) return;
|
||||
if ( globalConfig.useRealTime === false ) return;
|
||||
if ( isWas === false && $scope.showRealtimeChart == false ) return;
|
||||
|
||||
if ( isWas === true ) {
|
||||
if ( $scope.showRealtimeChart === true ) {
|
||||
$scope.closePopup();
|
||||
}
|
||||
startWS( applicationName );
|
||||
} else {
|
||||
stopWS();
|
||||
}
|
||||
|
||||
});
|
||||
$scope.resizePopup = function() {
|
||||
switch( screenState ) {
|
||||
case "full":
|
||||
$element.css({
|
||||
"height": "180px",
|
||||
"bottom": "184px"
|
||||
});
|
||||
$elAgentChartListWrapper.css("height", "150px");
|
||||
screenState = "small";
|
||||
break;
|
||||
case "small":
|
||||
$element.css({
|
||||
"height": ($window.innerHeight - 70) + "px",
|
||||
"bottom": ($window.innerHeight - 70 + 4) + "px"
|
||||
});
|
||||
$elAgentChartListWrapper.css("height", ($window.innerHeight - 70 - 30) + "px");
|
||||
screenState = "full";
|
||||
break;
|
||||
}
|
||||
}
|
||||
$scope.closePopup = function() {
|
||||
stopWS();
|
||||
stopChart();
|
||||
$scope.currentApplicationName = "";
|
||||
$scope.agentCount = 0;
|
||||
$scope.currentAgentCount = 0;
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* @class
|
||||
*/
|
||||
pinpointApp.constant('realtimeChartDirectiveConfig', {
|
||||
|
||||
});
|
||||
|
||||
pinpointApp.directive('realtimeChartDirective', [ 'realtimeChartDirectiveConfig', '$location',
|
||||
@@ -17,31 +18,34 @@
|
||||
replace: true,
|
||||
template: '<svg width="" height=""></svg>',
|
||||
link: function postLink(scope, element, attrs) {
|
||||
var aChartColor = scope[attrs["chartColor"]];
|
||||
var useLabel = attrs["useLabel"] === "true";
|
||||
var aRequestLabel = scope[attrs["requestLabel"]];
|
||||
var aRequestColor = scope[attrs["chartColor"]];
|
||||
var xAxisCount = parseInt( attrs["xcount"] );
|
||||
var namespace = attrs["namespace"];
|
||||
var svgWidth = parseInt( attrs["width"] );
|
||||
var svgHeight = parseInt( attrs["height"] );
|
||||
var svgWidth = parseInt( attrs["width"] );
|
||||
var showExtraInfo = attrs["showExtraInfo"] === "true";
|
||||
|
||||
var svg, svgX, svgY, yAxis, path, area, vLine, labels, tooltip, tooltipDate;
|
||||
var x_column = 10;
|
||||
var DEFAULT_Y_MAX = 50;
|
||||
var options = {
|
||||
labels: [ "Fast", "Normal", "Slow", "Very Slow"],
|
||||
domain: [1, x_column - 2],
|
||||
var svg, svgX, svgY, yAxis, path, area, vLine, labels, tooltip, tooltipDate, errorLabel;
|
||||
var d3Options = {
|
||||
domain: [1, xAxisCount - 2],
|
||||
interpolation: "basis",
|
||||
margin: useLabel ? {top: 6, right: 80, bottom: 6, left: 30} : {top: 6, right: 80, bottom: 6, left: 20}
|
||||
margin: {
|
||||
left: showExtraInfo ? 38 : 20,
|
||||
right: 80,
|
||||
top: 6,
|
||||
bottom: 6
|
||||
}
|
||||
};
|
||||
var latelyXPosition = -1;
|
||||
var latelyIndex = -1;
|
||||
var xAxisLength = options.domain[1];
|
||||
var aInnerStack = options.datum || getInitData();
|
||||
var lastPosition = -1;
|
||||
var lastIndex = -1;
|
||||
var aInnerStack = getInitData();
|
||||
var aRealTimeData = [];
|
||||
var transition = d3.select({}).transition().duration(1000).ease("linear");
|
||||
var width = svgWidth - ( useLabel ? options.margin.left : 0 ) - ( useLabel ? options.margin.right : 0 );
|
||||
var height = svgHeight - options.margin.top - options.margin.bottom;
|
||||
var sumOfMaxY = DEFAULT_Y_MAX;
|
||||
// var sumOfMaxY = sumOfMax(aInnerStack);
|
||||
var width = svgWidth - ( showExtraInfo ? d3Options.margin.left : 0 ) - ( showExtraInfo ? d3Options.margin.right : 0 );
|
||||
var height = svgHeight - d3Options.margin.top - d3Options.margin.bottom;
|
||||
var sumOfMaxY = 0;
|
||||
var yAxisFormat = d3.format("d");
|
||||
var stack = d3.layout.stack().y(function(d) { return d.y; });
|
||||
stack(aInnerStack);
|
||||
|
||||
@@ -51,58 +55,59 @@
|
||||
resetPath();
|
||||
resetTooltipLine();
|
||||
resetLabels();
|
||||
resetErrorLabel();
|
||||
|
||||
|
||||
function initGraph() {
|
||||
svg = d3.select( element.get(0) )
|
||||
.attr("width", svgWidth)
|
||||
.attr("height", svgHeight)
|
||||
.attr({
|
||||
"width": svgWidth,
|
||||
"height": svgHeight
|
||||
})
|
||||
.append("g")
|
||||
.attr("transform", "translate(" + (useLabel ? options.margin.left : 0) + "," + options.margin.top + ")");
|
||||
.attr({
|
||||
"class": "base",
|
||||
"transform": "translate(" + (showExtraInfo ? d3Options.margin.left : 0) + "," + d3Options.margin.top + ")"
|
||||
});
|
||||
|
||||
svg.append("defs").append("clipPath")
|
||||
svg.append("defs")
|
||||
.append("clipPath")
|
||||
.attr("id", "clip")
|
||||
.append("rect")
|
||||
.attr("width", width)
|
||||
.attr("height", height);
|
||||
.attr({
|
||||
"x": 1,
|
||||
"y": 0,
|
||||
"width": width,
|
||||
"height": height
|
||||
});
|
||||
}
|
||||
function getInitData() {
|
||||
var a = [];
|
||||
for( var i = 0 ; i < options.labels.length ; i++ ) {
|
||||
a.push( d3.range(xAxisLength + 2).map(function() { return { y: 0 }; }) );
|
||||
var now = Date.now();
|
||||
for( var i = 0 ; i < aRequestLabel.length ; i++ ) {
|
||||
a.push( d3.range(xAxisCount).map(function() { return { y: 0, d: now }; }) );
|
||||
}
|
||||
return a;
|
||||
}
|
||||
// function resetSumOfMax() {
|
||||
// sumOfMaxY = parseInt( sumOfMax(aInnerStack) ) + 10;
|
||||
// }
|
||||
// function sumOfMax(datum) {
|
||||
// var sum = 0;
|
||||
// for (var i = 0 ; i < datum.length ; i++ ) {
|
||||
// sum += Math.ceil( d3.max( datum[i], function( d ) {
|
||||
// return d.y;
|
||||
// }) );
|
||||
// }
|
||||
// return sum === 0 ? DEFAULT_Y_MAX : sum;
|
||||
// }
|
||||
function resetAxis() {
|
||||
svgX = d3.scale.linear().domain(options.domain).range([0, width]);
|
||||
svgX = d3.scale.linear().domain(d3Options.domain).range([0, width]);
|
||||
svgY = d3.scale.linear().domain([0, sumOfMaxY]).range([height, 0]);
|
||||
if ( useLabel ) {
|
||||
yAxis = d3.svg.axis().scale(svgY).ticks(3).orient("left");
|
||||
if ( showExtraInfo ) {
|
||||
yAxis = d3.svg.axis().scale(svgY).ticks(3).orient("left").tickFormat(yAxisFormat);
|
||||
svg.append("g").attr("class", "y axis");
|
||||
}
|
||||
resetYAxis();
|
||||
}
|
||||
function resetYAxis() {
|
||||
svgY = d3.scale.linear().domain([0, sumOfMaxY]).range([height, 0]);
|
||||
if ( useLabel ) {
|
||||
if ( showExtraInfo ) {
|
||||
yAxis = d3.svg.axis().scale(svgY).ticks(3).orient("left");
|
||||
svg.selectAll("g.y.axis").call(yAxis);
|
||||
}
|
||||
}
|
||||
function resetArea() {
|
||||
area = d3.svg.area()
|
||||
.interpolate(options.interpolation)
|
||||
.interpolate(d3Options.interpolation)
|
||||
.x(function(d, i) { return svgX(i); })
|
||||
.y0(function(d, i) { return svgY(d.y0); })
|
||||
.y1(function(d, i) { return svgY(d.y + d.y0); });
|
||||
@@ -115,9 +120,11 @@
|
||||
.data(aInnerStack)
|
||||
.enter()
|
||||
.append("path")
|
||||
.attr("class", "area ")
|
||||
.attr("fill", function(d, i) { return aChartColor[i]; })
|
||||
.attr("d", area);
|
||||
.attr({
|
||||
"class": "area ",
|
||||
"fill": function(d, i) { return aRequestColor[i]; },
|
||||
"d": area
|
||||
});
|
||||
}
|
||||
function redrawPath() {
|
||||
path.attr("d", area)
|
||||
@@ -125,46 +132,44 @@
|
||||
.transition()
|
||||
.attr("transform", "translate(" + svgX(0) + ")");
|
||||
}
|
||||
// function clearPath() {
|
||||
// path.attr("d", area).attr("transform", null);
|
||||
// }
|
||||
function resetTooltipLine() {
|
||||
if ( useLabel === false ) return;
|
||||
var vLineOutPosition = -(options.margin.left + 100);
|
||||
if ( showExtraInfo === false ) return;
|
||||
var vLineOutPosition = -(d3Options.margin.left + 100);
|
||||
svg
|
||||
.on("mouseout", function() {
|
||||
var position = d3.mouse(this);
|
||||
vLine
|
||||
.transition()
|
||||
.attr("x1", vLineOutPosition)
|
||||
.attr("x1", vLineOutPosition)
|
||||
.attr("x2", vLineOutPosition);
|
||||
tooltip
|
||||
.attr("transform", "translate(" + vLineOutPosition + ", " + vLineOutPosition + ")");
|
||||
tooltipDate.text("");
|
||||
|
||||
latelyXPosition = -1;
|
||||
latelyIndex = -1;
|
||||
lastPosition = -1;
|
||||
lastIndex = -1;
|
||||
})
|
||||
.on("mousemove", function(d) {
|
||||
latelyIndex = parseInt( svgX.invert( d3.mouse(this)[0] ) );
|
||||
latelyXPosition = parseInt( d3.mouse(this)[0] );
|
||||
latelyXPosition = latelyXPosition > width ? vLineOutPosition : latelyXPosition;
|
||||
lastIndex = parseInt( svgX.invert( d3.mouse(this)[0] ) );
|
||||
lastPosition = parseInt( d3.mouse(this)[0] );
|
||||
lastPosition = lastPosition > width ? vLineOutPosition : lastPosition;
|
||||
vLine
|
||||
.transition()
|
||||
.delay(0)
|
||||
.duration(0)
|
||||
.attr("x1", latelyXPosition)
|
||||
.attr("x2", latelyXPosition);
|
||||
resetTooltipLabel( getPositionData( latelyIndex ) );
|
||||
.attr("x1", lastPosition)
|
||||
.attr("x2", lastPosition);
|
||||
resetTooltipLabel( getPositionData( lastIndex ) );
|
||||
});
|
||||
|
||||
vLine = svg
|
||||
.append("line")
|
||||
.attr("class", "guideLine")
|
||||
.attr("x1", 0)
|
||||
.attr("y1", 10)
|
||||
.attr("x2", 0)
|
||||
.attr("y2", height);
|
||||
.attr({
|
||||
"class": "guideLine",
|
||||
"x1": 0,
|
||||
"y1": 10,
|
||||
"x2": 0,
|
||||
"y2": height
|
||||
});
|
||||
|
||||
tooltip = svg
|
||||
.append("g")
|
||||
@@ -173,34 +178,39 @@
|
||||
});
|
||||
tooltip
|
||||
.append("rect")
|
||||
.attr("width", 20)
|
||||
.attr("height", 90)
|
||||
.attr("fill", "#000");
|
||||
.attr({
|
||||
"width": 40,
|
||||
"height": 90,
|
||||
"fill": "#000",
|
||||
"fill-opacity": "0.7"
|
||||
});
|
||||
|
||||
tooltip
|
||||
.selectAll("text")
|
||||
.data( options.labels )
|
||||
.data( aRequestLabel )
|
||||
.enter()
|
||||
.append("text")
|
||||
.attr("x", function(d, i) {
|
||||
return 6;
|
||||
return 37;
|
||||
})
|
||||
.attr("y", function(d, i) {
|
||||
return ((aChartColor.length - i - 1) * 20 + 20) + "px";
|
||||
return ((aRequestColor.length - i - 1) * 20 + 20) + "px";
|
||||
})
|
||||
.attr("fill", function(d, i) {
|
||||
return aChartColor[i];
|
||||
return aRequestColor[i];
|
||||
})
|
||||
.style("font-size", "12px")
|
||||
.text(function(d, i) {
|
||||
return options.labels[i];
|
||||
return aRequestLabel[i];
|
||||
});
|
||||
tooltipDate = svg.append("text")
|
||||
.attr("x", "29%")
|
||||
.attr("y", "6px")
|
||||
.attr("fill", "#000")
|
||||
.attr("text-anchor", "middle")
|
||||
.attr("font-size", "14px")
|
||||
.attr({
|
||||
"x": "29%",
|
||||
"y": "6px",
|
||||
"fill": "#000",
|
||||
"text-anchor": "middle",
|
||||
"font-size": "14px"
|
||||
})
|
||||
.text("");
|
||||
}
|
||||
function getPositionData( index ) {
|
||||
@@ -209,50 +219,61 @@
|
||||
for( var i = 0 ; i < aInnerStack.length ; i++ ) {
|
||||
a.push( {
|
||||
y: aInnerStack[i][index] ? aInnerStack[i][index].y : 0,
|
||||
d: aInnerStack[i][index].d
|
||||
d: aInnerStack[i][index] ? aInnerStack[i][index].d : Date.now()
|
||||
});
|
||||
}
|
||||
return a;
|
||||
}
|
||||
function resetTooltipLabel( datum ) {
|
||||
if ( useLabel === false ) return;
|
||||
if ( latelyXPosition === -1 || latelyIndex === -1 ) return;
|
||||
if ( showExtraInfo === false ) return;
|
||||
if ( lastPosition === -1 || lastIndex === -1 ) return;
|
||||
tooltip
|
||||
.attr("transform", "translate(" + (latelyXPosition - 30) + ", 10)")
|
||||
.attr("transform", "translate(" + (lastPosition - 44) + ", 10)")
|
||||
.selectAll("text")
|
||||
.attr("text-anchor", "end")
|
||||
.text(function(d, i) {
|
||||
return datum[i].y;
|
||||
});
|
||||
tooltipDate.text( d3.time.format("%Y.%m.%d %H:%M:%S")(new Date(datum[0].d)) );
|
||||
}
|
||||
function resetLabels( datum ) {
|
||||
if ( useLabel === false ) return;
|
||||
if ( showExtraInfo === false ) return;
|
||||
labels = svg.append("g")
|
||||
.attr("transform", function(d, i) {
|
||||
return "translate(" + (svgWidth - options.margin.left - options.margin.right + 4) + ",10)";
|
||||
return "translate(" + (svgWidth - d3Options.margin.left - d3Options.margin.right + 4) + ",10)";
|
||||
})
|
||||
.selectAll("text")
|
||||
.data( options.labels )
|
||||
.data( aRequestLabel )
|
||||
.enter()
|
||||
.append("text")
|
||||
.attr("y", function(d, i) {
|
||||
return ( (options.labels.length - i - 1) / options.labels.length) * 100 + "%";
|
||||
return ( (aRequestLabel.length - i - 1) / aRequestLabel.length) * 100 + "%";
|
||||
})
|
||||
.attr("fill", function(d, i) {
|
||||
return aChartColor[i];
|
||||
return aRequestColor[i];
|
||||
})
|
||||
.attr("font-size", "12px")
|
||||
.attr("font-weight", "bold")
|
||||
.text(function(d, i) {
|
||||
return options.labels[i];
|
||||
return aRequestLabel[i];
|
||||
});
|
||||
}
|
||||
function resetErrorLabel() {
|
||||
errorLabel = svg.append("text")
|
||||
.attr({
|
||||
"y": "40%",
|
||||
"x": "50%",
|
||||
"font-weight": "bold",
|
||||
"text-anchor": "middle",
|
||||
"fill": "#F00"
|
||||
});
|
||||
}
|
||||
function resetLabelData( datum ) {
|
||||
if ( useLabel === false ) return;
|
||||
if ( showExtraInfo === false ) return;
|
||||
labels
|
||||
.data( datum )
|
||||
.text(function(d, i) {
|
||||
return typeof d.y !== "undefined" ? ( d.y + " : " + options.labels[i] ) : options.labels[i];
|
||||
return typeof d.y !== "undefined" ? ( d.y + " : " + aRequestLabel[i] ) : aRequestLabel[i];
|
||||
});
|
||||
}
|
||||
function tick() {
|
||||
@@ -261,7 +282,6 @@
|
||||
|
||||
var aNewData = aRealTimeData.shift();
|
||||
resetLabelData( aNewData );
|
||||
// resetSumOfMax();
|
||||
resetYAxis();
|
||||
|
||||
var i = 0;
|
||||
@@ -273,7 +293,7 @@
|
||||
for( i = 0 ; i < aInnerStack.length ; i++ ) {
|
||||
aInnerStack[i].shift();
|
||||
}
|
||||
resetTooltipLabel( getPositionData( latelyIndex ) );
|
||||
resetTooltipLabel( getPositionData( lastIndex ) );
|
||||
}).transition().each("start", function() {
|
||||
tick();
|
||||
});
|
||||
@@ -282,20 +302,18 @@
|
||||
|
||||
scope.$on('realtimeChartDirective.onData.' + namespace, function (event, aNewRequestCount, timeStamp, maxY) {
|
||||
sumOfMaxY = maxY;
|
||||
|
||||
aRealTimeData.push( (function() {
|
||||
var a = [];
|
||||
for (var i = 0 ; i < aNewRequestCount.length ; i++ ) {
|
||||
a.push({
|
||||
// @TestCode
|
||||
y: parseInt(aNewRequestCount[i] + (Math.random() * 10)),
|
||||
// y: parseInt( aNewRequestCount[i]),
|
||||
d: timeStamp
|
||||
});
|
||||
errorLabel.text("");
|
||||
aRealTimeData.push( aNewRequestCount.map(function(v, i) {
|
||||
return {
|
||||
y: parseInt( v ),
|
||||
d: timeStamp
|
||||
}
|
||||
return a;
|
||||
})() );
|
||||
}) );
|
||||
});
|
||||
scope.$on('realtimeChartDirective.onError.' + namespace, function (event, errorMessage, timeStamp, maxY) {
|
||||
sumOfMaxY = maxY;
|
||||
errorLabel.text( errorMessage );
|
||||
});
|
||||
scope.$on('realtimeChartDirective.clear.' + namespace, function (event, aNewRequestCount, timeStamp) {
|
||||
aRealTimeData.length = 0;
|
||||
aInnerStack.length = 0;
|
||||
|
||||
@@ -418,6 +418,7 @@
|
||||
<script src="common/services/user-locales.service.js?v=${buildTime}"></script>
|
||||
<script src="common/services/help-content.service.js?v=${buildTime}"></script>
|
||||
<script src="common/services/analytics.service.js?v=${buildTime}"></script>
|
||||
<script src="common/services/preference.service.js?v=${buildTime}"></script>
|
||||
<script src="common/help/help-content-en.js?v=${buildTime}"></script>
|
||||
<script src="common/help/help-content-ko.js?v=${buildTime}"></script>
|
||||
<script src="common/help/help-content-template.js?v=${buildTime}"></script>
|
||||
|
||||
@@ -5,101 +5,14 @@
|
||||
<div class="main-container" ng-class="getMainContainerClass()">
|
||||
<div class="main">
|
||||
<server-map-directive></server-map-directive>
|
||||
<div ng-controller="RealtimeChartCtrl" class="realtime" style="position:relative;width:98%;height:180px;left:1%;bottom:184px;z-index:10;background-color:#F0F3F4;border-radius:6px;border:2px solid #64a71a" ng-show="showRealtime">
|
||||
<style>
|
||||
.chart-title {
|
||||
color: white;
|
||||
width: 100%;
|
||||
padding: 2px 0px 2px 6px;
|
||||
position: absolute;
|
||||
border-radius: 3px 3px 0px 0px;
|
||||
background-color: #7ED321;
|
||||
}
|
||||
.chart-close {
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
margin-right: 6px;
|
||||
}
|
||||
.agent-sum-chart {
|
||||
top: 28px;
|
||||
left: 0px;
|
||||
width: 280px;
|
||||
cursor: crosshair;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
background-color: #FFF;
|
||||
}
|
||||
.agent-sum-chart div {
|
||||
font-weight: bold;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.agent-chart-list {
|
||||
top: -119px;
|
||||
height: 150px;
|
||||
padding: 2px 4px 2px 4px;
|
||||
position: relative;
|
||||
overflow-y: auto;
|
||||
margin-left: 280px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
.agent-chart {
|
||||
float: left;
|
||||
width: 120px;
|
||||
height: 70px;
|
||||
margin: 1px 2px 1px 4px;
|
||||
background-color: #FFF;
|
||||
box-shadow: 1px 1px 3px 0px rgba(0,0,0,0.75);
|
||||
}
|
||||
.agent-chart > div {
|
||||
color: #000;
|
||||
padding: 1px;
|
||||
overflow: hidden;
|
||||
font-size: 10px;
|
||||
word-wrap: normal;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
background-color: #7ED321;
|
||||
}
|
||||
.agent-sum-chart svg {
|
||||
font: 10px sans-serif;
|
||||
display: block;
|
||||
}
|
||||
.agent-chart-list svg {
|
||||
font: 8px sans-serif;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.agent-sum-chart .axis path, .axis line, .agent-chart-list .axis path, .axis line {
|
||||
fill: none;
|
||||
stroke: #000;
|
||||
shape-rendering: crispEdges;
|
||||
}
|
||||
.agent-sum-chart .guideLine, .agent-chart-list .guideLine {
|
||||
fill: none;
|
||||
stroke: #000;
|
||||
shape-rendering: crispEdges;
|
||||
}
|
||||
|
||||
.agent-sum-chart .x.axis area, .agent-chart-list .x.axis area {
|
||||
shape-rendering: auto;
|
||||
}
|
||||
.agent-sum-chart .area, .agent-chart-list .area {
|
||||
stroke: none;
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
.agent-chart-list text {
|
||||
font-size: 8px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div ng-controller="RealtimeChartCtrl" class="realtime" style="" ng-show="showRealtimeChart">
|
||||
<div class="chart-title">
|
||||
<span>Realtime Active Thread Chart</span>
|
||||
<span class="chart-close glyphicon glyphicon-remove" aria-hidden="true" ng-click="closePopup()"></span>
|
||||
<span class="chart-expand glyphicon glyphicon-fullscreen" aria-hidden="true" ng-click="resizePopup()"></span>
|
||||
</div>
|
||||
<div class="agent-sum-chart">
|
||||
<div>{{currentApplicationName}} ({{agentCount == 0 ? "..." : agentCount}})</div>
|
||||
<div>{{currentApplicationName}} ({{currentAgentCount == 0 ? "..." : currentAgentCount}})</div>
|
||||
</div>
|
||||
<div class="agent-chart-list"></div>
|
||||
</div>
|
||||
|
||||
+5
-3
@@ -7,10 +7,12 @@
|
||||
* @name ScatterFullScreenModeCtrl
|
||||
* @class
|
||||
*/
|
||||
pinpointApp.controller('ScatterFullScreenModeCtrl', [ '$scope', '$rootScope', '$routeParams', '$timeout', 'NavbarVoService', 'AnalyticsService',
|
||||
function ($scope, $rootScope, $routeParams, $timeout, NavbarVoService, analyticsService) {
|
||||
pinpointApp.controller('ScatterFullScreenModeCtrl', [ '$scope', '$rootScope', '$window', '$routeParams', '$timeout', 'NavbarVoService', 'AnalyticsService',
|
||||
function ($scope, $rootScope, $window, $routeParams, $timeout, NavbarVoService, analyticsService) {
|
||||
analyticsService.send(analyticsService.CONST.SCATTER_FULL_SCREEN_PAGE);
|
||||
// define private variables
|
||||
$window.htoScatter = $window.htoScatter || {};
|
||||
$window.$routeParams = $window.$routeParams || $routeParams;
|
||||
// define private variables
|
||||
var oNavbarVoService;
|
||||
|
||||
// initialize
|
||||
|
||||
@@ -233,4 +233,105 @@ canvas {outline:none}
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.realtime {
|
||||
left: 1%;
|
||||
width: 98%;
|
||||
height: 180px;
|
||||
border: 2px solid #64a71a;
|
||||
bottom: 184px;
|
||||
z-index: 10;
|
||||
position: relative;
|
||||
border-radius: 6px;
|
||||
background-color: #F0F3F4;
|
||||
}
|
||||
.realtime .chart-title {
|
||||
color: white;
|
||||
width: 100%;
|
||||
padding: 2px 0px 2px 6px;
|
||||
position: absolute;
|
||||
border-radius: 3px 3px 0px 0px;
|
||||
background-color: #7ED321;
|
||||
}
|
||||
.realtime .chart-close {
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
margin-right: 6px;
|
||||
}
|
||||
.realtime .chart-expand {
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
margin-right: 6px;
|
||||
}
|
||||
.realtime .agent-sum-chart {
|
||||
top: 28px;
|
||||
left: 0px;
|
||||
width: 280px;
|
||||
cursor: crosshair;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
background-color: #FFF;
|
||||
}
|
||||
.realtime .agent-sum-chart div {
|
||||
font-weight: bold;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.realtime .agent-chart-list {
|
||||
top: -119px;
|
||||
height: 150px;
|
||||
padding: 2px 4px 2px 4px;
|
||||
position: relative;
|
||||
overflow-y: auto;
|
||||
margin-left: 280px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
.realtime .agent-chart {
|
||||
float: left;
|
||||
width: 120px;
|
||||
height: 70px;
|
||||
margin: 1px 2px 1px 4px;
|
||||
box-shadow: 1px 1px 3px 0px rgba(0,0,0,0.75);
|
||||
border-radius: 4px 4px 0px 0px;
|
||||
background-color: #FFF;
|
||||
}
|
||||
.realtime .agent-chart > div {
|
||||
color: #000;
|
||||
padding: 1px;
|
||||
overflow: hidden;
|
||||
font-size: 10px;
|
||||
word-wrap: normal;
|
||||
text-align: center;
|
||||
font-family: Times;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
border-radius: 4px 4px 0px 0px;
|
||||
background-color: rgba(126, 211, 33, 0.5);
|
||||
}
|
||||
.realtime .agent-sum-chart svg {
|
||||
font: 10px sans-serif;
|
||||
display: block;
|
||||
}
|
||||
.realtime .agent-chart-list svg {
|
||||
font: 8px sans-serif;
|
||||
display: block;
|
||||
}
|
||||
.realtime .agent-sum-chart .axis path, .axis line, .agent-chart-list .axis path, .axis line {
|
||||
fill: none;
|
||||
stroke: #000;
|
||||
shape-rendering: crispEdges;
|
||||
}
|
||||
.realtime .agent-sum-chart .guideLine, .agent-chart-list .guideLine {
|
||||
fill: none;
|
||||
stroke: #000;
|
||||
shape-rendering: crispEdges;
|
||||
}
|
||||
.realtime .agent-sum-chart .x.axis area, .agent-chart-list .x.axis area {
|
||||
shape-rendering: auto;
|
||||
}
|
||||
.realtime .agent-sum-chart .area, .agent-chart-list .area {
|
||||
stroke: none;
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
.realtime .agent-chart-list text {
|
||||
font-size: 8px;
|
||||
}
|
||||
|
||||
|
||||
+10
-3
@@ -40,11 +40,13 @@ public class AgentActiveThreadCountListTest {
|
||||
String hostName1 = "hostName1";
|
||||
String hostName2 = "hostName2";
|
||||
|
||||
AgentActiveThreadCount status1 = new AgentActiveThreadCount(hostName1, TRouteResult.NOT_ACCEPTABLE, null);
|
||||
AgentActiveThreadCount status1 = new AgentActiveThreadCount(hostName1);
|
||||
status1.setFail(TRouteResult.NOT_ACCEPTABLE.name());
|
||||
|
||||
TCmdActiveThreadCountRes response = new TCmdActiveThreadCountRes();
|
||||
response.setActiveThreadCount(Arrays.asList(1, 2, 3, 4));
|
||||
AgentActiveThreadCount status2 = new AgentActiveThreadCount(hostName2, TRouteResult.OK, response);
|
||||
AgentActiveThreadCount status2 = new AgentActiveThreadCount(hostName2);
|
||||
status2.setResult(response);
|
||||
|
||||
AgentActiveThreadCountList list = new AgentActiveThreadCountList(5);
|
||||
list.add(status1);
|
||||
@@ -64,7 +66,12 @@ public class AgentActiveThreadCountListTest {
|
||||
}
|
||||
|
||||
void assertDataWithSerializedJsonString(Map data, TRouteResult routeResult, List<Integer> status) {
|
||||
Assert.assertEquals(data.get("code"), routeResult.getValue());
|
||||
if (routeResult == TRouteResult.OK) {
|
||||
Assert.assertEquals(data.get("code"), 0);
|
||||
} else {
|
||||
Assert.assertEquals(data.get("code"), -1);
|
||||
}
|
||||
|
||||
Assert.assertEquals(data.get("message"), routeResult.name());
|
||||
|
||||
if (status != null) {
|
||||
|
||||
Reference in New Issue
Block a user