Merge branch 'master' of https://github.com/naver/pinpoint into #88_multiple_classLoader_support

Conflicts:
	profiler/src/main/java/com/navercorp/pinpoint/test/PluginTestAgent.java
This commit is contained in:
Woonduk Kang
2015-03-23 18:42:20 +09:00
96 changed files with 2622 additions and 558 deletions
+5 -1
View File
@@ -88,7 +88,11 @@
</goals>
</execution>
</executions>
</plugin>
<configuration>
<!-- AbstractPinpointPluginTestSuite needs this to resolve path of required jars -->
<useSystemClassLoader>false</useSystemClassLoader>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
+5 -1
View File
@@ -56,6 +56,10 @@ profiler.tcpdatasender.command.accept.enable=true
#profiler.applicationservertype=TOMCAT
#profiler.applicationservertype=BLOC
###########################################################
# application type detect order #
###########################################################
profiler.type.detect.order=
###########################################################
# user defined classes #
@@ -216,4 +220,4 @@ profiler.log4j.logging.transactioninfo=false
###########################################################
# logback
###########################################################
profiler.logback.logging.transactioninfo=false
profiler.logback.logging.transactioninfo=false
@@ -0,0 +1,72 @@
/**
* 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.jdk.http;
import static com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier.ExpectedAnnotation.*;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.URL;
import org.junit.Test;
import org.junit.runner.RunWith;
import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier;
import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder;
import com.navercorp.pinpoint.test.plugin.JvmVersion;
import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite;
/**
* @author Jongho Moon
*
*/
@RunWith(PinpointPluginTestSuite.class)
@JvmVersion({6, 7, 8})
public class HttpURLConnectionIT {
@Test
public void test() throws Exception {
URL url = new URL("http://www.naver.com");
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.getHeaderFields();
PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance();
Class<?> targetClass = Class.forName("sun.net.www.protocol.http.HttpURLConnection");
Method getInputStream = targetClass.getMethod("getInputStream");
verifier.verifySpanCount(1);
verifier.verifySpanEvent("JDK_HTTPURLCONNECTOR", getInputStream, null, null, "www.naver.com", annotation("http.url", "http://www.naver.com"));
}
@Test
public void testConnectTwice() throws Exception {
URL url = new URL("http://www.naver.com");
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.connect();
connection.getInputStream();
PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance();
verifier.printSpans(System.out);
Class<?> targetClass = Class.forName("sun.net.www.protocol.http.HttpURLConnection");
Method connect = targetClass.getMethod("connect");
verifier.verifySpanCount(1);
verifier.verifySpanEvent("JDK_HTTPURLCONNECTOR", connect, null, null, "www.naver.com", annotation("http.url", "http://www.naver.com"));
}
}
@@ -56,6 +56,10 @@ profiler.tcpdatasender.command.accept.enable=true
#profiler.applicationservertype=TOMCAT
#profiler.applicationservertype=BLOC
###########################################################
# application type detect order #
###########################################################
profiler.type.detect.order=
###########################################################
# user defined classes #
@@ -194,4 +198,4 @@ profiler.log4j.logging.transactioninfo=false
###########################################################
# logback
###########################################################
profiler.logback.logging.transactioninfo=false
profiler.logback.logging.transactioninfo=false
@@ -18,11 +18,13 @@ package com.navercorp.pinpoint.bootstrap.config;
import com.navercorp.pinpoint.bootstrap.util.NumberUtils;
import com.navercorp.pinpoint.bootstrap.util.spring.PropertyPlaceholderHelper;
import com.navercorp.pinpoint.common.ServiceType;
import com.navercorp.pinpoint.common.util.PropertyUtils;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -210,6 +212,7 @@ public class ProfilerConfig {
private long agentInfoSendRetryInterval = DEFAULT_AGENT_INFO_SEND_RETRY_INTERVAL;
private String applicationServerType;
private List<String> applicationTypeDetectOrder = Collections.emptyList();
private boolean log4jLoggingTransactionInfo;
private boolean logbackLoggingTransactionInfo;
@@ -589,6 +592,10 @@ public class ProfilerConfig {
public Filter<String> getProfilableClassFilter() {
return profilableClassFilter;
}
public List<String> getApplicationTypeDetectOrder() {
return applicationTypeDetectOrder;
}
public String getApplicationServerType() {
return applicationServerType;
@@ -768,8 +775,10 @@ public class ProfilerConfig {
this.agentInfoSendRetryInterval = readLong("profiler.agentInfo.send.retry.interval", DEFAULT_AGENT_INFO_SEND_RETRY_INTERVAL);
// service type
this.applicationServerType = readString("profiler.applicationservertype", ServiceType.STAND_ALONE.getName());
this.applicationServerType = readString("profiler.applicationservertype", null);
// application type detector order
this.applicationTypeDetectOrder = readTypeDetectOrder("profiler.type.detect.order");
// TODO have to remove
// profile package included in order to test "call stack view".
@@ -836,6 +845,15 @@ public class ProfilerConfig {
return result;
}
public List<String> readTypeDetectOrder(String propertyName) {
String value = properties.getProperty(propertyName);
if (value == null) {
return Collections.emptyList();
}
String[] orders = value.trim().split(",");
return Arrays.asList(orders);
}
public boolean readBoolean(String propertyName, boolean defaultValue) {
String value = properties.getProperty(propertyName, Boolean.toString(defaultValue));
boolean result = Boolean.parseBoolean(value);
@@ -845,7 +863,6 @@ public class ProfilerConfig {
return result;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("ProfilerConfig{");
@@ -929,6 +946,7 @@ public class ProfilerConfig {
sb.append(", profilableClassFilter=").append(profilableClassFilter);
sb.append(", DEFAULT_AGENT_INFO_SEND_RETRY_INTERVAL=").append(DEFAULT_AGENT_INFO_SEND_RETRY_INTERVAL);
sb.append(", agentInfoSendRetryInterval=").append(agentInfoSendRetryInterval);
sb.append(", applicationTypeDetectOrder='").append(applicationTypeDetectOrder).append('\'');
sb.append(", applicationServerType=").append(applicationServerType);
sb.append('}');
return sb.toString();
@@ -93,4 +93,10 @@ public interface RecordableTrace {
void recordAcceptorHost(String host);
int getStackFrameId();
}
Object getAttribute(String key);
Object setAttribute(String key, Object value);
Object removeAttribute(String key);
}
@@ -36,4 +36,9 @@ public interface StackOperation {
void traceBlockEnd();
void traceBlockEnd(int stackId);
Object setTraceBlockAttachment(Object attachment);
Object getTraceBlockAttachment();
Object removeTraceBlockAttachment();
}
@@ -110,6 +110,8 @@ public interface InstrumentClass {
boolean hasDeclaredMethod(String methodName, String[] args);
boolean hasMethod(String methodName, String[] parameterTypeArray, String returnType);
boolean hasField(String name, String type);
InstrumentClass getNestedClass(String className);
@@ -0,0 +1,49 @@
/**
* 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.plugin;
import com.navercorp.pinpoint.bootstrap.resolver.ConditionProvider;
import com.navercorp.pinpoint.common.ServiceType;
/**
* @author Jongho Moon
*
*/
public interface ApplicationTypeDetector {
/**
* Returns the {@link ServiceType} representing the current plugin,
* with code in a range corresponding to {@link com.navercorp.pinpoint.common.ServiceTypeCategory#SERVER}
*
* @return the {@link ServiceType} representing the current plugin
* @see ServiceType#isWas()
* @see com.navercorp.pinpoint.common.ServiceTypeCategory#SERVER
*/
public ServiceType getServerType();
/**
* Checks whether the provided conditions satisfy the requirements given by the plugins implementing this class.
*
* <p>This method allows the agent to go through each of the registered plugins with classes implementing this interface,
* checking whether the execution environment satisfies the requirements specified in them, returning <tt>true</tt> if the
* requirements are satisfied.
*
* @param provider conditions provided by the current application
* @return <tt>true</tt> if the provided conditions satisfy the requirements, <tt>false</tt> if otherwise
* @see ConditionProvider
*/
public boolean detect(ConditionProvider provider);
}
@@ -19,5 +19,5 @@ package com.navercorp.pinpoint.bootstrap.plugin;
public interface ProfilerPlugin {
void setUp(ProfilerPluginSetupContext context);
void setup(ProfilerPluginSetupContext context);
}
@@ -28,8 +28,8 @@ public interface ProfilerPluginSetupContext {
public Object setAttribute(String key, Object value);
public Object getAttribute(String key);
public ClassEditorBuilder newClassEditorBuilder();
public ClassEditorBuilder getClassEditorBuilder(String targetClassName);
public void addClassEditor(ClassEditor classEditor);
public void addServerTypeDetector(ServerTypeDetector... detectors);
public void addApplicationTypeDetector(ApplicationTypeDetector... detectors);
}
@@ -0,0 +1,41 @@
/**
* 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.plugin.editor;
import com.navercorp.pinpoint.bootstrap.instrument.MethodFilter;
/**
* @author Jongho Moon
*
*/
public interface BaseClassEditorBuilder {
public abstract void injectFieldAccessor(String fieldName);
public abstract void injectMetadata(String name);
public abstract void injectMetadata(String name, String initialValueType);
public abstract void injectInterceptor(String className, Object... constructorArgs);
public abstract void weave(String aspectClassName);
public abstract MethodEditorBuilder editMethods(MethodFilter filter);
public abstract MethodEditorBuilder editMethod(String name, String... parameterTypeNames);
public abstract ConstructorEditorBuilder editConstructor(String... parameterTypeNames);
}
@@ -19,7 +19,6 @@ package com.navercorp.pinpoint.bootstrap.plugin.editor;
*
*/
public interface BaseMethodEditorBuilder {
void condition(ClassCondition condition);
void injectInterceptor(String interceptorClassName, Object... constructorArguments);
void exceptionHandler(MethodEditorExceptionHandler handler);
void property(MethodEditorProperty... properties);
@@ -17,7 +17,8 @@
package com.navercorp.pinpoint.bootstrap.plugin.editor;
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass;
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginContext;
public interface ClassCondition {
boolean check(ClassLoader classLoader, InstrumentClass target);
boolean check(ProfilerPluginContext context, ClassLoader classLoader, InstrumentClass target);
}
@@ -0,0 +1,93 @@
/**
* 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.plugin.editor;
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass;
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginContext;
/**
* @author Jongho Moon
*
*/
public class ClassConditions {
public static ClassCondition hasField(String name) {
return new HasField(name);
}
public static ClassCondition hasField(String name, String type) {
return new HasField(name, type);
}
public static ClassCondition hasMethod(String name, String returnType, String... paramTypes) {
return new HasMethod(name, returnType, paramTypes);
}
public static ClassCondition hasDeclaredMethod(String name, String... paramTypes) {
return new HasDeclaredMethod(name, paramTypes);
}
private static class HasField implements ClassCondition {
private final String name;
private final String type;
public HasField(String name) {
this(name, null);
}
public HasField(String name, String type) {
this.name = name;
this.type = type;
}
@Override
public boolean check(ProfilerPluginContext context, ClassLoader classLoader, InstrumentClass target) {
return target.hasField(name, type);
}
}
private static class HasMethod implements ClassCondition {
private final String name;
private final String returnType;
private final String[] paramTypes;
public HasMethod(String name, String returnType, String... paramTypes) {
this.name = name;
this.returnType = returnType;
this.paramTypes = paramTypes;
}
@Override
public boolean check(ProfilerPluginContext context, ClassLoader classLoader, InstrumentClass target) {
return target.hasMethod(name, paramTypes, returnType);
}
}
private static class HasDeclaredMethod implements ClassCondition {
private final String name;
private final String[] paramTypes;
public HasDeclaredMethod(String name, String[] paramTypes) {
this.name = name;
this.paramTypes = paramTypes;
}
@Override
public boolean check(ProfilerPluginContext context, ClassLoader classLoader, InstrumentClass target) {
return target.hasDeclaredMethod(name, paramTypes);
}
}
}
@@ -14,7 +14,6 @@
*/
package com.navercorp.pinpoint.bootstrap.plugin.editor;
import com.navercorp.pinpoint.bootstrap.instrument.MethodFilter;
@@ -22,27 +21,7 @@ import com.navercorp.pinpoint.bootstrap.instrument.MethodFilter;
* @author Jongho Moon
*
*/
public interface ClassEditorBuilder {
public void target(String targetClassName);
public void condition(ClassCondition condition);
public void injectFieldSnooper(String fieldName);
public void injectMetadata(String name);
public void injectMetadata(String name, String initialValueType);
public void injectInterceptor(String className, Object... constructorArgs);
public void weave(String aspectClassName);
public MethodEditorBuilder editMethods(MethodFilter filter);
public MethodEditorBuilder editMethod(String name, String... parameterTypeNames);
public ConstructorEditorBuilder editConstructor(String... parameterTypeNames);
public interface ClassEditorBuilder extends BaseClassEditorBuilder {
public void conditional(ClassCondition condition, ConditionalClassEditorSetup descriptor);
public ClassEditor build();
}
@@ -12,15 +12,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.navercorp.pinpoint.bootstrap.plugin;
package com.navercorp.pinpoint.bootstrap.plugin.editor;
/**
* @author Jongho Moon
*
*/
public interface ServerTypeDetector {
public String getServerTypeName();
public boolean detect();
public boolean canOverride(String serverType);
public interface ConditionalClassEditorBuilder extends BaseClassEditorBuilder {
}
@@ -12,15 +12,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.navercorp.pinpoint.test.plugin;
package com.navercorp.pinpoint.bootstrap.plugin.editor;
/**
* @author Jongho Moon
*
*/
public class ChildProcessException extends Exception {
public ChildProcessException(String message, StackTraceElement[] stackTrace) {
super(message);
setStackTrace(stackTrace);
}
public interface ConditionalClassEditorSetup {
public void setup(ConditionalClassEditorBuilder conditional);
}
@@ -0,0 +1,72 @@
/*
* Copyright 2015 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.resolver;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.navercorp.pinpoint.bootstrap.plugin.ApplicationTypeDetector;
import com.navercorp.pinpoint.common.ServiceType;
/**
* This class attempts to resolve the current application type through {@link ServerTypeDetector}s.
* The application type is resolved by checking the conditions defined in each of the loaded detector's {@code detect} method.
* <p>
* If no match is found, the application type defaults to {@code ServiceType.STAND_ALONE}
*
* @author HyunGil Jeong
*/
public class ApplicationServerTypePluginResolver {
private final Logger logger = Logger.getLogger(ApplicationServerTypePluginResolver.class.getName());
private final List<ApplicationTypeDetector> applicationTypeDetectors;
private final ConditionProvider conditionProvider;
private static final ServiceType DEFAULT_SERVER_TYPE = ServiceType.STAND_ALONE;
public ApplicationServerTypePluginResolver(List<ApplicationTypeDetector> serverTypeDetectors) {
this(serverTypeDetectors, ConditionProvider.DEFAULT_CONDITION_PROVIDER);
}
public ApplicationServerTypePluginResolver(List<ApplicationTypeDetector> serverTypeDetectors, ConditionProvider conditionProvider) {
if (serverTypeDetectors == null) {
throw new IllegalArgumentException("applicationTypeDetectors should not be null");
}
if (conditionProvider == null) {
throw new IllegalArgumentException("conditionProvider should not be null");
}
this.applicationTypeDetectors = serverTypeDetectors;
this.conditionProvider = conditionProvider;
}
public ServiceType resolve() {
for (ApplicationTypeDetector currentDetector : this.applicationTypeDetectors) {
logger.log(Level.INFO, "Attempting to resolve using " + currentDetector.getClass());
if (currentDetector.detect(this.conditionProvider)) {
logger.log(Level.INFO, "Match found using " + currentDetector.getClass().getSimpleName());
return currentDetector.getServerType();
} else {
logger.log(Level.INFO, "No match found using " + currentDetector.getClass());
}
}
logger.log(Level.INFO, "Server type not resolved. Defaulting to " + DEFAULT_SERVER_TYPE.getName());
return DEFAULT_SERVER_TYPE;
}
}
@@ -0,0 +1,105 @@
/*
* Copyright 2015 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.resolver;
import com.navercorp.pinpoint.bootstrap.resolver.condition.ClassResourceCondition;
import com.navercorp.pinpoint.bootstrap.resolver.condition.MainClassCondition;
import com.navercorp.pinpoint.bootstrap.resolver.condition.PropertyCondition;
/**
*
* @author HyunGil Jeong
*/
public class ConditionProvider {
public static final ConditionProvider DEFAULT_CONDITION_PROVIDER = new ConditionProvider();
private final MainClassCondition mainClassCondition;
private final PropertyCondition systemPropertyCondition;
private final ClassResourceCondition classResourceCondition;
private ConditionProvider() {
this(new MainClassCondition(), new PropertyCondition(), new ClassResourceCondition());
}
ConditionProvider(MainClassCondition mainClassCondition, PropertyCondition systemPropertyCondition, ClassResourceCondition classResourceCondition) {
this.mainClassCondition = mainClassCondition;
this.systemPropertyCondition = systemPropertyCondition;
this.classResourceCondition = classResourceCondition;
}
/**
* Returns the fully qualified class name of the application's main class.
*
* @return the fully qualified class name of the main class, or an empty string if the main class cannot be resolved
* @see MainClassCondition#getValue()
*/
public String getMainClass() {
return this.mainClassCondition.getValue();
}
/**
* Checks if the specified value matches the fully qualified class name of the application's main class.
* If the main class cannot be resolved, the method return <tt>false</tt>.
*
* @param condition the value to check against the application's main class name
* @return <tt>true</tt> if the specified value matches the name of the main class;
* <tt>false</tt> if otherwise, or if the main class cannot be resolved
* @see MainClassCondition#check(String)
*/
public boolean checkMainClass(String mainClass) {
return this.mainClassCondition.check(mainClass);
}
/**
* Returns the system property value for the specified key.
*
* @return the system property value, or an empty string if the key is null or empty
*/
public String getSystemPropertyValue(String systemPropertyKey) {
if (systemPropertyKey == null || systemPropertyKey.isEmpty()) {
return "";
}
return this.systemPropertyCondition.getValue().getProperty(systemPropertyKey);
}
/**
* Checks if the specified value is in the system property.
*
* @param requiredKey the values to check if they exist in the system property
* @return <tt>true</tt> if the specified key is in the system property;
* <tt>false</tt> if otherwise, or if <tt>null</tt> or empty key is provided
*/
public boolean checkSystemProperty(String systemPropertyKey) {
return this.systemPropertyCondition.check(systemPropertyKey);
}
/**
* Checks if the specified class can be found in the current System ClassLoader's search path.
*
* @param requiredClass the fully qualified class name of the class to check
* @return <tt>true</tt> if the specified class can be found in the system class loader's search path,
* <tt>false</tt> if otherwise
* @see ClassResourceCondition#check(String)
*/
public boolean checkForClass(String requiredClass) {
return this.classResourceCondition.check(requiredClass);
}
}
@@ -0,0 +1,48 @@
/*
* Copyright 2015 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.resolver.condition;
/**
* @author HyunGil Jeong
*
*/
public class ClassResourceCondition implements Condition<String> {
private static final String CLASS_EXTENSION = ".class";
private String getClassNameAsResource(String className) {
String classNameAsResource = className.replace('.', '/');
return classNameAsResource.endsWith(CLASS_EXTENSION) ? classNameAsResource : classNameAsResource.concat(CLASS_EXTENSION);
}
/**
* Checks if the specified class can be found in the current System ClassLoader's search path.
*
* @param requiredClass the fully qualified class name of the class to check
* @return <tt>true</tt> if the specified class can be found in the system class loader's search path,
* <tt>false</tt> if otherwise
*/
@Override
public boolean check(String requiredClass) {
if (requiredClass == null || requiredClass.isEmpty()) {
return false;
}
String classNameAsResource = getClassNameAsResource(requiredClass);
return (ClassLoader.getSystemResource(classNameAsResource) != null);
}
}
@@ -0,0 +1,26 @@
/*
* Copyright 2015 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.resolver.condition;
/**
* @author HyunGil Jeong
*/
public interface Condition<T> {
public boolean check(T condition);
}
@@ -0,0 +1,26 @@
/*
* Copyright 2015 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.resolver.condition;
/**
* @author HyunGil Jeong
*/
public interface ConditionValue<V> {
public V getValue();
}
@@ -0,0 +1,103 @@
/*
* Copyright 2015 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.resolver.condition;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.navercorp.pinpoint.common.util.SimpleProperty;
import com.navercorp.pinpoint.common.util.SystemProperty;
import com.navercorp.pinpoint.common.util.SystemPropertyKey;
/**
* @author HyunGil Jeong
*
*/
public class MainClassCondition implements Condition<String>, ConditionValue<String> {
private final Logger logger = Logger.getLogger(MainClassCondition.class.getName());
private static final String MANIFEST_MAIN_CLASS_KEY = "Main-Class";
private static final String NOT_FOUND = null;
private final String applicationMainClassName;
public MainClassCondition() {
this(SystemProperty.INSTANCE);
}
public MainClassCondition(SimpleProperty property) {
if (property == null) {
throw new IllegalArgumentException("properties should not be null");
}
this.applicationMainClassName = getMainClassName(property);
}
/**
* Checks if the specified value matches the fully qualified class name of the application's main class.
* If the main class cannot be resolved, the method return <tt>false</tt>.
*
* @param condition the value to check against the application's main class name
* @return <tt>true</tt> if the specified value matches the name of the main class;
* <tt>false</tt> if otherwise, or if the main class cannot be resolved
*/
@Override
public boolean check(String condition) {
if (this.applicationMainClassName == NOT_FOUND) {
return false;
} else {
return this.applicationMainClassName.equals(condition);
}
}
/**
* Returns the fully qualified class name of the application's main class.
*
* @return the fully qualified class name of the main class, or an empty string if the main class cannot be resolved
*/
@Override
public String getValue() {
if (this.applicationMainClassName == NOT_FOUND) {
return "";
}
return this.applicationMainClassName;
}
private String getMainClassName(SimpleProperty property) {
String javaCommand = property.getProperty(SystemPropertyKey.SUN_JAVA_COMMAND.getKey(), "").split(" ")[0];
if (javaCommand.isEmpty()) {
logger.log(Level.WARNING, "Error retrieving main class from " + property.getClass().getName());
return NOT_FOUND;
} else if (javaCommand.endsWith(".jar")) {
return extractMainClassFromJar(javaCommand);
} else {
return javaCommand;
}
}
private String extractMainClassFromJar(String jarName) {
try {
JarFile bootstrapJar = new JarFile(jarName);
return bootstrapJar.getManifest().getMainAttributes().getValue(MANIFEST_MAIN_CLASS_KEY);
} catch (Throwable t) {
logger.log(Level.WARNING, "Error retrieving main class from jar file : " + jarName, t);
return NOT_FOUND;
}
}
}
@@ -0,0 +1,63 @@
/*
* Copyright 2015 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.resolver.condition;
import com.navercorp.pinpoint.common.util.SimpleProperty;
import com.navercorp.pinpoint.common.util.SystemProperty;
/**
* @author HyunGil Jeong
*
*/
public class PropertyCondition implements Condition<String>, ConditionValue<SimpleProperty> {
private final SimpleProperty property;
public PropertyCondition() {
this(SystemProperty.INSTANCE);
}
public PropertyCondition(SimpleProperty property) {
this.property = property;
}
/**
* Checks if the specified value is in <tt>SimpleProperty</tt>.
*
* @param requiredKey the values to check if they exist in <tt>SimpleProperty</tt>
* @return <tt>true</tt> if the specified key is in <tt>SimpleProperty</tt>;
* <tt>false</tt> if otherwise, or if <tt>null</tt> or empty key is provided
*/
@Override
public boolean check(String requiredKey) {
if (requiredKey == null || requiredKey.isEmpty()) {
return false;
}
return (this.property.getProperty(requiredKey) != null);
}
/**
* Returns the <tt>SimpleProperty</tt>.
*
* @return the {@link SimpleProperty} instance
*/
@Override
public SimpleProperty getValue() {
return this.property;
}
}
@@ -16,9 +16,11 @@
package com.navercorp.pinpoint.bootstrap.interceptor;
import java.util.HashMap;
import java.util.Map;
import com.navercorp.pinpoint.bootstrap.context.Trace;
import com.navercorp.pinpoint.bootstrap.context.TraceId;
import com.navercorp.pinpoint.bootstrap.interceptor.MethodDescriptor;
import com.navercorp.pinpoint.common.AnnotationKey;
import com.navercorp.pinpoint.common.ServiceType;
import com.navercorp.pinpoint.common.util.Clock;
@@ -36,7 +38,10 @@ public class MockTrace implements Trace {
private boolean sampled = true;
private Clock clock = SystemClock.INSTANCE;
private final Map<String, Object> attributeMap = new HashMap<String, Object>();
private Object attachment;
public void setClock(Clock clock) {
this.clock = clock;
}
@@ -214,4 +219,38 @@ public class MockTrace implements Trace {
public short getServiceType() {
return ServiceType.UNDEFINED.getCode();
}
@Override
public Object getAttribute(String key) {
return attributeMap.get(key);
}
@Override
public Object setAttribute(String key, Object value) {
return attributeMap.put(key, value);
}
@Override
public Object removeAttribute(String key) {
return attributeMap.remove(key);
}
@Override
public Object setTraceBlockAttachment(Object attachment) {
Object copy = this.attachment;
this.attachment = attachment;
return copy;
}
@Override
public Object getTraceBlockAttachment() {
return this.attachment;
}
@Override
public Object removeTraceBlockAttachment() {
Object copy = this.attachment;
this.attachment = null;
return copy;
}
}
@@ -0,0 +1,196 @@
/*
* Copyright 2015 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.resolver;
import static org.junit.Assert.*;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import com.navercorp.pinpoint.bootstrap.resolver.condition.ClassResourceCondition;
import com.navercorp.pinpoint.bootstrap.resolver.condition.MainClassCondition;
import com.navercorp.pinpoint.bootstrap.resolver.condition.PropertyCondition;
import com.navercorp.pinpoint.common.util.SimpleProperty;
import com.navercorp.pinpoint.common.util.SystemPropertyKey;
/**
* @author HyunGil Jeong
*/
public class ConditionProviderTest {
private static final String TEST_MAIN_CLASS = "test.main.class";
private static final String TEST_PROPERTY_KEY = "test.property.key";
private static final String TEST_PROPERTY_VALUE = "test.property.value";
private ConditionProvider conditionProvider;
@Before
public void setUp() throws Exception {
this.conditionProvider = new ConditionProvider(
new MainClassCondition(PROPERTY_FOR_TEST),
new PropertyCondition(PROPERTY_FOR_TEST),
new ClassResourceCondition()
);
}
@Test
public void getMainClassShouldReturnApplicationMainClass() {
// Given
final String expectedMainClass = TEST_MAIN_CLASS;
// When
String actualMainClass = this.conditionProvider.getMainClass();
// Then
assertEquals(expectedMainClass, actualMainClass);
}
@Test
public void checkMainClassShouldReturnTrueForMatchingMainClasses() {
// Given
final String matchingMainClass = TEST_MAIN_CLASS;
// When
boolean matches = this.conditionProvider.checkMainClass(matchingMainClass);
// Then
assertTrue(matches);
}
@Test
public void checkMainClassShouldReturnFalseForNonMatchingMainClasses() {
// Given
final String someOtherMainClass = "some.other.main.class";
// When
boolean matches = this.conditionProvider.checkMainClass(someOtherMainClass);
// Then
assertFalse(matches);
}
@Test
public void checkMainClassShouldReturnForNullParameter() {
// Given
// When
boolean matches = this.conditionProvider.checkMainClass(null);
// Then
assertFalse(matches);
}
@Test
public void checkMainClassShouldReturnForEmptyParameter() {
// Given
// When
boolean matches = this.conditionProvider.checkMainClass("");
// Then
assertFalse(matches);
}
@Test
public void getSystemPropertyValueShouldReturnCorrectValue() {
// Given
final String expectedValue = TEST_PROPERTY_VALUE;
// When
String actualValue = this.conditionProvider.getSystemPropertyValue(TEST_PROPERTY_KEY);
// Then
assertEquals(expectedValue, actualValue);
}
@Test
public void getSystemPropertyValueShouldReturnEmptyStringForNullKey() {
// Given
final String expectedValue = "";
// When
String actualValue = this.conditionProvider.getSystemPropertyValue(null);
// Then
assertEquals(expectedValue, actualValue);
}
@Test
public void getSystemPropertyValueShouldReturnEmptyStringForEmptyKey() {
// Given
final String expectedValue = "";
// When
String actualValue = this.conditionProvider.getSystemPropertyValue("");
// Then
assertEquals(expectedValue, actualValue);
}
@Test
public void checkSystemPropertyShouldReturnTrueForExistingKeys() {
// Given
// When
boolean exists = this.conditionProvider.checkSystemProperty(TEST_PROPERTY_KEY);
// Then
assertTrue(exists);
}
@Test
public void checkSystemPropertyShouldReturnFalseForNonExistingKeys() {
// Given
final String nonExistingKey = "some.other.property.key";
// When
boolean exists = this.conditionProvider.checkSystemProperty(nonExistingKey);
// Then
assertFalse(exists);
}
@Test
public void checkSystemPropertyShouldReturnFalseForNullKeys() {
// Given
// When
boolean exists = this.conditionProvider.checkSystemProperty(null);
// Then
assertFalse(exists);
}
@Test
public void checkSystemPropertyShouldReturnFalseForEmptyKeys() {
// Given
// When
boolean exists = this.conditionProvider.checkSystemProperty("");
// Then
assertFalse(exists);
}
private static final SimpleProperty PROPERTY_FOR_TEST = new SimpleProperty() {
@SuppressWarnings("serial")
private final Map<String, String> properties = new HashMap<String, String>() {{
put(SystemPropertyKey.SUN_JAVA_COMMAND.getKey(), TEST_MAIN_CLASS);
put(TEST_PROPERTY_KEY, TEST_PROPERTY_VALUE);
}};
@Override
public void setProperty(String key, String value) {
this.properties.put(key, value);
}
@Override
public String getProperty(String key) {
return this.properties.get(key);
}
@Override
public String getProperty(String key, String defaultValue) {
if (this.properties.containsKey(key)) {
return this.properties.get(key);
}
return defaultValue;
}
};
}
@@ -0,0 +1,147 @@
/*
* Copyright 2015 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.resolver.condition;
import static org.junit.Assert.*;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import com.navercorp.pinpoint.bootstrap.resolver.condition.MainClassCondition;
import com.navercorp.pinpoint.common.util.SimpleProperty;
import com.navercorp.pinpoint.common.util.SystemPropertyKey;
/**
* @author HyunGil Jeong
*/
public class MainClassConditionTest {
private static final String TEST_MAIN_CLASS = "main.class.for.Test";
@Test
public void getValueShouldReturnBootstrapMainClass() {
// Given
SimpleProperty property = createTestProperty(TEST_MAIN_CLASS);
MainClassCondition mainClassCondition = new MainClassCondition(property);
// When
String expectedMainClass = mainClassCondition.getValue();
// Then
assertEquals(TEST_MAIN_CLASS, expectedMainClass);
}
@Test
public void getValueShouldReturnEmptyStringWhenMainClassCannotBeResolved() {
// Given
SimpleProperty property = createTestProperty();
MainClassCondition mainClassCondition = new MainClassCondition(property);
// When
String expectedMainClass = mainClassCondition.getValue();
// Then
assertEquals("", expectedMainClass);
}
@Test
public void testMatch() {
// Given
SimpleProperty property = createTestProperty(TEST_MAIN_CLASS);
MainClassCondition mainClassCondition = new MainClassCondition(property);
// When
boolean matches = mainClassCondition.check(TEST_MAIN_CLASS);
// Then
assertTrue(matches);
}
@Test
public void testNoMatch() {
// Given
String givenBootstrapMainClass = "some.other.main.class";
SimpleProperty property = createTestProperty(givenBootstrapMainClass);
MainClassCondition mainClassCondition = new MainClassCondition(property);
// When
boolean matches = mainClassCondition.check(TEST_MAIN_CLASS);
// Then
assertFalse(matches);
}
@Test
public void nullConditionShouldNotMatch() {
// Given
SimpleProperty property = createTestProperty(TEST_MAIN_CLASS);
MainClassCondition mainClassCondition = new MainClassCondition(property);
// When
boolean matches = mainClassCondition.check(null);
// Then
assertFalse(matches);
}
@Test
public void shouldNotMatchWhenMainClassCannotBeResolved() {
// Given
SimpleProperty property = createTestProperty();
MainClassCondition mainClassCondition = new MainClassCondition(property);
// When
boolean matches = mainClassCondition.check(null);
// Then
assertFalse(matches);
}
@Test
public void shouldNotMatchWhenWhenJarFileCannotBeFound() {
// Given
SimpleProperty property = createTestProperty("non-existent-test-jar.jar");
MainClassCondition mainClassCondition = new MainClassCondition(property);
// When
boolean matches = mainClassCondition.check(null);
// Then
assertFalse(matches);
}
private static SimpleProperty createTestProperty() {
return new SimpleProperty() {
private final Map<String, String> properties = new HashMap<String, String>();
@Override
public void setProperty(String key, String value) {
this.properties.put(key, value);
}
@Override
public String getProperty(String key) {
return this.properties.get(key);
}
@Override
public String getProperty(String key, String defaultValue) {
if (this.properties.containsKey(key)) {
return this.properties.get(key);
} else {
return defaultValue;
}
}
};
}
private static SimpleProperty createTestProperty(String testMainClass) {
SimpleProperty testProperty = createTestProperty();
testProperty.setProperty(SystemPropertyKey.SUN_JAVA_COMMAND.getKey(), testMainClass);
return testProperty;
}
}
@@ -0,0 +1,122 @@
/*
* Copyright 2015 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.resolver.condition;
import static org.junit.Assert.*;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import com.navercorp.pinpoint.bootstrap.resolver.condition.PropertyCondition;
import com.navercorp.pinpoint.common.util.SystemProperty;
/**
* @author HyunGil Jeong
*/
public class SystemPropertyConditionTest {
@Test
public void testMatch() {
// Given
final String existingSystemProperty1 = "set.one.key.one";
final String existingSystemProperty2 = "set.one.key.two";
SystemProperty property = createTestProperty(existingSystemProperty1, existingSystemProperty2);
PropertyCondition systemPropertyCondition = new PropertyCondition(property);
// When
boolean firstKeyExists = systemPropertyCondition.check(existingSystemProperty1);
boolean secondKeyExists = systemPropertyCondition.check(existingSystemProperty2);
// Then
assertTrue(firstKeyExists);
assertTrue(secondKeyExists);
}
@Test
public void testNoMatch() {
// Given
final String existingSystemProperty = "existing.system.property";
SystemProperty property = createTestProperty(existingSystemProperty);
PropertyCondition systemPropertyCondition = new PropertyCondition(property);
// When
boolean keyExists = systemPropertyCondition.check("some.other.property");
// Then
assertFalse(keyExists);
}
@Test
public void emptyConditionShouldNotMatch() {
// Given
final String existingSystemProperty = "existing.system.property";
SystemProperty property = createTestProperty(existingSystemProperty);
PropertyCondition systemPropertyCondition = new PropertyCondition(property);
// When
boolean matches = systemPropertyCondition.check("");
// Then
assertFalse(matches);
}
@Test
public void nullConditionShouldNotMatch() {
// Given
final String existingSystemProperty = "existing.system.property";
SystemProperty property = createTestProperty(existingSystemProperty);
PropertyCondition systemPropertyCondition = new PropertyCondition(property);
// When
boolean matches = systemPropertyCondition.check(null);
// Then
assertFalse(matches);
}
private static SystemProperty createTestProperty() {
return new SystemProperty() {
private final Map<String, String> properties = new HashMap<String, String>();
@Override
public void setProperty(String key, String value) {
this.properties.put(key, value);
}
@Override
public String getProperty(String key) {
return this.properties.get(key);
}
@Override
public String getProperty(String key, String defaultValue) {
if (this.properties.containsKey(key)) {
return this.properties.get(key);
} else {
return defaultValue;
}
}
};
}
private static SystemProperty createTestProperty(String ... keys) {
SystemProperty property = createTestProperty();
if (keys == null) {
return property;
}
for (String key : keys) {
property.setProperty(key, "");
}
return property;
}
}
@@ -149,6 +149,66 @@ public class ServiceType {
public String toString() {
return desc;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
ServiceType other = (ServiceType) obj;
if (code != other.code) {
return false;
}
if (desc == null) {
if (other.desc != null) {
return false;
}
} else if (!desc.equals(other.desc)) {
return false;
}
if (histogramSchema == null) {
if (other.histogramSchema != null) {
return false;
}
} else if (!histogramSchema.equals(other.histogramSchema)) {
return false;
}
if (includeDestinationId != other.includeDestinationId) {
return false;
}
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
if (recordStatistics != other.recordStatistics) {
return false;
}
if (terminal != other.terminal) {
return false;
}
return true;
}
// Undefined Service Code
public static final ServiceType UNDEFINED = of(-1, "UNDEFINED", NORMAL_SCHEMA, TERMINAL);
@@ -215,7 +275,7 @@ public class ServiceType {
// Connector, Client
public static final ServiceType HTTP_CLIENT = of(9050, "HTTP_CLIENT", NORMAL_SCHEMA, RECORD_STATISTICS);
public static final ServiceType HTTP_CLIENT_INTERNAL = of(9051, "HTTP_CLIENT_INTERNAL", "HTTP_CLIENT", NORMAL_SCHEMA);
public static final ServiceType JDK_HTTPURLCONNECTOR = of(9055, "JDK_HTTPURLCONNECTOR", "JDK_HTTPCONNECTOR", NORMAL_SCHEMA);
// public static final ServiceType JDK_HTTPURLCONNECTOR = of(9055, "JDK_HTTPURLCONNECTOR", "JDK_HTTPCONNECTOR", NORMAL_SCHEMA);
public static final ServiceType NPC_CLIENT = of(9060, "NPC_CLIENT", NORMAL_SCHEMA, RECORD_STATISTICS);
public static final ServiceType NIMM_CLIENT = of(9070, "NIMM_CLIENT", NORMAL_SCHEMA, RECORD_STATISTICS);
@@ -78,7 +78,7 @@ public class TypeProviderLoader {
}
TypeSetupContextImpl context = new TypeSetupContextImpl(provider.getClass());
provider.setUp(context);
provider.setup(context);
setupContextList.add(context);
@@ -20,5 +20,5 @@ package com.navercorp.pinpoint.common.plugin;
*
*/
public interface TypeProvider {
void setUp(TypeSetupContext context);
void setup(TypeSetupContext context);
}
@@ -53,7 +53,6 @@ public class DefaultDisplayArgument {
public static final DisplayArgumentMatcher HTTP_CLIENT_MATCHER = createArgumentMatcher(ServiceType.HTTP_CLIENT, AnnotationKey.HTTP_URL);
public static final DisplayArgumentMatcher HTTP_CLIENT_INTERNAL_MATCHER = createArgumentMatcher(ServiceType.HTTP_CLIENT_INTERNAL, AnnotationKey.HTTP_CALL_RETRY_COUNT);
public static final DisplayArgumentMatcher JDK_HTTPURLCONNECTOR_MATCHER = createArgumentMatcher(ServiceType.JDK_HTTPURLCONNECTOR, AnnotationKey.HTTP_URL);
@@ -29,7 +29,8 @@ public enum SystemPropertyKey {
JAVA_VM_NAME("java.vm.name"),
JAVA_VM_VERSION("java.vm.version"),
JAVA_VM_INFO("java.vm.info"),
JAVA_VM_SPECIFICATION_VERSION("java.vm.specification.version");
JAVA_VM_SPECIFICATION_VERSION("java.vm.specification.version"),
SUN_JAVA_COMMAND("sun.java.command"); // May be unsupported depending on the JVM.
private final String key;
@@ -150,7 +150,7 @@ public class ServiceTypeInitializerTest {
}
@Override
public void setUp(TypeSetupContext context) {
public void setup(TypeSetupContext context) {
for (ServiceType type : serviceTypes) {
context.addType(type);
}
+4
View File
@@ -0,0 +1,4 @@
/target/
/.settings/
/.classpath
/.project
+26
View File
@@ -0,0 +1,26 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.navercorp.pinpoint</groupId>
<artifactId>pom</artifactId>
<relativePath>../..</relativePath>
<version>1.1.0-SNAPSHOT</version>
</parent>
<artifactId>pinpoint-jdk-http-plugin</artifactId>
<name>pinpoint-jdk-http-plugin</name>
<packaging>jar</packaging>
<dependencies>
<!-- should be replaced with below dependencies after pinpoint-test
project is completed -->
<dependency>
<groupId>com.navercorp.pinpoint</groupId>
<artifactId>pinpoint-profiler</artifactId>
</dependency>
<!-- <dependency> <groupId>com.navercorp.pinpoint</groupId> <artifactId>pinpoint-bootstrap</artifactId>
</dependency> <dependency> <groupId>com.navercorp.pinpoint</groupId> <artifactId>pinpoint-test</artifactId>
<scope>test</scope> </dependency> -->
</dependencies>
</project>
@@ -0,0 +1,27 @@
/**
* 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.jdk.http;
import static com.navercorp.pinpoint.common.HistogramSchema.*;
import com.navercorp.pinpoint.common.ServiceType;
/**
* @author Jongho Moon
*
*/
public interface JdkHttpConstants {
public static final ServiceType SERVICE_TYPE = ServiceType.of(9055, "JDK_HTTPURLCONNECTOR", "JDK_HTTPCONNECTOR", NORMAL_SCHEMA);
}
@@ -0,0 +1,53 @@
package com.navercorp.pinpoint.plugin.jdk.http;
/*
* 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.
*/
import static com.navercorp.pinpoint.bootstrap.plugin.editor.ClassConditions.*;
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin;
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext;
import com.navercorp.pinpoint.bootstrap.plugin.editor.ClassEditorBuilder;
import com.navercorp.pinpoint.bootstrap.plugin.editor.ConditionalClassEditorBuilder;
import com.navercorp.pinpoint.bootstrap.plugin.editor.ConditionalClassEditorSetup;
/**
*
* @author Jongho Moon
*
*/
public class JdkHttpPlugin implements ProfilerPlugin {
@Override
public void setup(ProfilerPluginSetupContext context) {
ClassEditorBuilder builder = context.getClassEditorBuilder("sun.net.www.protocol.http.HttpURLConnection");
builder.injectFieldAccessor("connected");
builder.injectInterceptor("com.navercorp.pinpoint.plugin.jdk.http.interceptor.HttpURLConnectionInterceptor");
// JDK 8
builder.conditional(hasField("connecting", "boolean"),
new ConditionalClassEditorSetup() {
@Override
public void setup(ConditionalClassEditorBuilder conditional) {
conditional.injectFieldAccessor("connecting");
}
}
);
context.addClassEditor(builder.build());
}
}
@@ -0,0 +1,33 @@
/**
* 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.jdk.http;
import com.navercorp.pinpoint.common.AnnotationKey;
import com.navercorp.pinpoint.common.AnnotationKeyMatcher.ExactMatcher;
import com.navercorp.pinpoint.common.plugin.TypeProvider;
import com.navercorp.pinpoint.common.plugin.TypeSetupContext;
/**
* @author Jongho Moon
*
*/
public class JdkHttpTypeProvider implements TypeProvider, JdkHttpConstants {
@Override
public void setup(TypeSetupContext context) {
context.addType(SERVICE_TYPE, new ExactMatcher(AnnotationKey.HTTP_URL));
}
}
@@ -0,0 +1,162 @@
/*
* 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.jdk.http.interceptor;
import java.net.HttpURLConnection;
import java.net.URL;
import com.navercorp.pinpoint.bootstrap.FieldAccessor;
import com.navercorp.pinpoint.bootstrap.context.Header;
import com.navercorp.pinpoint.bootstrap.context.Trace;
import com.navercorp.pinpoint.bootstrap.context.TraceContext;
import com.navercorp.pinpoint.bootstrap.context.TraceId;
import com.navercorp.pinpoint.bootstrap.interceptor.MethodDescriptor;
import com.navercorp.pinpoint.bootstrap.interceptor.SimpleAroundInterceptor;
import com.navercorp.pinpoint.bootstrap.logging.PLogger;
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
import com.navercorp.pinpoint.bootstrap.plugin.Cached;
import com.navercorp.pinpoint.bootstrap.plugin.Name;
import com.navercorp.pinpoint.bootstrap.plugin.Scope;
import com.navercorp.pinpoint.bootstrap.plugin.TargetMethod;
import com.navercorp.pinpoint.bootstrap.plugin.Targets;
import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils;
import com.navercorp.pinpoint.common.AnnotationKey;
import com.navercorp.pinpoint.plugin.jdk.http.JdkHttpConstants;
/**
* @author netspider
* @author emeroad
*/
@Scope("HttpURLConnection")
@Targets(methods={
@TargetMethod(name="connect"),
@TargetMethod(name="getInputStream"),
@TargetMethod(name="getOutputStream")
})
public class HttpURLConnectionInterceptor implements SimpleAroundInterceptor, JdkHttpConstants {
/**
*
*/
private static final Object TRACE_BLOCK_BEGIN_MARKER = new Object();
private final PLogger logger = PLoggerFactory.getLogger(this.getClass());
private final boolean isDebug = logger.isDebugEnabled();
private final TraceContext traceContext;
private final MethodDescriptor descriptor;
private final FieldAccessor connectedAccessor;
private final FieldAccessor connectingAccessor;
public HttpURLConnectionInterceptor(TraceContext traceContext, @Cached MethodDescriptor descriptor, @Name("connected") FieldAccessor connectedAccessor, @Name("connecting") FieldAccessor connectingAccessor) {
this.traceContext = traceContext;
this.descriptor = descriptor;
this.connectedAccessor = connectedAccessor;
this.connectingAccessor = connectingAccessor;
}
@Override
public void before(Object target, Object[] args) {
if (isDebug) {
logger.beforeInterceptor(target, args);
}
Trace trace = traceContext.currentRawTraceObject();
if (trace == null) {
return;
}
HttpURLConnection request = (HttpURLConnection) target;
boolean connected = (Boolean)connectedAccessor.get(target);
boolean connecting = connectingAccessor.isApplicable(target) && (Boolean)connectingAccessor.get(target);
if (connected || connecting) {
return;
}
final boolean sampling = trace.canSampled();
if (!sampling) {
request.setRequestProperty(Header.HTTP_SAMPLED.toString(), SamplingFlagUtils.SAMPLING_RATE_FALSE);
return;
}
trace.traceBlockBegin();
trace.setTraceBlockAttachment(TRACE_BLOCK_BEGIN_MARKER);
trace.markBeforeTime();
TraceId nextId = trace.getTraceId().getNextTraceId();
trace.recordNextSpanId(nextId.getSpanId());
request.setRequestProperty(Header.HTTP_TRACE_ID.toString(), nextId.getTransactionId());
request.setRequestProperty(Header.HTTP_SPAN_ID.toString(), String.valueOf(nextId.getSpanId()));
request.setRequestProperty(Header.HTTP_PARENT_SPAN_ID.toString(), String.valueOf(nextId.getParentSpanId()));
request.setRequestProperty(Header.HTTP_FLAGS.toString(), String.valueOf(nextId.getFlags()));
request.setRequestProperty(Header.HTTP_PARENT_APPLICATION_NAME.toString(), traceContext.getApplicationName());
request.setRequestProperty(Header.HTTP_PARENT_APPLICATION_TYPE.toString(), Short.toString(traceContext.getServerTypeCode()));
trace.recordServiceType(SERVICE_TYPE);
final URL url = request.getURL();
final String host = url.getHost();
final int port = url.getPort();
// TODO How to represent protocol?
String endpoint = getEndpoint(host, port);
// Don't record end point because it's same with destination id.
trace.recordDestinationId(endpoint);
trace.recordAttribute(AnnotationKey.HTTP_URL, url.toString());
}
private String getEndpoint(String host, int port) {
if (port < 0) {
return host;
}
StringBuilder sb = new StringBuilder(32);
sb.append(host);
sb.append(':');
sb.append(port);
return sb.toString();
}
@Override
public void after(Object target, Object[] args, Object result, Throwable throwable) {
if (isDebug) {
// do not log result
logger.afterInterceptor(target, args);
}
Trace trace = traceContext.currentTraceObject();
if (trace == null) {
return;
}
Object marker = trace.getTraceBlockAttachment();
if (marker != TRACE_BLOCK_BEGIN_MARKER) {
return;
}
try {
trace.recordApi(descriptor);
trace.recordException(throwable);
trace.markAfterTime();
} finally {
trace.traceBlockEnd();
}
}
}
@@ -0,0 +1 @@
com.navercorp.pinpoint.plugin.jdk.http.JdkHttpPlugin
@@ -0,0 +1 @@
com.navercorp.pinpoint.plugin.jdk.http.JdkHttpTypeProvider
+12 -6
View File
@@ -12,12 +12,23 @@
<packaging>pom</packaging>
<modules>
<module>jdk-http</module>
<module>redis</module>
<module>servlet</module>
<module>tomcat</module>
<module>redis</module>
</modules>
<dependencies>
<dependency>
<groupId>com.navercorp.pinpoint</groupId>
<artifactId>pinpoint-jdk-http-plugin</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.navercorp.pinpoint</groupId>
<artifactId>pinpoint-redis-plugin</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.navercorp.pinpoint</groupId>
<artifactId>pinpoint-servlet-plugin</artifactId>
@@ -28,10 +39,5 @@
<artifactId>pinpoint-tomcat-plugin</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.navercorp.pinpoint</groupId>
<artifactId>pinpoint-redis-plugin</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
@@ -57,7 +57,7 @@ public class RedisPlugin implements ProfilerPlugin, RedisConstants {
private final PLogger logger = PLoggerFactory.getLogger(this.getClass());
@Override
public void setUp(ProfilerPluginSetupContext context) {
public void setup(ProfilerPluginSetupContext context) {
final RedisPluginConfig config = new RedisPluginConfig(context.getConfig());
final boolean enabled = config.isEnabled();
final boolean pipelineEnabled = config.isPipelineEnabled();
@@ -86,8 +86,7 @@ public class RedisPlugin implements ProfilerPlugin, RedisConstants {
}
private ClassEditorBuilder addJedisExtendedClassEditor(ProfilerPluginSetupContext context, RedisPluginConfig config, final String targetClassName) {
final ClassEditorBuilder classEditorBuilder = context.newClassEditorBuilder();
classEditorBuilder.target(targetClassName);
final ClassEditorBuilder classEditorBuilder = context.getClassEditorBuilder(targetClassName);
final ConstructorEditorBuilder constructorEditorBuilderArg1 = classEditorBuilder.editConstructor(STRING);
constructorEditorBuilderArg1.property(MethodEditorProperty.IGNORE_IF_NOT_EXIST);
@@ -125,8 +124,7 @@ public class RedisPlugin implements ProfilerPlugin, RedisConstants {
// Client
private void addJedisClientClassEditor(ProfilerPluginSetupContext context, RedisPluginConfig config) {
final ClassEditorBuilder classEditorBuilder = context.newClassEditorBuilder();
classEditorBuilder.target(JEDIS_CLIENT);
final ClassEditorBuilder classEditorBuilder = context.getClassEditorBuilder(JEDIS_CLIENT);
classEditorBuilder.injectMetadata(METADATA_END_POINT);
final ConstructorEditorBuilder constructorEditorBuilderArg1 = classEditorBuilder.editConstructor(STRING);
@@ -161,8 +159,7 @@ public class RedisPlugin implements ProfilerPlugin, RedisConstants {
}
private ClassEditorBuilder addJedisPipelineBaseExtendedClassEditor(ProfilerPluginSetupContext context, RedisPluginConfig config, String targetClassName) {
final ClassEditorBuilder classEditorBuilder = context.newClassEditorBuilder();
classEditorBuilder.target(targetClassName);
final ClassEditorBuilder classEditorBuilder = context.getClassEditorBuilder(targetClassName);
final MethodEditorBuilder methodEditorBuilder = classEditorBuilder.editMethods(new NameBasedMethodFilter(JedisPipelineMethodNames.get()));
methodEditorBuilder.exceptionHandler(new MethodEditorExceptionHandler() {
@@ -21,7 +21,7 @@ import com.navercorp.pinpoint.common.plugin.TypeSetupContext;
public class RedisTypeProvider implements TypeProvider, RedisConstants{
@Override
public void setUp(TypeSetupContext context) {
public void setup(TypeSetupContext context) {
context.addType(REDIS);
}
}
@@ -26,13 +26,12 @@ import com.navercorp.pinpoint.bootstrap.plugin.editor.MethodEditorBuilder;
public class ServletPlugin implements ProfilerPlugin {
@Override
public void setUp(ProfilerPluginSetupContext context) {
public void setup(ProfilerPluginSetupContext context) {
addHttpServletEditor(context);
}
private void addHttpServletEditor(ProfilerPluginSetupContext context) {
ClassEditorBuilder builder = context.newClassEditorBuilder();
builder.target("javax.servlet.http.HttpServlet");
ClassEditorBuilder builder = context.getClassEditorBuilder("javax.servlet.http.HttpServlet");
MethodEditorBuilder doGetBuilder = builder.editMethod("doGet", "javax.servlet.http.HttpServletRequest", "javax.servlet.http.HttpServletResponse");
doGetBuilder.injectInterceptor("com.navercorp.pinpoint.profiler.modifier.method.interceptor.MethodInterceptor", ServletConstants.SERVLET);
@@ -24,7 +24,7 @@ import com.navercorp.pinpoint.common.plugin.TypeSetupContext;
public class ServletTypeProvider implements TypeProvider {
@Override
public void setUp(TypeSetupContext context) {
public void setup(TypeSetupContext context) {
context.addType(ServletConstants.SERVLET);
}
@@ -14,47 +14,33 @@
*/
package com.navercorp.pinpoint.plugin.tomcat;
import java.io.File;
import com.navercorp.pinpoint.bootstrap.logging.PLogger;
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
import com.navercorp.pinpoint.bootstrap.plugin.ServerTypeDetector;
import com.navercorp.pinpoint.common.util.SystemProperty;
import com.navercorp.pinpoint.bootstrap.plugin.ApplicationTypeDetector;
import com.navercorp.pinpoint.bootstrap.resolver.ConditionProvider;
import com.navercorp.pinpoint.common.ServiceType;
/**
* @author Jongho Moon
* @author HyunGil Jeong
*
*/
public class TomcatDetector implements ServerTypeDetector, TomcatConstants {
private final PLogger logger = PLoggerFactory.getLogger(getClass());
public class TomcatDetector implements ApplicationTypeDetector, TomcatConstants {
private static final String REQUIRED_MAIN_CLASS = "org.apache.catalina.startup.Bootstrap";
private static final String REQUIRED_SYSTEM_PROPERTY = "catalina.home";
private static final String REQUIRED_CLASS = "org.apache.catalina.startup.Bootstrap";
@Override
public String getServerTypeName() {
return TYPE_NAME;
}
public boolean detect() {
String homeDir = SystemProperty.INSTANCE.getProperty("catalina.home");
if (homeDir == null) {
logger.debug("catalina.home is not defined. This is not a Tomcat instance");
return false;
}
File catalinaJar = new File(homeDir, "/lib/catalina.jar");
if (!catalinaJar.exists()) {
logger.debug(catalinaJar + " is not exist. This is not a Tomcat instance");
return false;
}
logger.debug("catalina.home (" + homeDir + ") is defined and " + catalinaJar + " is exist. This is a Tomcat instance");
return catalinaJar.exists();
public ServiceType getServerType() {
return TOMCAT;
}
@Override
public boolean canOverride(String serverType) {
return false;
public boolean detect(ConditionProvider provider) {
return provider.checkMainClass(REQUIRED_MAIN_CLASS) &&
provider.checkSystemProperty(REQUIRED_SYSTEM_PROPERTY) &&
provider.checkForClass(REQUIRED_CLASS);
}
}
@@ -31,8 +31,8 @@ public class TomcatPlugin implements ProfilerPlugin {
* @see com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin#setUp(com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext)
*/
@Override
public void setUp(ProfilerPluginSetupContext context) {
context.addServerTypeDetector(new TomcatDetector());
public void setup(ProfilerPluginSetupContext context) {
context.addApplicationTypeDetector(new TomcatDetector());
TomcatConfiguration config = new TomcatConfiguration(context.getConfig());
@@ -48,22 +48,19 @@ public class TomcatPlugin implements ProfilerPlugin {
}
private void addRequestFacadeEditor(ProfilerPluginSetupContext context) {
ClassEditorBuilder builder = context.newClassEditorBuilder();
builder.target("org.apache.catalina.connector.RequestFacade");
ClassEditorBuilder builder = context.getClassEditorBuilder("org.apache.catalina.connector.RequestFacade");
builder.weave("com.navercorp.pinpoint.plugin.tomcat.aspect.RequestFacadeAspect");
context.addClassEditor(builder.build());
}
private void addStandardHostValveEditor(ProfilerPluginSetupContext context, TomcatConfiguration config) {
ClassEditorBuilder builder = context.newClassEditorBuilder();
builder.target("org.apache.catalina.core.StandardHostValve");
ClassEditorBuilder builder = context.getClassEditorBuilder("org.apache.catalina.core.StandardHostValve");
builder.injectInterceptor("com.navercorp.pinpoint.plugin.tomcat.interceptor.StandardHostValveInvokeInterceptor", config.getTomcatExcludeUrlFilter());
context.addClassEditor(builder.build());
}
private void addStandardServiceEditor(ProfilerPluginSetupContext context) {
ClassEditorBuilder builder = context.newClassEditorBuilder();
builder.target("org.apache.catalina.core.StandardService");
ClassEditorBuilder builder = context.getClassEditorBuilder("org.apache.catalina.core.StandardService");
// Tomcat 6
MethodEditorBuilder startEditor = builder.editMethod("start");
@@ -79,8 +76,7 @@ public class TomcatPlugin implements ProfilerPlugin {
}
private void addTomcatConnectorEditor(ProfilerPluginSetupContext context) {
ClassEditorBuilder builder = context.newClassEditorBuilder();
builder.target("org.apache.catalina.connector.Connector");
ClassEditorBuilder builder = context.getClassEditorBuilder("org.apache.catalina.connector.Connector");
// Tomcat 6
MethodEditorBuilder initializeEditor = builder.editMethod("initialize");
@@ -96,8 +92,7 @@ public class TomcatPlugin implements ProfilerPlugin {
}
private void addWebappLoaderEditor(ProfilerPluginSetupContext context) {
ClassEditorBuilder builder = context.newClassEditorBuilder();
builder.target("org.apache.catalina.loader.WebappLoader");
ClassEditorBuilder builder = context.getClassEditorBuilder("org.apache.catalina.loader.WebappLoader");
// Tomcat 6 - org.apache.catalina.loader.WebappLoader.start()
@@ -24,7 +24,7 @@ import com.navercorp.pinpoint.common.plugin.TypeSetupContext;
public class TomcatTypeProvider implements TypeProvider, TomcatConstants {
@Override
public void setUp(TypeSetupContext context) {
public void setup(TypeSetupContext context) {
context.addType(TOMCAT);
}
@@ -55,6 +55,10 @@ profiler.tcpdatasender.command.accept.enable=true
#profiler.applicationservertype=TOMCAT
#profiler.applicationservertype=BLOC
###########################################################
# application type detect order #
###########################################################
profiler.type.detect.order=
###########################################################
# user defined classes #
@@ -51,7 +51,6 @@ import com.navercorp.pinpoint.common.ServiceType;
import com.navercorp.pinpoint.common.plugin.PluginLoader;
import com.navercorp.pinpoint.common.service.DefaultServiceTypeRegistryService;
import com.navercorp.pinpoint.common.service.ServiceTypeRegistryService;
import com.navercorp.pinpoint.exception.PinpointException;
import com.navercorp.pinpoint.profiler.context.DefaultServerMetaDataHolder;
import com.navercorp.pinpoint.profiler.context.DefaultTraceContext;
import com.navercorp.pinpoint.profiler.context.storage.BufferedStorageFactory;
@@ -190,15 +189,12 @@ public class DefaultAgent implements Agent {
String applicationServerTypeString = profilerConfig.getApplicationServerType();
ServiceType applicationServerType = this.serviceTypeRegistryService.findServiceTypeByName(applicationServerTypeString);
final ApplicationServerTypeResolver typeResolver = new ApplicationServerTypeResolver(pluginContexts, applicationServerType, this.serviceTypeRegistryService);
if (!typeResolver.resolve()) {
throw new PinpointException("ApplicationServerType not found.");
}
final ApplicationServerTypeResolver typeResolver = new ApplicationServerTypeResolver(pluginContexts, applicationServerType, profilerConfig.getApplicationTypeDetectOrder());
final AgentInformationFactory agentInformationFactory = new AgentInformationFactory();
this.agentInformation = agentInformationFactory.createAgentInformation(typeResolver.getServerType());
this.agentInformation = agentInformationFactory.createAgentInformation(typeResolver.resolve());
logger.info("agentInformation:{}", agentInformation);
CommandDispatcher commandDispatcher = createCommandDispatcher();
this.tcpDataSender = createTcpDataSender(commandDispatcher);
@@ -288,7 +284,7 @@ public class DefaultAgent implements Agent {
logger.info("Loading plugin: {}", plugin.getClass().getName());
DefaultProfilerPluginContext context = new DefaultProfilerPluginContext(this);
plugin.setUp(context);
plugin.setup(context);
pluginContexts.add(context);
}
@@ -16,7 +16,16 @@
package com.navercorp.pinpoint.profiler.context;
import com.navercorp.pinpoint.bootstrap.context.*;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.navercorp.pinpoint.bootstrap.context.AttributeScope;
import com.navercorp.pinpoint.bootstrap.context.Trace;
import com.navercorp.pinpoint.bootstrap.context.TraceContext;
import com.navercorp.pinpoint.bootstrap.context.TraceId;
import com.navercorp.pinpoint.bootstrap.interceptor.MethodDescriptor;
import com.navercorp.pinpoint.bootstrap.util.StringUtils;
import com.navercorp.pinpoint.common.AnnotationKey;
@@ -27,9 +36,6 @@ import com.navercorp.pinpoint.exception.PinpointException;
import com.navercorp.pinpoint.profiler.context.storage.Storage;
import com.navercorp.pinpoint.thrift.dto.TIntStringStringValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author netspider
@@ -52,6 +58,8 @@ public final class DefaultTrace implements Trace {
private Storage storage;
private final TraceContext traceContext;
private final Map<String, Object> attributeMap = new HashMap<String, Object>();
// use for calculating depth of each Span.
private int latestStackIndex = -1;
@@ -547,4 +555,34 @@ public final class DefaultTrace implements Trace {
public short getServiceType() {
return currentStackFrame.getServiceType();
}
@Override
public Object getAttribute(String key) {
return attributeMap.get(key);
}
@Override
public Object setAttribute(String key, Object value) {
return attributeMap.put(key, value);
}
@Override
public Object removeAttribute(String key) {
return attributeMap.remove(key);
}
@Override
public Object setTraceBlockAttachment(Object attachment) {
return currentStackFrame.attachFrameObject(attachment);
}
@Override
public Object getTraceBlockAttachment() {
return currentStackFrame.getFrameObject();
}
@Override
public Object removeTraceBlockAttachment() {
return currentStackFrame.detachFrameObject();
}
}
@@ -16,6 +16,9 @@
package com.navercorp.pinpoint.profiler.context;
import java.util.HashMap;
import java.util.Map;
import com.navercorp.pinpoint.bootstrap.context.Trace;
import com.navercorp.pinpoint.bootstrap.context.TraceId;
import com.navercorp.pinpoint.bootstrap.interceptor.MethodDescriptor;
@@ -30,6 +33,8 @@ import com.navercorp.pinpoint.common.util.ParsingResult;
public class DisableTrace implements Trace {
public static final DisableTrace INSTANCE = new DisableTrace();
private final Map<String, Object> attributeMap = new HashMap<String, Object>();
private DisableTrace() {
}
@@ -204,4 +209,34 @@ public class DisableTrace implements Trace {
public short getServiceType() {
throw new UnsupportedOperationException();
}
@Override
public Object getAttribute(String key) {
return attributeMap.get(key);
}
@Override
public Object setAttribute(String key, Object value) {
return attributeMap.put(key, value);
}
@Override
public Object removeAttribute(String key) {
return attributeMap.remove(key);
}
@Override
public Object setTraceBlockAttachment(Object attachment) {
throw new UnsupportedOperationException();
}
@Override
public Object getTraceBlockAttachment() {
throw new UnsupportedOperationException();
}
@Override
public Object removeTraceBlockAttachment() {
throw new UnsupportedOperationException();
}
}
@@ -16,6 +16,12 @@
package com.navercorp.pinpoint.profiler.context;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.navercorp.pinpoint.bootstrap.context.Trace;
import com.navercorp.pinpoint.bootstrap.context.TraceContext;
import com.navercorp.pinpoint.bootstrap.context.TraceId;
@@ -26,9 +32,6 @@ import com.navercorp.pinpoint.common.util.DefaultParsingResult;
import com.navercorp.pinpoint.common.util.ParsingResult;
import com.navercorp.pinpoint.exception.PinpointException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author emeroad
*/
@@ -37,7 +40,7 @@ public class MetricTrace implements Trace {
private static final Logger logger = LoggerFactory.getLogger(MetricTrace.class.getName());
private static final boolean isDebug = logger.isDebugEnabled();
private static final boolean isTrace = logger.isTraceEnabled();
private static final int EXCEPTION_MARK = -1;
private static final ParsingResult PARSING_RESULT = new DefaultParsingResult("", new StringBuilder());
@@ -50,6 +53,8 @@ public class MetricTrace implements Trace {
private final TraceContext traceContext;
private final Map<String, Object> attributeMap = new HashMap<String, Object>();
// use for calculating depth of each Span.
private int latestStackIndex = -1;
private StackFrame currentStackFrame;
@@ -369,4 +374,34 @@ public class MetricTrace implements Trace {
public short getServiceType() {
return currentStackFrame.getServiceType();
}
@Override
public Object getAttribute(String key) {
return attributeMap.get(key);
}
@Override
public Object setAttribute(String key, Object value) {
return attributeMap.put(key, value);
}
@Override
public Object removeAttribute(String key) {
return attributeMap.remove(key);
}
@Override
public Object setTraceBlockAttachment(Object attachment) {
return currentStackFrame.attachFrameObject(attachment);
}
@Override
public Object getTraceBlockAttachment() {
return currentStackFrame.getFrameObject();
}
@Override
public Object removeTraceBlockAttachment() {
return currentStackFrame.detachFrameObject();
}
}
@@ -110,8 +110,10 @@ public class RootStackFrame implements StackFrame {
}
@Override
public void attachFrameObject(Object frameObject) {
public Object attachFrameObject(Object frameObject) {
Object copy = this.frameObject;
this.frameObject = frameObject;
return copy;
}
@Override
@@ -114,8 +114,10 @@ public class SpanEventStackFrame implements StackFrame {
}
@Override
public void attachFrameObject(Object frameObject) {
public Object attachFrameObject(Object frameObject) {
Object copy = this.frameObject;
this.frameObject = frameObject;
return copy;
}
@Override
@@ -50,7 +50,7 @@ public interface StackFrame {
short getServiceType();
void attachFrameObject(Object frameObject);
Object attachFrameObject(Object frameObject);
Object getFrameObject();
@@ -913,6 +913,17 @@ public class JavaAssistClass implements InstrumentClass {
return false;
}
}
@Override
public boolean hasField(String name, String type) {
try {
ctClass.getField(name, type);
} catch (NotFoundException e) {
return false;
}
return true;
}
@Override
public InstrumentClass getNestedClass(String className) {
@@ -941,7 +952,7 @@ public class JavaAssistClass implements InstrumentClass {
try {
// FIXME Which is better? getField() or getDeclaredField()? getFiled() seems like better chioce if we want to add getter to child classes.
CtField traceVariable = ctClass.getField(variableName);
CtMethod getterMethod = CtNewMethod.getter(getterName, traceVariable);
CtMethod getterMethod = CtNewMethod.make("public " + traceVariable.getType().getName() + " " + getterName + "() { return " + variableName + "; }", ctClass);
ctClass.addMethod(getterMethod);
} catch (NotFoundException ex) {
throw new InstrumentException(variableName + " addVariableAccessor fail. Cause:" + ex.getMessage(), ex);
@@ -965,14 +976,49 @@ public class JavaAssistClass implements InstrumentClass {
}
try {
CtMethod getterMethod = CtNewMethod.make("public " + getter.getReturnType().getName() + " " + getter.getName() + "() { return " + fieldName + "; }", ctClass);
CtField field = ctClass.getField(fieldName);
String expression;
if (field.getType().isPrimitive()) {
String fieldType = field.getType().getName();
String wrapperType = getWrapperClassName(fieldType);
expression = wrapperType + ".valueOf(" + fieldName + ")";
} else {
expression = fieldName;
}
CtMethod getterMethod = CtNewMethod.make("public " + getter.getReturnType().getName() + " " + getter.getName() + "() { return " + expression + "; }", ctClass);
ctClass.addMethod(getterMethod);
CtClass ctInterface = instrumentor.getClass(interfaceType.getClassLoader(), interfaceType.getName());
ctClass.addInterface(ctInterface);
} catch (NotFoundException ex) {
throw new InstrumentException("Failed to add getter. No such field: " + fieldName, ex);
} catch (Exception e) {
// Cannot happen. Reaching here means a bug.
throw new InstrumentException("Fail to add getter: " + interfaceType.getName(), e);
}
}
private String getWrapperClassName(String primitiveType) {
if ("boolean".equals(primitiveType)) {
return "java.lang.Boolean";
} else if ("byte".equals(primitiveType)) {
return "java.lang.Byte";
} else if ("short".equals(primitiveType)) {
return "java.lang.Short";
} else if ("int".equals(primitiveType)) {
return "java.lang.Integer";
} else if ("long".equals(primitiveType)) {
return "java.lang.Long";
} else if ("float".equals(primitiveType)) {
return "java.lang.Float";
} else if ("double".equals(primitiveType)) {
return "java.lang.Double";
} else if ("void".equals(primitiveType)) {
return "java.lang.Void";
}
throw new IllegalArgumentException(primitiveType);
}
}
@@ -138,10 +138,6 @@ public class DefaultModifierRegistry implements ModifierRegistry {
addModifier(new DefaultHttpMethodRetryHandlerModifier(byteCodeInstrumentor, agent));
}
// JDK HTTPUrlConnector
HttpURLConnectionModifier httpURLConnectionModifier = new HttpURLConnectionModifier(byteCodeInstrumentor, agent);
addModifier(httpURLConnectionModifier);
// ning async http client
addModifier(new AsyncHttpClientModifier(byteCodeInstrumentor, agent));
@@ -18,6 +18,9 @@ package com.navercorp.pinpoint.profiler.modifier.connector.jdkhttpconnector;
import java.security.ProtectionDomain;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.navercorp.pinpoint.bootstrap.Agent;
import com.navercorp.pinpoint.bootstrap.instrument.ByteCodeInstrumentor;
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass;
@@ -25,15 +28,13 @@ import com.navercorp.pinpoint.bootstrap.instrument.InstrumentException;
import com.navercorp.pinpoint.profiler.modifier.AbstractModifier;
import com.navercorp.pinpoint.profiler.modifier.connector.jdkhttpconnector.interceptor.ConnectMethodInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* TODO Fix class loader issue.
* @author netspider
*
*/
public class HttpURLConnectionModifier extends AbstractModifier {
private final static String SCOPE = "HttpURLConnectoin";
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@@ -52,9 +53,22 @@ public class HttpURLConnectionModifier extends AbstractModifier {
try {
InstrumentClass aClass = byteCodeInstrumentor.getClass(classLoader, javassistClassName, classFileBuffer);
ConnectMethodInterceptor connectMethodInterceptor = new ConnectMethodInterceptor();
aClass.addInterceptor("connect", null, connectMethodInterceptor);
aClass.addScopeInterceptor("connect", null, connectMethodInterceptor, SCOPE);
ConnectMethodInterceptor getInputStreamInterceptor = new ConnectMethodInterceptor();
aClass.addScopeInterceptor("getInputStream", null, getInputStreamInterceptor, SCOPE);
ConnectMethodInterceptor getOutputStreamInterceptor = new ConnectMethodInterceptor();
aClass.addScopeInterceptor("getOutputStream", null, getOutputStreamInterceptor, SCOPE);
aClass.addGetter("__isConnected", "connected", "boolean");
if (aClass.hasField("connecting", "boolean")) {
aClass.addGetter("__isConnecting", "connecting", "boolean");
}
return aClass.toBytecode();
} catch (InstrumentException e) {
logger.warn("HttpURLConnectionModifier fail. Caused:", e.getMessage(), e);
@@ -30,6 +30,7 @@ import com.navercorp.pinpoint.bootstrap.interceptor.TraceContextSupport;
import com.navercorp.pinpoint.bootstrap.logging.PLogger;
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils;
import com.navercorp.pinpoint.bootstrap.util.MetaObject;
import com.navercorp.pinpoint.common.AnnotationKey;
import com.navercorp.pinpoint.common.ServiceType;
@@ -38,6 +39,7 @@ import com.navercorp.pinpoint.common.ServiceType;
* @author emeroad
*/
public class ConnectMethodInterceptor implements SimpleAroundInterceptor, ByteCodeMethodDescriptorSupport, TraceContextSupport {
private final MetaObject<Boolean> isConnected = new MetaObject<Boolean>("__isConnected");
private final PLogger logger = PLoggerFactory.getLogger(this.getClass());
private final boolean isDebug = logger.isDebugEnabled();
@@ -56,10 +58,13 @@ public class ConnectMethodInterceptor implements SimpleAroundInterceptor, ByteCo
}
HttpURLConnection request = (HttpURLConnection) target;
final boolean setRequestHeader = !isConnected.invoke(target);
final boolean sampling = trace.canSampled();
if (!sampling) {
request.setRequestProperty(Header.HTTP_SAMPLED.toString(), SamplingFlagUtils.SAMPLING_RATE_FALSE);
if (setRequestHeader) {
request.setRequestProperty(Header.HTTP_SAMPLED.toString(), SamplingFlagUtils.SAMPLING_RATE_FALSE);
}
return;
}
@@ -70,16 +75,17 @@ public class ConnectMethodInterceptor implements SimpleAroundInterceptor, ByteCo
TraceId nextId = trace.getTraceId().getNextTraceId();
trace.recordNextSpanId(nextId.getSpanId());
request.setRequestProperty(Header.HTTP_TRACE_ID.toString(), nextId.getTransactionId());
request.setRequestProperty(Header.HTTP_SPAN_ID.toString(), String.valueOf(nextId.getSpanId()));
request.setRequestProperty(Header.HTTP_PARENT_SPAN_ID.toString(), String.valueOf(nextId.getParentSpanId()));
request.setRequestProperty(Header.HTTP_FLAGS.toString(), String.valueOf(nextId.getFlags()));
request.setRequestProperty(Header.HTTP_PARENT_APPLICATION_NAME.toString(), traceContext.getApplicationName());
request.setRequestProperty(Header.HTTP_PARENT_APPLICATION_TYPE.toString(), Short.toString(traceContext.getServerTypeCode()));
trace.recordServiceType(ServiceType.JDK_HTTPURLCONNECTOR);
if (setRequestHeader) {
request.setRequestProperty(Header.HTTP_TRACE_ID.toString(), nextId.getTransactionId());
request.setRequestProperty(Header.HTTP_SPAN_ID.toString(), String.valueOf(nextId.getSpanId()));
request.setRequestProperty(Header.HTTP_PARENT_SPAN_ID.toString(), String.valueOf(nextId.getParentSpanId()));
request.setRequestProperty(Header.HTTP_FLAGS.toString(), String.valueOf(nextId.getFlags()));
request.setRequestProperty(Header.HTTP_PARENT_APPLICATION_NAME.toString(), traceContext.getApplicationName());
request.setRequestProperty(Header.HTTP_PARENT_APPLICATION_TYPE.toString(), Short.toString(traceContext.getServerTypeCode()));
}
// trace.recordServiceType(ServiceType.JDK_HTTPURLCONNECTOR);
final URL url = request.getURL();
final String host = url.getHost();
@@ -19,5 +19,6 @@ package com.navercorp.pinpoint.profiler.modifier.log;
* @author minwoo.jung
*/
public class MdcKey {
public static final String TRANSACTION_ID = "TransactionID";
public static final String TRANSACTION_ID = "PtransactionId";
public static final String SPAN_ID = "PspanId";
}
@@ -46,9 +46,11 @@ public class LoggingEventOfLog4jInterceptor implements SimpleAroundInterceptor,
if (trace == null) {
MDC.remove(MdcKey.TRANSACTION_ID);
MDC.remove(MdcKey.SPAN_ID);
return;
} else {
MDC.put(MdcKey.TRANSACTION_ID, trace.getTraceId().getTransactionId());
MDC.put(MdcKey.SPAN_ID, String.valueOf(trace.getTraceId().getSpanId()));
}
}
@@ -46,9 +46,11 @@ public class LoggingEventOfLogbackInterceptor implements SimpleAroundInterceptor
if (trace == null) {
MDC.remove(MdcKey.TRANSACTION_ID);
MDC.remove(MdcKey.SPAN_ID);
return;
} else {
MDC.put(MdcKey.TRANSACTION_ID, trace.getTraceId().getTransactionId());
MDC.put(MdcKey.SPAN_ID, String.valueOf(trace.getTraceId().getSpanId()));
}
}
@@ -28,9 +28,9 @@ import com.navercorp.pinpoint.bootstrap.MetadataAccessor;
import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig;
import com.navercorp.pinpoint.bootstrap.context.TraceContext;
import com.navercorp.pinpoint.bootstrap.instrument.ByteCodeInstrumentor;
import com.navercorp.pinpoint.bootstrap.plugin.ApplicationTypeDetector;
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginContext;
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext;
import com.navercorp.pinpoint.bootstrap.plugin.ServerTypeDetector;
import com.navercorp.pinpoint.bootstrap.plugin.editor.ClassEditor;
import com.navercorp.pinpoint.bootstrap.plugin.editor.ClassEditorBuilder;
import com.navercorp.pinpoint.profiler.DefaultAgent;
@@ -39,7 +39,7 @@ import com.navercorp.pinpoint.profiler.plugin.editor.DefaultClassEditorBuilder;
public class DefaultProfilerPluginContext implements ProfilerPluginSetupContext, ProfilerPluginContext {
private final DefaultAgent agent;
private final List<ServerTypeDetector> serverTypeDetectors = new ArrayList<ServerTypeDetector>();
private final List<ApplicationTypeDetector> serverTypeDetectors = new ArrayList<ApplicationTypeDetector>();
private final List<ClassEditor> classEditors = new ArrayList<ClassEditor>();
private final ConcurrentMap<String, Object> attributeMap = new ConcurrentHashMap<String, Object>();
@@ -54,8 +54,8 @@ public class DefaultProfilerPluginContext implements ProfilerPluginSetupContext,
}
@Override
public ClassEditorBuilder newClassEditorBuilder() {
return new DefaultClassEditorBuilder(this);
public ClassEditorBuilder getClassEditorBuilder(String targetClassName) {
return new DefaultClassEditorBuilder(this, targetClassName);
}
@Override
@@ -137,8 +137,8 @@ public class DefaultProfilerPluginContext implements ProfilerPluginSetupContext,
}
@Override
public void addServerTypeDetector(ServerTypeDetector... detectors) {
for (ServerTypeDetector detector : detectors) {
public void addApplicationTypeDetector(ApplicationTypeDetector... detectors) {
for (ApplicationTypeDetector detector : detectors) {
serverTypeDetectors.add(detector);
}
}
@@ -147,7 +147,7 @@ public class DefaultProfilerPluginContext implements ProfilerPluginSetupContext,
return classEditors;
}
public List<ServerTypeDetector> getServerTypeDetectors() {
public List<ApplicationTypeDetector> getApplicationTypeDetectors() {
return serverTypeDetectors;
}
}
@@ -22,6 +22,7 @@ import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -35,12 +36,22 @@ public class PluginClassLoaderFactory {
private final URL[] pluginJars;
private final ConcurrentHashMap<ClassLoader, ClassLoader> cache = new ConcurrentHashMap<ClassLoader, ClassLoader>();
private final AtomicReference<ClassLoader> forBootstrapClassLoader = new AtomicReference<ClassLoader>();
public PluginClassLoaderFactory(URL[] pluginJars) {
this.pluginJars = pluginJars;
}
public ClassLoader get(ClassLoader loader) {
public ClassLoader get(ClassLoader loader) {
if (loader == null) {
// boot class loader
return getForBootstrap();
} else {
return getForPlain(loader);
}
}
private ClassLoader getForPlain(ClassLoader loader) {
final ClassLoader forPlugin = cache.get(loader);
if (forPlugin != null) {
return forPlugin;
@@ -50,12 +61,32 @@ public class PluginClassLoaderFactory {
final ClassLoader before = cache.putIfAbsent(loader, newInstance);
if (before == null) {
return newInstance;
}
else {
} else {
close (newInstance);
return before;
}
}
private ClassLoader getForBootstrap() {
final ClassLoader forPlugin = forBootstrapClassLoader.get();
if (forPlugin != null) {
return forPlugin;
}
// Strictly, should pass null as parent class loader.
// But if so, All the types used by interceptors have to be loaded by bootstrap class loader.
// So we use system class loader as parent.
final ClassLoader newInstance = createPluginClassLoader(pluginJars, ClassLoader.getSystemClassLoader());
boolean success = forBootstrapClassLoader.compareAndSet(null, newInstance);
if (success) {
return newInstance;
} else {
close (newInstance);
return forBootstrapClassLoader.get();
}
}
private PluginClassLoader createPluginClassLoader(final URL[] urls, final ClassLoader parent) {
if (SECURITY_MANAGER != null) {
@@ -17,29 +17,24 @@
package com.navercorp.pinpoint.profiler.plugin.editor;
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass;
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginContext;
import com.navercorp.pinpoint.bootstrap.plugin.editor.ClassCondition;
import com.navercorp.pinpoint.bootstrap.plugin.editor.DedicatedClassEditor;
public class ConditionalClassEditor implements DedicatedClassEditor {
public class ConditionalClassRecipe implements ClassRecipe {
private final ProfilerPluginContext context;
private final ClassCondition condition;
private final DedicatedClassEditor delegate;
private final ClassRecipe delegate;
public ConditionalClassEditor(ClassCondition condition, DedicatedClassEditor delegate) {
public ConditionalClassRecipe(ProfilerPluginContext context, ClassCondition condition, ClassRecipe delegate) {
this.context = context;
this.condition = condition;
this.delegate = delegate;
}
@Override
public byte[] edit(ClassLoader classLoader, InstrumentClass target) {
if (condition.check(classLoader, target)) {
return delegate.edit(classLoader, target);
public void edit(ClassLoader classLoader, InstrumentClass target) throws Exception {
if (condition.check(context, classLoader, target)) {
delegate.edit(classLoader, target);
}
return null;
}
@Override
public String getTargetClassName() {
return delegate.getTargetClassName();
}
}
@@ -17,20 +17,23 @@
package com.navercorp.pinpoint.profiler.plugin.editor;
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass;
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginContext;
import com.navercorp.pinpoint.bootstrap.plugin.editor.ClassCondition;
public class ConditionalMethodEditor implements MethodEditor {
private final ProfilerPluginContext context;
private final ClassCondition condition;
private final MethodEditor delegate;
public ConditionalMethodEditor(ClassCondition condition, MethodEditor delegate) {
public ConditionalMethodEditor(ProfilerPluginContext context, ClassCondition condition, MethodEditor delegate) {
this.context = context;
this.condition = condition;
this.delegate = delegate;
}
@Override
public void edit(ClassLoader classLoader, InstrumentClass target) throws Exception {
if (condition.check(classLoader, target)) {
if (condition.check(context, classLoader, target)) {
delegate.edit(classLoader, target);
}
}
@@ -26,6 +26,8 @@ import com.navercorp.pinpoint.bootstrap.MetadataAccessor;
import com.navercorp.pinpoint.bootstrap.instrument.MethodFilter;
import com.navercorp.pinpoint.bootstrap.plugin.editor.ClassCondition;
import com.navercorp.pinpoint.bootstrap.plugin.editor.ClassEditorBuilder;
import com.navercorp.pinpoint.bootstrap.plugin.editor.ConditionalClassEditorBuilder;
import com.navercorp.pinpoint.bootstrap.plugin.editor.ConditionalClassEditorSetup;
import com.navercorp.pinpoint.bootstrap.plugin.editor.ConstructorEditorBuilder;
import com.navercorp.pinpoint.bootstrap.plugin.editor.DedicatedClassEditor;
import com.navercorp.pinpoint.bootstrap.plugin.editor.MethodEditorBuilder;
@@ -38,31 +40,34 @@ import com.navercorp.pinpoint.profiler.plugin.MetadataInjector;
import com.navercorp.pinpoint.profiler.plugin.interceptor.AnnotatedInterceptorInjector;
import com.navercorp.pinpoint.profiler.plugin.interceptor.TargetAnnotatedInterceptorInjector;
public class DefaultClassEditorBuilder implements ClassEditorBuilder {
public class DefaultClassEditorBuilder implements ClassEditorBuilder, ConditionalClassEditorBuilder, RecipeBuilder<ClassRecipe> {
private final DefaultProfilerPluginContext pluginContext;
private final List<ClassRecipe> recipes = new ArrayList<ClassRecipe>();
private final List<RecipeBuilder<ClassRecipe>> recipeBuilders = new ArrayList<RecipeBuilder<ClassRecipe>>();
private String targetClassName;
private ClassCondition condition;
private final ClassCondition condition;
private final String targetClassName;
public DefaultClassEditorBuilder(DefaultProfilerPluginContext pluginContext) {
this.pluginContext = pluginContext;
}
@Override
public void target(String targetClassName) {
this.targetClassName = targetClassName;
public DefaultClassEditorBuilder(DefaultProfilerPluginContext pluginContext, String targetClassName) {
this(pluginContext, targetClassName, null);
}
@Override
public void condition(ClassCondition condition) {
private DefaultClassEditorBuilder(DefaultProfilerPluginContext pluginContext, String targetClassName, ClassCondition condition) {
this.pluginContext = pluginContext;
this.targetClassName = targetClassName;
this.condition = condition;
}
@Override
public void conditional(ClassCondition condition, ConditionalClassEditorSetup describer) {
DefaultClassEditorBuilder conditional = new DefaultClassEditorBuilder(pluginContext, targetClassName, condition);
describer.setup(conditional);
recipeBuilders.add(conditional);
}
@Override
public void injectFieldSnooper(String fieldName) {
public void injectFieldAccessor(String fieldName) {
FieldAccessor snooper = pluginContext.allocateFieldSnooper(fieldName);
recipes.add(new FieldSnooperInjector(snooper, fieldName));
}
@@ -113,25 +118,14 @@ public class DefaultClassEditorBuilder implements ClassEditorBuilder {
@Override
public DedicatedClassEditor build() {
ClassRecipe recipe = buildClassRecipe();
DedicatedClassEditor editor = buildClassEditor(recipe);
return editor;
}
private DedicatedClassEditor buildClassEditor(ClassRecipe recipe) {
DedicatedClassEditor editor = new DefaultDedicatedClassEditor(targetClassName, recipe);
if (condition != null) {
editor = new ConditionalClassEditor(condition, editor);
}
return editor;
return new DefaultDedicatedClassEditor(targetClassName, recipe);
}
private ClassRecipe buildClassRecipe() {
List<ClassRecipe> recipes = new ArrayList<ClassRecipe>(this.recipes);
for (RecipeBuilder<ClassRecipe> builder : recipeBuilders) {
recipes.add(builder.build());
recipes.add(builder.buildRecipe());
}
if (recipes.isEmpty()) {
@@ -142,10 +136,19 @@ public class DefaultClassEditorBuilder implements ClassEditorBuilder {
return recipe;
}
private interface RecipeBuilder<T> {
public T build();
@Override
public ClassRecipe buildRecipe() {
if (condition == null) {
throw new IllegalStateException();
}
ClassRecipe recipe = buildClassRecipe();
return new ConditionalClassRecipe(pluginContext, condition, recipe);
}
private class TargetAnnotatedInterceptorInjectorBuilder implements RecipeBuilder<ClassRecipe> {
private final String interceptorClassName;
private final Object[] constructorArguments;
@@ -156,7 +159,7 @@ public class DefaultClassEditorBuilder implements ClassEditorBuilder {
}
@Override
public ClassRecipe build() {
public ClassRecipe buildRecipe() {
return new TargetAnnotatedInterceptorInjector(pluginContext, interceptorClassName, constructorArguments);
}
}
@@ -171,7 +174,7 @@ public class DefaultClassEditorBuilder implements ClassEditorBuilder {
}
@Override
public MethodRecipe build() {
public MethodRecipe buildRecipe() {
return new AnnotatedInterceptorInjector(pluginContext, interceptorClassName, constructorArguments);
}
}
@@ -182,7 +185,6 @@ public class DefaultClassEditorBuilder implements ClassEditorBuilder {
private final MethodFilter filter;
private final List<RecipeBuilder<MethodRecipe>> recipeBuilders = new ArrayList<RecipeBuilder<MethodRecipe>>();
private final EnumSet<MethodEditorProperty> properties = EnumSet.noneOf(MethodEditorProperty.class);
private ClassCondition condition;
private MethodEditorExceptionHandler exceptionHandler;
private DefaultMethodEditorBuilder(String... parameterTypeNames) {
@@ -203,11 +205,6 @@ public class DefaultClassEditorBuilder implements ClassEditorBuilder {
this.filter = filter;
}
@Override
public void condition(ClassCondition condition) {
this.condition = condition;
}
@Override
public void property(MethodEditorProperty... properties) {
this.properties.addAll(Arrays.asList(properties));
@@ -223,7 +220,8 @@ public class DefaultClassEditorBuilder implements ClassEditorBuilder {
this.exceptionHandler = handler;
}
public MethodEditor build() {
@Override
public MethodEditor buildRecipe() {
List<MethodRecipe> recipes = buildMethodRecipe();
MethodEditor editor = buildMethodEditor(recipes);
@@ -240,10 +238,6 @@ public class DefaultClassEditorBuilder implements ClassEditorBuilder {
editor = new ConstructorEditor(parameterTypeNames, recipes, exceptionHandler, properties.contains(MethodEditorProperty.IGNORE_IF_NOT_EXIST));
}
if (condition != null) {
editor = new ConditionalMethodEditor(condition, editor);
}
return editor;
}
@@ -256,7 +250,7 @@ public class DefaultClassEditorBuilder implements ClassEditorBuilder {
List<MethodRecipe> recipes = new ArrayList<MethodRecipe>(recipeBuilders.size());
for (RecipeBuilder<MethodRecipe> builder : recipeBuilders) {
recipes.add(builder.build());
recipes.add(builder.buildRecipe());
}
return recipes;
@@ -0,0 +1,23 @@
/**
* 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.plugin.editor;
/**
* @author Jongho Moon
*
*/
interface RecipeBuilder<T> {
T buildRecipe();
}
@@ -17,85 +17,73 @@
package com.navercorp.pinpoint.profiler.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.navercorp.pinpoint.bootstrap.plugin.ServerTypeDetector;
import com.navercorp.pinpoint.bootstrap.plugin.ApplicationTypeDetector;
import com.navercorp.pinpoint.bootstrap.resolver.ApplicationServerTypePluginResolver;
import com.navercorp.pinpoint.common.ServiceType;
import com.navercorp.pinpoint.common.service.ServiceTypeRegistryService;
import com.navercorp.pinpoint.profiler.plugin.DefaultProfilerPluginContext;
/**
* @author emeroad
* @author netspider
* @author hyungil.jeong
*/
public class ApplicationServerTypeResolver {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private ServiceType serverType;
private final ServiceType defaultType;
private final List<ServerTypeDetector> detectors = new ArrayList<ServerTypeDetector>();
private final ApplicationServerTypePluginResolver resolver;
private final List<ApplicationTypeDetector> detectors = new ArrayList<ApplicationTypeDetector>();
private final ServiceTypeRegistryService serviceTypeRegistryService;
public ApplicationServerTypeResolver(List<DefaultProfilerPluginContext> plugins, ServiceType defaultType, ServiceTypeRegistryService serviceTypeRegistryService) {
if (serviceTypeRegistryService == null) {
throw new NullPointerException("serviceTypeRegistryService must not be null");
public ApplicationServerTypeResolver(List<DefaultProfilerPluginContext> plugins, ServiceType defaultType, List<String> orderedDetectors) {
if (isValidApplicationServerType(defaultType)) {
this.defaultType = defaultType;
} else {
this.defaultType = ServiceType.UNDEFINED;
}
this.serviceTypeRegistryService = serviceTypeRegistryService;
this.defaultType = defaultType;
for (DefaultProfilerPluginContext context : plugins) {
detectors.addAll(context.getServerTypeDetectors());
Map<String, ApplicationTypeDetector> registeredDetectors = getRegisteredServerTypeDetectors(plugins);
for (String orderedDetector : orderedDetectors) {
if (registeredDetectors.containsKey(orderedDetector)) {
this.detectors.add(registeredDetectors.remove(orderedDetector));
}
}
}
public String[] getServerLibPath() {
return new String[0];
}
public ServiceType getServerType() {
return serverType;
this.detectors.addAll(registeredDetectors.values());
this.resolver = new ApplicationServerTypePluginResolver(this.detectors);
}
public boolean resolve() {
String serverType = null;
for (ServerTypeDetector detector : detectors) {
logger.debug("try to resolve using {}", detector.getClass());
if (serverType != null && !detector.canOverride(serverType)) {
continue;
}
if (detector.detect()) {
serverType = detector.getServerTypeName();
if (logger.isInfoEnabled()) {
logger.info("Resolved applicationServerType [{}] by {}", serverType, detector.getClass().getName());
}
private Map<String, ApplicationTypeDetector> getRegisteredServerTypeDetectors(List<DefaultProfilerPluginContext> plugins) {
Map<String, ApplicationTypeDetector> registeredDetectors = new HashMap<String, ApplicationTypeDetector>();
for (DefaultProfilerPluginContext context : plugins) {
for (ApplicationTypeDetector detector : context.getApplicationTypeDetectors()) {
registeredDetectors.put(detector.getClass().getName(), detector);
}
}
if (serverType != null) {
this.serverType = serviceTypeRegistryService.findServiceTypeByName(serverType);
return true;
}
if (defaultType != null) {
// TODO validate default type. is defaultType a server type?
this.serverType = defaultType;
return registeredDetectors;
}
public ServiceType resolve() {
ServiceType resolvedApplicationServerType;
if (this.defaultType == ServiceType.UNDEFINED) {
resolvedApplicationServerType = this.resolver.resolve();
logger.info("Resolved ApplicationServerType : {}", resolvedApplicationServerType.getName());
} else {
this.serverType = ServiceType.STAND_ALONE;
resolvedApplicationServerType = this.defaultType;
logger.info("Configured ApplicationServerType : {}", resolvedApplicationServerType.getName());
}
if (logger.isInfoEnabled()) {
logger.info("Configured applicationServerType:{}", defaultType);
return resolvedApplicationServerType;
}
private boolean isValidApplicationServerType(ServiceType serviceType) {
if (serviceType == null) {
return false;
}
return true;
return serviceType.isWas();
}
}
@@ -43,6 +43,8 @@ import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier;
import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder;
import com.navercorp.pinpoint.common.AnnotationKey;
import com.navercorp.pinpoint.common.ServiceType;
import com.navercorp.pinpoint.common.service.AnnotationKeyRegistryService;
import com.navercorp.pinpoint.common.service.DefaultAnnotationKeyRegistryService;
import com.navercorp.pinpoint.common.service.ServiceTypeRegistryService;
import com.navercorp.pinpoint.profiler.DefaultAgent;
import com.navercorp.pinpoint.profiler.context.Span;
@@ -114,7 +116,7 @@ public class PluginTestAgent extends DefaultAgent implements PluginTestVerifier
ServiceType expectedType = findServiceType(serviceTypeName);
ServiceType actualType = getAgentInformation().getServerType();
if (expectedType != actualType) {
if (!expectedType.equals(actualType)) {
throw new AssertionError("Expected server type: " + expectedType.getName() + "[" + expectedType.getCode() + "] but was " + actualType + "[" + actualType.getCode() + "]");
}
}
@@ -202,7 +204,7 @@ public class PluginTestAgent extends DefaultAgent implements PluginTestVerifier
public void verifySpanEvent(String serviceTypeName, Method method, String rpc, String endPoint, String destinationId, ExpectedAnnotation... annotations) {
ServiceType serviceType = findServiceType(serviceTypeName);
int apiId = findApiId(method);
Expected expected = new Expected(Span.class, serviceType, apiId, rpc, endPoint, null, destinationId, annotations);
Expected expected = new Expected(SpanEvent.class, serviceType, apiId, rpc, endPoint, null, destinationId, annotations);
verifySpan(expected);
}
@@ -453,7 +453,8 @@ public class JavaAssistClassTest {
public void testAddGetter() throws Exception {
final TestClassLoader loader = getTestClassLoader();
final String testClassObject = "com.navercorp.pinpoint.profiler.interceptor.bci.TestObject3";
final FieldAccessor snooper = FieldAccessor.get(0);
final FieldAccessor accessor0 = FieldAccessor.get(0);
final FieldAccessor accessor1 = FieldAccessor.get(1);
final TestModifier testModifier = new TestModifier(loader.getInstrumentor(), loader.getProfilerConfig()) {
@Override
@@ -461,7 +462,8 @@ public class JavaAssistClassTest {
try {
logger.info("modify cl:{}", classLoader);
InstrumentClass aClass = byteCodeInstrumentor.getClass(classLoader, testClassObject, classFileBuffer);
aClass.addGetter(snooper.getType(), "value");
aClass.addGetter(accessor0.getType(), "value");
aClass.addGetter(accessor1.getType(), "intValue");
return aClass.toBytecode();
} catch (InstrumentException e) {
@@ -475,15 +477,21 @@ public class JavaAssistClassTest {
loader.initialize();
Object testObject = loader.loadClass(testClassObject).newInstance();
Assert.assertTrue(snooper.isApplicable(testObject));
Assert.assertTrue(accessor0.isApplicable(testObject));
Assert.assertTrue(accessor1.isApplicable(testObject));
String value = "hehe";
int intValue = 99;
Method method = testObject.getClass().getMethod("setValue", String.class);
method.invoke(testObject, value);
Assert.assertEquals(value, snooper.get(testObject));
Assert.assertEquals(value, accessor0.get(testObject));
Method setIntValue = testObject.getClass().getMethod("setIntValue", int.class);
setIntValue.invoke(testObject, intValue);
Assert.assertEquals(intValue, accessor1.get(testObject));
}
}
@@ -20,10 +20,15 @@ package com.navercorp.pinpoint.profiler.interceptor.bci;
*/
public class TestObject3 {
private String value;
private int intValue;
public void setValue(String value) {
this.value = value;
}
public void setIntValue(int value) {
this.intValue = value;
}
@Override
public String toString() {
@@ -63,9 +63,9 @@ public class DefaultClassEditorBuilderTest {
when(aClass.addInterceptor(eq(methodName), eq(parameterTypeNames), isA(Interceptor.class))).thenReturn(0);
DefaultProfilerPluginContext context = new DefaultProfilerPluginContext(agent);
DefaultClassEditorBuilder builder = new DefaultClassEditorBuilder(context);
DefaultClassEditorBuilder builder = new DefaultClassEditorBuilder(context, "TargetClass");
builder.injectMetadata("a", "java.util.HashMap");
builder.injectFieldSnooper("someField");
builder.injectFieldAccessor("someField");
MethodEditorBuilder ib = builder.editMethod(methodName, parameterTypeNames);
ib.injectInterceptor("com.navercorp.pinpoint.profiler.plugin.TestInterceptor", "provided");
@@ -1,197 +1,201 @@
#
# Pinpoint agent configuration
#
###########################################################
# Collector server #
###########################################################
profiler.collector.ip=127.0.0.1
# placeHolder support "${key}"
profiler.collector.span.ip=${profiler.collector.ip}
profiler.collector.span.port=9996
# placeHolder support "${key}"
profiler.collector.stat.ip=${profiler.collector.ip}
profiler.collector.stat.port=9995
# placeHolder support "${key}"
profiler.collector.tcp.ip=${profiler.collector.ip}
profiler.collector.tcp.port=9994
###########################################################
# Profiler Global Configuration #
###########################################################
profiler.enable=true
profiler.jvm.collect.interval=1000
profiler.sampling.enable=true
# Set sampling rate. If you set it to 10, 1 out of 10 transaction will be sampled.
profiler.sampling.rate=1
profiler.io.buffering.enable=true
profiler.io.buffering.buffersize=20
profiler.spandatasender.write.queue.size=5120
#profiler.spandatasender.socket.sendbuffersize=1048576
#profiler.spandatasender.socket.timeout=3000
profiler.spandatasender.chunk.size=16384
profiler.statdatasender.write.queue.size=5120
#profiler.statdatasender.socket.sendbuffersize=1048576
#profiler.statdatasender.socket.timeout=3000
profiler.statdatasender.chunk.size=16384
profiler.agentInfo.send.retry.interval=300000
# Allows TCP data command
profiler.tcpdatasender.command.accept.enable=true
###########################################################
# application type #
###########################################################
#profiler.applicationservertype=TOMCAT
#profiler.applicationservertype=BLOC
###########################################################
# user defined classes #
###########################################################
profiler.include=
###########################################################
# TOMCAT #
###########################################################
profiler.tomcat.hidepinpointheader=true
profiler.tomcat.excludeurl=/aa/test.html, /bb/exclude.html
###########################################################
# JDBC #
###########################################################
profiler.jdbc=true
profiler.jdbc.sqlcachesize=1024
profiler.jdbc.maxsqlbindvaluesize=1024
#
# MYSQL
#
profiler.jdbc.mysql=true
profiler.jdbc.mysql.setautocommit=true
profiler.jdbc.mysql.commit=true
profiler.jdbc.mysql.rollback=true
#
# MSSQL Jtds
#
profiler.jdbc.jtds=true
profiler.jdbc.jtds.setautocommit=true
profiler.jdbc.jtds.commit=true
profiler.jdbc.jtds.rollback=true
#
# Oracle
#
profiler.jdbc.oracle=true
profiler.jdbc.oracle.setautocommit=true
profiler.jdbc.oracle.commit=true
profiler.jdbc.oracle.rollback=true
#
# CUBRID
#
profiler.jdbc.cubrid=true
profiler.jdbc.cubrid.setautocommit=true
profiler.jdbc.cubrid.commit=true
profiler.jdbc.cubrid.rollback=true
#
# DBCP
#
profiler.jdbc.dbcp=true
profiler.jdbc.dbcp.connectionclose=true
###########################################################
# Apache HTTP Client 4.x #
###########################################################
profiler.apache.httpclient4=true
profiler.apache.httpclient4.cookie=true
# When cookies should be dumped. It could be ALWAYS or EXCEPTION.
profiler.apache.httpclient4.cookie.dumptype=ALWAYS
profiler.apache.httpclient4.cookie.sampling.rate=1
# Dump entities of POST or PUT request. limited to entities which is HttpEtity.isRepeatable() == true.
profiler.apache.httpclient4.entity=true
# When entities should be dumped. ALWAYS or EXCEPTION.
profiler.apache.httpclient4.entity.dumptype=ALWAYS
profiler.apache.httpclient4.entity.sampling.rate=1
profiler.apache.nio.httpclient4=true
###########################################################
# Ning Async HTTP Client #
###########################################################
profiler.ning.asynchttpclient=true
profiler.ning.asynchttpclient.cookie=true
profiler.ning.asynchttpclient.cookie.dumptype=ALWAYS
profiler.ning.asynchttpclient.cookie.dumpsize=1024
profiler.ning.asynchttpclient.cookie.sampling.rate=1
profiler.ning.asynchttpclient.entity=true
profiler.ning.asynchttpclient.entity.dumptype=ALWAYS
profiler.ning.asynchttpclient.entity.dumpsize=1024
profiler.ning.asynchttpclient.entity.sampling.rate=1
profiler.ning.asynchttpclient.param=true
profiler.ning.asynchttpclient.param.dumptype=ALWAYS
profiler.ning.asynchttpclient.param.dumpsize=1024
profiler.ning.asynchttpclient.param.sampling.rate=1
###########################################################
# Arcus #
###########################################################
profiler.arcus=true
profiler.arcus.keytrace=true
###########################################################
# Memcached #
###########################################################
profiler.memcached=true
profiler.memcached.keytrace=true
###########################################################
# ibatis #
###########################################################
profiler.orm.ibatis=true
###########################################################
# mybatis #
###########################################################
profiler.orm.mybatis=true
###########################################################
# spring-beans
###########################################################
profiler.spring.beans=true
profiler.spring.beans.name.pattern=ma.*, outer
profiler.spring.beans.class.pattern=.*Morae
profiler.spring.beans.annotation=org.springframework.stereotype.Component
###########################################################
# log4j
###########################################################
profiler.log4j.logging.transactioninfo=false
###########################################################
# logback
###########################################################
profiler.logback.logging.transactioninfo=false
#
# Pinpoint agent configuration
#
###########################################################
# Collector server #
###########################################################
profiler.collector.ip=127.0.0.1
# placeHolder support "${key}"
profiler.collector.span.ip=${profiler.collector.ip}
profiler.collector.span.port=9996
# placeHolder support "${key}"
profiler.collector.stat.ip=${profiler.collector.ip}
profiler.collector.stat.port=9995
# placeHolder support "${key}"
profiler.collector.tcp.ip=${profiler.collector.ip}
profiler.collector.tcp.port=9994
###########################################################
# Profiler Global Configuration #
###########################################################
profiler.enable=true
profiler.jvm.collect.interval=1000
profiler.sampling.enable=true
# Set sampling rate. If you set it to 10, 1 out of 10 transaction will be sampled.
profiler.sampling.rate=1
profiler.io.buffering.enable=true
profiler.io.buffering.buffersize=20
profiler.spandatasender.write.queue.size=5120
#profiler.spandatasender.socket.sendbuffersize=1048576
#profiler.spandatasender.socket.timeout=3000
profiler.spandatasender.chunk.size=16384
profiler.statdatasender.write.queue.size=5120
#profiler.statdatasender.socket.sendbuffersize=1048576
#profiler.statdatasender.socket.timeout=3000
profiler.statdatasender.chunk.size=16384
profiler.agentInfo.send.retry.interval=300000
# Allows TCP data command
profiler.tcpdatasender.command.accept.enable=true
###########################################################
# application type #
###########################################################
#profiler.applicationservertype=TOMCAT
#profiler.applicationservertype=BLOC
###########################################################
# application type detect order #
###########################################################
profiler.type.detect.order=
###########################################################
# user defined classes #
###########################################################
profiler.include=
###########################################################
# TOMCAT #
###########################################################
profiler.tomcat.hidepinpointheader=true
profiler.tomcat.excludeurl=/aa/test.html, /bb/exclude.html
###########################################################
# JDBC #
###########################################################
profiler.jdbc=true
profiler.jdbc.sqlcachesize=1024
profiler.jdbc.maxsqlbindvaluesize=1024
#
# MYSQL
#
profiler.jdbc.mysql=true
profiler.jdbc.mysql.setautocommit=true
profiler.jdbc.mysql.commit=true
profiler.jdbc.mysql.rollback=true
#
# MSSQL Jtds
#
profiler.jdbc.jtds=true
profiler.jdbc.jtds.setautocommit=true
profiler.jdbc.jtds.commit=true
profiler.jdbc.jtds.rollback=true
#
# Oracle
#
profiler.jdbc.oracle=true
profiler.jdbc.oracle.setautocommit=true
profiler.jdbc.oracle.commit=true
profiler.jdbc.oracle.rollback=true
#
# CUBRID
#
profiler.jdbc.cubrid=true
profiler.jdbc.cubrid.setautocommit=true
profiler.jdbc.cubrid.commit=true
profiler.jdbc.cubrid.rollback=true
#
# DBCP
#
profiler.jdbc.dbcp=true
profiler.jdbc.dbcp.connectionclose=true
###########################################################
# Apache HTTP Client 4.x #
###########################################################
profiler.apache.httpclient4=true
profiler.apache.httpclient4.cookie=true
# When cookies should be dumped. It could be ALWAYS or EXCEPTION.
profiler.apache.httpclient4.cookie.dumptype=ALWAYS
profiler.apache.httpclient4.cookie.sampling.rate=1
# Dump entities of POST or PUT request. limited to entities which is HttpEtity.isRepeatable() == true.
profiler.apache.httpclient4.entity=true
# When entities should be dumped. ALWAYS or EXCEPTION.
profiler.apache.httpclient4.entity.dumptype=ALWAYS
profiler.apache.httpclient4.entity.sampling.rate=1
profiler.apache.nio.httpclient4=true
###########################################################
# Ning Async HTTP Client #
###########################################################
profiler.ning.asynchttpclient=true
profiler.ning.asynchttpclient.cookie=true
profiler.ning.asynchttpclient.cookie.dumptype=ALWAYS
profiler.ning.asynchttpclient.cookie.dumpsize=1024
profiler.ning.asynchttpclient.cookie.sampling.rate=1
profiler.ning.asynchttpclient.entity=true
profiler.ning.asynchttpclient.entity.dumptype=ALWAYS
profiler.ning.asynchttpclient.entity.dumpsize=1024
profiler.ning.asynchttpclient.entity.sampling.rate=1
profiler.ning.asynchttpclient.param=true
profiler.ning.asynchttpclient.param.dumptype=ALWAYS
profiler.ning.asynchttpclient.param.dumpsize=1024
profiler.ning.asynchttpclient.param.sampling.rate=1
###########################################################
# Arcus #
###########################################################
profiler.arcus=true
profiler.arcus.keytrace=true
###########################################################
# Memcached #
###########################################################
profiler.memcached=true
profiler.memcached.keytrace=true
###########################################################
# ibatis #
###########################################################
profiler.orm.ibatis=true
###########################################################
# mybatis #
###########################################################
profiler.orm.mybatis=true
###########################################################
# spring-beans
###########################################################
profiler.spring.beans=true
profiler.spring.beans.name.pattern=ma.*, outer
profiler.spring.beans.class.pattern=.*Morae
profiler.spring.beans.annotation=org.springframework.stereotype.Component
###########################################################
# log4j
###########################################################
profiler.log4j.logging.transactioninfo=false
###########################################################
# logback
###########################################################
profiler.logback.logging.transactioninfo=false
+5 -1
View File
@@ -55,6 +55,10 @@ profiler.tcpdatasender.command.accept.enable=true
#profiler.applicationservertype=TOMCAT
#profiler.applicationservertype=BLOC
###########################################################
# application type detect order #
###########################################################
profiler.type.detect.order=
###########################################################
# user defined classes #
@@ -206,4 +210,4 @@ profiler.log4j.logging.transactioninfo=false
###########################################################
# logback
###########################################################
profiler.logback.logging.transactioninfo=false
profiler.logback.logging.transactioninfo=false
@@ -99,6 +99,10 @@ public abstract class AbstractPinpointPluginTestSuite extends Suite {
javaHome = SystemProperty.INSTANCE.getEnv(envName);
}
if (javaHome == null) {
return null;
}
builder.append(javaHome);
builder.append(File.separatorChar);
builder.append("bin");
@@ -219,6 +223,14 @@ public abstract class AbstractPinpointPluginTestSuite extends Suite {
try {
for (int ver : jvmVersions) {
String javaExe = getJavaExecutable(ver);
// TODO for now, java 8 is not mandatory to build pinpoint.
// so failing to find java installation should not cause build failure.
if (javaExe == null) {
System.out.println("Cannot find Java version " + ver + ". Skip test with Java " + ver);
continue;
}
PinpointPluginTestContext context = new PinpointPluginTestContext(agentJar, configFile, requiredLibraries, getTestClass().getJavaClass(), testClassLocation, jvmArguments, debug, ver, javaExe);
List<PinpointPluginTestInstance> cases = createTestCases(context);
@@ -18,7 +18,6 @@ import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -29,9 +28,6 @@ import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import com.navercorp.pinpoint.common.util.SimpleProperty;
import com.navercorp.pinpoint.common.util.SystemProperty;
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
@@ -65,13 +61,15 @@ import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.navercorp.pinpoint.bootstrap.PinpointBootStrap;
import com.navercorp.pinpoint.common.util.SimpleProperty;
import com.navercorp.pinpoint.common.util.SystemProperty;
/**
* @author Jongho Moon
*
*/
public class DependencyResolver {
private static final String FOLLOW_PRECEDING = "FOLLOW_PRECEDING";
private static final String FOLLOW_PRECEEDING = "FOLLOW_PRECEEDING";
private static final String DEFAULT_LOCAL_REPOSITORY = "target/local-repo";
private static final Logger logger = Logger.getLogger(PinpointBootStrap.class.getName());
@@ -241,12 +239,12 @@ public class DependencyResolver {
int second = a.indexOf(':', first + 1);
if (second == -1) {
a += ":" + FOLLOW_PRECEDING;
a += ":" + FOLLOW_PRECEEDING;
}
DefaultArtifact artifact = new DefaultArtifact(a);
if (FOLLOW_PRECEDING.equals(artifact.getVersion())) {
if (FOLLOW_PRECEEDING.equals(artifact.getVersion())) {
if (lastCompanion != null) {
lastCompanion.add(artifact);
} else {
@@ -22,7 +22,6 @@ import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import org.junit.runner.Description;
import org.junit.runner.JUnitCore;
@@ -59,8 +59,11 @@ public class ForkedPinpointPluginTestRunner extends BlockJUnit4ClassRunner {
PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance();
verifier.initialize(manageTraceObject);
fromSuper.evaluate();
verifier.cleanUp(manageTraceObject);
try {
fromSuper.evaluate();
} finally {
verifier.cleanUp(manageTraceObject);
}
}
};
}
@@ -14,7 +14,6 @@
*/
package com.navercorp.pinpoint.test.plugin;
import java.util.regex.Pattern;
/**
* @author Jongho Moon
@@ -0,0 +1,45 @@
/**
* 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.test.plugin;
/**
* @author Jongho Moon
*
*/
@SuppressWarnings("serial")
public class PinpointPluginTestException extends RuntimeException {
public PinpointPluginTestException(String message, StackTraceElement[] stackTrace) {
super(message);
setStackTrace(stackTrace);
}
public PinpointPluginTestException() {
super();
}
public PinpointPluginTestException(String message, Throwable cause) {
super(message, cause);
}
public PinpointPluginTestException(String message) {
super(message);
}
public PinpointPluginTestException(Throwable cause) {
super(cause);
}
}
@@ -214,7 +214,7 @@ public class PinpointPluginTestStatement extends Statement implements PinpointPl
return failure;
}
private ChildProcessException toException(String message, String exceptionClass, List<String> traceInText) {
private PinpointPluginTestException toException(String message, String exceptionClass, List<String> traceInText) {
StackTraceElement[] stackTrace = new StackTraceElement[traceInText.size()];
for (int i = 0; i < traceInText.size(); i++) {
@@ -224,6 +224,6 @@ public class PinpointPluginTestStatement extends Statement implements PinpointPl
stackTrace[i] = new StackTraceElement(tokens[0], tokens[1], tokens[2], Integer.parseInt(tokens[3]));
}
return new ChildProcessException(exceptionClass + ": " + message, stackTrace);
return new PinpointPluginTestException(exceptionClass + ": " + message, stackTrace);
}
}
@@ -18,6 +18,7 @@ import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
@@ -83,7 +84,21 @@ public class PinpointPluginTestSuite extends AbstractPinpointPluginTestSuite imp
return createCasesWithLibraryPath(context);
}
throw new IllegalStateException("Cannot happen");
return createCasesWithJdkOnly(context);
}
private List<PinpointPluginTestInstance> createCasesWithJdkOnly(PinpointPluginTestContext context) {
List<PinpointPluginTestInstance> cases = new ArrayList<PinpointPluginTestInstance>();
if (testOnSystemClassLoader) {
cases.add(new NormalPluginTestCase(context, "", Collections.<String>emptyList(), true));
}
if (testOnChildClassLoader) {
cases.add(new NormalPluginTestCase(context, "", Collections.<String>emptyList(), false));
}
return cases;
}
@@ -18,10 +18,24 @@ package com.navercorp.pinpoint.web.controller;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import com.navercorp.pinpoint.web.applicationmap.ApplicationMap;
import com.navercorp.pinpoint.web.calltree.span.SpanAlign;
import com.navercorp.pinpoint.web.filter.Filter;
@@ -36,19 +50,9 @@ import com.navercorp.pinpoint.web.vo.BusinessTransactions;
import com.navercorp.pinpoint.web.vo.LimitedScanResult;
import com.navercorp.pinpoint.web.vo.Range;
import com.navercorp.pinpoint.web.vo.TransactionId;
import com.navercorp.pinpoint.web.vo.callstacks.Record;
import com.navercorp.pinpoint.web.vo.callstacks.RecordSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
/**
* @author emeroad
*/
@@ -68,6 +72,9 @@ public class BusinessTransactionController {
@Autowired
private FilterBuilder filterBuilder;
@Value("#{pinpointWebProps['log.enable'] ?: false}")
private boolean logLinkEnable;
/**
* executed URLs in applicationname query within from ~ to timeframe
@@ -164,6 +171,7 @@ public class BusinessTransactionController {
ApplicationMap map = filteredMapService.selectApplicationMap(traceId);
mv.addObject("nodes", map.getNodes());
mv.addObject("links", map.getLinks());
mv.addObject("logLinkEnable", logLinkEnable);
// call stacks
RecordSet recordSet = this.transactionInfoService.createRecordSet(spanAligns, focusTimestamp);
@@ -38,6 +38,7 @@ import com.navercorp.pinpoint.web.vo.scatter.ScatterIndex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StopWatch;
@@ -64,6 +65,16 @@ public class ScatterChartController {
@Autowired
private FilterBuilder filterBuilder;
@Value("#{pinpointWebProps['log.enable'] ?: false}")
private boolean logLinkEnable;
@Value("#{pinpointWebProps['log.button.name'] ?: ''}")
private String logButtonName;
@Value("#{pinpointWebProps['log.page.url'] ?: ''}")
private String logPageUrl;
private static final String PREFIX_TRANSACTION_ID = "I";
private static final String PREFIX_TIME = "T";
@@ -222,7 +233,12 @@ public class ScatterChartController {
List<SpanBo> metadata = scatter.selectTransactionMetadata(query);
model.addAttribute("metadata", metadata);
}
if (logLinkEnable) {
model.addAttribute("logButtonName", logButtonName);
model.addAttribute("logPageUrl", logPageUrl);
}
return "transactionmetadata";
}
@@ -18,6 +18,8 @@ package com.navercorp.pinpoint.web.service;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import com.navercorp.pinpoint.common.AnnotationKey;
@@ -46,6 +48,7 @@ import org.apache.commons.lang.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
/**
@@ -68,6 +71,15 @@ public class TransactionInfoServiceImpl implements TransactionInfoService {
@Autowired
private AnnotationKeyRegistryService annotationKeyRegistryService;
@Value("#{pinpointWebProps['log.enable'] ?: false}")
private boolean logLinkEnable;
@Value("#{pinpointWebProps['log.button.name'] ?: ''}")
private String logButtonName;
@Value("#{pinpointWebProps['log.page.url'] ?: ''}")
private String logPageUrl;
@Override
public BusinessTransactions selectBusinessTransactions(List<TransactionId> transactionIdList, String applicationName, Range range, Filter filter) {
if (transactionIdList == null) {
@@ -153,6 +165,11 @@ public class TransactionInfoServiceImpl implements TransactionInfoService {
}
recordSet.setRecordList(recordList);
if (logLinkEnable) {
addlogLink(recordSet);
}
return recordSet;
}
@@ -165,6 +182,66 @@ public class TransactionInfoServiceImpl implements TransactionInfoService {
}
}
private void addlogLink(RecordSet recordSet) {
List<Record> records = recordSet.getRecordList();
List<TransactionInfo> transactionInfoes = new LinkedList<TransactionInfo>();
for (Iterator<Record> iterator = records.iterator(); iterator.hasNext();) {
Record record = (Record) iterator.next();
if(record.getTransactionId() == null) {
continue;
}
TransactionInfo transactionInfo = new TransactionInfo(record.getTransactionId(), record.getSpanId());
if (transactionInfoes.contains(transactionInfo)) {
continue;
};
record.setLogPageUrl(logPageUrl);
record.setLogButtonName(logButtonName);
transactionInfoes.add(transactionInfo);
}
}
private class TransactionInfo {
private final String transactionId;
private final long spanId;
public TransactionInfo(String transactionId, long spanId) {
this.transactionId = transactionId;
this.spanId = spanId;
}
public String getTransactionId() {
return transactionId;
}
public long getSpanId() {
return spanId;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof TransactionInfo == false) {
return false;
}
TransactionInfo transactionInfo = (TransactionInfo)obj;
if (!transactionId.equals(transactionInfo.getTransactionId())) {
return false;
}
if (spanId != transactionInfo.getSpanId()) {
return false;
}
return true;
}
}
private long getStartTime(List<SpanAlign> spanAlignList) {
if (spanAlignList == null || spanAlignList.size() == 0) {
@@ -314,7 +391,9 @@ public class TransactionInfoServiceImpl implements TransactionInfoService {
registry.findServiceType(spanBo.getServiceType()),
null,
spanAlign.isHasChild(),
false);
false,
spanBo.getTransactionId(),
spanBo.getSpanId());
record.setSimpleClassName(apiDescription.getSimpleClassName());
record.setFullApiDescription(method);
recordList.add(record);
@@ -334,7 +413,9 @@ public class TransactionInfoServiceImpl implements TransactionInfoService {
registry.findServiceType(spanBo.getServiceType()),
null,
spanAlign.isHasChild(),
false);
false,
spanBo.getTransactionId(),
spanBo.getSpanId());
record.setSimpleClassName("");
record.setFullApiDescription("");
recordList.add(record);
@@ -388,7 +469,9 @@ public class TransactionInfoServiceImpl implements TransactionInfoService {
/* spanEventBo.getDestinationId(), spanEventBo.getServiceTypeCode(),*/
destinationId,
spanAlign.isHasChild(),
false);
false,
spanBo.getTransactionId(),
spanBo.getSpanId());
record.setSimpleClassName(apiDescription.getSimpleClassName());
record.setFullApiDescription(method);
@@ -416,7 +499,9 @@ public class TransactionInfoServiceImpl implements TransactionInfoService {
/*spanEventBo.getDestinationId(), spanEventBo.getServiceTypeCode(),*/
destinationId,
spanAlign.isHasChild(),
false);
false,
spanBo.getTransactionId(),
spanBo.getSpanId());
record.setSimpleClassName("");
record.setFullApiDescription(method);
@@ -454,7 +539,9 @@ public class TransactionInfoServiceImpl implements TransactionInfoService {
null,
null,
false,
false);
false,
spanBo.getTransactionId(),
spanBo.getSpanId());
}
} else {
final SpanEventBo spanEventBo = spanAlign.getSpanEventBo();
@@ -474,7 +561,9 @@ public class TransactionInfoServiceImpl implements TransactionInfoService {
null,
null,
false,
true);
true,
null,
0);
}
}
return null;
@@ -529,7 +618,7 @@ public class TransactionInfoServiceImpl implements TransactionInfoService {
for (AnnotationBo ann : annotationBoList) {
AnnotationKey annotation = findAnnotationKey(ann.getKey());
if (annotation.isViewInRecordSet()) {
Record record = new Record(depth, getNextId(), parentId, false, annotation.getName(), ann.getValue().toString(), 0L, 0L, 0, null, null, null, null, false, false);
Record record = new Record(depth, getNextId(), parentId, false, annotation.getName(), ann.getValue().toString(), 0L, 0L, 0, null, null, null, null, false, false, null, 0);
recordList.add(record);
}
}
@@ -538,7 +627,7 @@ public class TransactionInfoServiceImpl implements TransactionInfoService {
}
private Record createParameterRecord(int depth, int parentId, String method, String argument) {
return new Record(depth, getNextId(), parentId, false, method, argument, 0L, 0L, 0, null, null, null, null, false, false);
return new Record(depth, getNextId(), parentId, false, method, argument, 0L, 0L, 0, null, null, null, null, false, false, null, 0);
}
}
@@ -44,11 +44,18 @@ public class Record {
private final String destinationId;
private final boolean excludeFromTimeline;
private final String transactionId;
private final long spanId;
private boolean focused;
private boolean hasChild;
private boolean hasException;
private String logPageUrl;
private String logButtonName;
public Record(int tab, int id, int parentId, boolean method, String title, String arguments, long begin, long elapsed, long gap, String agent, String applicationName, ServiceType serviceType, String destinationId, boolean hasChild, boolean hasException) {
public Record(int tab, int id, int parentId, boolean method, String title, String arguments, long begin, long elapsed, long gap, String agent, String applicationName, ServiceType serviceType, String destinationId, boolean hasChild, boolean hasException, String transactionId, long spanId) {
this.tab = tab;
this.id = id;
this.parentId = parentId;
@@ -68,6 +75,9 @@ public class Record {
this.excludeFromTimeline = serviceType == null || serviceType.isInternalMethod();
this.hasChild = hasChild;
this.hasException = hasException;
this.transactionId = transactionId;
this.spanId = spanId;
}
public int getId() {
@@ -175,6 +185,30 @@ public class Record {
public boolean getHasException() {
return hasException;
}
public String getTransactionId() {
return transactionId;
}
public long getSpanId() {
return spanId;
}
public void setLogPageUrl(String logPageUrl) {
this.logPageUrl = logPageUrl;
}
public void setLogButtonName(String logButtonName) {
this.logButtonName = logButtonName;
}
public String getLogPageUrl() {
return this.logPageUrl;
}
public String getLogButtonName() {
return this.logButtonName;
}
@Override
@@ -6,4 +6,9 @@ cluster.zookeeper.sessiontimeout=3000
cluster.zookeeper.retry.interval=5000
# FIXME - should be removed for proper authentication
admin.password=admin
admin.password=admin
#log site link
#log.enable=false
#log.page.url=
#log.button.name=
@@ -10,6 +10,7 @@
"callStackStart" : ${callstackStart},
"callStackEnd" : ${callstackEnd},
"completeState" : "${completeState}",
"logLinkEnable" : ${logLinkEnable},
"callStackIndex" : {
"depth":0,
"begin":1,
@@ -31,7 +32,9 @@
"apiType":17,
"agent":18,
"isFocused":19,
"hasException":20
"hasException":20,
"logButtonName":21,
"logPageUrl":22
},
"callStack" : [
<c:forEach items="${callstack}" var="record" varStatus="status">[
@@ -55,7 +58,19 @@ ${record.hasChild},
"${record.apiType}",
"${record.agent}",
${record.focused},
${record.hasException}
${record.hasException},
"${record.logButtonName}",
<c:choose>
<c:when test="${not empty record.logPageUrl}">
<c:url value="${record.logPageUrl}" var="logPageUrl">
<c:param name="transactionId" value="${record.transactionId}" />
<c:param name="spanId" value="${record.spanId}" />
<c:param name="time" value="${record.begin}" />
</c:url>
"${logPageUrl}"
</c:when>
<c:otherwise>""</c:otherwise>
</c:choose>
]<c:if test="${!status.last}">,</c:if></c:forEach>
],
"applicationMapData" : {
@@ -13,7 +13,14 @@
"agentId" : "${span.agentId}",
"endpoint" : "${span.endPoint}",
"exception" : ${span.errCode},
"remoteAddr" : "${span.remoteAddr}"
"remoteAddr" : "${span.remoteAddr}"<c:if test="${not empty logPageUrl}">,
"logButtonName" : "${logButtonName}",
<c:url value="${logPageUrl}" var="url">
<c:param name="transactionId" value="${span.transactionId}" />
<c:param name="time" value="${span.startTime}" />
</c:url>
"logPageUrl" : "${url}"
</c:if>
}
<c:if test="${!status.last}">,</c:if>
</c:forEach>
@@ -12,12 +12,12 @@ pinpointApp.directive('distributedCallFlow', [ '$filter', '$timeout',
link: function postLink(scope, element, attrs) {
// initialize variables
var grid, columns, dataView, lastAgent;
var grid, dataView, lastAgent;
// initialize variables of methods
var initialize, treeFormatter, treeFilter, parseData, execTimeFormatter,
getColorByString, progressBarFormatter, argumentFormatter, hasChildNode;
//getColorByString, progressBarFormatter, argumentFormatter, linkFormatter, hasChildNode;
// getColorByString, progressBarFormatter, argumentFormatter, hasChildNode;
getColorByString, progressBarFormatter, argumentFormatter, linkFormatter, hasChildNode;
// bootstrap
window.callStacks = []; // Due to Slick.Data.DataView, must use window property to resolve scope-related problems.
@@ -125,14 +125,26 @@ pinpointApp.directive('distributedCallFlow', [ '$filter', '$timeout',
};
//linkFormatter = function (row, cell, value, columnDef, dataConrtext) {
// var html = [];
// html.push('<a class="btn btn-default btn-xs"');
// html.push('href="')
// html.push(value);
// html.push('" target="_blank">nelo</a>');
// return html.join('');
//};
linkFormatter = function (row, cell, value, columnDef, dataContext) {
if (!value || 0 === value.length) {
return;
}
var html = [];
html.push('<a class="btn btn-default btn-xs"');
html.push('href="')
html.push(value);
html.push('" target="_blank">');
var item = dataView.getItemById(dataContext.id);
var logButtonName = item.logButtonName;
html.push(logButtonName);
html.push('</a>');
return html.join('');
};
/**
* exec time formatter
@@ -171,21 +183,6 @@ pinpointApp.directive('distributedCallFlow', [ '$filter', '$timeout',
return "<span class='percent-complete-bar' style='background:" + color + ";width:" + value + "%'></span>";
};
// columns
columns = [
{id: "method", name: "Method", field: "method", width: 400, formatter: treeFormatter},
{id: "argument", name: "Argument", field: "argument", width: 300, formatter: argumentFormatter},
{id: "exec-time", name: "Exec Time", field: "execTime", width: 90, formatter: execTimeFormatter},
{id: "gap-ms", name: "Gap(ms)", field: "gapMs", width: 60, cssClass: "right-align"},
{id: "time-ms", name: "Time(ms)", field: "timeMs", width: 60, cssClass: "right-align"},
{id: "time-per", name: "Time(%)", field: "timePer", width: 100, formatter: progressBarFormatter},
{id: "class", name: "Class", field: "class", width: 120},
{id: "api-type", name: "Api Type", field: "apiType", width: 90},
{id: "agent", name: "Agent", field: "agent", width: 130},
{id: "application-name", name: "Application Name", field: "applicationName", width: 150}//,
//{id: "Loglink", name: "log", field: "logLink", width: 50, formatter:linkFormatter}
];
/**
* parse data
* @param index
@@ -211,8 +208,9 @@ pinpointApp.directive('distributedCallFlow', [ '$filter', '$timeout',
agent: val[index['agent']],
applicationName: val[index['applicationName']],
hasException: val[index['hasException']],
isMethod: val[index['isMethod']] //,
//logLink : "http://localhost/urllogLink/"
isMethod: val[index['isMethod']] ,
logLink : val[index['logPageUrl']],
logButtonName : val[index['logButtonName']],
});
});
return result;
@@ -253,6 +251,23 @@ pinpointApp.directive('distributedCallFlow', [ '$filter', '$timeout',
// };
dataView.endUpdate();
var columns = [
{id: "method", name: "Method", field: "method", width: 400, formatter: treeFormatter},
{id: "argument", name: "Argument", field: "argument", width: 300, formatter: argumentFormatter},
{id: "exec-time", name: "Exec Time", field: "execTime", width: 90, formatter: execTimeFormatter},
{id: "gap-ms", name: "Gap(ms)", field: "gapMs", width: 60, cssClass: "right-align"},
{id: "time-ms", name: "Time(ms)", field: "timeMs", width: 60, cssClass: "right-align"},
{id: "time-per", name: "Time(%)", field: "timePer", width: 100, formatter: progressBarFormatter},
{id: "class", name: "Class", field: "class", width: 120},
{id: "api-type", name: "Api Type", field: "apiType", width: 90},
{id: "agent", name: "Agent", field: "agent", width: 130},
{id: "application-name", name: "Application Name", field: "applicationName", width: 150}
];
if (t.logLinkEnable) {
columns.push({id: "Loglink", name: "log", field: "logLink", width: 50, formatter:linkFormatter});
}
grid = new Slick.Grid(element.get(0), dataView, columns, options);
var isSingleClick = true, clickTimeout = false;
@@ -66,7 +66,7 @@
<td ng-click="traceByApplication(transaction)" style="cursor:pointer;text-align:center;"><span class="glyphicon glyphicon-fire" ng-show="transaction.exception == 1"></span></td>
<td ng-click="traceByApplication(transaction)" style="cursor:pointer">{{transaction.agentId}}</td>
<td ng-click="traceByApplication(transaction)" style="cursor:pointer">{{transaction.remoteAddr}}</td>
<td ng-click="traceByApplication(transaction)" style="cursor:pointer">{{transaction.traceId}}</td>
<td ng-click="traceByApplication(transaction)" style="cursor:pointer">{{transaction.traceId}} <a ng-if="transaction.logPageUrl" class="btn btn-default btn-xs" href="{{transaction.logPageUrl}}" target="_blank">{{transaction.logButtonName}}</a> </td>
</tr>
</tbody>
</table>