Skip to content

Commit

Permalink
[#2496] Add datasource metric collection
Browse files Browse the repository at this point in the history
Apply dbcp2 plugin to collect datasource metrics
  • Loading branch information
koo-taejin authored and emeroad committed Feb 2, 2017
1 parent 7b2c380 commit 73af3b1
Show file tree
Hide file tree
Showing 10 changed files with 333 additions and 25 deletions.
5 changes: 5 additions & 0 deletions plugins/dbcp2/pom.xml
Expand Up @@ -34,5 +34,10 @@
<artifactId>pinpoint-bootstrap-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
@@ -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";

}
Expand Up @@ -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);
}

}
Expand Up @@ -26,18 +26,13 @@
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;

public class CommonsDbcp2Plugin implements ProfilerPlugin, TransformTemplateAware {

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;
Expand All @@ -62,24 +57,46 @@ 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();
}
});
}

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;
Expand Down
@@ -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();

}
@@ -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;
}

}
@@ -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);
}

}
@@ -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.
Expand All @@ -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<DataSourceMonitor> 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) {

}

}

0 comments on commit 73af3b1

Please sign in to comment.