diff --git a/plugins/dbcp2/pom.xml b/plugins/dbcp2/pom.xml index 0ad0c242f82b..f31351567b61 100644 --- a/plugins/dbcp2/pom.xml +++ b/plugins/dbcp2/pom.xml @@ -34,5 +34,10 @@ pinpoint-bootstrap-core provided + + org.apache.commons + commons-dbcp2 + provided + diff --git a/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/CommonsDbcp2Constants.java b/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/CommonsDbcp2Constants.java new file mode 100644 index 000000000000..73a778c0d187 --- /dev/null +++ b/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/CommonsDbcp2Constants.java @@ -0,0 +1,39 @@ +/* + * Copyright 2017 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.commons.dbcp2; + +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; + +/** + * @author Taejin Koo + */ +public class CommonsDbcp2Constants { + + public static final String SCOPE = "DBCP2_SCOPE"; + + public static final ServiceType SERVICE_TYPE = ServiceTypeFactory.of(6052, "DBCP2"); + + public static final String ACCESSOR_DATASOURCE_MONITOR = "com.navercorp.pinpoint.plugin.commons.dbcp2.DataSourceMonitorAccessor"; + + public static final String INTERCEPTOR_CONSTRUCTOR = "com.navercorp.pinpoint.plugin.commons.dbcp2.interceptor.DataSourceConstructorInterceptor"; + public static final String INTERCEPTOR_CLOSE = "com.navercorp.pinpoint.plugin.commons.dbcp2.interceptor.DataSourceCloseInterceptor"; + + public static final String INTERCEPTOR_GET_CONNECTION = "com.navercorp.pinpoint.plugin.commons.dbcp2.interceptor.DataSourceGetConnectionInterceptor"; + public static final String INTERCEPTOR_CLOSE_CONNECTION = "com.navercorp.pinpoint.plugin.commons.dbcp2.interceptor.DataSourceCloseConnectionInterceptor"; + +} diff --git a/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/CommonsDbcp2MetadataProvider.java b/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/CommonsDbcp2MetadataProvider.java index d8a5b3c8b823..5b9319a3ac01 100644 --- a/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/CommonsDbcp2MetadataProvider.java +++ b/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/CommonsDbcp2MetadataProvider.java @@ -25,7 +25,7 @@ public class CommonsDbcp2MetadataProvider implements TraceMetadataProvider { */ @Override public void setup(TraceMetadataSetupContext context) { - context.addServiceType(CommonsDbcp2Plugin.DBCP2_SERVICE_TYPE); + context.addServiceType(CommonsDbcp2Constants.SERVICE_TYPE); } } diff --git a/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/CommonsDbcp2Plugin.java b/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/CommonsDbcp2Plugin.java index 39e7166587ed..e20abf67b1fd 100644 --- a/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/CommonsDbcp2Plugin.java +++ b/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/CommonsDbcp2Plugin.java @@ -26,8 +26,6 @@ import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; import java.security.ProtectionDomain; @@ -35,9 +33,6 @@ public class CommonsDbcp2Plugin implements ProfilerPlugin, TransformTemplateAwar private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); - public static final ServiceType DBCP2_SERVICE_TYPE = ServiceTypeFactory.of(6052, "DBCP2"); - public static final String DBCP2_SCOPE = "DBCP2_SCOPE"; - private CommonsDbcp2Config config; private TransformTemplate transformTemplate; @@ -62,7 +57,7 @@ private void addPoolGuardConnectionWrapperTransformer() { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); - target.addInterceptor("com.navercorp.pinpoint.plugin.commons.dbcp2.interceptor.DataSourceCloseInterceptor"); + target.addInterceptor(CommonsDbcp2Constants.INTERCEPTOR_CLOSE_CONNECTION); return target.toBytecode(); } }); @@ -70,16 +65,38 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin private void addBasicDataSourceTransformer() { transformTemplate.transform("org.apache.commons.dbcp2.BasicDataSource", new TransformCallback() { - + @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); - target.addInterceptor("com.navercorp.pinpoint.plugin.commons.dbcp2.interceptor.DataSourceGetConnectionInterceptor"); + + if (isAvailableDataSourceMonitor(target)) { + target.addField(CommonsDbcp2Constants.ACCESSOR_DATASOURCE_MONITOR); + target.addInterceptor(CommonsDbcp2Constants.INTERCEPTOR_CONSTRUCTOR); + target.addInterceptor(CommonsDbcp2Constants.INTERCEPTOR_CLOSE); + } + + target.addInterceptor(CommonsDbcp2Constants.INTERCEPTOR_GET_CONNECTION); return target.toBytecode(); } }); } + private boolean isAvailableDataSourceMonitor(InstrumentClass target) { + boolean hasMethod = target.hasMethod("getUrl"); + if (!hasMethod) { + return false; + } + + hasMethod = target.hasMethod("getNumActive"); + if (!hasMethod) { + return false; + } + + hasMethod = target.hasMethod("getMaxTotal"); + return hasMethod; + } + @Override public void setTransformTemplate(TransformTemplate transformTemplate) { this.transformTemplate = transformTemplate; diff --git a/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/DataSourceMonitorAccessor.java b/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/DataSourceMonitorAccessor.java new file mode 100644 index 000000000000..328a46cb46fe --- /dev/null +++ b/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/DataSourceMonitorAccessor.java @@ -0,0 +1,27 @@ +/* + * Copyright 2017 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.commons.dbcp2; + +/** + * @author Taejin Koo + */ +public interface DataSourceMonitorAccessor { + + void _$PINPOINT$_setDataSourceMonitor(Dbcp2DataSourceMonitor dataSourceMonitor); + Dbcp2DataSourceMonitor _$PINPOINT$_getDataSourceMonitor(); + +} diff --git a/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/Dbcp2DataSourceMonitor.java b/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/Dbcp2DataSourceMonitor.java new file mode 100644 index 000000000000..50994142b3a2 --- /dev/null +++ b/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/Dbcp2DataSourceMonitor.java @@ -0,0 +1,69 @@ +/* + * Copyright 2017 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.commons.dbcp2; + +import com.navercorp.pinpoint.bootstrap.plugin.monitor.DataSourceMonitor; +import com.navercorp.pinpoint.common.trace.ServiceType; +import org.apache.commons.dbcp2.BasicDataSource; + +/** + * @author Taejin Koo + */ +public class Dbcp2DataSourceMonitor implements DataSourceMonitor { + + private final BasicDataSource dataSource; + private volatile boolean closed = false; + + public Dbcp2DataSourceMonitor(BasicDataSource dataSource) { + this.dataSource = dataSource; + } + + @Override + public ServiceType getServiceType() { + return CommonsDbcp2Constants.SERVICE_TYPE; + } + + @Override + public String getName() { + return null; + } + + @Override + public String getUrl() { + return dataSource.getUrl(); + } + + @Override + public int getActiveConnectionSize() { + return dataSource.getNumActive(); + } + + @Override + public int getMaxConnectionSize() { + return dataSource.getMaxTotal(); + } + + @Override + public boolean isDisabled() { + return closed; + } + + public void close() { + closed = true; + } + +} diff --git a/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/interceptor/DataSourceCloseConnectionInterceptor.java b/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/interceptor/DataSourceCloseConnectionInterceptor.java new file mode 100644 index 000000000000..38bf24ff304f --- /dev/null +++ b/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/interceptor/DataSourceCloseConnectionInterceptor.java @@ -0,0 +1,46 @@ +/* + * Copyright 2016 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.commons.dbcp2.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; +import com.navercorp.pinpoint.bootstrap.interceptor.annotation.Scope; +import com.navercorp.pinpoint.bootstrap.interceptor.annotation.TargetMethod; +import com.navercorp.pinpoint.plugin.commons.dbcp2.CommonsDbcp2Constants; + +@Scope(CommonsDbcp2Constants.SCOPE) +@TargetMethod(name="close") +public class DataSourceCloseConnectionInterceptor extends SpanEventSimpleAroundInterceptorForPlugin { + + public DataSourceCloseConnectionInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + super(traceContext, descriptor); + } + + @Override + public void doInBeforeTrace(SpanEventRecorder recorder, final Object target, Object[] args) { + } + + @Override + public void doInAfterTrace(SpanEventRecorder trace, Object target, Object[] args, Object result, Throwable throwable) { + trace.recordServiceType(CommonsDbcp2Constants.SERVICE_TYPE); + trace.recordApi(getMethodDescriptor()); + trace.recordException(throwable); + } + +} diff --git a/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/interceptor/DataSourceCloseInterceptor.java b/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/interceptor/DataSourceCloseInterceptor.java index c29488a4bf74..848d8574d8a3 100644 --- a/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/interceptor/DataSourceCloseInterceptor.java +++ b/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/interceptor/DataSourceCloseInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2017 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,30 +17,58 @@ package com.navercorp.pinpoint.plugin.commons.dbcp2.interceptor; import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; import com.navercorp.pinpoint.bootstrap.context.TraceContext; -import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; import com.navercorp.pinpoint.bootstrap.interceptor.annotation.Scope; import com.navercorp.pinpoint.bootstrap.interceptor.annotation.TargetMethod; -import com.navercorp.pinpoint.plugin.commons.dbcp2.CommonsDbcp2Plugin; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.monitor.DataSourceMonitor; +import com.navercorp.pinpoint.bootstrap.plugin.monitor.PluginMonitorContext; +import com.navercorp.pinpoint.bootstrap.plugin.monitor.PluginMonitorRegistry; +import com.navercorp.pinpoint.plugin.commons.dbcp2.CommonsDbcp2Constants; +import com.navercorp.pinpoint.plugin.commons.dbcp2.DataSourceMonitorAccessor; +import com.navercorp.pinpoint.plugin.commons.dbcp2.Dbcp2DataSourceMonitor; -@Scope(CommonsDbcp2Plugin.DBCP2_SCOPE) +/** + * @author Taejin Koo + */ +@Scope(CommonsDbcp2Constants.SCOPE) @TargetMethod(name="close") -public class DataSourceCloseInterceptor extends SpanEventSimpleAroundInterceptorForPlugin { +public class DataSourceCloseInterceptor implements AroundInterceptor { + + private static final PLogger logger = PLoggerFactory.getLogger(DataSourceCloseInterceptor.class); + + private final TraceContext traceContext; + private final MethodDescriptor methodDescriptor; - public DataSourceCloseInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { - super(traceContext, descriptor); + public DataSourceCloseInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + this.traceContext = traceContext; + this.methodDescriptor = methodDescriptor; } @Override - public void doInBeforeTrace(SpanEventRecorder recorder, final Object target, Object[] args) { + public void before(Object target, Object[] args) { + PluginMonitorContext pluginMonitorContext = traceContext.getPluginMonitorContext(); + PluginMonitorRegistry dataSourceMonitorRegistry = pluginMonitorContext.getDataSourceMonitorRegistry(); + if (dataSourceMonitorRegistry == null) { + return; + } + + if ((target instanceof DataSourceMonitorAccessor)) { + Dbcp2DataSourceMonitor dataSourceMonitor = ((DataSourceMonitorAccessor) target)._$PINPOINT$_getDataSourceMonitor(); + + if (dataSourceMonitor != null) { + ((DataSourceMonitorAccessor) target)._$PINPOINT$_setDataSourceMonitor(null); + dataSourceMonitor.close(); + dataSourceMonitorRegistry.unregister(dataSourceMonitor); + } + } } @Override - public void doInAfterTrace(SpanEventRecorder trace, Object target, Object[] args, Object result, Throwable throwable) { - trace.recordServiceType(CommonsDbcp2Plugin.DBCP2_SERVICE_TYPE); - trace.recordApi(getMethodDescriptor()); - trace.recordException(throwable); + public void after(Object target, Object[] args, Object result, Throwable throwable) { + } } diff --git a/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/interceptor/DataSourceConstructorInterceptor.java b/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/interceptor/DataSourceConstructorInterceptor.java new file mode 100644 index 000000000000..2a2dd64b921c --- /dev/null +++ b/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/interceptor/DataSourceConstructorInterceptor.java @@ -0,0 +1,77 @@ +/* + * Copyright 2017 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.commons.dbcp2.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.interceptor.annotation.Scope; +import com.navercorp.pinpoint.bootstrap.interceptor.annotation.TargetConstructor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.monitor.DataSourceMonitor; +import com.navercorp.pinpoint.bootstrap.plugin.monitor.PluginMonitorContext; +import com.navercorp.pinpoint.bootstrap.plugin.monitor.PluginMonitorRegistry; +import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils; +import com.navercorp.pinpoint.plugin.commons.dbcp2.CommonsDbcp2Constants; +import com.navercorp.pinpoint.plugin.commons.dbcp2.DataSourceMonitorAccessor; +import com.navercorp.pinpoint.plugin.commons.dbcp2.Dbcp2DataSourceMonitor; +import org.apache.commons.dbcp2.BasicDataSource; + +/** + * @author Taejin Koo + */ +@Scope(CommonsDbcp2Constants.SCOPE) +@TargetConstructor +public class DataSourceConstructorInterceptor implements AroundInterceptor { + + private static final PLogger logger = PLoggerFactory.getLogger(DataSourceConstructorInterceptor.class); + + private final TraceContext traceContext; + private final MethodDescriptor methodDescriptor; + + + public DataSourceConstructorInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + this.traceContext = traceContext; + this.methodDescriptor = methodDescriptor; + } + + @Override + public void before(Object target, Object[] args) { + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (!InterceptorUtils.isSuccess(throwable)) { + return; + } + + PluginMonitorContext pluginMonitorContext = traceContext.getPluginMonitorContext(); + PluginMonitorRegistry dataSourceMonitorRegistry = pluginMonitorContext.getDataSourceMonitorRegistry(); + if (dataSourceMonitorRegistry == null) { + return; + } + + if ((target instanceof DataSourceMonitorAccessor)) { + Dbcp2DataSourceMonitor dbcpDataSourceMonitor = new Dbcp2DataSourceMonitor((BasicDataSource)target); + dataSourceMonitorRegistry.register(dbcpDataSourceMonitor); + + ((DataSourceMonitorAccessor) target)._$PINPOINT$_setDataSourceMonitor(dbcpDataSourceMonitor); + } + } + +} diff --git a/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/interceptor/DataSourceGetConnectionInterceptor.java b/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/interceptor/DataSourceGetConnectionInterceptor.java index 5f5f91cdd34a..f7e7d529feb7 100644 --- a/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/interceptor/DataSourceGetConnectionInterceptor.java +++ b/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/interceptor/DataSourceGetConnectionInterceptor.java @@ -23,9 +23,9 @@ import com.navercorp.pinpoint.bootstrap.interceptor.annotation.Scope; import com.navercorp.pinpoint.bootstrap.interceptor.annotation.TargetMethod; import com.navercorp.pinpoint.bootstrap.interceptor.annotation.TargetMethods; -import com.navercorp.pinpoint.plugin.commons.dbcp2.CommonsDbcp2Plugin; +import com.navercorp.pinpoint.plugin.commons.dbcp2.CommonsDbcp2Constants; -@Scope(CommonsDbcp2Plugin.DBCP2_SCOPE) +@Scope(CommonsDbcp2Constants.SCOPE) @TargetMethods({ @TargetMethod(name="getConnection"), @TargetMethod(name="getConnection", paramTypes={"java.lang.String", "java.lang.String"}) @@ -42,7 +42,7 @@ public void doInBeforeTrace(SpanEventRecorder recorder, final Object target, Obj @Override public void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { - recorder.recordServiceType(CommonsDbcp2Plugin.DBCP2_SERVICE_TYPE); + recorder.recordServiceType(CommonsDbcp2Constants.SERVICE_TYPE); if (args == null) { // getConnection() without any arguments recorder.recordApi(getMethodDescriptor());