This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git


The following commit(s) were added to refs/heads/master by this push:
     new 6ae5174  Provide plugin for Solr-7.x(client) (#2730)
6ae5174 is described below

commit 6ae517423ce4ea3bbd523f80f56c685b9f8fc60e
Author: daming <[email protected]>
AuthorDate: Wed Jun 5 22:54:45 2019 +0800

    Provide plugin for Solr-7.x(client) (#2730)
    
    * new branch for solrj-plugin
    
    * rollback and add module solrj-plugin
    
    * preparing to pr
    
    * to resolve reviewers' suggestions
    
    * remove unused code
    
    * remove unused code
    
    * remove unused comments
    
    * To avoid NPE
    
    * fix typo
    
    * Change to JRE6
    
    * fix pom.xml merge incorrectly. and java.net.URL instead of Regex
    
    * Using RuntimeContext instead of ThreadLocal
    
    * To reduce unnecessary tags
    
    * add test cases
    
    * fix validation fail
    
    * add solrj-plugin into component-libraries & Supported-list
    
    * to trace all patch to avoid recheck status of span
    
    * remove unnecessary properites
    
    * remove unnecessary tags
    
    * Add the config to document of setup
---
 .../network/trace/component/ComponentsDefine.java  |   3 +
 .../skywalking/apm/agent/core/conf/Config.java     |  12 +
 apm-sniffer/apm-sdk-plugin/pom.xml                 |   3 +-
 .../apm-sdk-plugin/solrj-7.x-plugin/pom.xml        |  47 +++
 .../apm/plugin/solrj/SolrClientInterceptor.java    | 229 +++++++++++
 .../apm/plugin/solrj/SolrConnectorInterceptor.java |  59 +++
 .../apm/plugin/solrj/commons/SolrjInstance.java    |  39 ++
 .../apm/plugin/solrj/commons/SolrjTags.java        |  39 ++
 .../solrj/define/HttpClientInstrumentation.java    |  64 +++
 .../solrj/define/SolrClientInstrumentation.java    |  75 ++++
 .../src/main/resources/skywalking-plugin.def       |  18 +
 .../plugin/solrj/SolrClientInterceptorTest.java    | 428 +++++++++++++++++++++
 docs/en/setup/service-agent/java-agent/README.md   |   2 +
 .../service-agent/java-agent/Supported-list.md     |   1 +
 .../src/test/resources/component-libraries.yml     |   7 +
 .../src/main/resources/component-libraries.yml     |   7 +
 16 files changed, 1032 insertions(+), 1 deletion(-)

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 38f9dca..c8dec42 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 class 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 14ef3a0..a1e4f81 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 class Config {
              */
             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 e850ccd..71725d3 100644
--- a/apm-sniffer/apm-sdk-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/pom.xml
@@ -73,6 +73,7 @@
         <module>dubbo-2.7.x-conflict-patch</module>
         <module>vertx-plugins</module>
         <module>resteasy-plugin</module>
+        <module>solrj-7.x-plugin</module>
     </modules>
     <packaging>pom</packaging>
 
@@ -182,4 +183,4 @@
             </plugin>
         </plugins>
     </build>
-</project>
+</project>
\ 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 0000000..31b931a
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/pom.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  ~
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <parent>
+        <artifactId>apm-sdk-plugin</artifactId>
+        <groupId>org.apache.skywalking</groupId>
+        <version>6.2.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>apm-solrj-7.x-plugin</artifactId>
+    <packaging>jar</packaging>
+
+    <name>solrj-7.x-plugin</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <solr-solrj.version>7.7.1</solr-solrj.version>
+       </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.solr</groupId>
+            <artifactId>solr-solrj</artifactId>
+            <version>${solr-solrj.version}</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+</project>
\ 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 0000000..5c4d69a
--- /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<SolrInputDocument> documents = ur.getDocuments();
+                    if (documents == null) {
+                        String actionName = "DELETE_BY_IDS";
+
+                        List<String> deleteBy = ur.getDeleteById();
+                        if (deleteBy == null) {
+                            actionName = "DELETE_BY_QUERY";
+                            deleteBy = ur.getDeleteQuery();
+                        }
+                        if (deleteBy == null) {
+                            deleteBy = new ArrayList<String>();
+                        }
+                        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<Object> result = (NamedList<Object>) ret;
+            NamedList<Object> header = (NamedList<Object>) 
result.get("responseHeader");
+
+            if (header != null) {
+                span.tag(SolrjTags.TAG_Q_TIME, 
String.valueOf(header.get("QTime")));
+            }
+            SolrDocumentList list = (SolrDocumentList) result.get("response");
+            if (list != null) {
+                span.tag(SolrjTags.TAG_NUM_FOUND, 
String.valueOf(list.getNumFound()));
+            }
+        }
+
+        ContextManager.stopSpan();
+        return ret;
+    }
+
+    @Override
+    public void handleMethodException(EnhancedInstance objInst, Method method, 
Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
+        if (ContextManager.isActive()) {
+            AbstractSpan span = ContextManager.activeSpan();
+            int code = 500;
+            if (t instanceof SolrException) {
+                code = ((SolrException) t).code();
+            }
+            span.tag(SolrjTags.TAG_STATUS, String.valueOf(code));
+            span.errorOccurred().log(t);
+        }
+    }
+
+    private static final AbstractSpan getSpan(String operatorName, String 
remotePeer) {
+        return ContextManager.createExitSpan(operatorName, remotePeer)
+                .setComponent(ComponentsDefine.SOLRJ)
+                .setLayer(SpanLayer.DB)
+                .tag(Tags.DB_TYPE, DB_TYPE);
+    }
+
+    private static final String getOperatorNameWithAction(String collection, 
String path, String action) {
+        return String.format("solrJ/%s%s/%s", collection, path, action);
+    }
+
+    private static final String getOperatorName(String collection, String 
path) {
+        return String.format("solrJ/%s%s", collection, path);
+    }
+
+    private static final String getCollection(SolrjInstance instance, Object 
argument) {
+        if (null == argument) {
+            return instance.getCollection();
+        }
+        return String.valueOf(argument);
+    }
+
+    private static final SolrParams getParams(SolrParams params) {
+        if (params == null) {
+            return new ModifiableSolrParams();
+        }
+        return params;
+    }
+
+    private static final String toQueryString(SolrParams params) {
+        final StringBuilder sb = new StringBuilder(128);
+        boolean first = true;
+        for (final Iterator<String> it = params.getParameterNamesIterator(); 
it.hasNext();) {
+            final String name = it.next();
+            for (String val : params.getParams(name)) {
+                sb.append(first ? '?' : 
'&').append(name).append('=').append(val);
+                first = false;
+            }
+        }
+        return sb.toString();
+    }
+}
diff --git 
a/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/SolrConnectorInterceptor.java
 
b/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/SolrConnectorInterceptor.java
new file mode 100644
index 0000000..d6c00b5
--- /dev/null
+++ 
b/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/SolrConnectorInterceptor.java
@@ -0,0 +1,59 @@
+/*
+ * 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.http.client.methods.HttpUriRequest;
+import org.apache.skywalking.apm.agent.core.context.CarrierItem;
+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.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 java.lang.reflect.Method;
+
+public class SolrConnectorInterceptor implements 
InstanceMethodsAroundInterceptor {
+
+    @Override
+    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] 
allArguments, Class<?>[] argumentsTypes,
+                             MethodInterceptResult result) throws Throwable {
+        HttpUriRequest request = (HttpUriRequest) allArguments[0];
+
+        ContextCarrier carrier = new ContextCarrier();
+        ContextManager.inject(carrier);
+
+        CarrierItem items = carrier.items();
+        while (items.hasNext()) {
+            items = items.next();
+            request.setHeader(items.getHeadKey(), items.getHeadValue());
+        }
+    }
+
+    @Override
+    public Object afterMethod(EnhancedInstance objInst, Method method, 
Object[] allArguments, Class<?>[] argumentsTypes,
+                              Object ret) throws Throwable {
+        return ret;
+    }
+
+    @Override
+    public void handleMethodException(EnhancedInstance objInst, Method method, 
Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
+        if (ContextManager.isActive()) {
+            ContextManager.activeSpan().errorOccurred().log(t);
+        }
+    }
+}
diff --git 
a/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/commons/SolrjInstance.java
 
b/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/commons/SolrjInstance.java
new file mode 100644
index 0000000..91e4cfb
--- /dev/null
+++ 
b/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/commons/SolrjInstance.java
@@ -0,0 +1,39 @@
+/*
+ * 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.commons;
+
+public class SolrjInstance {
+    private String collection = "Unknown";
+    private String remotePeer = "Unknown";
+
+    public String getCollection() {
+        return collection;
+    }
+
+    public void setCollection(String collection) {
+        this.collection = collection;
+    }
+
+    public String getRemotePeer() {
+        return remotePeer;
+    }
+
+    public void setRemotePeer(String remotePeer) {
+        this.remotePeer = remotePeer;
+    }
+}
diff --git 
a/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/commons/SolrjTags.java
 
b/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/commons/SolrjTags.java
new file mode 100644
index 0000000..3040b85
--- /dev/null
+++ 
b/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/commons/SolrjTags.java
@@ -0,0 +1,39 @@
+/*
+ * 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.commons;
+
+import org.apache.skywalking.apm.agent.core.context.tag.StringTag;
+
+public class SolrjTags {
+    public static StringTag TAG_QT = new StringTag("qt");
+    public static StringTag TAG_COLLECTION = new StringTag("collection");
+
+    public static StringTag TAG_Q_TIME = new StringTag("QTime");
+    public static StringTag TAG_STATUS = new StringTag("status");
+
+    public static StringTag TAG_START = new StringTag("start");
+    public static StringTag TAG_SORT_BY = new StringTag("sort");
+    public static StringTag TAG_NUM_FOUND = new StringTag("numFound");
+
+    public static StringTag TAG_SOFT_COMMIT = new StringTag("softCommit");
+    public static StringTag TAG_COMMIT_WITHIN = new StringTag("commitWithin");
+    public static StringTag TAG_MAX_OPTIMIZE_SEGMENTS = new 
StringTag("maxOptimizeSegs");
+
+    public static StringTag TAG_DOCS_SIZE = new StringTag("docsSize");
+    public static StringTag TAG_DELETE_VALUE = new StringTag("delete.by");
+}
diff --git 
a/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/define/HttpClientInstrumentation.java
 
b/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/define/HttpClientInstrumentation.java
new file mode 100644
index 0000000..56e752b
--- /dev/null
+++ 
b/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/define/HttpClientInstrumentation.java
@@ -0,0 +1,64 @@
+/*
+ * 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.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import net.bytebuddy.matcher.ElementMatchers;
+import org.apache.http.client.methods.HttpUriRequest;
+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;
+
+public class HttpClientInstrumentation extends 
ClassInstanceMethodsEnhancePluginDefine {
+    private static String ENHANCE_CLASS = 
"org.apache.http.impl.client.CloseableHttpClient";
+
+    @Override
+    protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+        return new ConstructorInterceptPoint[]{};
+    }
+
+    @Override
+    protected InstanceMethodsInterceptPoint[] 
getInstanceMethodsInterceptPoints() {
+        return new InstanceMethodsInterceptPoint[]{
+            new InstanceMethodsInterceptPoint() {
+                @Override
+                public boolean isOverrideArgs() {
+                    return false;
+                }
+
+                @Override
+                public ElementMatcher<MethodDescription> getMethodsMatcher() {
+                    return 
ElementMatchers.named("execute").and(ElementMatchers.takesArgument(0, 
HttpUriRequest.class));
+                }
+
+                @Override
+                public String getMethodsInterceptor() {
+                    return 
"org.apache.skywalking.apm.plugin.solrj.SolrConnectorInterceptor";
+                }
+            }
+        };
+    }
+
+    @Override
+    protected ClassMatch enhanceClass() {
+        return NameMatch.byName(ENHANCE_CLASS);
+    }
+}
\ 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/define/SolrClientInstrumentation.java
 
b/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/define/SolrClientInstrumentation.java
new file mode 100644
index 0000000..75f3a2e
--- /dev/null
+++ 
b/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/define/SolrClientInstrumentation.java
@@ -0,0 +1,75 @@
+/*
+ * 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.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import net.bytebuddy.matcher.ElementMatchers;
+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;
+
+public class SolrClientInstrumentation extends 
ClassInstanceMethodsEnhancePluginDefine {
+
+    @Override
+    protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+        return new ConstructorInterceptPoint[]{
+            new ConstructorInterceptPoint() {
+
+                @Override
+                public String getConstructorInterceptor() {
+                    return 
"org.apache.skywalking.apm.plugin.solrj.SolrClientInterceptor";
+                }
+
+                @Override
+                public ElementMatcher<MethodDescription> 
getConstructorMatcher() {
+                    return ElementMatchers.any();
+                }
+            }
+        };
+    }
+
+    @Override
+    protected InstanceMethodsInterceptPoint[] 
getInstanceMethodsInterceptPoints() {
+        return new InstanceMethodsInterceptPoint[]{
+            new InstanceMethodsInterceptPoint() {
+                @Override
+                public boolean isOverrideArgs() {
+                    return false;
+                }
+
+                @Override
+                public ElementMatcher<MethodDescription> getMethodsMatcher() {
+                    return 
ElementMatchers.named("request").and(ElementMatchers.takesArguments(3));
+                }
+
+                @Override
+                public String getMethodsInterceptor() {
+                    return 
"org.apache.skywalking.apm.plugin.solrj.SolrClientInterceptor";
+                }
+            }
+        };
+    }
+
+    @Override
+    protected ClassMatch enhanceClass() {
+        return 
NameMatch.byName("org.apache.solr.client.solrj.impl.HttpSolrClient");
+    }
+}
\ No newline at end of file
diff --git 
a/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/resources/skywalking-plugin.def
 
b/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 0000000..fd2fd6c
--- /dev/null
+++ 
b/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1,18 @@
+# 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.
+
+solrj-7.x=org.apache.skywalking.apm.plugin.solrj.define.SolrClientInstrumentation
+solrj-7.x=org.apache.skywalking.apm.plugin.solrj.define.HttpClientInstrumentation
\ No newline at end of file
diff --git 
a/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/solrj/SolrClientInterceptorTest.java
 
b/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/solrj/SolrClientInterceptorTest.java
new file mode 100644
index 0000000..c7311a8
--- /dev/null
+++ 
b/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/solrj/SolrClientInterceptorTest.java
@@ -0,0 +1,428 @@
+/*
+ * 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 com.google.common.collect.Lists;
+import org.apache.skywalking.apm.agent.core.conf.Config;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
+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.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.test.helper.SegmentHelper;
+import org.apache.skywalking.apm.agent.test.tools.*;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.solrj.commons.SolrjInstance;
+import org.apache.solr.client.solrj.ResponseParser;
+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.*;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.util.NamedList;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.modules.junit4.PowerMockRunnerDelegate;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import static org.mockito.Mockito.when;
+
+@RunWith(PowerMockRunner.class)
+@PowerMockRunnerDelegate(TracingSegmentRunner.class)
+public class SolrClientInterceptorTest {
+    SolrClientInterceptor interceptor = new SolrClientInterceptor();
+
+    @SegmentStoragePoint
+    private SegmentStorage segmentStorage;
+
+    @Rule
+    public AgentServiceRule serviceRule = new AgentServiceRule();
+
+    @Mock
+    private HttpSolrClient client;
+
+    @Mock
+    private Method method;
+
+    @Mock
+    private EnhancedInstance enhancedInstance;
+
+    private Object[] arguments = null;
+    private Class[] argumentType = new Class[] {
+        SolrRequest.class,
+        ResponseParser.class,
+        String.class
+    };
+    private String collection = null;
+    private HttpSolrClient.Builder builder;
+
+    @Mock
+    private SolrjInstance instance;
+    private NamedList<Object> header;
+
+    @Before
+    public void setup() throws Exception {
+        builder = new 
HttpSolrClient.Builder().withBaseSolrUrl("http://solr-server:8983/solr/collection";);
+        enhancedInstance = new EnhanceHttpSolrClient(builder);
+
+        when(instance.getCollection()).thenReturn("collection");
+        when(instance.getRemotePeer()).thenReturn("solr-server:8983");
+        enhancedInstance.setSkyWalkingDynamicField(instance);
+
+        header = new NamedList<Object>();
+        header.add("status", 0);
+        header.add("QTime", 5);
+
+//        Config.Plugin.SolrJ.TRACE_STATEMENT = true;
+//        Config.Plugin.SolrJ.TRACE_OPS_PARAMS = true;
+    }
+
+
+    @Test
+    public void testConstructor() throws Throwable {
+        arguments = new Object[] {builder};
+        interceptor.onConstruct(enhancedInstance, arguments);
+        SolrjInstance instance = (SolrjInstance) 
enhancedInstance.getSkyWalkingDynamicField();
+        Assert.assertEquals(instance.getRemotePeer(), "solr-server:8983");
+        Assert.assertEquals(instance.getCollection(), "collection");
+    }
+
+
+    @Test
+    public void testUpdateWithAdd() throws Throwable {
+        UpdateRequest request = new UpdateRequest();
+        List<SolrInputDocument> docs = Lists.newArrayList();
+        for (int start = 0; start < 100; start++) {
+            SolrInputDocument doc = new SolrInputDocument();
+            doc.addField("id", start);
+            docs.add(doc);
+        }
+        arguments = new Object[] {
+            request.add(docs),
+            null,
+            collection
+        };
+        interceptor.beforeMethod(enhancedInstance, method, arguments, 
argumentType, null);
+        interceptor.afterMethod(enhancedInstance, method, arguments, 
argumentType, getResponse());
+
+        List<TraceSegment> segments = segmentStorage.getTraceSegments();
+        Assert.assertEquals(segments.size(), 1);
+
+        List<AbstractTracingSpan> spans = 
SegmentHelper.getSpans(segments.get(0));
+        Assert.assertEquals(spans.size(), 1);
+
+        AbstractTracingSpan span = spans.get(0);
+        int pox = 0;
+        if (Config.Plugin.SolrJ.TRACE_STATEMENT) {
+            SpanAssert.assertTag(span, ++pox, "100");
+        }
+        if (Config.Plugin.SolrJ.TRACE_OPS_PARAMS) {
+            SpanAssert.assertTag(span, ++pox, "-1");
+        }
+        spanCommonAssert(span, pox,"solrJ/collection/update/ADD");
+    }
+
+    @Test
+    public void testUpdateWithCommit() throws Throwable {
+        final boolean softCommit = false;
+        AbstractUpdateRequest request = (new 
UpdateRequest()).setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true, 
false);
+        arguments = new Object[]{
+            request,
+            null,
+            collection
+        };
+        interceptor.beforeMethod(enhancedInstance, method, arguments, 
argumentType, null);
+        interceptor.afterMethod(enhancedInstance, method, arguments, 
argumentType, getResponse());
+
+        List<TraceSegment> segments = segmentStorage.getTraceSegments();
+        Assert.assertEquals(segments.size(), 1);
+
+        List<AbstractTracingSpan> spans = 
SegmentHelper.getSpans(segments.get(0));
+        Assert.assertEquals(spans.size(), 1);
+
+        int start = 0;
+        AbstractTracingSpan span = spans.get(0);
+        if (Config.Plugin.SolrJ.TRACE_OPS_PARAMS) {
+            SpanAssert.assertTag(span, ++start, String.valueOf(softCommit));
+        }
+        spanCommonAssert(span, start, "solrJ/collection/update/COMMIT");
+    }
+
+    @Test
+    public void testUpdateWithOptimize() throws Throwable {
+        final int maxSegments = 1;
+        AbstractUpdateRequest request = (new 
UpdateRequest()).setAction(AbstractUpdateRequest.ACTION.OPTIMIZE, false, true, 
maxSegments);
+        arguments = new Object[]{
+            request,
+            null,
+            collection
+        };
+        interceptor.beforeMethod(enhancedInstance, method, arguments, 
argumentType, null);
+        interceptor.afterMethod(enhancedInstance, method, arguments, 
argumentType, getResponse());
+
+        List<TraceSegment> segments = segmentStorage.getTraceSegments();
+        List<AbstractTracingSpan> spans = 
SegmentHelper.getSpans(segments.get(0));
+
+        Assert.assertEquals(segments.size(), 1);
+        Assert.assertEquals(spans.size(), 1);
+
+        AbstractTracingSpan span = spans.get(0);
+        int start = 0;
+        if (Config.Plugin.SolrJ.TRACE_OPS_PARAMS) {
+            SpanAssert.assertTag(span, ++start, String.valueOf(maxSegments));
+        }
+        spanCommonAssert(span, start, "solrJ/collection/update/OPTIMIZE");
+    }
+
+    @Test
+    public void testQuery() throws Throwable {
+        QueryRequest request = new QueryRequest();
+        arguments = new Object[] {
+            request,
+            null,
+            collection
+        };
+
+        interceptor.beforeMethod(enhancedInstance, method, arguments, 
argumentType, null);
+        interceptor.afterMethod(enhancedInstance, method, arguments, 
argumentType, getQueryResponse());
+
+        List<TraceSegment> segments = segmentStorage.getTraceSegments();
+        List<AbstractTracingSpan> spans = 
SegmentHelper.getSpans(segments.get(0));
+
+        Assert.assertEquals(segments.size(), 1);
+        Assert.assertEquals(spans.size(), 1);
+
+        AbstractTracingSpan span = spans.get(0);
+        querySpanAssert(span, "/select", 100, "solrJ/collection/select");
+    }
+
+    @Test
+    public void testGet() throws Throwable {
+        ModifiableSolrParams reqParams = new ModifiableSolrParams();
+        if (StringUtils.isEmpty(reqParams.get("qt"))) {
+            reqParams.set("qt", new String[]{"/get"});
+        }
+        reqParams.set("ids", new String[] {"99", "98"});
+        QueryRequest request = new QueryRequest(reqParams);
+
+        arguments = new Object[] {
+            request,
+            null,
+            collection
+        };
+        interceptor.beforeMethod(enhancedInstance, method, arguments, 
argumentType, null);
+        interceptor.afterMethod(enhancedInstance, method, arguments, 
argumentType, getGetResponse());
+
+        List<TraceSegment> segments = segmentStorage.getTraceSegments();
+        List<AbstractTracingSpan> spans = 
SegmentHelper.getSpans(segments.get(0));
+        Assert.assertEquals(segments.size(), 1);
+        Assert.assertEquals(spans.size(), 1);
+
+        AbstractTracingSpan span = spans.get(0);
+        querySpanAssert(span, "/get", 1, "solrJ/collection/get");
+    }
+
+    @Test
+    public void testDeleteById() throws Throwable {
+        UpdateRequest request = new UpdateRequest();
+        arguments = new Object[] {
+            request.deleteById("12"),
+            null,
+            collection
+        };
+        interceptor.beforeMethod(enhancedInstance, method, arguments, 
argumentType, null);
+        interceptor.afterMethod(enhancedInstance, method, arguments, 
argumentType, getResponse());
+
+        List<TraceSegment> segments = segmentStorage.getTraceSegments();
+        List<AbstractTracingSpan> spans = 
SegmentHelper.getSpans(segments.get(0));
+
+        Assert.assertEquals(segments.size(), 1);
+        Assert.assertEquals(spans.size(), 1);
+
+        AbstractTracingSpan span = spans.get(0);
+        spanDeleteAssert(span, "solrJ/collection/update/DELETE_BY_IDS", 
"[12]");
+    }
+
+    @Test
+    public void testDeleteByQuery() throws Throwable {
+        UpdateRequest request = new UpdateRequest();
+        arguments = new Object[] {
+            request.deleteByQuery("id:[2 TO 5]"),
+            null,
+            collection
+        };
+        interceptor.beforeMethod(enhancedInstance, method, arguments, 
argumentType, null);
+        interceptor.afterMethod(enhancedInstance, method, arguments, 
argumentType, getResponse());
+
+        List<TraceSegment> segments = segmentStorage.getTraceSegments();
+        List<AbstractTracingSpan> spans = 
SegmentHelper.getSpans(segments.get(0));
+
+        Assert.assertEquals(segments.size(), 1);
+        Assert.assertEquals(spans.size(), 1);
+
+        AbstractTracingSpan span = spans.get(0);
+        spanDeleteAssert(span, "solrJ/collection/update/DELETE_BY_QUERY", 
"[id:[2 TO 5]]");
+    }
+
+    @Test
+    public void testException() throws Throwable {
+        QueryRequest request = new QueryRequest();
+        arguments = new Object[] {
+            request,
+            null,
+            collection
+        };
+        NamedList<Object> response = new NamedList<Object>();
+        NamedList<Object> header = new NamedList<Object>();
+        header.add("status", 500);
+        header.add("QTime", 5);
+        response.add("responseHeader", header);
+
+        interceptor.beforeMethod(enhancedInstance, method, arguments, 
argumentType, null);
+        interceptor.handleMethodException(enhancedInstance, method, arguments, 
argumentType,
+                new SolrException(SolrException.ErrorCode.SERVER_ERROR, "for 
test",  new Exception()));
+        interceptor.afterMethod(enhancedInstance, method, arguments, 
argumentType, response);
+
+        List<TraceSegment> segments = segmentStorage.getTraceSegments();
+        List<AbstractTracingSpan> spans = 
SegmentHelper.getSpans(segments.get(0));
+
+        Assert.assertEquals(segments.size(), 1);
+        Assert.assertEquals(spans.size(), 1);
+
+        AbstractTracingSpan span = spans.get(0);
+        SpanAssert.assertOccurException(span, true);
+    }
+
+
+
+    private void querySpanAssert(AbstractSpan span, String qt, int numFound, 
String operationName) {
+        Assert.assertEquals(span.getOperationName(), operationName);
+        SpanAssert.assertTag(span, 0, "Solr");
+        SpanAssert.assertTag(span, 1, "0");
+        SpanAssert.assertTag(span, 2, qt);
+
+        int start = 3;
+        if (Config.Plugin.SolrJ.TRACE_STATEMENT) {
+            start++;
+        }
+        SpanAssert.assertTag(span, start++, "5");
+        SpanAssert.assertTag(span, start++, String.valueOf(numFound));
+    }
+
+    private void spanCommonAssert(AbstractSpan span, int start, String 
operationName) {
+        SpanAssert.assertComponent(span, ComponentsDefine.SOLRJ);
+        SpanAssert.assertOccurException(span, false);
+        SpanAssert.assertLogSize(span, 0);
+        SpanAssert.assertLayer(span, SpanLayer.DB);
+
+        SpanAssert.assertTag(span, 0, "Solr");
+        SpanAssert.assertTag(span, start + 1, "5");
+
+        Assert.assertEquals(span.getOperationName(), operationName);
+    }
+
+    private void spanDeleteAssert(AbstractSpan span, String operationName, 
String statement) {
+        Assert.assertEquals(span.getOperationName(), operationName);
+        SpanAssert.assertComponent(span, ComponentsDefine.SOLRJ);
+        SpanAssert.assertOccurException(span, false);
+        SpanAssert.assertLogSize(span, 0);
+        SpanAssert.assertLayer(span, SpanLayer.DB);
+
+        SpanAssert.assertTag(span, 0, "Solr");
+
+        int start = 0;
+        if (Config.Plugin.SolrJ.TRACE_STATEMENT) {
+            SpanAssert.assertTag(span, ++start, statement);
+        }
+        if (Config.Plugin.SolrJ.TRACE_OPS_PARAMS) {
+            SpanAssert.assertTag(span, ++start, "-1");
+        }
+
+        SpanAssert.assertTag(span, start + 1, "5");
+    }
+
+    private NamedList<Object> getResponse() {
+        NamedList<Object> response = new NamedList<Object>();
+        response.add("responseHeader", header);
+        return response;
+    }
+
+    private NamedList<Object> getQueryResponse() {
+        NamedList<Object> response = new NamedList<Object>();
+        response.add("responseHeader", header);
+        SolrDocumentList list = new SolrDocumentList();
+        list.setStart(0);
+        list.setNumFound(100);
+        list.setMaxScore(.0f);
+
+        for (int start = 0; start < 10; start++) {
+            SolrDocument doc = new SolrDocument();
+            doc.addField("id", start);
+            doc.addField("_version", 1634676349644832768L);
+            list.add(doc);
+        }
+        response.add("response", list);
+        return response;
+    }
+
+    private NamedList<Object> getGetResponse() {
+        NamedList<Object> response = new NamedList<Object>();
+        response.add("responseHeader", header);
+        SolrDocumentList list = new SolrDocumentList();
+        list.setStart(0);
+        list.setNumFound(1);
+        list.setMaxScore(.0f);
+
+        SolrDocument doc = new SolrDocument();
+        doc.addField("id", 1);
+        doc.addField("_version", 1634676349644832768L);
+        list.add(doc);
+
+        response.add("response", list);
+        return response;
+    }
+
+    class EnhanceHttpSolrClient extends HttpSolrClient implements 
EnhancedInstance {
+        Object value = null;
+
+        protected EnhanceHttpSolrClient(Builder builder) {
+            super(builder);
+        }
+
+        @Override
+        public Object getSkyWalkingDynamicField() {
+            return value;
+        }
+
+        @Override
+        public void setSkyWalkingDynamicField(Object value) {
+            this.value = value;
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/docs/en/setup/service-agent/java-agent/README.md 
b/docs/en/setup/service-agent/java-agent/README.md
index a14cd44..9b727d5 100644
--- a/docs/en/setup/service-agent/java-agent/README.md
+++ b/docs/en/setup/service-agent/java-agent/README.md
@@ -82,6 +82,8 @@ property key | Description | Default |
 `plugin.elasticsearch.trace_dsl`|If true, trace all the DSL(Domain Specific 
Language) in ElasticSearch access, default is false.|`false`|
 `plugin.springmvc.use_qualified_name_as_endpoint_name`|If true, the fully 
qualified method name will be used as the endpoint name instead of the request 
URL, default is false.|`false`|
 `plugin.toolit.use_qualified_name_as_operation_name`|If true, the fully 
qualified method name will be used as the operation name instead of the given 
operation name, default is false.|`false`|
+`plugin.solrj.trace_statement`|If true, trace all the query parameters(include 
deleteByIds and deleteByQuery) in Solr query request, default is false.|`false`|
+`plugin.solrj.trace_ops_params`|If true, trace all the operation parameters in 
Solr request, default is false.|`false`|
 
 ## Optional Plugins
 Java agent plugins are all pluggable. Optional plugins could be provided in 
`optional-plugins` folder under agent or 3rd party repositores.
diff --git a/docs/en/setup/service-agent/java-agent/Supported-list.md 
b/docs/en/setup/service-agent/java-agent/Supported-list.md
index 2baf906..dcfda3d 100644
--- a/docs/en/setup/service-agent/java-agent/Supported-list.md
+++ b/docs/en/setup/service-agent/java-agent/Supported-list.md
@@ -53,6 +53,7 @@
     * [Xmemcached](https://github.com/killme2008/xmemcached) 2.x
   * [Elasticsearch](https://github.com/elastic/elasticsearch)
     * 
[transport-client](https://github.com/elastic/elasticsearch/tree/master/client/transport)
 5.2.x-5.6.x
+  * [SolrJ](https://lucene.apache.org/solr) 7.0.0-7.7.1
 * Service Discovery
   * [Netflix Eureka](https://github.com/Netflix/eureka)
 * Distributed Coordination
diff --git a/oap-server/server-core/src/test/resources/component-libraries.yml 
b/oap-server/server-core/src/test/resources/component-libraries.yml
index 97733d8..86d29e5 100644
--- a/oap-server/server-core/src/test/resources/component-libraries.yml
+++ b/oap-server/server-core/src/test/resources/component-libraries.yml
@@ -198,6 +198,12 @@ spring-cloud-gateway:
 RESTEasy:
   id: 62
   languages: Java
+SolrJ:
+  id: 63
+  languages: Java
+Solr:
+  id: 64
+  languages: Java
 
 # .NET/.NET Core components
 # [3000, 4000) for C#/.NET only
@@ -295,3 +301,4 @@ Component-Server-Mappings:
   Pomelo.EntityFrameworkCore.MySql: Mysql
   Npgsql.EntityFrameworkCore.PostgreSQL: PostgreSQL
   transport-client: Elasticsearch
+  SolrJ: Solr
diff --git 
a/oap-server/server-starter/src/main/resources/component-libraries.yml 
b/oap-server/server-starter/src/main/resources/component-libraries.yml
index 4d95988..87e213f 100644
--- a/oap-server/server-starter/src/main/resources/component-libraries.yml
+++ b/oap-server/server-starter/src/main/resources/component-libraries.yml
@@ -216,6 +216,12 @@ spring-cloud-gateway:
 RESTEasy:
   id: 62
   languages: Java
+SolrJ:
+  id: 63
+  languages: Java
+Solr:
+  id: 64
+  languages: Java
 
 # .NET/.NET Core components
 # [3000, 4000) for C#/.NET only
@@ -315,3 +321,4 @@ Component-Server-Mappings:
   Pomelo.EntityFrameworkCore.MySql: Mysql
   Npgsql.EntityFrameworkCore.PostgreSQL: PostgreSQL
   transport-client: Elasticsearch
+  SolrJ: Solr

Reply via email to