package org.skywalking.apm.plugin.jedis.v2; import org.skywalking.apm.agent.core.context.ContextManager; import org.skywalking.apm.agent.core.plugin.interceptor.EnhancedClassInstanceContext; import org.skywalking.apm.agent.core.plugin.interceptor.assist.NoConcurrencyAccessObject; import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodInvokeContext; import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor; import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; import org.skywalking.apm.util.StringUtil; import org.skywalking.apm.trace.Span; import org.skywalking.apm.trace.tag.Tags; /** * {@link JedisMethodInterceptor} intercept all method of {@link redis.clients.jedis.Jedis} * or {@link redis.clients.jedis.JedisCluster}. {@link JedisMethodInterceptor} record * the redis host, operation name and the key of the operation. * * @author zhangxin */ public class JedisMethodInterceptor extends NoConcurrencyAccessObject implements InstanceMethodsAroundInterceptor { /** * The key name that redis connection information in {@link EnhancedClassInstanceContext#context}. */ protected static final String KEY_OF_REDIS_CONN_INFO = "REDIS_CONNECTION_INFO"; /** * The key name that multiple redis hosts in {@link EnhancedClassInstanceContext#context}. */ protected static final String KEY_OF_REDIS_HOSTS = "KEY_OF_REDIS_HOSTS"; /** * The key name that redis host in {@link EnhancedClassInstanceContext#context}. * it will be null if the value that fetch from {@link EnhancedClassInstanceContext#context} * by using {@link #KEY_OF_REDIS_HOSTS} is not null. */ protected static final String KEY_OF_REDIS_HOST = "KEY_OF_REDIS_HOST"; /** * The key name that redis port in {@link EnhancedClassInstanceContext#context}. * It can not be null if the value that fetch from {@link EnhancedClassInstanceContext#context} by * using {@link #KEY_OF_REDIS_HOST} is not null. */ protected static final String KEY_OF_REDIS_PORT = "KEY_OF_REDIS_PORT"; private static final String REDIS_COMPONENT = "Redis"; @Override public void beforeMethod(final EnhancedClassInstanceContext context, final InstanceMethodInvokeContext interceptorContext, MethodInterceptResult result) { this.whenEnter(context, interceptorContext); } /** * set peer host information for the current active span. */ private void tagPeer(Span span, EnhancedClassInstanceContext context) { String redisHosts = (String) context.get(KEY_OF_REDIS_HOSTS); if (!StringUtil.isEmpty(redisHosts)) { Tags.PEERS.set(span, (String) context.get(KEY_OF_REDIS_HOSTS)); } else { Tags.PEER_HOST.set(span, (String) context.get(KEY_OF_REDIS_HOST)); Tags.PEER_PORT.set(span, (Integer) context.get(KEY_OF_REDIS_PORT)); } } @Override public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext, Object ret) { this.whenExist(context); return ret; } @Override public void handleMethodException(Throwable t, EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext) { ContextManager.activeSpan().log(t); } @Override protected void enter(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext) { Span span = ContextManager.createSpan("Jedis/" + interceptorContext.methodName()); Tags.COMPONENT.set(span, REDIS_COMPONENT); Tags.DB_TYPE.set(span, REDIS_COMPONENT); Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_CLIENT); tagPeer(span, context); Tags.SPAN_LAYER.asDB(span); if (StringUtil.isEmpty(context.get(KEY_OF_REDIS_HOST, String.class))) { Tags.PEERS.set(span, String.valueOf(context.get(KEY_OF_REDIS_HOSTS))); } else { Tags.PEER_HOST.set(span, context.get(KEY_OF_REDIS_HOST, String.class)); Tags.PEER_PORT.set(span, (Integer) context.get(KEY_OF_REDIS_PORT)); } if (interceptorContext.allArguments().length > 0 && interceptorContext.allArguments()[0] instanceof String) { Tags.DB_STATEMENT.set(span, interceptorContext.methodName() + " " + interceptorContext.allArguments()[0]); } } @Override protected void exit() { ContextManager.stopSpan(); } }