Introduce LogHelper to prevent excessive byte[] logging

CLOSES #682
pull/687/head
Philipp Marx 8 years ago
parent 90b3547b25
commit 7bb3e486b9

@ -45,6 +45,7 @@ import org.redisson.client.protocol.pubsub.Message;
import org.redisson.client.protocol.pubsub.PubSubMessage;
import org.redisson.client.protocol.pubsub.PubSubPatternMessage;
import org.redisson.client.protocol.pubsub.PubSubStatusMessage;
import org.redisson.misc.LogHelper;
import org.redisson.misc.RPromise;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -203,11 +204,11 @@ public class CommandDecoder extends ReplayingDecoder<State> {
RPromise<Void> promise = commandBatch.getPromise();
if (error != null) {
if (!promise.tryFailure(error) && promise.cause() instanceof RedisTimeoutException) {
log.warn("response has been skipped due to timeout! channel: {}, command: {}", ctx.channel(), data);
log.warn("response has been skipped due to timeout! channel: {}, command: {}",ctx.channel(), LogHelper.toString(data));
}
} else {
if (!promise.trySuccess(null) && promise.cause() instanceof RedisTimeoutException) {
log.warn("response has been skipped due to timeout! channel: {}, command: {}", ctx.channel(), data);
log.warn("response has been skipped due to timeout! channel: {}, command: {}", ctx.channel(), LogHelper.toString(data));
}
}

@ -21,6 +21,7 @@ import java.util.List;
import org.redisson.client.codec.Codec;
import org.redisson.client.protocol.decoder.MultiDecoder;
import org.redisson.misc.LogHelper;
import org.redisson.misc.RPromise;
/**
@ -85,7 +86,7 @@ public class CommandData<T, R> implements QueueCommand {
@Override
public String toString() {
return "CommandData [promise=" + promise + ", command=" + command + ", params="
+ Arrays.toString(params) + ", codec=" + codec + "]";
+ LogHelper.toString(params) + ", codec=" + codec + "]";
}
@Override

@ -49,6 +49,7 @@ import org.redisson.connection.ConnectionManager;
import org.redisson.connection.MasterSlaveEntry;
import org.redisson.connection.NodeSource;
import org.redisson.connection.NodeSource.Redirect;
import org.redisson.misc.LogHelper;
import org.redisson.misc.RPromise;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -520,7 +521,7 @@ public class CommandAsyncService implements CommandAsyncExecutor {
if (details.getAttempt() == connectionManager.getConfig().getRetryAttempts()) {
if (details.getException() == null) {
details.setException(new RedisTimeoutException("Command execution timeout for command: " + command + " with params: " + Arrays.toString(details.getParams())));
details.setException(new RedisTimeoutException("Command execution timeout for command: " + command + " with params: " + LogHelper.toString(details.getParams())));
}
details.getAttemptPromise().tryFailure(details.getException());
return;
@ -605,7 +606,7 @@ public class CommandAsyncService implements CommandAsyncExecutor {
if (!future.isSuccess()) {
details.setException(new WriteRedisConnectionException(
"Can't write command: " + details.getCommand() + ", params: " + Arrays.toString(details.getParams()) + " to channel: " + future.channel(), future.cause()));
"Can't write command: " + details.getCommand() + ", params: " + LogHelper.toString(details.getParams()) + " to channel: " + future.channel(), future.cause()));
return;
}
@ -629,7 +630,7 @@ public class CommandAsyncService implements CommandAsyncExecutor {
public void run(Timeout timeout) throws Exception {
details.getAttemptPromise().tryFailure(
new RedisTimeoutException("Redis server response timeout (" + timeoutAmount + " ms) occured for command: " + details.getCommand()
+ " with params: " + Arrays.toString(details.getParams()) + " channel: " + connection.getChannel()));
+ " with params: " + LogHelper.toString(details.getParams()) + " channel: " + connection.getChannel()));
}
};

@ -0,0 +1,81 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed 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.redisson.misc;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Objects;
/**
* @author Philipp Marx
*/
public class LogHelper {
private static final int MAX_COLLECTION_LOG_SIZE = Integer.valueOf(System.getProperty("redisson.maxCollectionLogSize", "10"));
private static final int MAX_STRING_LOG_SIZE = Integer.valueOf(System.getProperty("redisson.maxStringLogSize", "100"));
private LogHelper() {
}
public static <T> String toString(T object) {
if (object == null) {
return "null";
} else if (object instanceof String) {
return toStringString((String) object);
} else if (object.getClass().isArray()) {
return toArrayString(object);
} else if (object instanceof Collection) {
return toCollectionString((Collection<?>) object);
} else {
return Objects.toString(object);
}
}
private static String toStringString(String string) {
if (string.length() > MAX_STRING_LOG_SIZE) {
return new StringBuilder(string.substring(0, MAX_STRING_LOG_SIZE)).append("...").toString();
} else {
return string;
}
}
private static String toCollectionString(Collection<?> collection) {
return toArrayString(collection.toArray(new Object[collection.size()]));
}
private static String toArrayString(Object array) {
int length = Array.getLength(array) - 1;
if (length == -1) {
return "[]";
}
StringBuilder b = new StringBuilder(length * 3);
b.append('[');
for (int i = 0;; ++i) {
b.append(toString(Array.get(array, i)));
if (i == length) {
return b.append(']').toString();
}
b.append(", ");
if (i == MAX_COLLECTION_LOG_SIZE - 1) {
return b.append("...]").toString();
}
}
}
}

@ -0,0 +1,223 @@
package org.redisson.misc;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
/**
* @author Philipp Marx
*/
public class LogHelperTest {
@Test
public void toStringWithNull() {
assertThat(LogHelper.toString(null), is("null"));
}
@Test
public void toStringWithNestedPrimitives() {
Object[] input = new Object[] { "0", 1, 2L, 3.1D, 4.2F, (byte) 5, '6' };
assertThat(LogHelper.toString(input), is("[0, 1, 2, 3.1, 4.2, 5, 6]"));
}
@Test
public void toStringWithPrimitive() {
assertThat(LogHelper.toString("0"), is("0"));
assertThat(LogHelper.toString(1), is("1"));
assertThat(LogHelper.toString(2L), is("2"));
assertThat(LogHelper.toString(3.1D), is("3.1"));
assertThat(LogHelper.toString(4.2F), is("4.2"));
assertThat(LogHelper.toString((byte) 5), is("5"));
assertThat(LogHelper.toString('6'), is("6"));
}
@Test
public void toStringWithNestedSmallArrays() {
String[] strings = new String[] { "0" };
int[] ints = new int[] { 1 };
long[] longs = new long[] { 2L };
double[] doubles = new double[] { 3.1D };
float[] floats = new float[] { 4.2F };
byte[] bytes = new byte[] { (byte) 5 };
char[] chars = new char[] { '6' };
Object[] input = new Object[] { strings, ints, longs, doubles, floats, bytes, chars };
assertThat(LogHelper.toString(input), is("[[0], [1], [2], [3.1], [4.2], [5], [6]]"));
}
@Test
public void toStringWithNestedSmallCollections() {
List<String> strings = Arrays.asList("0" );
List<Integer> ints = Arrays.asList( 1 );
List<Long> longs = Arrays.asList( 2L );
List<Double> doubles = Arrays.asList( 3.1D );
List<Float> floats = Arrays.asList( 4.2F );
List<Byte> bytes = Arrays.asList( (byte) 5 );
List<Character> chars = Arrays.asList( '6' );
Object[] input = new Object[] { strings, ints, longs, doubles, floats, bytes, chars };
assertThat(LogHelper.toString(input), is("[[0], [1], [2], [3.1], [4.2], [5], [6]]"));
}
@Test
public void toStringWithSmallArrays() {
String[] strings = new String[] { "0" };
int[] ints = new int[] { 1 };
long[] longs = new long[] { 2L };
double[] doubles = new double[] { 3.1D };
float[] floats = new float[] { 4.2F };
byte[] bytes = new byte[] { (byte) 5 };
char[] chars = new char[] { '6' };
assertThat(LogHelper.toString(strings), is("[0]"));
assertThat(LogHelper.toString(ints), is("[1]"));
assertThat(LogHelper.toString(longs), is("[2]"));
assertThat(LogHelper.toString(doubles), is("[3.1]"));
assertThat(LogHelper.toString(floats), is("[4.2]"));
assertThat(LogHelper.toString(bytes), is("[5]"));
assertThat(LogHelper.toString(chars), is("[6]"));
}
@Test
public void toStringWithSmallCollections() {
List<String> strings = Collections.nCopies(1, "0");
List<Integer> ints = Collections.nCopies(1, 1);
List<Long> longs = Collections.nCopies(1, 2L);
List<Double> doubles = Collections.nCopies(1, 3.1D);
List<Float> floats = Collections.nCopies(1, 4.2F);
List<Byte> bytes = Collections.nCopies(1, (byte)5);
List<Character> chars = Collections.nCopies(1, '6');
assertThat(LogHelper.toString(strings), is("[0]"));
assertThat(LogHelper.toString(ints), is("[1]"));
assertThat(LogHelper.toString(longs), is("[2]"));
assertThat(LogHelper.toString(doubles), is("[3.1]"));
assertThat(LogHelper.toString(floats), is("[4.2]"));
assertThat(LogHelper.toString(bytes), is("[5]"));
assertThat(LogHelper.toString(chars), is("[6]"));
}
@Test
public void toStringWithNestedBigArrays() {
String[] strings = new String[15];
Arrays.fill(strings, "0");
int[] ints = new int[15];
Arrays.fill(ints, 1);
long[] longs = new long[15];
Arrays.fill(longs, 2L);
double[] doubles = new double[15];
Arrays.fill(doubles, 3.1D);
float[] floats = new float[15];
Arrays.fill(floats, 4.2F);
byte[] bytes = new byte[15];
Arrays.fill(bytes, (byte) 5);
char[] chars = new char[15];
Arrays.fill(chars, '6');
Object[] input = new Object[] { strings, ints, longs, doubles, floats, bytes, chars };
StringBuilder sb = new StringBuilder();
sb.append("[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...], ");
sb.append("[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...], ");
sb.append("[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ...], ");
sb.append("[3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, ...], ");
sb.append("[4.2, 4.2, 4.2, 4.2, 4.2, 4.2, 4.2, 4.2, 4.2, 4.2, ...], ");
sb.append("[5, 5, 5, 5, 5, 5, 5, 5, 5, 5, ...], ");
sb.append("[6, 6, 6, 6, 6, 6, 6, 6, 6, 6, ...]]");
assertThat(LogHelper.toString(input), is(sb.toString()));
}
@Test
public void toStringWithNestedBigCollections() {
List<String> strings = Collections.nCopies(15, "0");
List<Integer> ints = Collections.nCopies(15, 1);
List<Long> longs = Collections.nCopies(15, 2L);
List<Double> doubles = Collections.nCopies(15, 3.1D);
List<Float> floats = Collections.nCopies(15, 4.2F);
List<Byte> bytes = Collections.nCopies(15, (byte)5);
List<Character> chars = Collections.nCopies(15, '6');
Object[] input = new Object[] { strings, ints, longs, doubles, floats, bytes, chars };
StringBuilder sb = new StringBuilder();
sb.append("[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...], ");
sb.append("[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...], ");
sb.append("[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ...], ");
sb.append("[3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, ...], ");
sb.append("[4.2, 4.2, 4.2, 4.2, 4.2, 4.2, 4.2, 4.2, 4.2, 4.2, ...], ");
sb.append("[5, 5, 5, 5, 5, 5, 5, 5, 5, 5, ...], ");
sb.append("[6, 6, 6, 6, 6, 6, 6, 6, 6, 6, ...]]");
assertThat(LogHelper.toString(input), is(sb.toString()));
}
@Test
public void toStringWithBigArrays() {
String[] strings = new String[15];
Arrays.fill(strings, "0");
int[] ints = new int[15];
Arrays.fill(ints, 1);
long[] longs = new long[15];
Arrays.fill(longs, 2L);
double[] doubles = new double[15];
Arrays.fill(doubles, 3.1D);
float[] floats = new float[15];
Arrays.fill(floats, 4.2F);
byte[] bytes = new byte[15];
Arrays.fill(bytes, (byte) 5);
char[] chars = new char[15];
Arrays.fill(chars, '6');
assertThat(LogHelper.toString(strings), is("[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...]"));
assertThat(LogHelper.toString(ints), is("[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...]"));
assertThat(LogHelper.toString(longs), is("[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ...]"));
assertThat(LogHelper.toString(doubles), is("[3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, ...]"));
assertThat(LogHelper.toString(floats), is("[4.2, 4.2, 4.2, 4.2, 4.2, 4.2, 4.2, 4.2, 4.2, 4.2, ...]"));
assertThat(LogHelper.toString(bytes), is("[5, 5, 5, 5, 5, 5, 5, 5, 5, 5, ...]"));
assertThat(LogHelper.toString(chars), is("[6, 6, 6, 6, 6, 6, 6, 6, 6, 6, ...]"));
}
@Test
public void toStringWithBigCollections() {
List<String> strings = Collections.nCopies(15, "0");
List<Integer> ints = Collections.nCopies(15, 1);
List<Long> longs = Collections.nCopies(15, 2L);
List<Double> doubles = Collections.nCopies(15, 3.1D);
List<Float> floats = Collections.nCopies(15, 4.2F);
List<Byte> bytes = Collections.nCopies(15, (byte)5);
List<Character> chars = Collections.nCopies(15, '6');
assertThat(LogHelper.toString(strings), is("[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...]"));
assertThat(LogHelper.toString(ints), is("[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...]"));
assertThat(LogHelper.toString(longs), is("[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ...]"));
assertThat(LogHelper.toString(doubles), is("[3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, ...]"));
assertThat(LogHelper.toString(floats), is("[4.2, 4.2, 4.2, 4.2, 4.2, 4.2, 4.2, 4.2, 4.2, 4.2, ...]"));
assertThat(LogHelper.toString(bytes), is("[5, 5, 5, 5, 5, 5, 5, 5, 5, 5, ...]"));
assertThat(LogHelper.toString(chars), is("[6, 6, 6, 6, 6, 6, 6, 6, 6, 6, ...]"));
}
@Test
public void toStringWithSmallString() {
char[] charsForStr = new char[100];
Arrays.fill(charsForStr, '7');
String string = new String(charsForStr);
assertThat(LogHelper.toString(string), is(string));
}
@Test
public void toStringWithBigString() {
char[] charsForStr = new char[150];
Arrays.fill(charsForStr, '7');
String string = new String(charsForStr);
assertThat(LogHelper.toString(string), is(string.substring(0, 100) + "..."));
}
}
Loading…
Cancel
Save