From 6ae517423ce4ea3bbd523f80f56c685b9f8fc60e Mon Sep 17 00:00:00 2001 From: daming Date: Wed, 5 Jun 2019 22:54:45 +0800 Subject: [PATCH] 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 --- .../trace/component/ComponentsDefine.java | 3 + .../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 ++ .../plugin/solrj/SolrClientInterceptor.java | 229 ++++++++++ .../solrj/SolrConnectorInterceptor.java | 59 +++ .../plugin/solrj/commons/SolrjInstance.java | 39 ++ .../apm/plugin/solrj/commons/SolrjTags.java | 39 ++ .../define/HttpClientInstrumentation.java | 64 +++ .../define/SolrClientInstrumentation.java | 75 +++ .../src/main/resources/skywalking-plugin.def | 18 + .../solrj/SolrClientInterceptorTest.java | 428 ++++++++++++++++++ .../setup/service-agent/java-agent/README.md | 2 + .../java-agent/Supported-list.md | 1 + .../test/resources/component-libraries.yml | 7 + .../main/resources/component-libraries.yml | 7 + 16 files changed, 1032 insertions(+), 1 deletion(-) create mode 100644 apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/pom.xml create mode 100644 apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/SolrClientInterceptor.java create mode 100644 apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/SolrConnectorInterceptor.java create mode 100644 apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/commons/SolrjInstance.java create mode 100644 apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/commons/SolrjTags.java create mode 100644 apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/define/HttpClientInstrumentation.java create mode 100644 apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solrj/define/SolrClientInstrumentation.java create mode 100644 apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/main/resources/skywalking-plugin.def create mode 100644 apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/solrj/SolrClientInterceptorTest.java 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 38f9dcad14..c8dec42ee0 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 14ef3a0a47..a1e4f81dcc 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 e850ccd8b2..71725d366f 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 0000000000..31b931ade3 --- /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 0000000000..5c4d69a22b --- /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 result = (NamedList) ret; + NamedList header = (NamedList) 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 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 0000000000..d6c00b5662 --- /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 0000000000..91e4cfb362 --- /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 0000000000..3040b850b5 --- /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 0000000000..56e752b072 --- /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 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 0000000000..75f3a2e27b --- /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 getConstructorMatcher() { + return ElementMatchers.any(); + } + } + }; + } + + @Override + protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[]{ + new InstanceMethodsInterceptPoint() { + @Override + public boolean isOverrideArgs() { + return false; + } + + @Override + public ElementMatcher 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 0000000000..fd2fd6cd0b --- /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 0000000000..c7311a8c6b --- /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 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(); + 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 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 segments = segmentStorage.getTraceSegments(); + Assert.assertEquals(segments.size(), 1); + + List 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 segments = segmentStorage.getTraceSegments(); + Assert.assertEquals(segments.size(), 1); + + List 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 segments = segmentStorage.getTraceSegments(); + List 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 segments = segmentStorage.getTraceSegments(); + List 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 segments = segmentStorage.getTraceSegments(); + List 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 segments = segmentStorage.getTraceSegments(); + List 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 segments = segmentStorage.getTraceSegments(); + List 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 response = new NamedList(); + NamedList header = new NamedList(); + 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 segments = segmentStorage.getTraceSegments(); + List 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 getResponse() { + NamedList response = new NamedList(); + response.add("responseHeader", header); + return response; + } + + private NamedList getQueryResponse() { + NamedList response = new NamedList(); + 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 getGetResponse() { + NamedList response = new NamedList(); + 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 a14cd44b78..9b727d5d2a 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 2baf906a2e..dcfda3d8ca 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 97733d8026..86d29e5206 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 4d9598842b..87e213f1ad 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 -- GitLab