Skip to content

Commit

Permalink
[pinpoint-apm#10940] Fix mongodb reactive streams driver interceptor
Browse files Browse the repository at this point in the history
  • Loading branch information
jaehong-kim committed Apr 23, 2024
1 parent 14ad90c commit 769649d
Show file tree
Hide file tree
Showing 12 changed files with 140 additions and 84 deletions.
4 changes: 4 additions & 0 deletions agent-module/agent-testweb/mongodb-plugin-testweb/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>com.navercorp.pinpoint</groupId>
<artifactId>pinpoint-agent-testweb-commons</artifactId>
</dependency>

<!-- https://mvnrepository.com/artifact/org.mongodb/mongodb-driver -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2022 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.pinpoint.test.plugin;

import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MongoConfig {

@Bean
public MongoClient mongo() {
MongoClient mongoClient = MongoClients.create(MongoServer.getUri());
return mongoClient;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
Expand All @@ -29,8 +28,8 @@
import com.mongodb.client.model.UpdateOptions;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import com.pinpoint.test.common.view.ApiLinkPage;
import com.pinpoint.test.common.view.HrefTag;
import org.bson.BsonArray;
import org.bson.BsonBinary;
import org.bson.BsonBinarySubType;
Expand All @@ -55,13 +54,20 @@
import org.bson.Document;
import org.bson.types.Decimal128;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;

import static com.mongodb.client.model.Filters.and;
Expand All @@ -84,21 +90,33 @@ public class MongoPluginController {
private static final String DATABASE_NAME_2 = "myMongoDb2";
private static final String COLLECTION_NAME = "customers";

@Autowired
private MongoClient mongoClient;

@PostConstruct
public void start() {
final String connectionString = MongoServer.getUri();
this.mongoClient = MongoClients.create(connectionString);

private final RequestMappingHandlerMapping handlerMapping;

@Autowired
public MongoPluginController(RequestMappingHandlerMapping handlerMapping) {
this.handlerMapping = handlerMapping;
}

@PreDestroy
public void shutdown() {
if (mongoClient != null) {
mongoClient.close();
@GetMapping("/")
String welcome() {
Map<RequestMappingInfo, HandlerMethod> handlerMethods = this.handlerMapping.getHandlerMethods();
List<HrefTag> list = new ArrayList<>();
for (RequestMappingInfo info : handlerMethods.keySet()) {
for (String path : info.getDirectPaths()) {
list.add(HrefTag.of(path));
}
}
list.sort(Comparator.comparing(HrefTag::getPath));
return new ApiLinkPage("mongodb-reactive-plugin-testweb")
.addHrefTag(list)
.build();
}


@RequestMapping(value = "/mongodb/insert")
public String insert() {
MongoCollection<Document> collection = getDatabase(DATABASE_NAME).getCollection(COLLECTION_NAME);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
import org.testcontainers.containers.MongoDBContainer;
import org.testcontainers.utility.DockerImageName;

import java.util.concurrent.TimeUnit;

@Ignore
public class MongodbTest {
private static MongoDBContainer container;
Expand All @@ -50,6 +48,5 @@ public static void select() {
@Test
public void test() throws Exception {
System.out.println("TEST");
TimeUnit.HOURS.sleep(8);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,11 @@
*/
public class UnKnownDatabaseInfo {
public static final DatabaseInfo INSTANCE;
public static final DatabaseInfo MONGO_INSTANCE;

static{
final List<String> urls = new ArrayList<>();
urls.add("unknown");
INSTANCE = new DefaultDatabaseInfo(ServiceType.UNKNOWN_DB, ServiceType.UNKNOWN_DB_EXECUTE_QUERY, "unknown", "unknown", urls, "unknown", false);

MONGO_INSTANCE = new MongoDatabaseInfo(ServiceType.UNKNOWN_DB, ServiceType.UNKNOWN_DB_EXECUTE_QUERY, "unknown", "unknown", urls, "unknown", "unknown", false, "unknown", "unknown");
}

public static DatabaseInfo createUnknownDataBase(String url) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@
*/
package com.navercorp.pinpoint.plugin.mongo;

import com.navercorp.pinpoint.bootstrap.plugin.jdbc.MongoDatabaseInfo;
import com.navercorp.pinpoint.common.trace.AnnotationKey;
import com.navercorp.pinpoint.common.trace.AnnotationKeyFactory;
import com.navercorp.pinpoint.common.trace.ServiceType;
import com.navercorp.pinpoint.common.trace.ServiceTypeFactory;

import java.util.Arrays;

import static com.navercorp.pinpoint.common.trace.AnnotationKeyProperty.VIEW_IN_RECORD_SET;
import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.INCLUDE_DESTINATION_ID;
import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.RECORD_STATISTICS;
Expand Down Expand Up @@ -82,4 +85,6 @@ private MongoConstants() {
public static final ServiceType MONGODB = ServiceTypeFactory.of(2650, "MONGO", TERMINAL, INCLUDE_DESTINATION_ID);
public static final ServiceType MONGO_EXECUTE_QUERY = ServiceTypeFactory.of(2651, "MONGO_EXECUTE_QUERY", "MONGO", TERMINAL, RECORD_STATISTICS, INCLUDE_DESTINATION_ID);
public static final ServiceType MONGO_REACTIVE = ServiceTypeFactory.of(2652, "MONGO_REACTIVE", "MONGO");

public static final MongoDatabaseInfo UNKNOWN_MONGO_DATABASE_INFO = new MongoDatabaseInfo(ServiceType.UNKNOWN_DB, ServiceType.UNKNOWN_DB_EXECUTE_QUERY, "unknown", "unknown", Arrays.asList("unknown"), "unknown", "unknown", false, "unknown", "unknown");
}
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,12 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin
if (constructorMethod12 != null) {
constructorMethod12.addInterceptor(MongoClientConstructorInterceptor.class);
}
// 4.2
// MongoClient(final MongoClientSettings settings, @Nullable final MongoClientOptions options, @Nullable final MongoDriverInformation mongoDriverInformation)
final InstrumentMethod constructorMethod13 = target.getConstructor("com.mongodb.MongoClientSettings", "com.mongodb.MongoClientOptions", "com.mongodb.MongoDriverInformation");
if (constructorMethod13 != null) {
constructorMethod13.addInterceptor(MongoClientConstructorInterceptor.class);
}

final InstrumentMethod getDatabaseMethod = target.getDeclaredMethod("getDatabase", "java.lang.String");
if (getDatabaseMethod != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import com.navercorp.pinpoint.bootstrap.context.DatabaseInfo;
import com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor;
import com.navercorp.pinpoint.bootstrap.plugin.jdbc.MongoDatabaseInfo;

/**
* @author Woonduk Kang(emeroad)
Expand All @@ -26,14 +27,13 @@ public final class DatabaseInfoUtils {
private DatabaseInfoUtils() {
}

public static DatabaseInfo getDatabaseInfo(Object target, DatabaseInfo defaultDatabaseInfo) {
public static MongoDatabaseInfo getDatabaseInfo(Object target, MongoDatabaseInfo defaultDatabaseInfo) {
if (target instanceof DatabaseInfoAccessor) {
final DatabaseInfo databaseInfo = ((DatabaseInfoAccessor) target)._$PINPOINT$_getDatabaseInfo();
if (databaseInfo != null) {
return databaseInfo;
if (databaseInfo instanceof MongoDatabaseInfo) {
return (MongoDatabaseInfo) databaseInfo;
}
}
return defaultDatabaseInfo;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@

package com.navercorp.pinpoint.plugin.mongo.interceptor;

import com.mongodb.MongoClientSettings;
import com.mongodb.ServerAddress;
import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor;
import com.navercorp.pinpoint.bootstrap.logging.PluginLogManager;
import com.navercorp.pinpoint.bootstrap.logging.PluginLogger;
import com.navercorp.pinpoint.common.plugin.util.HostAndPort;
import com.navercorp.pinpoint.common.util.ArrayArgumentUtils;
import com.navercorp.pinpoint.plugin.mongo.HostListAccessor;
import com.navercorp.pinpoint.plugin.mongo.MongoUtil;

import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -53,35 +55,48 @@ public void after(Object target, Object[] args, Object result, Throwable throwab
}

try {
// over 4.2
final MongoClientSettings mongoClientSettings = ArrayArgumentUtils.getArgument(args, 0, MongoClientSettings.class);
if (mongoClientSettings != null) {
List<String> list = MongoUtil.getHostList(mongoClientSettings);
setHostList(target, list);
return;
}

final List<String> hostList = new ArrayList<>();
// arg0 is ServerAddress
final ServerAddress serverAddress = ArrayArgumentUtils.getArgument(args, 0, ServerAddress.class);
if (serverAddress != null) {
final String hostAddress = HostAndPort.toHostAndPortString(serverAddress.getHost(), serverAddress.getPort());
hostList.add(hostAddress);
} else {
// arg0 is List<ServerAddress>
final List<?> list = ArrayArgumentUtils.getArgument(args, 0, List.class);
if (list != null) {
for (Object o : list) {
if (o instanceof ServerAddress) {
// Set multi address.
final ServerAddress address = (ServerAddress) o;
final String hostAddress = HostAndPort.toHostAndPortString(address.getHost(), address.getPort());
hostList.add(hostAddress);
}
}
}
setHostList(target, hostList);
return;
}

((HostListAccessor) target)._$PINPOINT$_setHostList(hostList);
if (isDebug) {
logger.debug("Set hostList={}", hostList);
// arg0 is List<ServerAddress>
final List<?> list = ArrayArgumentUtils.getArgument(args, 0, List.class);
if (list != null) {
for (Object o : list) {
if (o instanceof ServerAddress) {
// Set multi address.
final ServerAddress address = (ServerAddress) o;
final String hostAddress = HostAndPort.toHostAndPortString(address.getHost(), address.getPort());
hostList.add(hostAddress);
}
}
setHostList(target, hostList);
}
} catch (Throwable th) {
if (logger.isWarnEnabled()) {
logger.warn("AFTER error. Caused:{}", th.getMessage(), th);
}
}
}
}

private void setHostList(Object target, List<String> hostList) {
((HostListAccessor) target)._$PINPOINT$_setHostList(hostList);
if (isDebug) {
logger.debug("Set hostList={}", hostList);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,11 @@

import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor;
import com.navercorp.pinpoint.bootstrap.context.AsyncContext;
import com.navercorp.pinpoint.bootstrap.context.DatabaseInfo;
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.plugin.jdbc.MongoDatabaseInfo;
import com.navercorp.pinpoint.bootstrap.plugin.jdbc.UnKnownDatabaseInfo;
import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils;
import com.navercorp.pinpoint.plugin.mongo.HostListAccessor;
import com.navercorp.pinpoint.plugin.mongo.MongoConstants;
Expand All @@ -47,25 +45,18 @@ public MongoCollectionImplReadOperationInterceptor(TraceContext traceContext, Me
@Override
public void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) {
recorder.recordApi(methodDescriptor);

if (Boolean.FALSE == (target instanceof HostListAccessor)) {
return;
}

final List<String> hostList = ((HostListAccessor) target)._$PINPOINT$_getHostList();
if (hostList == null) {
return;
MongoDatabaseInfo databaseInfo = DatabaseInfoUtils.getDatabaseInfo(target, MongoConstants.UNKNOWN_MONGO_DATABASE_INFO);
if (target instanceof HostListAccessor) {
final List<String> hostList = ((HostListAccessor) target)._$PINPOINT$_getHostList();
if (hostList != null) {
databaseInfo = new MongoDatabaseInfo(MongoConstants.MONGODB, MongoConstants.MONGO_EXECUTE_QUERY, null, null, hostList, databaseInfo.getDatabaseId(), databaseInfo.getCollectionName(), databaseInfo.getReadPreference(), databaseInfo.getWriteConcern());
}
}
recorder.recordServiceType(databaseInfo.getExecuteQueryType());
recorder.recordEndPoint(databaseInfo.getMultipleHost());
recorder.recordDestinationId(databaseInfo.getDatabaseId());

final DatabaseInfo databaseInfo = DatabaseInfoUtils.getDatabaseInfo(target, UnKnownDatabaseInfo.MONGO_INSTANCE);
final MongoDatabaseInfo mongoDatabaseInfo = new MongoDatabaseInfo(MongoConstants.MONGODB, MongoConstants.MONGO_EXECUTE_QUERY,
null, null, hostList, databaseInfo.getDatabaseId(), ((MongoDatabaseInfo) databaseInfo).getCollectionName(), ((MongoDatabaseInfo) databaseInfo).getReadPreference(), ((MongoDatabaseInfo) databaseInfo).getWriteConcern());

recorder.recordServiceType(mongoDatabaseInfo.getExecuteQueryType());
recorder.recordEndPoint(mongoDatabaseInfo.getMultipleHost());
recorder.recordDestinationId(mongoDatabaseInfo.getDatabaseId());

MongoUtil.recordMongoCollection(recorder, mongoDatabaseInfo.getCollectionName(), mongoDatabaseInfo.getReadPreference());
MongoUtil.recordMongoCollection(recorder, databaseInfo.getCollectionName(), databaseInfo.getReadPreference());
}

@Override
Expand Down
Loading

0 comments on commit 769649d

Please sign in to comment.