提交 80af1667 编写于 作者: S scolia 提交者: wu-sheng

feat: add support of mongodb v3.7.x or higher (#3591)

* feat: add support of mongodb v3.7.x or higher

* feat: remove mapping, using EnhancedInstance to mark remotePeer

* feat: add support of v3.6.x

* fix: disable support will 3.6.x, which will throw ClassCircularityError exception

* style: clean code

* fix support of 3.8.x~3.11.1, update test case and doc

* update stage name

* rename class

* rename stage
上级 69a28d45
...@@ -66,7 +66,7 @@ pipeline { ...@@ -66,7 +66,7 @@ pipeline {
sh './mvnw -f test/plugin/pom.xml clean package -DskipTests -Dbuild_id=wl3_${BUILD_ID} docker:build' sh './mvnw -f test/plugin/pom.xml clean package -DskipTests -Dbuild_id=wl3_${BUILD_ID} docker:build'
} }
} }
stage('Test Cases Report (137)') { stage('Test Cases Report (149)') {
steps { steps {
echo "reserve." echo "reserve."
} }
...@@ -96,7 +96,7 @@ pipeline { ...@@ -96,7 +96,7 @@ pipeline {
sh 'bash test/plugin/run.sh --build_id=wl3_${BUILD_ID} sofarpc-scenario' sh 'bash test/plugin/run.sh --build_id=wl3_${BUILD_ID} sofarpc-scenario'
} }
} }
stage('mongodb 3.0-3.5.0 (5)') { stage('mongodb 3.4.0-3.11.1 (17)') {
steps { steps {
sh 'bash test/plugin/run.sh --build_id=wl3_${BUILD_ID} mongodb-3.x-scenario' sh 'bash test/plugin/run.sh --build_id=wl3_${BUILD_ID} mongodb-3.x-scenario'
} }
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<mongo-java-driver.version>3.4.2</mongo-java-driver.version> <mongo-java-driver.version>3.11.0</mongo-java-driver.version>
</properties> </properties>
<dependencies> <dependencies>
......
...@@ -17,67 +17,86 @@ ...@@ -17,67 +17,86 @@
*/ */
package org.apache.skywalking.apm.plugin.mongodb.v3.define; package org.apache.skywalking.apm.plugin.mongodb.v3.define.v30;
import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine; import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch; import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch; import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint; import org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.v30.MongoDBInterceptor;
import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType; import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
/**
* Enhance {@code com.mongodb.Mongo} instance, and intercept {@code com.mongodb.Mongo#execute(...)} method,
* this method is a unified entrance of execute mongo command.
* <p>
* support: 3.0.x~3.5.x
*
* @author scolia
* @see MongoDBInterceptor
*/
@SuppressWarnings({"Duplicates"})
public class MongoDBInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { public class MongoDBInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
private static final String WITNESS_CLASS = "com.mongodb.connection.WriteCommandProtocol";
private static final String ENHANCE_CLASS = "com.mongodb.Mongo"; private static final String ENHANCE_CLASS = "com.mongodb.Mongo";
private static final String MONGDB_METHOD_INTERCET_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.MongoDBMethodInterceptor"; private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.v30.MongoDBInterceptor";
@Override
protected String[] witnessClasses() {
// this class only exist in version: 3.0.x~3.5.x
return new String[]{WITNESS_CLASS};
}
@Override
protected ClassMatch enhanceClass() {
return NameMatch.byName(ENHANCE_CLASS);
}
@Override @Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[] { return new ConstructorInterceptPoint[]{new ConstructorInterceptPoint() {
new ConstructorInterceptPoint() { @Override
@Override public ElementMatcher<MethodDescription> getConstructorMatcher() {
public ElementMatcher<MethodDescription> getConstructorMatcher() { return takesArgumentWithType(0, "com.mongodb.connection.Cluster");
return takesArgumentWithType(0, "com.mongodb.connection.Cluster"); }
}
@Override
@Override public String getConstructorInterceptor() {
public String getConstructorInterceptor() { return INTERCEPTOR_CLASS;
return MONGDB_METHOD_INTERCET_CLASS;
}
} }
}
}; };
} }
@Override @Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[] { return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {
new InstanceMethodsInterceptPoint() { @Override
@Override public ElementMatcher<MethodDescription> getMethodsMatcher() {
public ElementMatcher<MethodDescription> getMethodsMatcher() { return named("execute");
return named("execute"); }
}
@Override
@Override public String getMethodsInterceptor() {
public String getMethodsInterceptor() { return INTERCEPTOR_CLASS;
return MONGDB_METHOD_INTERCET_CLASS;
}
@Override
public boolean isOverrideArgs() {
return false;
}
} }
@Override
public boolean isOverrideArgs() {
return false;
}
}
}; };
} }
@Override
protected ClassMatch enhanceClass() {
return NameMatch.byName(ENHANCE_CLASS);
}
} }
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.skywalking.apm.plugin.mongodb.v3.define.v37;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.v37.MongoDBClientDelegateInterceptor;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
/**
* Enhance {@code com.mongodb.client.internal.MongoClientDelegate} instance, and intercept
* {@code com.mongodb.client.internal.MongoClientDelegate#getOperationExecutor()}, this is the only way to
* get OperationExecutor which is unified entrance of execute mongo command. we can mark OperationExecutor
* which connection belongs to.
* <p>
* support: 3.7.x or higher
*
* @author scolia
* @see MongoDBOperationExecutorInstrumentation
* @see MongoDBClientDelegateInterceptor
*/
public class MongoDBClientDelegateInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
private static final String ENHANCE_CLASS = "com.mongodb.client.internal.MongoClientDelegate";
private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.v37.MongoDBClientDelegateInterceptor";
@Override
protected String[] witnessClasses() {
return new String[]{ENHANCE_CLASS};
}
@Override
protected ClassMatch enhanceClass() {
return byName(ENHANCE_CLASS);
}
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[]{new ConstructorInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getConstructorMatcher() {
return takesArgumentWithType(0, "com.mongodb.connection.Cluster");
}
@Override
public String getConstructorInterceptor() {
return INTERCEPTOR_CLASS;
}
}
};
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("getOperationExecutor");
}
@Override
public String getMethodsInterceptor() {
return INTERCEPTOR_CLASS;
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.skywalking.apm.plugin.mongodb.v3.define.v37;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;
import org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
import org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.v37.MongoDBOperationExecutorInterceptor;
/**
* {@code com.mongodb.client.internal.OperationExecutor} which is unified entrance of execute mongo command.
* so we can intercept {@code com.mongodb.client.internal.OperationExecutor#execute(...)} method
* to known which command will be execute.
* <p>
* support: 3.7.x
*
* @author scolia
* @see MongoDBOperationExecutorInterceptor
*/
@SuppressWarnings({"Duplicates"})
public class MongoDBOperationExecutorInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
private static final String WITNESS_CLASS = "com.mongodb.client.internal.MongoClientDelegate";
private static final String ENHANCE_CLASS = "com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor";
private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.v37.MongoDBOperationExecutorInterceptor";
private static final String METHOD_NAME = "execute";
private static final String ARGUMENT_TYPE = "com.mongodb.session.ClientSession";
@Override
protected String[] witnessClasses() {
return new String[]{WITNESS_CLASS};
}
@Override
protected ClassMatch enhanceClass() {
return NameMatch.byName(ENHANCE_CLASS);
}
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return ElementMatchers
// 3.7.x
.named(METHOD_NAME).and(ArgumentTypeNameMatch.takesArgumentWithType(1, ARGUMENT_TYPE))
.or(ElementMatchers.<MethodDescription>named(METHOD_NAME)
.and(ArgumentTypeNameMatch.takesArgumentWithType(2, ARGUMENT_TYPE))
);
}
@Override
public String getMethodsInterceptor() {
return INTERCEPTOR_CLASS;
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.skywalking.apm.plugin.mongodb.v3.define.v38;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;
import org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
/**
* same whit {@link org.apache.skywalking.apm.plugin.mongodb.v3.define.v37.MongoDBOperationExecutorInstrumentation}
* <p>
* support: 3.8.x or higher
*
* @author scolia
*/
public class MongoDBOperationExecutorInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
private static final String WITNESS_CLASS = "com.mongodb.client.ClientSession";
private static final String ENHANCE_CLASS = "com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor";
private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.v37.MongoDBOperationExecutorInterceptor";
private static final String METHOD_NAME = "execute";
private static final String ARGUMENT_TYPE = "com.mongodb.client.ClientSession";
@Override
protected String[] witnessClasses() {
return new String[]{WITNESS_CLASS};
}
@Override
protected ClassMatch enhanceClass() {
return NameMatch.byName(ENHANCE_CLASS);
}
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return ElementMatchers
// 3.8.x~3.11.x
.named(METHOD_NAME).and(ArgumentTypeNameMatch.takesArgumentWithType(2, ARGUMENT_TYPE))
.or(ElementMatchers.<MethodDescription>named(METHOD_NAME)
.and(ArgumentTypeNameMatch.takesArgumentWithType(3, ARGUMENT_TYPE))
);
}
@Override
public String getMethodsInterceptor() {
return INTERCEPTOR_CLASS;
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.v30;
import com.mongodb.connection.Cluster;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.logging.api.ILog;
import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.plugin.mongodb.v3.support.MongoRemotePeerHelper;
import org.apache.skywalking.apm.plugin.mongodb.v3.support.MongoSpanHelper;
import java.lang.reflect.Method;
/**
* Intercept method of {@code com.mongodb.Mongo#execute(ReadOperation, ReadPreference)} or
* {@code com.mongodb.Mongo#execute(WriteOperation)}. record the MongoDB host, operation name and the key of the
* operation.
* <p>
* only supported: 3.0.x-3.5.x
*
* @author scolia
*/
@SuppressWarnings({"deprecation", "Duplicates"})
public class MongoDBInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor {
private static final ILog logger = LogManager.getLogger(MongoDBInterceptor.class);
@Override
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
Cluster cluster = (Cluster) allArguments[0];
String peers = MongoRemotePeerHelper.getRemotePeer(cluster);
objInst.setSkyWalkingDynamicField(peers);
}
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, MethodInterceptResult result) {
String executeMethod = allArguments[0].getClass().getSimpleName();
String remotePeer = (String) objInst.getSkyWalkingDynamicField();
if (logger.isDebugEnable()) {
logger.debug("Mongo execute: [executeMethod: {}, remotePeer: {}]", executeMethod, remotePeer);
}
MongoSpanHelper.createExitSpan(executeMethod, remotePeer, allArguments[0]);
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Object ret) {
ContextManager.stopSpan();
return ret;
}
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Throwable t) {
AbstractSpan activeSpan = ContextManager.activeSpan();
activeSpan.errorOccurred();
activeSpan.log(t);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.v37;
import com.mongodb.connection.Cluster;
import org.apache.skywalking.apm.agent.core.logging.api.ILog;
import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.plugin.mongodb.v3.support.MongoRemotePeerHelper;
import java.lang.reflect.Method;
/**
* @author scolia
*/
@SuppressWarnings("Duplicates")
public class MongoDBClientDelegateInterceptor implements InstanceConstructorInterceptor, InstanceMethodsAroundInterceptor {
private static final ILog logger = LogManager.getLogger(MongoDBClientDelegateInterceptor.class);
@SuppressWarnings("deprecation")
@Override
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
Cluster cluster = (Cluster) allArguments[0];
String remotePeer = MongoRemotePeerHelper.getRemotePeer(cluster);
objInst.setSkyWalkingDynamicField(remotePeer);
}
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, MethodInterceptResult result) {
// do nothing
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Object ret) {
if (ret instanceof EnhancedInstance) {
// pass remotePeer to OperationExecutor, which will be wrapper as EnhancedInstance
// @see: org.apache.skywalking.apm.plugin.mongodb.v3.define.v37.MongoDBOperationExecutorInstrumentation
EnhancedInstance retInstance = (EnhancedInstance) ret;
String remotePeer = (String) objInst.getSkyWalkingDynamicField();
if (logger.isDebugEnable()) {
logger.debug("Mark OperationExecutor remotePeer: {}", remotePeer);
}
retInstance.setSkyWalkingDynamicField(remotePeer);
}
return ret;
}
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
// do nothing
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.v37;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.logging.api.ILog;
import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.plugin.mongodb.v3.support.MongoSpanHelper;
import java.lang.reflect.Method;
/**
* @author scolia
*/
@SuppressWarnings("Duplicates")
public class MongoDBOperationExecutorInterceptor implements InstanceMethodsAroundInterceptor {
private static final ILog logger = LogManager.getLogger(MongoDBOperationExecutorInterceptor.class);
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
MethodInterceptResult result) {
String executeMethod = allArguments[0].getClass().getSimpleName();
// OperationExecutor has be mark it's remotePeer
// @see: MongoDBClientDelegateInterceptor.afterMethod
String remotePeer = (String) objInst.getSkyWalkingDynamicField();
if (logger.isDebugEnable()) {
logger.debug("Mongo execute: [executeMethod: {}, remotePeer: {}]", executeMethod, remotePeer);
}
MongoSpanHelper.createExitSpan(executeMethod, remotePeer, allArguments[0]);
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
Object ret) {
ContextManager.stopSpan();
return ret;
}
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Throwable t) {
AbstractSpan activeSpan = ContextManager.activeSpan();
activeSpan.errorOccurred();
activeSpan.log(t);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.skywalking.apm.plugin.mongodb.v3.support;
/**
* @author scolia
*/
public class MongoConstants {
private MongoConstants() {
}
public static final String DB_TYPE = "MongoDB";
public static final String MONGO_DB_OP_PREFIX = "MongoDB/";
public static final int FILTER_LENGTH_LIMIT = 256;
public static final String EMPTY = "";
}
...@@ -17,140 +17,101 @@ ...@@ -17,140 +17,101 @@
*/ */
package org.apache.skywalking.apm.plugin.mongodb.v3; package org.apache.skywalking.apm.plugin.mongodb.v3.support;
import com.mongodb.ReadPreference;
import com.mongodb.ServerAddress;
import com.mongodb.bulk.DeleteRequest; import com.mongodb.bulk.DeleteRequest;
import com.mongodb.bulk.InsertRequest; import com.mongodb.bulk.InsertRequest;
import com.mongodb.bulk.UpdateRequest; import com.mongodb.bulk.UpdateRequest;
import com.mongodb.bulk.WriteRequest; import com.mongodb.bulk.WriteRequest;
import com.mongodb.connection.Cluster; import com.mongodb.operation.*;
import com.mongodb.connection.ServerDescription;
import com.mongodb.operation.CountOperation;
import com.mongodb.operation.CreateCollectionOperation;
import com.mongodb.operation.CreateIndexesOperation;
import com.mongodb.operation.CreateViewOperation;
import com.mongodb.operation.DeleteOperation;
import com.mongodb.operation.DistinctOperation;
import com.mongodb.operation.FindAndDeleteOperation;
import com.mongodb.operation.FindAndReplaceOperation;
import com.mongodb.operation.FindAndUpdateOperation;
import com.mongodb.operation.FindOperation;
import com.mongodb.operation.GroupOperation;
import com.mongodb.operation.InsertOperation;
import com.mongodb.operation.ListCollectionsOperation;
import com.mongodb.operation.MapReduceToCollectionOperation;
import com.mongodb.operation.MapReduceWithInlineResultsOperation;
import com.mongodb.operation.MixedBulkWriteOperation;
import com.mongodb.operation.ReadOperation;
import com.mongodb.operation.UpdateOperation;
import com.mongodb.operation.WriteOperation;
import java.lang.reflect.Method;
import java.util.List;
import org.apache.skywalking.apm.agent.core.conf.Config;
import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
import org.bson.BsonDocument; import org.bson.BsonDocument;
import java.util.List;
/** /**
* {@link MongoDBMethodInterceptor} intercept method of {@link com.mongodb.Mongo#execute(ReadOperation, ReadPreference)} * @author scolia
* or {@link com.mongodb.Mongo#execute(WriteOperation)}. record the mongoDB host, operation name and the key of the
* operation.
*
* @author baiyang
*/ */
public class MongoDBMethodInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor { @SuppressWarnings({"deprecation", "Duplicates"})
public class MongoOperationHelper {
private static final String DB_TYPE = "MongoDB";
private static final String MONGO_DB_OP_PREFIX = "MongoDB/";
private static final int FILTER_LENGTH_LIMIT = 256; private MongoOperationHelper() {
private static final String EMPTY = ""; }
/** /**
* Convert ReadOperation interface or WriteOperation interface to the implementation class. Get the method name and * Convert ReadOperation interface or WriteOperation interface to the implementation class. Get the method name and
* filter info. * filter info.
*/ */
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
private String getTraceParam(Object obj) { public static String getTraceParam(Object obj) {
if (obj instanceof CountOperation) { if (obj instanceof CountOperation) {
BsonDocument filter = ((CountOperation)obj).getFilter(); BsonDocument filter = ((CountOperation) obj).getFilter();
return limitFilter(filter.toString()); return limitFilter(filter.toString());
} else if (obj instanceof DistinctOperation) { } else if (obj instanceof DistinctOperation) {
BsonDocument filter = ((DistinctOperation)obj).getFilter(); BsonDocument filter = ((DistinctOperation) obj).getFilter();
return limitFilter(filter.toString()); return limitFilter(filter.toString());
} else if (obj instanceof FindOperation) { } else if (obj instanceof FindOperation) {
BsonDocument filter = ((FindOperation)obj).getFilter(); BsonDocument filter = ((FindOperation) obj).getFilter();
return limitFilter(filter.toString()); return limitFilter(filter.toString());
} else if (obj instanceof GroupOperation) { } else if (obj instanceof GroupOperation) {
BsonDocument filter = ((GroupOperation)obj).getFilter(); BsonDocument filter = ((GroupOperation) obj).getFilter();
return limitFilter(filter.toString()); return limitFilter(filter.toString());
} else if (obj instanceof ListCollectionsOperation) { } else if (obj instanceof ListCollectionsOperation) {
BsonDocument filter = ((ListCollectionsOperation)obj).getFilter(); BsonDocument filter = ((ListCollectionsOperation) obj).getFilter();
return limitFilter(filter.toString()); return limitFilter(filter.toString());
} else if (obj instanceof MapReduceWithInlineResultsOperation) { } else if (obj instanceof MapReduceWithInlineResultsOperation) {
BsonDocument filter = ((MapReduceWithInlineResultsOperation)obj).getFilter(); BsonDocument filter = ((MapReduceWithInlineResultsOperation) obj).getFilter();
return limitFilter(filter.toString()); return limitFilter(filter.toString());
} else if (obj instanceof DeleteOperation) { } else if (obj instanceof DeleteOperation) {
List<DeleteRequest> writeRequestList = ((DeleteOperation)obj).getDeleteRequests(); List<DeleteRequest> writeRequestList = ((DeleteOperation) obj).getDeleteRequests();
return getFilter(writeRequestList); return getFilter(writeRequestList);
} else if (obj instanceof InsertOperation) { } else if (obj instanceof InsertOperation) {
List<InsertRequest> writeRequestList = ((InsertOperation)obj).getInsertRequests(); List<InsertRequest> writeRequestList = ((InsertOperation) obj).getInsertRequests();
return getFilter(writeRequestList); return getFilter(writeRequestList);
} else if (obj instanceof UpdateOperation) { } else if (obj instanceof UpdateOperation) {
List<UpdateRequest> writeRequestList = ((UpdateOperation)obj).getUpdateRequests(); List<UpdateRequest> writeRequestList = ((UpdateOperation) obj).getUpdateRequests();
return getFilter(writeRequestList); return getFilter(writeRequestList);
} else if (obj instanceof CreateCollectionOperation) { } else if (obj instanceof CreateCollectionOperation) {
String filter = ((CreateCollectionOperation)obj).getCollectionName(); String filter = ((CreateCollectionOperation) obj).getCollectionName();
return limitFilter(filter); return limitFilter(filter);
} else if (obj instanceof CreateIndexesOperation) { } else if (obj instanceof CreateIndexesOperation) {
List<String> filter = ((CreateIndexesOperation)obj).getIndexNames(); List<String> filter = ((CreateIndexesOperation) obj).getIndexNames();
return limitFilter(filter.toString()); return limitFilter(filter.toString());
} else if (obj instanceof CreateViewOperation) { } else if (obj instanceof CreateViewOperation) {
String filter = ((CreateViewOperation)obj).getViewName(); String filter = ((CreateViewOperation) obj).getViewName();
return limitFilter(filter); return limitFilter(filter);
} else if (obj instanceof FindAndDeleteOperation) { } else if (obj instanceof FindAndDeleteOperation) {
BsonDocument filter = ((FindAndDeleteOperation)obj).getFilter(); BsonDocument filter = ((FindAndDeleteOperation) obj).getFilter();
return limitFilter(filter.toString()); return limitFilter(filter.toString());
} else if (obj instanceof FindAndReplaceOperation) { } else if (obj instanceof FindAndReplaceOperation) {
BsonDocument filter = ((FindAndReplaceOperation)obj).getFilter(); BsonDocument filter = ((FindAndReplaceOperation) obj).getFilter();
return limitFilter(filter.toString()); return limitFilter(filter.toString());
} else if (obj instanceof FindAndUpdateOperation) { } else if (obj instanceof FindAndUpdateOperation) {
BsonDocument filter = ((FindAndUpdateOperation)obj).getFilter(); BsonDocument filter = ((FindAndUpdateOperation) obj).getFilter();
return limitFilter(filter.toString()); return limitFilter(filter.toString());
} else if (obj instanceof MapReduceToCollectionOperation) { } else if (obj instanceof MapReduceToCollectionOperation) {
BsonDocument filter = ((MapReduceToCollectionOperation)obj).getFilter(); BsonDocument filter = ((MapReduceToCollectionOperation) obj).getFilter();
return limitFilter(filter.toString()); return limitFilter(filter.toString());
} else if (obj instanceof MixedBulkWriteOperation) { } else if (obj instanceof MixedBulkWriteOperation) {
List<? extends WriteRequest> writeRequestList = ((MixedBulkWriteOperation)obj).getWriteRequests(); List<? extends WriteRequest> writeRequestList = ((MixedBulkWriteOperation) obj).getWriteRequests();
return getFilter(writeRequestList); return getFilter(writeRequestList);
} else { } else {
return EMPTY; return MongoConstants.EMPTY;
} }
} }
private String getFilter(List<? extends WriteRequest> writeRequestList) { private static String getFilter(List<? extends WriteRequest> writeRequestList) {
StringBuilder params = new StringBuilder(); StringBuilder params = new StringBuilder();
for (WriteRequest request : writeRequestList) { for (WriteRequest request : writeRequestList) {
if (request instanceof InsertRequest) { if (request instanceof InsertRequest) {
params.append(((InsertRequest)request).getDocument().toString()).append(","); params.append(((InsertRequest) request).getDocument().toString()).append(",");
} else if (request instanceof DeleteRequest) { } else if (request instanceof DeleteRequest) {
params.append(((DeleteRequest)request).getFilter()).append(","); params.append(((DeleteRequest) request).getFilter()).append(",");
} else if (request instanceof UpdateRequest) { } else if (request instanceof UpdateRequest) {
params.append(((UpdateRequest)request).getFilter()).append(","); params.append(((UpdateRequest) request).getFilter()).append(",");
} }
if (params.length() > FILTER_LENGTH_LIMIT) { if (params.length() > MongoConstants.FILTER_LENGTH_LIMIT) {
params.append("..."); params.append("...");
break; break;
} }
...@@ -158,54 +119,13 @@ public class MongoDBMethodInterceptor implements InstanceMethodsAroundIntercepto ...@@ -158,54 +119,13 @@ public class MongoDBMethodInterceptor implements InstanceMethodsAroundIntercepto
return params.toString(); return params.toString();
} }
private String limitFilter(String filter) { private static String limitFilter(String filter) {
final StringBuilder params = new StringBuilder(); final StringBuilder params = new StringBuilder();
if (filter.length() > FILTER_LENGTH_LIMIT) { if (filter.length() > MongoConstants.FILTER_LENGTH_LIMIT) {
return params.append(filter.substring(0, FILTER_LENGTH_LIMIT)).append("...").toString(); return params.append(filter, 0, MongoConstants.FILTER_LENGTH_LIMIT).append("...").toString();
} else { } else {
return filter; return filter;
} }
} }
@Override public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
Object[] arguments = allArguments;
String executeMethod = arguments[0].getClass().getSimpleName();
String remotePeer = (String)objInst.getSkyWalkingDynamicField();
AbstractSpan span = ContextManager.createExitSpan(MONGO_DB_OP_PREFIX + executeMethod, new ContextCarrier(), remotePeer);
span.setComponent(ComponentsDefine.MONGO_DRIVER);
Tags.DB_TYPE.set(span, DB_TYPE);
SpanLayer.asDB(span);
if (Config.Plugin.MongoDB.TRACE_PARAM) {
Tags.DB_STATEMENT.set(span, executeMethod + " " + this.getTraceParam(arguments[0]));
}
}
@Override public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Object ret) throws Throwable {
ContextManager.stopSpan();
return ret;
}
@Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Throwable t) {
AbstractSpan activeSpan = ContextManager.activeSpan();
activeSpan.errorOccurred();
activeSpan.log(t);
}
@Override
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
Cluster cluster = (Cluster)allArguments[0];
StringBuilder peers = new StringBuilder();
for (ServerDescription description : cluster.getDescription().getServerDescriptions()) {
ServerAddress address = description.getAddress();
peers.append(address.getHost() + ":" + address.getPort() + ";");
}
objInst.setSkyWalkingDynamicField(peers.subSequence(0, peers.length() - 1).toString());
}
} }
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.skywalking.apm.plugin.mongodb.v3.support;
import com.mongodb.ServerAddress;
import com.mongodb.connection.Cluster;
import com.mongodb.connection.ServerDescription;
/**
* @author scolia
*/
@SuppressWarnings("deprecation")
public class MongoRemotePeerHelper {
private MongoRemotePeerHelper() {
}
public static String getRemotePeer(Cluster cluster) {
StringBuilder peersBuilder = new StringBuilder();
for (ServerDescription description : cluster.getDescription().getAll()) {
ServerAddress address = description.getAddress();
peersBuilder.append(address.getHost()).append(":").append(address.getPort()).append(";");
}
return peersBuilder.substring(0, peersBuilder.length() - 1);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.skywalking.apm.plugin.mongodb.v3.support;
import org.apache.skywalking.apm.agent.core.conf.Config;
import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
/**
* @author scolia
*/
public class MongoSpanHelper {
private MongoSpanHelper() {
}
public static void createExitSpan(String executeMethod, String remotePeer, Object operation) {
AbstractSpan span = ContextManager.createExitSpan(MongoConstants.MONGO_DB_OP_PREFIX + executeMethod, new ContextCarrier(), remotePeer);
span.setComponent(ComponentsDefine.MONGO_DRIVER);
Tags.DB_TYPE.set(span, MongoConstants.DB_TYPE);
SpanLayer.asDB(span);
if (Config.Plugin.MongoDB.TRACE_PARAM) {
Tags.DB_STATEMENT.set(span, executeMethod + " " + MongoOperationHelper.getTraceParam(operation));
}
}
}
...@@ -14,4 +14,10 @@ ...@@ -14,4 +14,10 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.MongoDBInstrumentation # v3.0.x~v3.5.x
mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.v30.MongoDBInstrumentation
# v3.7.x~
mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.v37.MongoDBClientDelegateInstrumentation
mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.v37.MongoDBOperationExecutorInstrumentation
# v3.8.x~
mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.v38.MongoDBOperationExecutorInstrumentation
\ No newline at end of file
...@@ -17,13 +17,11 @@ ...@@ -17,13 +17,11 @@
*/ */
package org.apache.skywalking.apm.plugin.mongodb.v3; package org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.v30;
import com.mongodb.Mongo; import com.mongodb.Mongo;
import com.mongodb.MongoNamespace; import com.mongodb.MongoNamespace;
import com.mongodb.operation.FindOperation; import com.mongodb.operation.FindOperation;
import java.lang.reflect.Method;
import java.util.List;
import org.apache.skywalking.apm.agent.core.conf.Config; import org.apache.skywalking.apm.agent.core.conf.Config;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan; import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
import org.apache.skywalking.apm.agent.core.context.trace.LogDataEntity; import org.apache.skywalking.apm.agent.core.context.trace.LogDataEntity;
...@@ -33,11 +31,7 @@ import org.apache.skywalking.apm.agent.core.context.util.TagValuePair; ...@@ -33,11 +31,7 @@ import org.apache.skywalking.apm.agent.core.context.util.TagValuePair;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.test.helper.SegmentHelper; import org.apache.skywalking.apm.agent.test.helper.SegmentHelper;
import org.apache.skywalking.apm.agent.test.helper.SpanHelper; import org.apache.skywalking.apm.agent.test.helper.SpanHelper;
import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule; import org.apache.skywalking.apm.agent.test.tools.*;
import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
import org.apache.skywalking.apm.agent.test.tools.SpanAssert;
import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
import org.bson.BsonDocument; import org.bson.BsonDocument;
import org.bson.BsonString; import org.bson.BsonString;
import org.bson.codecs.Decoder; import org.bson.codecs.Decoder;
...@@ -52,13 +46,16 @@ import org.powermock.api.mockito.PowerMockito; ...@@ -52,13 +46,16 @@ import org.powermock.api.mockito.PowerMockito;
import org.powermock.modules.junit4.PowerMockRunner; import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate; import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import java.lang.reflect.Method;
import java.util.List;
import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@RunWith(PowerMockRunner.class) @RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(TracingSegmentRunner.class) @PowerMockRunnerDelegate(TracingSegmentRunner.class)
public class MongoDBMethodInterceptorTest { public class MongoDBInterceptorTest {
@SegmentStoragePoint @SegmentStoragePoint
private SegmentStorage segmentStorage; private SegmentStorage segmentStorage;
...@@ -66,7 +63,7 @@ public class MongoDBMethodInterceptorTest { ...@@ -66,7 +63,7 @@ public class MongoDBMethodInterceptorTest {
@Rule @Rule
public AgentServiceRule serviceRule = new AgentServiceRule(); public AgentServiceRule serviceRule = new AgentServiceRule();
private MongoDBMethodInterceptor interceptor; private MongoDBInterceptor interceptor;
@Mock @Mock
private EnhancedInstance enhancedInstance; private EnhancedInstance enhancedInstance;
...@@ -78,7 +75,7 @@ public class MongoDBMethodInterceptorTest { ...@@ -78,7 +75,7 @@ public class MongoDBMethodInterceptorTest {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
interceptor = new MongoDBMethodInterceptor(); interceptor = new MongoDBInterceptor();
Config.Plugin.MongoDB.TRACE_PARAM = true; Config.Plugin.MongoDB.TRACE_PARAM = true;
...@@ -91,8 +88,8 @@ public class MongoDBMethodInterceptorTest { ...@@ -91,8 +88,8 @@ public class MongoDBMethodInterceptorTest {
FindOperation findOperation = new FindOperation(mongoNamespace, decoder); FindOperation findOperation = new FindOperation(mongoNamespace, decoder);
findOperation.filter(document); findOperation.filter(document);
arguments = new Object[] {findOperation}; arguments = new Object[]{findOperation};
argumentTypes = new Class[] {findOperation.getClass()}; argumentTypes = new Class[]{findOperation.getClass()};
} }
@Test @Test
...@@ -125,7 +122,7 @@ public class MongoDBMethodInterceptorTest { ...@@ -125,7 +122,7 @@ public class MongoDBMethodInterceptorTest {
assertThat(span.getOperationName(), is("MongoDB/FindOperation")); assertThat(span.getOperationName(), is("MongoDB/FindOperation"));
assertThat(SpanHelper.getComponentId(span), is(42)); assertThat(SpanHelper.getComponentId(span), is(42));
List<TagValuePair> tags = SpanHelper.getTags(span); List<TagValuePair> tags = SpanHelper.getTags(span);
assertThat(tags.get(1).getValue(), is("FindOperation { \"name\" : \"by\" }")); assertThat(tags.get(1).getValue(), is("FindOperation {\"name\": \"by\"}"));
assertThat(tags.get(0).getValue(), is("MongoDB")); assertThat(tags.get(0).getValue(), is("MongoDB"));
assertThat(span.isExit(), is(true)); assertThat(span.isExit(), is(true));
assertThat(SpanHelper.getLayer(span), CoreMatchers.is(SpanLayer.DB)); assertThat(SpanHelper.getLayer(span), CoreMatchers.is(SpanLayer.DB));
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.v37;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.mockito.Mockito.when;
/**
* @author scolia
*/
@RunWith(PowerMockRunner.class)
public class MongoDBClientDelegateInterceptorTest {
private MongoDBClientDelegateInterceptor interceptor;
@Mock
private EnhancedInstance clientDelegateEnhancedInstance;
private EnhancedInstance retEnhancedInstance;
private final static String REMOTE_PEER = "127.0.0.1:27017";
@Before
public void setUp() {
interceptor = new MongoDBClientDelegateInterceptor();
retEnhancedInstance = new FieldEnhancedInstance();
when(clientDelegateEnhancedInstance.getSkyWalkingDynamicField()).thenReturn(REMOTE_PEER);
}
@Test
public void testAfterMethod() {
interceptor.afterMethod(clientDelegateEnhancedInstance, null, null, null, retEnhancedInstance);
Assert.assertEquals(REMOTE_PEER, retEnhancedInstance.getSkyWalkingDynamicField());
}
private static class FieldEnhancedInstance implements EnhancedInstance {
private Object skyWalkingDynamicField;
@Override
public Object getSkyWalkingDynamicField() {
return skyWalkingDynamicField;
}
@Override
public void setSkyWalkingDynamicField(Object value) {
this.skyWalkingDynamicField = value;
}
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.v37;
import com.mongodb.MongoNamespace;
import com.mongodb.ReadConcern;
import com.mongodb.client.internal.OperationExecutor;
import com.mongodb.operation.FindOperation;
import com.mongodb.operation.WriteOperation;
import org.apache.skywalking.apm.agent.core.conf.Config;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
import org.apache.skywalking.apm.agent.core.context.trace.LogDataEntity;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.apache.skywalking.apm.agent.core.context.util.TagValuePair;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.test.helper.SegmentHelper;
import org.apache.skywalking.apm.agent.test.helper.SpanHelper;
import org.apache.skywalking.apm.agent.test.tools.*;
import org.bson.BsonDocument;
import org.bson.BsonString;
import org.bson.codecs.Decoder;
import org.hamcrest.CoreMatchers;
import org.hamcrest.MatcherAssert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import java.lang.reflect.Method;
import java.util.List;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.when;
/**
* @author scolia
*/
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(TracingSegmentRunner.class)
public class MongoDBOperationExecutorInterceptorTest {
@SegmentStoragePoint
private SegmentStorage segmentStorage;
@Rule
public AgentServiceRule serviceRule = new AgentServiceRule();
@Mock
private EnhancedInstance enhancedInstance;
private MongoDBOperationExecutorInterceptor interceptor;
private Object[] arguments;
private Class[] argumentTypes;
@Before
public void setUp() {
interceptor = new MongoDBOperationExecutorInterceptor();
Config.Plugin.MongoDB.TRACE_PARAM = true;
when(enhancedInstance.getSkyWalkingDynamicField()).thenReturn("127.0.0.1:27017");
BsonDocument document = new BsonDocument();
document.append("name", new BsonString("by"));
MongoNamespace mongoNamespace = new MongoNamespace("test.user");
Decoder decoder = PowerMockito.mock(Decoder.class);
FindOperation findOperation = new FindOperation(mongoNamespace, decoder);
findOperation.filter(document);
arguments = new Object[]{findOperation};
argumentTypes = new Class[]{findOperation.getClass()};
}
@Test
public void testIntercept() throws Throwable {
interceptor.beforeMethod(enhancedInstance, getMethod(), arguments, argumentTypes, null);
interceptor.afterMethod(enhancedInstance, getMethod(), arguments, argumentTypes, null);
MatcherAssert.assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertRedisSpan(spans.get(0));
}
@Test
public void testInterceptWithException() throws Throwable {
interceptor.beforeMethod(enhancedInstance, getMethod(), arguments, argumentTypes, null);
interceptor.handleMethodException(enhancedInstance, getMethod(), arguments, argumentTypes, new RuntimeException());
interceptor.afterMethod(enhancedInstance, getMethod(), arguments, argumentTypes, null);
MatcherAssert.assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertRedisSpan(spans.get(0));
List<LogDataEntity> logDataEntities = SpanHelper.getLogs(spans.get(0));
assertThat(logDataEntities.size(), is(1));
SpanAssert.assertException(logDataEntities.get(0), RuntimeException.class);
}
private void assertRedisSpan(AbstractTracingSpan span) {
assertThat(span.getOperationName(), is("MongoDB/FindOperation"));
assertThat(SpanHelper.getComponentId(span), is(42));
List<TagValuePair> tags = SpanHelper.getTags(span);
assertThat(tags.get(1).getValue(), is("FindOperation {\"name\": \"by\"}"));
assertThat(tags.get(0).getValue(), is("MongoDB"));
assertThat(span.isExit(), is(true));
assertThat(SpanHelper.getLayer(span), CoreMatchers.is(SpanLayer.DB));
}
private Method getMethod() throws Exception {
return OperationExecutor.class.getMethod("execute", WriteOperation.class, ReadConcern.class);
}
}
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
* [Jedis](https://github.com/xetorthio/jedis) 2.x * [Jedis](https://github.com/xetorthio/jedis) 2.x
* [Redisson](https://github.com/redisson/redisson) Easy Java Redis client 3.5.2+ * [Redisson](https://github.com/redisson/redisson) Easy Java Redis client 3.5.2+
* [Lettuce](https://github.com/lettuce-io/lettuce-core) 5.x (Optional²) * [Lettuce](https://github.com/lettuce-io/lettuce-core) 5.x (Optional²)
* [MongoDB Java Driver](https://github.com/mongodb/mongo-java-driver) 2.13-2.14,3.4.0-3.5.0 * [MongoDB Java Driver](https://github.com/mongodb/mongo-java-driver) 2.13-2.14, 3.4.0-3.5.0, 3.7.x-3.11.1
* Memcached Client * Memcached Client
* [Spymemcached](https://github.com/couchbase/spymemcached) 2.x * [Spymemcached](https://github.com/couchbase/spymemcached) 2.x
* [Xmemcached](https://github.com/killme2008/xmemcached) 2.x * [Xmemcached](https://github.com/killme2008/xmemcached) 2.x
......
...@@ -19,3 +19,15 @@ ...@@ -19,3 +19,15 @@
3.4.2 3.4.2
3.4.3 3.4.3
3.5.0 3.5.0
3.7.0
3.7.1
3.8.0
3.8.1
3.8.2
3.9.0
3.9.1
3.10.0
3.10.1
3.10.2
3.11.0
3.11.1
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册