diff --git a/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java b/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
index 38f9dcad1417..c8dec42ee00f 100644
--- a/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
+++ b/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
@@ -122,6 +122,8 @@ public class ComponentsDefine {
public static final OfficialComponent RESTEASY = new OfficialComponent(62, "RESTEasy");
+ public static final OfficialComponent SOLRJ = new OfficialComponent(63, "solrj");
+
private static ComponentsDefine INSTANCE = new ComponentsDefine();
private String[] components;
@@ -179,6 +181,7 @@ public ComponentsDefine() {
addComponent(VERTX);
addComponent(SPRING_CLOUD_GATEWAY);
addComponent(RESTEASY);
+ addComponent(SOLRJ);
}
private void addComponent(OfficialComponent component) {
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Config.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Config.java
index 14ef3a0a4714..a1e4f81dccc3 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Config.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Config.java
@@ -193,5 +193,17 @@ public static class Toolkit {
*/
public static boolean USE_QUALIFIED_NAME_AS_OPERATION_NAME = false;
}
+
+ public static class SolrJ {
+ /**
+ * If true, trace all the query parameters(include deleteByIds and deleteByQuery) in Solr query request, default is false.
+ */
+ public static boolean TRACE_STATEMENT = false;
+
+ /**
+ * If true, trace all the operation parameters in Solr request, default is false.
+ */
+ public static boolean TRACE_OPS_PARAMS = false;
+ }
}
}
diff --git a/apm-sniffer/apm-sdk-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pom.xml
index e850ccd8b213..71725d366f31 100644
--- a/apm-sniffer/apm-sdk-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/pom.xml
@@ -73,6 +73,7 @@
dubbo-2.7.x-conflict-patch
vertx-plugins
resteasy-plugin
+ solrj-7.x-plugin
pom
@@ -182,4 +183,4 @@
-
+
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/pom.xml
new file mode 100644
index 000000000000..31b931ade3bb
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/pom.xml
@@ -0,0 +1,47 @@
+
+
+
+
+ apm-sdk-plugin
+ org.apache.skywalking
+ 6.2.0-SNAPSHOT
+
+ 4.0.0
+
+ apm-solrj-7.x-plugin
+ jar
+
+ solrj-7.x-plugin
+ http://maven.apache.org
+
+
+ UTF-8
+ 7.7.1
+
+
+
+
+ org.apache.solr
+ solr-solrj
+ ${solr-solrj.version}
+ provided
+
+
+
+
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/SolrClientInterceptor.java b/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/SolrClientInterceptor.java
new file mode 100644
index 000000000000..5c4d69a22bfb
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/SolrClientInterceptor.java
@@ -0,0 +1,229 @@
+/*
+ * 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.solrj;
+
+import org.apache.skywalking.apm.agent.core.conf.Config;
+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.apache.skywalking.apm.plugin.solrj.commons.SolrjInstance;
+import org.apache.skywalking.apm.plugin.solrj.commons.SolrjTags;
+import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.client.solrj.impl.HttpSolrClient;
+import org.apache.solr.client.solrj.request.AbstractUpdateRequest;
+import org.apache.solr.client.solrj.request.QueryRequest;
+import org.apache.solr.client.solrj.request.UpdateRequest;
+import org.apache.solr.common.SolrDocumentList;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.params.UpdateParams;
+import org.apache.solr.common.util.NamedList;
+
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class SolrClientInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor {
+ private static final String DB_TYPE = "Solr";
+
+ @Override
+ public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
+ SolrjInstance instance = new SolrjInstance();
+ HttpSolrClient client = (HttpSolrClient) objInst;
+
+ try {
+ URL url = new URL(client.getBaseURL());
+ instance.setRemotePeer(url.getHost() + ":" + url.getPort());
+
+ String path = url.getPath();
+ int idx = path.lastIndexOf('/');
+ if (idx > 0) {
+ instance.setCollection(path.substring(idx + 1));
+ }
+ } catch (MalformedURLException ignore) {
+ }
+ objInst.setSkyWalkingDynamicField(instance);
+ }
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ SolrRequest> request = (SolrRequest>) allArguments[0];
+ SolrjInstance instance = (SolrjInstance) objInst.getSkyWalkingDynamicField();
+
+ SolrParams params = getParams(request.getParams());
+ String collection = getCollection(instance, allArguments[2]);
+
+ if ("/update".equals(request.getPath())) {
+ AbstractUpdateRequest update = (AbstractUpdateRequest) request;
+
+ AbstractUpdateRequest.ACTION action = update.getAction();
+ if (action == null) {
+ if (update instanceof UpdateRequest) {
+ AbstractSpan span = null;
+
+ UpdateRequest ur = (UpdateRequest) update;
+ List documents = ur.getDocuments();
+ if (documents == null) {
+ String actionName = "DELETE_BY_IDS";
+
+ List deleteBy = ur.getDeleteById();
+ if (deleteBy == null) {
+ actionName = "DELETE_BY_QUERY";
+ deleteBy = ur.getDeleteQuery();
+ }
+ if (deleteBy == null) {
+ deleteBy = new ArrayList();
+ }
+ String operator = getOperatorNameWithAction(collection, request.getPath(), actionName);
+ span = getSpan(operator, instance.getRemotePeer());
+ if (Config.Plugin.SolrJ.TRACE_STATEMENT) {
+ span.tag(Tags.DB_STATEMENT, deleteBy.toString());
+ }
+ } else {
+ String operator = getOperatorNameWithAction(collection, request.getPath(), "ADD");
+ span = getSpan(operator, instance.getRemotePeer());
+ if (Config.Plugin.SolrJ.TRACE_STATEMENT) {
+ span.tag(SolrjTags.TAG_DOCS_SIZE, String.valueOf(documents.size()));
+ }
+ }
+ if (Config.Plugin.SolrJ.TRACE_OPS_PARAMS) {
+ span.tag(SolrjTags.TAG_COMMIT_WITHIN, String.valueOf(ur.getCommitWithin()));
+ }
+ } else {
+ getSpan(getOperatorName(collection, request.getPath()), instance.getRemotePeer());
+ }
+ } else {
+ String operator = getOperatorNameWithAction(collection, request.getPath(), action.name());
+ AbstractSpan span = getSpan(operator, instance.getRemotePeer());
+
+ if (Config.Plugin.SolrJ.TRACE_OPS_PARAMS) {
+ if (action == AbstractUpdateRequest.ACTION.COMMIT) {
+ span.tag(SolrjTags.TAG_SOFT_COMMIT, params.get(UpdateParams.SOFT_COMMIT, ""));
+ } else {
+ span.tag(SolrjTags.TAG_MAX_OPTIMIZE_SEGMENTS, params.get(UpdateParams.MAX_OPTIMIZE_SEGMENTS, "1"));
+ }
+ }
+ }
+ } else if (request instanceof QueryRequest) {
+ AbstractSpan span = getSpan(getOperatorName(collection, request.getPath()), instance.getRemotePeer());
+
+ span.tag(SolrjTags.TAG_START, params.get(CommonParams.START, "0"));
+ span.tag(SolrjTags.TAG_QT, params.get(CommonParams.QT, request.getPath()));
+
+ if (Config.Plugin.SolrJ.TRACE_STATEMENT) {
+ span.tag(Tags.DB_STATEMENT, toQueryString(params));
+ }
+ } else {
+ getSpan(getOperatorName(collection, request.getPath()), instance.getRemotePeer());
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Object ret) throws Throwable {
+ if (!ContextManager.isActive()) {
+ return ret;
+ }
+
+ AbstractSpan span = ContextManager.activeSpan();
+ if (ret != null) {
+ NamedList