diff --git a/agent/pom.xml b/agent/pom.xml index abfa4256e..18ea9c101 100644 --- a/agent/pom.xml +++ b/agent/pom.xml @@ -88,7 +88,11 @@ - + + + false + + org.apache.maven.plugins maven-assembly-plugin diff --git a/agent/src/main/resources/pinpoint.config b/agent/src/main/resources/pinpoint.config index 1232c4470..5d6f4dada 100644 --- a/agent/src/main/resources/pinpoint.config +++ b/agent/src/main/resources/pinpoint.config @@ -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 \ No newline at end of file +profiler.logback.logging.transactioninfo=false diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk/http/HttpURLConnectionIT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk/http/HttpURLConnectionIT.java new file mode 100644 index 000000000..e6121ddf3 --- /dev/null +++ b/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk/http/HttpURLConnectionIT.java @@ -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")); + } + +} diff --git a/agent/src/test/resources/pinpoint-spring-bean-test.config b/agent/src/test/resources/pinpoint-spring-bean-test.config index 3c787b397..5f6a9def2 100644 --- a/agent/src/test/resources/pinpoint-spring-bean-test.config +++ b/agent/src/test/resources/pinpoint-spring-bean-test.config @@ -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 \ No newline at end of file +profiler.logback.logging.transactioninfo=false diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/config/ProfilerConfig.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/config/ProfilerConfig.java index bf63f9344..36dac5b80 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/config/ProfilerConfig.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/config/ProfilerConfig.java @@ -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 applicationTypeDetectOrder = Collections.emptyList(); private boolean log4jLoggingTransactionInfo; private boolean logbackLoggingTransactionInfo; @@ -589,6 +592,10 @@ public class ProfilerConfig { public Filter getProfilableClassFilter() { return profilableClassFilter; } + + public List 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 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(); diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/context/RecordableTrace.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/context/RecordableTrace.java index fe07cff6f..5618a7e3f 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/context/RecordableTrace.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/context/RecordableTrace.java @@ -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); +} \ No newline at end of file diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/context/StackOperation.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/context/StackOperation.java index 204a73b08..088e1b7e5 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/context/StackOperation.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/context/StackOperation.java @@ -36,4 +36,9 @@ public interface StackOperation { void traceBlockEnd(); void traceBlockEnd(int stackId); + + + Object setTraceBlockAttachment(Object attachment); + Object getTraceBlockAttachment(); + Object removeTraceBlockAttachment(); } diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/InstrumentClass.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/InstrumentClass.java index c390c1a31..2cf452f50 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/InstrumentClass.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/InstrumentClass.java @@ -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); diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ApplicationTypeDetector.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ApplicationTypeDetector.java new file mode 100644 index 000000000..a818d0503 --- /dev/null +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ApplicationTypeDetector.java @@ -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. + * + *

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 true if the + * requirements are satisfied. + * + * @param provider conditions provided by the current application + * @return true if the provided conditions satisfy the requirements, false if otherwise + * @see ConditionProvider + */ + public boolean detect(ConditionProvider provider); +} diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ProfilerPlugin.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ProfilerPlugin.java index bab4f24cd..d30c9865a 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ProfilerPlugin.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ProfilerPlugin.java @@ -19,5 +19,5 @@ package com.navercorp.pinpoint.bootstrap.plugin; public interface ProfilerPlugin { - void setUp(ProfilerPluginSetupContext context); + void setup(ProfilerPluginSetupContext context); } diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ProfilerPluginSetupContext.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ProfilerPluginSetupContext.java index 8b56a1ba6..129e435eb 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ProfilerPluginSetupContext.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ProfilerPluginSetupContext.java @@ -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); } diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/BaseClassEditorBuilder.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/BaseClassEditorBuilder.java new file mode 100644 index 000000000..97cbfebab --- /dev/null +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/BaseClassEditorBuilder.java @@ -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); + +} \ No newline at end of file diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/BaseMethodEditorBuilder.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/BaseMethodEditorBuilder.java index 6387eb7e9..4f4811ab9 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/BaseMethodEditorBuilder.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/BaseMethodEditorBuilder.java @@ -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); diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/ClassCondition.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/ClassCondition.java index c0dd12dee..9c333e218 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/ClassCondition.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/ClassCondition.java @@ -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); } diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/ClassConditions.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/ClassConditions.java new file mode 100644 index 000000000..9bde418a8 --- /dev/null +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/ClassConditions.java @@ -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); + } + } +} diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/ClassEditorBuilder.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/ClassEditorBuilder.java index 2daf3e4cc..bcb3758c2 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/ClassEditorBuilder.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/ClassEditorBuilder.java @@ -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(); } \ No newline at end of file diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ServerTypeDetector.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/ConditionalClassEditorBuilder.java similarity index 75% rename from bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ServerTypeDetector.java rename to bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/ConditionalClassEditorBuilder.java index d517a0a60..c115ad35b 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ServerTypeDetector.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/ConditionalClassEditorBuilder.java @@ -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 { + } diff --git a/test/src/main/java/com/navercorp/pinpoint/test/plugin/ChildProcessException.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/ConditionalClassEditorSetup.java similarity index 71% rename from test/src/main/java/com/navercorp/pinpoint/test/plugin/ChildProcessException.java rename to bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/ConditionalClassEditorSetup.java index 07e29735a..3fd33ffa4 100644 --- a/test/src/main/java/com/navercorp/pinpoint/test/plugin/ChildProcessException.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/editor/ConditionalClassEditorSetup.java @@ -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); } diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/resolver/ApplicationServerTypePluginResolver.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/resolver/ApplicationServerTypePluginResolver.java new file mode 100644 index 000000000..55ae94214 --- /dev/null +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/resolver/ApplicationServerTypePluginResolver.java @@ -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. + *

+ * 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 applicationTypeDetectors; + + private final ConditionProvider conditionProvider; + + private static final ServiceType DEFAULT_SERVER_TYPE = ServiceType.STAND_ALONE; + + public ApplicationServerTypePluginResolver(List serverTypeDetectors) { + this(serverTypeDetectors, ConditionProvider.DEFAULT_CONDITION_PROVIDER); + } + + public ApplicationServerTypePluginResolver(List 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; + } +} diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/resolver/ConditionProvider.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/resolver/ConditionProvider.java new file mode 100644 index 000000000..b493c8419 --- /dev/null +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/resolver/ConditionProvider.java @@ -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 false. + * + * @param condition the value to check against the application's main class name + * @return true if the specified value matches the name of the main class; + * false 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 true if the specified key is in the system property; + * false if otherwise, or if null 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 true if the specified class can be found in the system class loader's search path, + * false if otherwise + * @see ClassResourceCondition#check(String) + */ + public boolean checkForClass(String requiredClass) { + return this.classResourceCondition.check(requiredClass); + } + +} diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/resolver/condition/ClassResourceCondition.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/resolver/condition/ClassResourceCondition.java new file mode 100644 index 000000000..89c9ba570 --- /dev/null +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/resolver/condition/ClassResourceCondition.java @@ -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 { + + 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 true if the specified class can be found in the system class loader's search path, + * false if otherwise + */ + @Override + public boolean check(String requiredClass) { + if (requiredClass == null || requiredClass.isEmpty()) { + return false; + } + String classNameAsResource = getClassNameAsResource(requiredClass); + return (ClassLoader.getSystemResource(classNameAsResource) != null); + } + +} diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/resolver/condition/Condition.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/resolver/condition/Condition.java new file mode 100644 index 000000000..51f0e5531 --- /dev/null +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/resolver/condition/Condition.java @@ -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 { + + public boolean check(T condition); + +} diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/resolver/condition/ConditionValue.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/resolver/condition/ConditionValue.java new file mode 100644 index 000000000..d05d274bb --- /dev/null +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/resolver/condition/ConditionValue.java @@ -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 { + + public V getValue(); + +} diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/resolver/condition/MainClassCondition.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/resolver/condition/MainClassCondition.java new file mode 100644 index 000000000..3d21d5390 --- /dev/null +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/resolver/condition/MainClassCondition.java @@ -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, ConditionValue { + + 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 false. + * + * @param condition the value to check against the application's main class name + * @return true if the specified value matches the name of the main class; + * false 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; + } + } + +} diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/resolver/condition/PropertyCondition.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/resolver/condition/PropertyCondition.java new file mode 100644 index 000000000..9e9f0d6af --- /dev/null +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/resolver/condition/PropertyCondition.java @@ -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, ConditionValue { + + private final SimpleProperty property; + + public PropertyCondition() { + this(SystemProperty.INSTANCE); + } + + public PropertyCondition(SimpleProperty property) { + this.property = property; + } + + /** + * Checks if the specified value is in SimpleProperty. + * + * @param requiredKey the values to check if they exist in SimpleProperty + * @return true if the specified key is in SimpleProperty; + * false if otherwise, or if null 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 SimpleProperty. + * + * @return the {@link SimpleProperty} instance + */ + @Override + public SimpleProperty getValue() { + return this.property; + } + +} diff --git a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/interceptor/MockTrace.java b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/interceptor/MockTrace.java index 05c1714b1..53fd9374c 100644 --- a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/interceptor/MockTrace.java +++ b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/interceptor/MockTrace.java @@ -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 attributeMap = new HashMap(); + 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; + } } diff --git a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/resolver/ConditionProviderTest.java b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/resolver/ConditionProviderTest.java new file mode 100644 index 000000000..e12a9e6f1 --- /dev/null +++ b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/resolver/ConditionProviderTest.java @@ -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 properties = new HashMap() {{ + 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; + } + + }; + +} diff --git a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/resolver/condition/MainClassConditionTest.java b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/resolver/condition/MainClassConditionTest.java new file mode 100644 index 000000000..3b5525ed3 --- /dev/null +++ b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/resolver/condition/MainClassConditionTest.java @@ -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 properties = new HashMap(); + + @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; + } + +} diff --git a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/resolver/condition/SystemPropertyConditionTest.java b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/resolver/condition/SystemPropertyConditionTest.java new file mode 100644 index 000000000..09eb25e2c --- /dev/null +++ b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/resolver/condition/SystemPropertyConditionTest.java @@ -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 properties = new HashMap(); + + @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; + } + +} diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/ServiceType.java b/commons/src/main/java/com/navercorp/pinpoint/common/ServiceType.java index 26e46f8cf..f51e8eb3f 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/ServiceType.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/ServiceType.java @@ -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); diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/TypeProviderLoader.java b/commons/src/main/java/com/navercorp/pinpoint/common/TypeProviderLoader.java index 1f1ae4cc1..0de27e94b 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/TypeProviderLoader.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/TypeProviderLoader.java @@ -78,7 +78,7 @@ public class TypeProviderLoader { } TypeSetupContextImpl context = new TypeSetupContextImpl(provider.getClass()); - provider.setUp(context); + provider.setup(context); setupContextList.add(context); diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/plugin/TypeProvider.java b/commons/src/main/java/com/navercorp/pinpoint/common/plugin/TypeProvider.java index 24e6765d9..894997b6f 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/plugin/TypeProvider.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/plugin/TypeProvider.java @@ -20,5 +20,5 @@ package com.navercorp.pinpoint.common.plugin; * */ public interface TypeProvider { - void setUp(TypeSetupContext context); + void setup(TypeSetupContext context); } diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/util/DefaultDisplayArgument.java b/commons/src/main/java/com/navercorp/pinpoint/common/util/DefaultDisplayArgument.java index 4d734cad8..bb441342e 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/util/DefaultDisplayArgument.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/util/DefaultDisplayArgument.java @@ -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); diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/util/SystemPropertyKey.java b/commons/src/main/java/com/navercorp/pinpoint/common/util/SystemPropertyKey.java index 785b3ca84..aab8eac87 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/util/SystemPropertyKey.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/util/SystemPropertyKey.java @@ -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; diff --git a/commons/src/test/java/com/navercorp/pinpoint/common/ServiceTypeInitializerTest.java b/commons/src/test/java/com/navercorp/pinpoint/common/ServiceTypeInitializerTest.java index 66d506f9a..94fc22a33 100644 --- a/commons/src/test/java/com/navercorp/pinpoint/common/ServiceTypeInitializerTest.java +++ b/commons/src/test/java/com/navercorp/pinpoint/common/ServiceTypeInitializerTest.java @@ -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); } diff --git a/plugins/jdk-http/.gitignore b/plugins/jdk-http/.gitignore new file mode 100644 index 000000000..8bd3a0588 --- /dev/null +++ b/plugins/jdk-http/.gitignore @@ -0,0 +1,4 @@ +/target/ +/.settings/ +/.classpath +/.project diff --git a/plugins/jdk-http/pom.xml b/plugins/jdk-http/pom.xml new file mode 100644 index 000000000..b75de18ab --- /dev/null +++ b/plugins/jdk-http/pom.xml @@ -0,0 +1,26 @@ + + 4.0.0 + + com.navercorp.pinpoint + pom + ../.. + 1.1.0-SNAPSHOT + + + pinpoint-jdk-http-plugin + pinpoint-jdk-http-plugin + jar + + + + + com.navercorp.pinpoint + pinpoint-profiler + + + + diff --git a/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/JdkHttpConstants.java b/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/JdkHttpConstants.java new file mode 100644 index 000000000..9c984bcca --- /dev/null +++ b/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/JdkHttpConstants.java @@ -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); +} diff --git a/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/JdkHttpPlugin.java b/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/JdkHttpPlugin.java new file mode 100644 index 000000000..d918e92dd --- /dev/null +++ b/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/JdkHttpPlugin.java @@ -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()); + } + +} diff --git a/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/JdkHttpTypeProvider.java b/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/JdkHttpTypeProvider.java new file mode 100644 index 000000000..d069f9e61 --- /dev/null +++ b/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/JdkHttpTypeProvider.java @@ -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)); + } + +} diff --git a/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/interceptor/HttpURLConnectionInterceptor.java b/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/interceptor/HttpURLConnectionInterceptor.java new file mode 100644 index 000000000..09e9536df --- /dev/null +++ b/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/interceptor/HttpURLConnectionInterceptor.java @@ -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(); + } + } +} \ No newline at end of file diff --git a/plugins/jdk-http/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin b/plugins/jdk-http/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin new file mode 100644 index 000000000..685e09b42 --- /dev/null +++ b/plugins/jdk-http/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.jdk.http.JdkHttpPlugin \ No newline at end of file diff --git a/plugins/jdk-http/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.plugin.TypeProvider b/plugins/jdk-http/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.plugin.TypeProvider new file mode 100644 index 000000000..4acd8efa1 --- /dev/null +++ b/plugins/jdk-http/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.plugin.TypeProvider @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.jdk.http.JdkHttpTypeProvider \ No newline at end of file diff --git a/plugins/pom.xml b/plugins/pom.xml index 450f950c3..3e8db9041 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -12,12 +12,23 @@ pom + jdk-http + redis servlet tomcat - redis + + com.navercorp.pinpoint + pinpoint-jdk-http-plugin + ${project.version} + + + com.navercorp.pinpoint + pinpoint-redis-plugin + ${project.version} + com.navercorp.pinpoint pinpoint-servlet-plugin @@ -28,10 +39,5 @@ pinpoint-tomcat-plugin ${project.version} - - com.navercorp.pinpoint - pinpoint-redis-plugin - ${project.version} - diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisPlugin.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisPlugin.java index aa391afdc..0f1483428 100644 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisPlugin.java +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisPlugin.java @@ -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() { diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisTypeProvider.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisTypeProvider.java index 799d9ae21..f22a9de02 100644 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisTypeProvider.java +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisTypeProvider.java @@ -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); } } diff --git a/plugins/servlet/src/main/java/com/navercorp/pinpoint/plugin/servlet/ServletPlugin.java b/plugins/servlet/src/main/java/com/navercorp/pinpoint/plugin/servlet/ServletPlugin.java index 4da2a840b..7f8940f1d 100644 --- a/plugins/servlet/src/main/java/com/navercorp/pinpoint/plugin/servlet/ServletPlugin.java +++ b/plugins/servlet/src/main/java/com/navercorp/pinpoint/plugin/servlet/ServletPlugin.java @@ -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); diff --git a/plugins/servlet/src/main/java/com/navercorp/pinpoint/plugin/servlet/ServletTypeProvider.java b/plugins/servlet/src/main/java/com/navercorp/pinpoint/plugin/servlet/ServletTypeProvider.java index 31b0aa9b6..b3fa9a67b 100644 --- a/plugins/servlet/src/main/java/com/navercorp/pinpoint/plugin/servlet/ServletTypeProvider.java +++ b/plugins/servlet/src/main/java/com/navercorp/pinpoint/plugin/servlet/ServletTypeProvider.java @@ -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); } diff --git a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatDetector.java b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatDetector.java index 9ff260ccb..1a259223c 100644 --- a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatDetector.java +++ b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatDetector.java @@ -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); } + } diff --git a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatPlugin.java b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatPlugin.java index d1e9793ca..d25fae544 100644 --- a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatPlugin.java +++ b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatPlugin.java @@ -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() diff --git a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatTypeProvider.java b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatTypeProvider.java index 76ee8ab6f..8b9bcb924 100644 --- a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatTypeProvider.java +++ b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatTypeProvider.java @@ -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); } diff --git a/plugins/tomcat/src/test/resources/pinpoint.config b/plugins/tomcat/src/test/resources/pinpoint.config index d8d1493fe..4fa92abdb 100644 --- a/plugins/tomcat/src/test/resources/pinpoint.config +++ b/plugins/tomcat/src/test/resources/pinpoint.config @@ -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 # diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultAgent.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultAgent.java index 041a34fed..19b7ea3d4 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultAgent.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultAgent.java @@ -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); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultTrace.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultTrace.java index 5ae481809..eeac88ca5 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultTrace.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultTrace.java @@ -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 attributeMap = new HashMap(); // 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(); + } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DisableTrace.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DisableTrace.java index 089ebcd95..a01800b3a 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DisableTrace.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DisableTrace.java @@ -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 attributeMap = new HashMap(); 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(); + } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/MetricTrace.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/MetricTrace.java index 1d3d0f699..ec57acfa3 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/MetricTrace.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/MetricTrace.java @@ -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 attributeMap = new HashMap(); + // 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(); + } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/RootStackFrame.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/RootStackFrame.java index 3764254c7..824a8de0d 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/RootStackFrame.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/RootStackFrame.java @@ -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 diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanEventStackFrame.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanEventStackFrame.java index 72b2a415d..637e43511 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanEventStackFrame.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanEventStackFrame.java @@ -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 diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/StackFrame.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/StackFrame.java index 8de91731a..48d654107 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/StackFrame.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/StackFrame.java @@ -50,7 +50,7 @@ public interface StackFrame { short getServiceType(); - void attachFrameObject(Object frameObject); + Object attachFrameObject(Object frameObject); Object getFrameObject(); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/interceptor/bci/JavaAssistClass.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/interceptor/bci/JavaAssistClass.java index e5754e296..545263cca 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/interceptor/bci/JavaAssistClass.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/interceptor/bci/JavaAssistClass.java @@ -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); + } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/DefaultModifierRegistry.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/DefaultModifierRegistry.java index 71d02eae9..2aec8f31f 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/DefaultModifierRegistry.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/DefaultModifierRegistry.java @@ -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)); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/connector/jdkhttpconnector/HttpURLConnectionModifier.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/connector/jdkhttpconnector/HttpURLConnectionModifier.java index 60ef94305..dc6ed8684 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/connector/jdkhttpconnector/HttpURLConnectionModifier.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/connector/jdkhttpconnector/HttpURLConnectionModifier.java @@ -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); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/connector/jdkhttpconnector/interceptor/ConnectMethodInterceptor.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/connector/jdkhttpconnector/interceptor/ConnectMethodInterceptor.java index 4f86d02c4..447c1812a 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/connector/jdkhttpconnector/interceptor/ConnectMethodInterceptor.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/connector/jdkhttpconnector/interceptor/ConnectMethodInterceptor.java @@ -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 isConnected = new MetaObject("__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(); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/MdcKey.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/MdcKey.java index 8e2086d2c..153898b9a 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/MdcKey.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/MdcKey.java @@ -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"; } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/log4j/interceptor/LoggingEventOfLog4jInterceptor.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/log4j/interceptor/LoggingEventOfLog4jInterceptor.java index 5f2d6f957..39ed1d2ba 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/log4j/interceptor/LoggingEventOfLog4jInterceptor.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/log4j/interceptor/LoggingEventOfLog4jInterceptor.java @@ -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())); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/logback/interceptor/LoggingEventOfLogbackInterceptor.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/logback/interceptor/LoggingEventOfLogbackInterceptor.java index b23e8824f..09a445b8f 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/logback/interceptor/LoggingEventOfLogbackInterceptor.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/logback/interceptor/LoggingEventOfLogbackInterceptor.java @@ -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())); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/DefaultProfilerPluginContext.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/DefaultProfilerPluginContext.java index dcbb67ba6..4afface7b 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/DefaultProfilerPluginContext.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/DefaultProfilerPluginContext.java @@ -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 serverTypeDetectors = new ArrayList(); + private final List serverTypeDetectors = new ArrayList(); private final List classEditors = new ArrayList(); private final ConcurrentMap attributeMap = new ConcurrentHashMap(); @@ -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 getServerTypeDetectors() { + public List getApplicationTypeDetectors() { return serverTypeDetectors; } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/PluginClassLoaderFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/PluginClassLoaderFactory.java index 5d470da0b..096452a2c 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/PluginClassLoaderFactory.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/PluginClassLoaderFactory.java @@ -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 cache = new ConcurrentHashMap(); + private final AtomicReference forBootstrapClassLoader = new AtomicReference(); 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) { diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/editor/ConditionalClassEditor.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/editor/ConditionalClassRecipe.java similarity index 60% rename from profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/editor/ConditionalClassEditor.java rename to profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/editor/ConditionalClassRecipe.java index e1b4e7ba9..2654fc12f 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/editor/ConditionalClassEditor.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/editor/ConditionalClassRecipe.java @@ -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(); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/editor/ConditionalMethodEditor.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/editor/ConditionalMethodEditor.java index 53f61d2a7..72c3287c9 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/editor/ConditionalMethodEditor.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/editor/ConditionalMethodEditor.java @@ -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); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/editor/DefaultClassEditorBuilder.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/editor/DefaultClassEditorBuilder.java index fd36f8d26..269345d1c 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/editor/DefaultClassEditorBuilder.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/editor/DefaultClassEditorBuilder.java @@ -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 { private final DefaultProfilerPluginContext pluginContext; private final List recipes = new ArrayList(); private final List> recipeBuilders = new ArrayList>(); - 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 recipes = new ArrayList(this.recipes); for (RecipeBuilder 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 { - 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 { 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> recipeBuilders = new ArrayList>(); private final EnumSet 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 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 recipes = new ArrayList(recipeBuilders.size()); for (RecipeBuilder builder : recipeBuilders) { - recipes.add(builder.build()); + recipes.add(builder.buildRecipe()); } return recipes; diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/editor/RecipeBuilder.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/editor/RecipeBuilder.java new file mode 100644 index 000000000..4ab6e029e --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/editor/RecipeBuilder.java @@ -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 buildRecipe(); +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/ApplicationServerTypeResolver.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/ApplicationServerTypeResolver.java index 6230c4763..7fe34f496 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/ApplicationServerTypeResolver.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/ApplicationServerTypeResolver.java @@ -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 detectors = new ArrayList(); + private final ApplicationServerTypePluginResolver resolver; + private final List detectors = new ArrayList(); - private final ServiceTypeRegistryService serviceTypeRegistryService; - - public ApplicationServerTypeResolver(List plugins, ServiceType defaultType, ServiceTypeRegistryService serviceTypeRegistryService) { - if (serviceTypeRegistryService == null) { - throw new NullPointerException("serviceTypeRegistryService must not be null"); + public ApplicationServerTypeResolver(List plugins, ServiceType defaultType, List 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 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 getRegisteredServerTypeDetectors(List plugins) { + Map registeredDetectors = new HashMap(); + 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(); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/test/PluginTestAgent.java b/profiler/src/main/java/com/navercorp/pinpoint/test/PluginTestAgent.java index db4654754..9418a81dc 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/test/PluginTestAgent.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/test/PluginTestAgent.java @@ -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); } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/JavaAssistClassTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/JavaAssistClassTest.java index 03e629cb1..02d614b2d 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/JavaAssistClassTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/JavaAssistClassTest.java @@ -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)); } } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/TestObject3.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/TestObject3.java index f4c77c4b7..8ee9b70e3 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/TestObject3.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/TestObject3.java @@ -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() { diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/DefaultClassEditorBuilderTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/DefaultClassEditorBuilderTest.java index bf6adb921..146d572cb 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/DefaultClassEditorBuilderTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/DefaultClassEditorBuilderTest.java @@ -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"); diff --git a/profiler/src/test/resources/pinpoint-spring-bean-test.config b/profiler/src/test/resources/pinpoint-spring-bean-test.config index 3c787b397..5a376f9a4 100644 --- a/profiler/src/test/resources/pinpoint-spring-bean-test.config +++ b/profiler/src/test/resources/pinpoint-spring-bean-test.config @@ -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 \ No newline at end of file +# +# 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 diff --git a/profiler/src/test/resources/pinpoint.config b/profiler/src/test/resources/pinpoint.config index 407712f5e..7494b10d8 100644 --- a/profiler/src/test/resources/pinpoint.config +++ b/profiler/src/test/resources/pinpoint.config @@ -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 \ No newline at end of file +profiler.logback.logging.transactioninfo=false diff --git a/test/src/main/java/com/navercorp/pinpoint/test/plugin/AbstractPinpointPluginTestSuite.java b/test/src/main/java/com/navercorp/pinpoint/test/plugin/AbstractPinpointPluginTestSuite.java index db491b213..621f2ac53 100644 --- a/test/src/main/java/com/navercorp/pinpoint/test/plugin/AbstractPinpointPluginTestSuite.java +++ b/test/src/main/java/com/navercorp/pinpoint/test/plugin/AbstractPinpointPluginTestSuite.java @@ -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 cases = createTestCases(context); diff --git a/test/src/main/java/com/navercorp/pinpoint/test/plugin/DependencyResolver.java b/test/src/main/java/com/navercorp/pinpoint/test/plugin/DependencyResolver.java index bdfa9a501..0bfd5c57f 100644 --- a/test/src/main/java/com/navercorp/pinpoint/test/plugin/DependencyResolver.java +++ b/test/src/main/java/com/navercorp/pinpoint/test/plugin/DependencyResolver.java @@ -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 { diff --git a/test/src/main/java/com/navercorp/pinpoint/test/plugin/ForkedPinpointPluginTest.java b/test/src/main/java/com/navercorp/pinpoint/test/plugin/ForkedPinpointPluginTest.java index 8f65ae6cb..78593e90e 100644 --- a/test/src/main/java/com/navercorp/pinpoint/test/plugin/ForkedPinpointPluginTest.java +++ b/test/src/main/java/com/navercorp/pinpoint/test/plugin/ForkedPinpointPluginTest.java @@ -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; diff --git a/test/src/main/java/com/navercorp/pinpoint/test/plugin/ForkedPinpointPluginTestRunner.java b/test/src/main/java/com/navercorp/pinpoint/test/plugin/ForkedPinpointPluginTestRunner.java index 0b9ffdc36..991bb6650 100644 --- a/test/src/main/java/com/navercorp/pinpoint/test/plugin/ForkedPinpointPluginTestRunner.java +++ b/test/src/main/java/com/navercorp/pinpoint/test/plugin/ForkedPinpointPluginTestRunner.java @@ -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); + } } }; } diff --git a/test/src/main/java/com/navercorp/pinpoint/test/plugin/PinpointPluginTestConstants.java b/test/src/main/java/com/navercorp/pinpoint/test/plugin/PinpointPluginTestConstants.java index d8988fe28..81bce378f 100644 --- a/test/src/main/java/com/navercorp/pinpoint/test/plugin/PinpointPluginTestConstants.java +++ b/test/src/main/java/com/navercorp/pinpoint/test/plugin/PinpointPluginTestConstants.java @@ -14,7 +14,6 @@ */ package com.navercorp.pinpoint.test.plugin; -import java.util.regex.Pattern; /** * @author Jongho Moon diff --git a/test/src/main/java/com/navercorp/pinpoint/test/plugin/PinpointPluginTestException.java b/test/src/main/java/com/navercorp/pinpoint/test/plugin/PinpointPluginTestException.java new file mode 100644 index 000000000..b3957aff9 --- /dev/null +++ b/test/src/main/java/com/navercorp/pinpoint/test/plugin/PinpointPluginTestException.java @@ -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); + } + + +} diff --git a/test/src/main/java/com/navercorp/pinpoint/test/plugin/PinpointPluginTestStatement.java b/test/src/main/java/com/navercorp/pinpoint/test/plugin/PinpointPluginTestStatement.java index 3042a9155..73c454a51 100644 --- a/test/src/main/java/com/navercorp/pinpoint/test/plugin/PinpointPluginTestStatement.java +++ b/test/src/main/java/com/navercorp/pinpoint/test/plugin/PinpointPluginTestStatement.java @@ -214,7 +214,7 @@ public class PinpointPluginTestStatement extends Statement implements PinpointPl return failure; } - private ChildProcessException toException(String message, String exceptionClass, List traceInText) { + private PinpointPluginTestException toException(String message, String exceptionClass, List 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); } } diff --git a/test/src/main/java/com/navercorp/pinpoint/test/plugin/PinpointPluginTestSuite.java b/test/src/main/java/com/navercorp/pinpoint/test/plugin/PinpointPluginTestSuite.java index 521082118..0b8ea9e31 100644 --- a/test/src/main/java/com/navercorp/pinpoint/test/plugin/PinpointPluginTestSuite.java +++ b/test/src/main/java/com/navercorp/pinpoint/test/plugin/PinpointPluginTestSuite.java @@ -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 createCasesWithJdkOnly(PinpointPluginTestContext context) { + List cases = new ArrayList(); + + if (testOnSystemClassLoader) { + cases.add(new NormalPluginTestCase(context, "", Collections.emptyList(), true)); + } + + if (testOnChildClassLoader) { + cases.add(new NormalPluginTestCase(context, "", Collections.emptyList(), false)); + } + + return cases; } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/controller/BusinessTransactionController.java b/web/src/main/java/com/navercorp/pinpoint/web/controller/BusinessTransactionController.java index 015af8204..6527ffd6c 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/controller/BusinessTransactionController.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/controller/BusinessTransactionController.java @@ -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); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/controller/ScatterChartController.java b/web/src/main/java/com/navercorp/pinpoint/web/controller/ScatterChartController.java index 86ae08b4f..2da2bb419 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/controller/ScatterChartController.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/controller/ScatterChartController.java @@ -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 metadata = scatter.selectTransactionMetadata(query); model.addAttribute("metadata", metadata); } - + + if (logLinkEnable) { + model.addAttribute("logButtonName", logButtonName); + model.addAttribute("logPageUrl", logPageUrl); + } + return "transactionmetadata"; } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/TransactionInfoServiceImpl.java b/web/src/main/java/com/navercorp/pinpoint/web/service/TransactionInfoServiceImpl.java index 09250d1e2..5771c1172 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/service/TransactionInfoServiceImpl.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/TransactionInfoServiceImpl.java @@ -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 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 records = recordSet.getRecordList(); + List transactionInfoes = new LinkedList(); + + for (Iterator 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 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); } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/callstacks/Record.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/callstacks/Record.java index 636c37eb4..7747a8cfa 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/vo/callstacks/Record.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/callstacks/Record.java @@ -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 diff --git a/web/src/main/resources/pinpoint-web.properties b/web/src/main/resources/pinpoint-web.properties index 51604645c..550306ee8 100644 --- a/web/src/main/resources/pinpoint-web.properties +++ b/web/src/main/resources/pinpoint-web.properties @@ -6,4 +6,9 @@ cluster.zookeeper.sessiontimeout=3000 cluster.zookeeper.retry.interval=5000 # FIXME - should be removed for proper authentication -admin.password=admin \ No newline at end of file +admin.password=admin + +#log site link +#log.enable=false +#log.page.url= +#log.button.name= diff --git a/web/src/main/webapp/WEB-INF/views/transactionInfoJson.jsp b/web/src/main/webapp/WEB-INF/views/transactionInfoJson.jsp index dafdc2cc8..dd7b2c4a3 100644 --- a/web/src/main/webapp/WEB-INF/views/transactionInfoJson.jsp +++ b/web/src/main/webapp/WEB-INF/views/transactionInfoJson.jsp @@ -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" : [ [ @@ -55,7 +58,19 @@ ${record.hasChild}, "${record.apiType}", "${record.agent}", ${record.focused}, -${record.hasException} +${record.hasException}, +"${record.logButtonName}", + + + + + + + + "${logPageUrl}" + + "" + ], ], "applicationMapData" : { diff --git a/web/src/main/webapp/WEB-INF/views/transactionmetadata.jsp b/web/src/main/webapp/WEB-INF/views/transactionmetadata.jsp index bfa3b9a67..1386f815e 100644 --- a/web/src/main/webapp/WEB-INF/views/transactionmetadata.jsp +++ b/web/src/main/webapp/WEB-INF/views/transactionmetadata.jsp @@ -13,7 +13,14 @@ "agentId" : "${span.agentId}", "endpoint" : "${span.endPoint}", "exception" : ${span.errCode}, - "remoteAddr" : "${span.remoteAddr}" + "remoteAddr" : "${span.remoteAddr}", + "logButtonName" : "${logButtonName}", + + + + + "logPageUrl" : "${url}" + } , diff --git a/web/src/main/webapp/scripts/directives/distributedCallFlow.js b/web/src/main/webapp/scripts/directives/distributedCallFlow.js index 689e27c1c..4be3976d1 100644 --- a/web/src/main/webapp/scripts/directives/distributedCallFlow.js +++ b/web/src/main/webapp/scripts/directives/distributedCallFlow.js @@ -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('nelo'); - // return html.join(''); - //}; + linkFormatter = function (row, cell, value, columnDef, dataContext) { + + if (!value || 0 === value.length) { + return; + } + + var html = []; + html.push(''); + + var item = dataView.getItemById(dataContext.id); + var logButtonName = item.logButtonName; + html.push(logButtonName); + + html.push(''); + + return html.join(''); + }; /** * exec time formatter @@ -171,21 +183,6 @@ pinpointApp.directive('distributedCallFlow', [ '$filter', '$timeout', return ""; }; - // 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; diff --git a/web/src/main/webapp/views/transactionTable.html b/web/src/main/webapp/views/transactionTable.html index 0da9ffbcb..fdd422558 100644 --- a/web/src/main/webapp/views/transactionTable.html +++ b/web/src/main/webapp/views/transactionTable.html @@ -66,7 +66,7 @@ {{transaction.agentId}} {{transaction.remoteAddr}} - {{transaction.traceId}} + {{transaction.traceId}} {{transaction.logButtonName}}