Skip to content

Commit

Permalink
INTERNAL: stacktrace all exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
oliviarla committed Nov 21, 2024
1 parent 132254c commit 79a854b
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/main/java/net/spy/memcached/ExceptionMessageFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ private static boolean isBulkOperation(Operation op, Collection<Operation> ops)
}

public static String createCompositeMessage(List<Exception> exceptions) {
if (exceptions == null || exceptions.isEmpty()) {
throw new IllegalArgumentException("At least one exception must be specified");
}

StringBuilder rv = new StringBuilder();
rv.append("Multiple exceptions (");
rv.append(exceptions.size());
Expand Down
42 changes: 41 additions & 1 deletion src/main/java/net/spy/memcached/internal/CompositeException.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package net.spy.memcached.internal;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
Expand All @@ -10,13 +12,51 @@ public class CompositeException extends ExecutionException {

private static final long serialVersionUID = -599478797582490012L;
private final ArrayList<Exception> exceptions = new ArrayList<>();
private final Throwable cause;

CompositeException(List<Exception> exceptions) {
public CompositeException(List<Exception> exceptions) {
super(ExceptionMessageFactory.createCompositeMessage(exceptions));

if (exceptions.size() > 1) {
StringWriter sw = new StringWriter();
sw.write(System.lineSeparator());
try (PrintWriter pw = new PrintWriter(sw)) {
for (Exception e : exceptions) {
e.printStackTrace(pw);
}
}

this.cause = new ExceptionOverview(sw.toString());
} else {
this.cause = exceptions.get(0);
}
this.exceptions.addAll(exceptions);
}

public List<Exception> getExceptions() {
return exceptions;
}

public int size() {
return exceptions.size();
}

@Override
public synchronized Throwable getCause() {
return cause;
}

static final class ExceptionOverview extends RuntimeException {

private static final long serialVersionUID = -641960514509105302L;

ExceptionOverview(String message) {
super(message);
}

@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
}
}
27 changes: 27 additions & 0 deletions src/test/java/net/spy/memcached/compat/log/LoggingTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@

// XXX: This really needs to get log4j configured first.

import java.util.ArrayList;
import java.util.List;

import net.spy.memcached.internal.CompositeException;
import net.spy.memcached.ops.OperationErrorType;
import net.spy.memcached.ops.OperationException;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

Expand Down Expand Up @@ -154,4 +161,24 @@ void testNoExceptionArg() throws Exception {
assertNull(t);
}

@Test
void logCompositeException() {
List<Exception> exceptions = new ArrayList<>();
exceptions.add(new OperationException(OperationErrorType.SERVER, "msg1"));
exceptions.add(new OperationException(OperationErrorType.CLIENT, "msg2"));
CompositeException exception = new CompositeException(exceptions);

logger.error("failed to get", exception);
}

@Test
void slf4jCompositeException() {
List<Exception> exceptions = new ArrayList<>();
exceptions.add(new OperationException(OperationErrorType.SERVER, "msg1"));
exceptions.add(new OperationException(OperationErrorType.CLIENT, "msg2"));
CompositeException exception = new CompositeException(exceptions);

Log4JLogger log4JLogger = new Log4JLogger(getClass().getName());
log4JLogger.error("failed to get", exception);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package net.spy.memcached.internal;

import java.util.ArrayList;
import java.util.List;

import net.spy.memcached.ops.OperationErrorType;
import net.spy.memcached.ops.OperationException;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertTrue;

class CompositeExceptionTest {

@Test
void printStackTraceOfAllExceptions() {
List<Exception> exceptions = new ArrayList<>();
exceptions.add(new OperationException(OperationErrorType.SERVER, "msg1"));
exceptions.add(new OperationException(OperationErrorType.CLIENT, "msg2"));
Exception e = throwError1();
exceptions.add(e);
CompositeException compositeException = new CompositeException(exceptions);
String message = compositeException.getCause().getMessage();

assertTrue(message
.contains("OperationException: SERVER: msg1"));
assertTrue(message
.contains("OperationException: CLIENT: msg2"));
assertTrue(message
.contains("OperationException: SERVER: msg3"));
assertTrue(message
.contains("at net.spy.memcached.internal.CompositeExceptionTest.throwError2"));
assertTrue(message
.contains("at net.spy.memcached.internal.CompositeExceptionTest.throwError1"));
}

private Exception throwError1() {
return throwError2();
}

private Exception throwError2() {
return new OperationException(OperationErrorType.SERVER, "msg3");
}
}

0 comments on commit 79a854b

Please sign in to comment.