Redis Lettuce span UI doesn't show detailed Redis command parameters in 'db.statement' field (#6614)
This commit is contained in:
parent
b8a040ea74
commit
fc7d8dcb5e
|
|
@ -27,6 +27,7 @@ Release Notes.
|
|||
* Replace hbase-1.x-plugin with hbase-1.x-2.x-plugin to adapt hbase client 2.x
|
||||
* Remove the close_before_method and close_after_method parameters of custom-enhance-plugin to avoid memory leaks.
|
||||
* Fix bug that springmvn-annotation-4.x-plugin, witness class does not exist in some versions.
|
||||
* Add Redis command parameters to 'db.statement' field on Lettuce span UI for displaying more info
|
||||
* Fix NullPointerException with `ReactiveRequestHolder.getHeaders`.
|
||||
|
||||
#### OAP-Backend
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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.boot.PluginConfig;
|
||||
|
||||
public class LettucePluginConfig {
|
||||
public static class Plugin {
|
||||
@PluginConfig(root = LettucePluginConfig.class)
|
||||
public static class Lettuce {
|
||||
/**
|
||||
* If set to true, the parameters of the Redis command would be collected.
|
||||
*/
|
||||
public static boolean TRACE_REDIS_PARAMETERS = false;
|
||||
/**
|
||||
* For the sake of performance, SkyWalking won't save Redis parameter string into the tag.
|
||||
* If TRACE_REDIS_PARAMETERS is set to true, the first {@code REDIS_PARAMETER_MAX_LENGTH} parameter
|
||||
* characters would be collected.
|
||||
* <p>
|
||||
* Set a negative number to save specified length of parameter string to the tag.
|
||||
*/
|
||||
public static int REDIS_PARAMETER_MAX_LENGTH = 128;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,7 +18,10 @@
|
|||
|
||||
package org.apache.skywalking.apm.plugin.lettuce.v5;
|
||||
|
||||
import io.lettuce.core.protocol.RedisCommand;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apache.skywalking.apm.agent.core.conf.Constants;
|
||||
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;
|
||||
|
|
@ -28,12 +31,18 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceC
|
|||
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.util.StringUtil;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import io.lettuce.core.protocol.CommandArgs;
|
||||
import io.lettuce.core.protocol.RedisCommand;
|
||||
|
||||
public class RedisChannelWriterInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor {
|
||||
|
||||
private static final String PASSWORD_MASK = "******";
|
||||
private static final String ABBR = "...";
|
||||
private static final String DELIMITER_SPACE = " ";
|
||||
private static final String AUTH = "AUTH";
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
MethodInterceptResult result) throws Throwable {
|
||||
|
|
@ -47,6 +56,9 @@ public class RedisChannelWriterInterceptor implements InstanceMethodsAroundInter
|
|||
String command = redisCommand.getType().name();
|
||||
operationName = operationName + command;
|
||||
dbStatement.append(command);
|
||||
if (LettucePluginConfig.Plugin.Lettuce.TRACE_REDIS_PARAMETERS) {
|
||||
dbStatement.append(DELIMITER_SPACE).append(getArgsStatement(redisCommand));
|
||||
}
|
||||
} else if (allArguments[0] instanceof Collection) {
|
||||
@SuppressWarnings("unchecked") Collection<RedisCommand> redisCommands = (Collection<RedisCommand>) allArguments[0];
|
||||
operationName = operationName + "BATCH_WRITE";
|
||||
|
|
@ -61,6 +73,20 @@ public class RedisChannelWriterInterceptor implements InstanceMethodsAroundInter
|
|||
Tags.DB_STATEMENT.set(span, dbStatement.toString());
|
||||
SpanLayer.asCache(span);
|
||||
}
|
||||
|
||||
private String getArgsStatement(RedisCommand redisCommand) {
|
||||
String statement;
|
||||
if (AUTH.equalsIgnoreCase(redisCommand.getType().name())) {
|
||||
statement = PASSWORD_MASK;
|
||||
} else {
|
||||
CommandArgs args = redisCommand.getArgs();
|
||||
statement = (args != null) ? args.toCommandString() : Constants.EMPTY_STRING;
|
||||
}
|
||||
if (StringUtil.isNotEmpty(statement) && statement.length() > LettucePluginConfig.Plugin.Lettuce.REDIS_PARAMETER_MAX_LENGTH) {
|
||||
statement = statement.substring(0, LettucePluginConfig.Plugin.Lettuce.REDIS_PARAMETER_MAX_LENGTH) + ABBR;
|
||||
}
|
||||
return statement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
|
|
|
|||
|
|
@ -18,10 +18,12 @@
|
|||
|
||||
package org.apache.skywalking.apm.plugin.lettuce.v5;
|
||||
|
||||
import io.lettuce.core.RedisURI;
|
||||
import io.lettuce.core.protocol.Command;
|
||||
import io.lettuce.core.protocol.CommandType;
|
||||
import io.lettuce.core.protocol.RedisCommand;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
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;
|
||||
|
|
@ -46,11 +48,12 @@ import org.mockito.Mock;
|
|||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import io.lettuce.core.RedisURI;
|
||||
import io.lettuce.core.codec.ByteArrayCodec;
|
||||
import io.lettuce.core.protocol.Command;
|
||||
import io.lettuce.core.protocol.CommandArgs;
|
||||
import io.lettuce.core.protocol.CommandType;
|
||||
import io.lettuce.core.protocol.RedisCommand;
|
||||
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PowerMockRunnerDelegate(TracingSegmentRunner.class)
|
||||
|
|
@ -89,6 +92,7 @@ public class RedisChannelWriterInterceptorTest {
|
|||
})
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
LettucePluginConfig.Plugin.Lettuce.TRACE_REDIS_PARAMETERS = true;
|
||||
mockRedisChannelWriterInstance = new MockInstance();
|
||||
mockClientOptionsInstance = new MockInstance();
|
||||
mockClientOptionsInstance.setSkyWalkingDynamicField("127.0.0.1:6379;127.0.0.1:6378;");
|
||||
|
|
@ -98,7 +102,8 @@ public class RedisChannelWriterInterceptorTest {
|
|||
@Test
|
||||
public void testInterceptor() throws Throwable {
|
||||
interceptor.onConstruct(mockRedisChannelWriterInstance, new Object[] {mockClientOptionsInstance});
|
||||
RedisCommand redisCommand = new Command(CommandType.SET, null);
|
||||
CommandArgs args = new CommandArgs(new ByteArrayCodec()).addKey("name".getBytes()).addValue("Tom".getBytes());
|
||||
RedisCommand redisCommand = new Command(CommandType.SET, null, args);
|
||||
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;"));
|
||||
|
|
@ -110,6 +115,7 @@ public class RedisChannelWriterInterceptorTest {
|
|||
assertThat(SpanHelper.getComponentId(spans.get(0)), is(57));
|
||||
List<TagValuePair> tags = SpanHelper.getTags(spans.get(0));
|
||||
assertThat(tags.get(0).getValue(), is("Redis"));
|
||||
assertThat(tags.get(1).getValue(), CoreMatchers.containsString("Tom"));
|
||||
assertThat(SpanHelper.getLayer(spans.get(0)), CoreMatchers.is(SpanLayer.CACHE));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -166,6 +166,8 @@ property key | Description | Default |
|
|||
`plugin.toolkit.log.grpc.reporter.server_port` | Specify which grpc server's port for log data to report to. | `11800` |
|
||||
`plugin.toolkit.log.grpc.reporter.max_message_size` | Specify the maximum size of log data for grpc client to report to. | `10485760` |
|
||||
`plugin.toolkit.log.grpc.reporter.upstream_timeout` | How long grpc client will timeout in sending data to upstream. Unit is second.|`30` seconds|
|
||||
`plugin.lettuce.trace_redis_parameters` | If set to true, the parameters of Redis commands would be collected by Lettuce agent.| `false` |
|
||||
`plugin.lettuce.redis_parameter_max_length` | If set to positive number and `plugin.lettuce.trace_redis_parameters` is set to `true`, Redis command parameters would be collected and truncated to this length.| `128` |
|
||||
|
||||
## Dynamic Configurations
|
||||
All configurations above are static, if you need to change some agent settings at runtime, please read [CDS - Configuration Discovery Service document](configuration-discovery.md) for more details.
|
||||
|
|
|
|||
|
|
@ -18,4 +18,4 @@
|
|||
|
||||
home="$(cd "$(dirname $0)"; pwd)"
|
||||
|
||||
java -Dredis.host=${REDIS_SERVERS} -jar ${agent_opts} ${home}/../libs/lettuce-scenario.jar &
|
||||
java -Dredis.host=${REDIS_SERVERS} -jar -Dskywalking.plugin.lettuce.trace_redis_parameters=true ${agent_opts} ${home}/../libs/lettuce-scenario.jar &
|
||||
|
|
@ -32,7 +32,7 @@ segmentItems:
|
|||
peer: not null
|
||||
tags:
|
||||
- {key: db.type, value: Redis}
|
||||
- {key: db.statement, value: GET}
|
||||
- {key: db.statement, value: GET key<key>}
|
||||
skipAnalysis: 'false'
|
||||
- operationName: Lettuce/BATCH_WRITE
|
||||
operationId: 0
|
||||
|
|
|
|||
Loading…
Reference in New Issue