提交 a36394d9 编写于 作者: 于玉桔 提交者: wu-sheng

Support lettuce plugin (#2152)

* Support lettuce plugin

* lettuce plugin bugfix

* lettuce plugin fix license issue

* lettuce plugin fix cluster and config issue

* plugin lettuce compatible with low 5.0.x version

* lettuce plugin support version accurately describes on Supported-list.md

* plugin lettuce compatible with low 5.0.2 version

* lettuce plugin fix wrong batch method intercept point

* move lettuce to optional plugins

* fix ci issue

* fix ci issue

* Modify the description file

* Pom code optimization

* Optimization operation name

* Optimization operation name2
上级 3b0a1d31
......@@ -110,6 +110,8 @@ public class ComponentsDefine {
public static final OfficialComponent REDISSON = new OfficialComponent(56, "Redisson");
public static final OfficialComponent LETTUCE = new OfficialComponent(57, "Lettuce");
private static ComponentsDefine INSTANCE = new ComponentsDefine();
private String[] components;
......@@ -119,7 +121,7 @@ public class ComponentsDefine {
}
public ComponentsDefine() {
components = new String[57];
components = new String[58];
addComponent(TOMCAT);
addComponent(HTTPCLIENT);
addComponent(DUBBO);
......@@ -161,6 +163,7 @@ public class ComponentsDefine {
addComponent(CANAL);
addComponent(GSON);
addComponent(REDISSON);
addComponent(LETTUCE);
}
private void addComponent(OfficialComponent component) {
......
<?xml version="1.0"?>
<!--
~ 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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.skywalking</groupId>
<artifactId>optional-plugins</artifactId>
<version>6.1.0-SNAPSHOT</version>
</parent>
<artifactId>apm-lettuce-5.x-plugin</artifactId>
<packaging>jar</packaging>
<name>lettuce-5.x-plugin</name>
<url>http://maven.apache.org</url>
<properties>
<lettuce-core.version>5.1.3.RELEASE</lettuce-core.version>
<compiler.version>1.8</compiler.version>
</properties>
<dependencies>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>${lettuce-core.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
/*
* 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.lettuce.v5;
import io.lettuce.core.protocol.AsyncCommand;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
import java.lang.reflect.Method;
import java.util.function.Consumer;
/**
* @author zhaoyuguang
*/
public class AsyncCommandMethodInterceptor implements InstanceMethodsAroundInterceptor {
@Override
@SuppressWarnings("unchecked")
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
AsyncCommand asyncCommand = (AsyncCommand) objInst;
String operationName = "Lettuce/" + asyncCommand.getType().name();
AbstractSpan span = ContextManager.createLocalSpan(operationName + "/onComplete");
span.setComponent(ComponentsDefine.LETTUCE);
allArguments[0] = new SWConsumer((Consumer) allArguments[0], ContextManager.capture(), operationName);
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Object ret) throws Throwable {
ContextManager.stopSpan();
return ret;
}
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Throwable t) {
ContextManager.activeSpan().errorOccurred().log(t);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.lettuce.v5;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
/**
* ClientOptions is the link between RedisChannelWriter and AbstractRedisClient.
* to enhance ClientOptions for bring peer(the cluster configuration information)
* in AbstractRedisClient to RedisChannelWriter.
*
* @author zhaoyuguang
*/
public class ClientOptionsConstructorInterceptor implements InstanceConstructorInterceptor {
@Override
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
}
}
/*
* 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.lettuce.v5;
import io.lettuce.core.protocol.RedisCommand;
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 java.lang.reflect.Method;
import java.util.Collection;
/**
* @author zhaoyuguang
*/
public class RedisChannelWriterInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor {
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
String peer = (String) objInst.getSkyWalkingDynamicField();
StringBuilder dbStatement = new StringBuilder();
String operationName = "Lettuce/";
if (allArguments[0] instanceof RedisCommand) {
RedisCommand redisCommand = (RedisCommand) allArguments[0];
String command = redisCommand.getType().name();
operationName = operationName + command;
dbStatement.append(command);
} else if (allArguments[0] instanceof Collection) {
@SuppressWarnings("unchecked")
Collection<RedisCommand> redisCommands = (Collection<RedisCommand>) allArguments[0];
operationName = operationName + "BATCH_WRITE";
for (RedisCommand redisCommand : redisCommands) {
dbStatement.append(redisCommand.getType().name()).append(";");
}
}
AbstractSpan span = ContextManager.createExitSpan(operationName, peer);
span.setComponent(ComponentsDefine.LETTUCE);
Tags.DB_TYPE.set(span, "Redis");
Tags.DB_STATEMENT.set(span, dbStatement.toString());
SpanLayer.asCache(span);
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Object ret) throws Throwable {
ContextManager.stopSpan();
return ret;
}
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Throwable t) {
AbstractSpan span = ContextManager.activeSpan();
span.errorOccurred();
span.log(t);
}
@Override
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
EnhancedInstance optionsInst = (EnhancedInstance) allArguments[0];
objInst.setSkyWalkingDynamicField(optionsInst.getSkyWalkingDynamicField());
}
}
/*
* 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.lettuce.v5;
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
/**
* @author zhaoyuguang
*/
public class RedisClientConstructorInterceptor implements InstanceConstructorInterceptor {
@Override
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
RedisURI redisURI = (RedisURI) allArguments[1];
RedisClient redisClient = (RedisClient) objInst;
EnhancedInstance optionsInst = (EnhancedInstance) redisClient.getOptions();
optionsInst.setSkyWalkingDynamicField(redisURI.getHost() + ":" + redisURI.getPort());
}
}
/*
* 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.lettuce.v5;
import io.lettuce.core.RedisURI;
import io.lettuce.core.cluster.RedisClusterClient;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
/**
* @author zhaoyuguang
*/
public class RedisClusterClientConstructorInterceptor implements InstanceConstructorInterceptor {
@Override
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
@SuppressWarnings("unchecked")
Iterable<RedisURI> redisURIs = (Iterable<RedisURI>) allArguments[1];
RedisClusterClient redisClusterClient = (RedisClusterClient) objInst;
StringBuilder peer = new StringBuilder();
for (RedisURI redisURI : redisURIs) {
peer.append(redisURI.getHost()).append(":").append(redisURI.getPort()).append(";");
}
EnhancedInstance optionsInst = (EnhancedInstance) redisClusterClient.getOptions();
optionsInst.setSkyWalkingDynamicField(peer.toString());
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.lettuce.v5;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
import java.util.function.Consumer;
/**
* @author zhaoyuguang
*/
public class SWConsumer<T> implements Consumer<T> {
private Consumer<T> consumer;
private ContextSnapshot snapshot;
private String operationName;
SWConsumer(Consumer<T> consumer, ContextSnapshot snapshot, String operationName) {
this.consumer = consumer;
this.snapshot = snapshot;
this.operationName = operationName;
}
@Override
public void accept(T t) {
AbstractSpan span = ContextManager.createLocalSpan(operationName + "/accept");
span.setComponent(ComponentsDefine.LETTUCE);
try {
ContextManager.continued(snapshot);
consumer.accept(t);
} catch (Throwable th) {
ContextManager.activeSpan().errorOccurred().log(th);
} finally {
ContextManager.stopSpan();
}
}
}
/*
* 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.lettuce.v5.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
/**
* @author zhaoyuguang
*/
public class AsyncCommandInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
private static final String ENHANCE_CLASS = "io.lettuce.core.protocol.AsyncCommand";
private static final String ASYNC_COMMAND_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.lettuce.v5.AsyncCommandMethodInterceptor";
@Override
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[]{
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("onComplete");
}
@Override
public String getMethodsInterceptor() {
return ASYNC_COMMAND_METHOD_INTERCEPTOR;
}
@Override
public boolean isOverrideArgs() {
return true;
}
}
};
}
@Override
public ClassMatch enhanceClass() {
return byName(ENHANCE_CLASS);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.lettuce.v5.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.any;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
/**
* @author zhaoyuguang
*/
public class ClientOptionsInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
private static final String ENHANCE_CLASS = "io.lettuce.core.ClientOptions";
private static final String CLIENT_OPTIONS_CONSTRUCTOR_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.lettuce.v5.ClientOptionsConstructorInterceptor";
@Override
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[]{
new ConstructorInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getConstructorMatcher() {
return any();
}
@Override
public String getConstructorInterceptor() {
return CLIENT_OPTIONS_CONSTRUCTOR_INTERCEPTOR_CLASS;
}
}
};
}
@Override
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[0];
}
@Override
public ClassMatch enhanceClass() {
return byName(ENHANCE_CLASS);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.lettuce.v5.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
/**
* The writeAndFlush method is used in versions lower than 5.0.2.RELEASE
*
* @author zhaoyuguang
*/
public class RedisChannelWriterInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
private static final String ENHANCE_CLASS = "io.lettuce.core.protocol.DefaultEndpoint";
private static final String REDIS_CHANNEL_WRITER_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.lettuce.v5.RedisChannelWriterInterceptor";
@Override
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[] {
new ConstructorInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getConstructorMatcher() {
return takesArgumentWithType(0, "io.lettuce.core.ClientOptions");
}
@Override
public String getConstructorInterceptor() {
return REDIS_CHANNEL_WRITER_INTERCEPTOR_CLASS;
}
}
};
}
@Override
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[]{
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("writeToChannelAndFlush").or(named("writeAndFlush"));
}
@Override
public String getMethodsInterceptor() {
return REDIS_CHANNEL_WRITER_INTERCEPTOR_CLASS;
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
@Override
public ClassMatch enhanceClass() {
return byName(ENHANCE_CLASS);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.lettuce.v5.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
/**
* @author zhaoyuguang
*/
public class RedisClientInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
private static final String ENHANCE_CLASS = "io.lettuce.core.RedisClient";
private static final String REDIS_CLIENT_CONSTRUCTOR_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.lettuce.v5.RedisClientConstructorInterceptor";
@Override
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[]{
new ConstructorInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getConstructorMatcher() {
return takesArgumentWithType(1, "io.lettuce.core.RedisURI");
}
@Override
public String getConstructorInterceptor() {
return REDIS_CLIENT_CONSTRUCTOR_INTERCEPTOR_CLASS;
}
}
};
}
@Override
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[0];
}
@Override
public ClassMatch enhanceClass() {
return byName(ENHANCE_CLASS);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.lettuce.v5.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
/**
* @author zhaoyuguang
*/
public class RedisClusterClientInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
private static final String ENHANCE_CLASS = "io.lettuce.core.cluster.RedisClusterClient";
private static final String REDIS_CLUSTER_CLIENT_CONSTRUCTOR_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.lettuce.v5.RedisClusterClientConstructorInterceptor";
@Override
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[]{
new ConstructorInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getConstructorMatcher() {
return takesArgumentWithType(1, "java.lang.Iterable");
}
@Override
public String getConstructorInterceptor() {
return REDIS_CLUSTER_CLIENT_CONSTRUCTOR_INTERCEPTOR_CLASS;
}
}
};
}
@Override
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[0];
}
@Override
public ClassMatch enhanceClass() {
return byName(ENHANCE_CLASS);
}
}
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
lettuce-5.x=org.apache.skywalking.apm.plugin.lettuce.v5.define.AsyncCommandInstrumentation
lettuce-5.x=org.apache.skywalking.apm.plugin.lettuce.v5.define.ClientOptionsInstrumentation
lettuce-5.x=org.apache.skywalking.apm.plugin.lettuce.v5.define.RedisChannelWriterInstrumentation
lettuce-5.x=org.apache.skywalking.apm.plugin.lettuce.v5.define.RedisClientInstrumentation
lettuce-5.x=org.apache.skywalking.apm.plugin.lettuce.v5.define.RedisClusterClientInstrumentation
\ No newline at end of file
/*
* 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.lettuce.v5;
import io.lettuce.core.protocol.Command;
import io.lettuce.core.protocol.CommandType;
import io.lettuce.core.protocol.RedisCommand;
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.context.util.TagValuePair;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.test.helper.SegmentHelper;
import org.apache.skywalking.apm.agent.test.helper.SpanHelper;
import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
import org.hamcrest.CoreMatchers;
import org.hamcrest.MatcherAssert;
import org.hamcrest.core.Is;
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.util.List;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* @author zhaoyuguang
*/
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(TracingSegmentRunner.class)
public class RedisChannelWriterInterceptorTest {
@SegmentStoragePoint
private SegmentStorage segmentStorage;
@Rule
public AgentServiceRule serviceRule = new AgentServiceRule();
@Mock
private MockInstance mockClientOptionsInstance;
@Mock
private MockInstance mockRedisChannelWriterInstance;
private RedisChannelWriterInterceptor interceptor;
private class MockInstance implements EnhancedInstance {
private Object object;
@Override
public Object getSkyWalkingDynamicField() {
return object;
}
@Override
public void setSkyWalkingDynamicField(Object value) {
this.object = value;
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
@Before
public void setUp() throws Exception {
mockRedisChannelWriterInstance = new MockInstance();
mockClientOptionsInstance = new MockInstance();
mockClientOptionsInstance.setSkyWalkingDynamicField("127.0.0.1:6379;127.0.0.1:6378;");
interceptor = new RedisChannelWriterInterceptor();
}
@Test
public void testInterceptor() throws Throwable {
interceptor.onConstruct(mockRedisChannelWriterInstance, new Object[]{mockClientOptionsInstance});
RedisCommand redisCommand = new Command(CommandType.SET, null);
interceptor.beforeMethod(mockRedisChannelWriterInstance, null, new Object[]{redisCommand}, null, null);
interceptor.afterMethod(mockRedisChannelWriterInstance, null, null, null, null);
MatcherAssert.assertThat((String) mockRedisChannelWriterInstance.getSkyWalkingDynamicField(), Is.is("127.0.0.1:6379;127.0.0.1:6378;"));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertThat(spans.size(), is(1));
assertThat(spans.get(0).getOperationName(), is("Lettuce/SET"));
assertThat(spans.get(0).isExit(), is(true));
assertThat(SpanHelper.getComponentId(spans.get(0)), is(57));
List<TagValuePair> tags = SpanHelper.getTags(spans.get(0));
assertThat(tags.get(0).getValue(), is("Redis"));
assertThat(SpanHelper.getLayer(spans.get(0)), CoreMatchers.is(SpanLayer.CACHE));
}
}
......@@ -44,6 +44,7 @@
<module>optional-spring-plugins</module>
<module>trace-ignore-plugin</module>
<module>gson-2.8.x-plugin</module>
<module>lettuce-5.x-plugin</module>
</modules>
<dependencies>
......
......@@ -198,6 +198,9 @@ Gson:
Redisson:
id: 56
languages: Java
Lettuce:
id: 57
languages: Java
# .NET/.NET Core components
......@@ -283,6 +286,7 @@ Component-Server-Mappings:
mysql-connector-java: Mysql
Jedis: Redis
Redisson: Redis
Lettuce: Redis
StackExchange.Redis: Redis
SqlClient: SqlServer
Npgsql: PostgreSQL
......
......@@ -56,6 +56,7 @@ Component-Server-Mappings:
Jedis: Redis
StackExchange.Redis: Redis
Redisson: Redis
Lettuce: Redis
SqlClient: SqlServer
Npgsql: PostgreSQL
MySqlConnector: Mysql
......
......@@ -87,6 +87,7 @@ Now, we have the following known optional plugins.
* [Trace Oracle and Resin](agent-optional-plugins/Oracle-Resin-plugins.md)
* [Filter traces through specified endpoint name patterns](agent-optional-plugins/trace-ignore-plugin.md)
* Gson serialization lib in optional plugin folder
* Lettuce 5.x(JRE1.8+) in optional plugin folder
## Advanced Features
* Set the settings through system properties for config file override. Read [setting override](Setting-override.md).
......
......@@ -41,6 +41,7 @@
* Redis
* [Jedis](https://github.com/xetorthio/jedis) 2.x
* [Redisson](https://github.com/redisson/redisson) Easy Java Redis client 3.5.2+
* [Lettuce](https://github.com/lettuce-io/lettuce-core) 5.x (Optional²)
* [MongoDB Java Driver](https://github.com/mongodb/mongo-java-driver) 2.13-2.14,3.3+
* Memcached Client
* [Spymemcached](https://github.com/couchbase/spymemcached) 2.x
......
......@@ -55,6 +55,8 @@ H2:
Component-Server-Mappings:
Jedis: Redis
StackExchange.Redis: Redis
Redisson: Redis
Lettuce: Redis
SqlClient: SqlServer
Npgsql: PostgreSQL
MySqlConnector: Mysql
......
......@@ -69,7 +69,7 @@ ExitSpan代表一个服务客户端或MQ的生产者,在SkyWalking的早期命
以下是有关跨线程传播的三个步骤:
1. 使用`ContextManager#capture`获取ContextSnapshot对象。
2. 让子线程以任何方式,通过方法参数或由现有参数携带来访问ContextSnapshot
3. 在子线程中使用`ContextManager#continies`
3. 在子线程中使用`ContextManager#continued`
## 核心 API
### ContextManager
......
......@@ -180,6 +180,9 @@ Undertow:
Redisson:
id: 56
languages: Java
Lettuce:
id: 57
languages: Java
# .NET/.NET Core components
# [3000, 4000) for C#/.NET only
......@@ -262,6 +265,7 @@ Component-Server-Mappings:
mysql-connector-java: Mysql
Jedis: Redis
Redisson: Redis
Lettuce: Redis
StackExchange.Redis: Redis
SqlClient: SqlServer
Npgsql: PostgreSQL
......
......@@ -198,6 +198,9 @@ Gson:
Redisson:
id: 56
languages: Java
Lettuce:
id: 57
languages: Java
# .NET/.NET Core components
......@@ -284,6 +287,7 @@ Component-Server-Mappings:
Jedis: Redis
StackExchange.Redis: Redis
Redisson: Redis
Lettuce: Redis
SqlClient: SqlServer
Npgsql: PostgreSQL
MySqlConnector: Mysql
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册