Skip to content

Commit 4886b75

Browse files
authored
feat: setter for Log of RetryTemplate (#471)
GH-470: Add `RetryTemplate.setLogger()` to avoid reflection in other places Fixes: #470 Issue link: #470 Spring Cloud Config does mutation in the `RetryTemplate` for its system loading logger via `RetryTemplateFactory`. * Expose setter for `logger` property to avoid reflection. * Add `RetryTemplateBuilder.withLogger()` for convenience
1 parent a34a627 commit 4886b75

File tree

4 files changed

+75
-3
lines changed

4 files changed

+75
-3
lines changed

src/main/java/org/springframework/retry/support/RetryTemplate.java

+14-1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
* @author Josh Long
7979
* @author Aleksandr Shamukov
8080
* @author Emanuele Ivaldi
81+
* @author Tobias Soloschenko
8182
*/
8283
public class RetryTemplate implements RetryOperations {
8384

@@ -87,7 +88,7 @@ public class RetryTemplate implements RetryOperations {
8788
*/
8889
private static final String GLOBAL_STATE = "state.global";
8990

90-
protected final Log logger = LogFactory.getLog(getClass());
91+
protected Log logger = LogFactory.getLog(getClass());
9192

9293
private volatile BackOffPolicy backOffPolicy = new NoBackOffPolicy();
9394

@@ -186,6 +187,18 @@ public boolean hasListeners() {
186187
return this.listeners.length > 0;
187188
}
188189

190+
/**
191+
* Setter for {@link Log}. If not applied the following is used:
192+
* <p>
193+
* {@code LogFactory.getLog(getClass())}
194+
* </p>
195+
* @param logger the logger the retry template uses for logging
196+
* @since 2.0.10
197+
*/
198+
public void setLogger(Log logger) {
199+
this.logger = logger;
200+
}
201+
189202
/**
190203
* Setter for {@link BackOffPolicy}.
191204
* @param backOffPolicy the {@link BackOffPolicy}

src/main/java/org/springframework/retry/support/RetryTemplateBuilder.java

+27
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.List;
2222
import java.util.function.Predicate;
2323

24+
import org.apache.commons.logging.Log;
2425
import org.springframework.classify.BinaryExceptionClassifier;
2526
import org.springframework.classify.BinaryExceptionClassifierBuilder;
2627
import org.springframework.retry.RetryListener;
@@ -79,12 +80,15 @@
7980
* @author Kim In Hoi
8081
* @author Andreas Ahlenstorf
8182
* @author Morulai Planinski
83+
* @author Tobias Soloschenko
8284
* @since 1.3
8385
*/
8486
public class RetryTemplateBuilder {
8587

8688
private RetryPolicy baseRetryPolicy;
8789

90+
private Log logger;
91+
8892
private BackOffPolicy backOffPolicy;
8993

9094
private List<RetryListener> listeners;
@@ -288,6 +292,23 @@ public RetryTemplateBuilder exponentialBackoff(Duration initialInterval, double
288292
return this.exponentialBackoff(initialInterval.toMillis(), multiplier, maxInterval.toMillis(), withRandom);
289293
}
290294

295+
/**
296+
* Applies a dedicated logger to the {@link RetryTemplate}. If not applied the
297+
* following is used:
298+
* <p>
299+
* {@code LogFactory.getLog(getClass())}
300+
* </p>
301+
* @param logger the logger which should be used for logging
302+
* @return this
303+
* @since 2.0.10
304+
*/
305+
public RetryTemplateBuilder withLogger(Log logger) {
306+
Assert.isNull(this.logger, "You have already applied a logger");
307+
Assert.notNull(logger, "The given logger should not be null");
308+
this.logger = logger;
309+
return this;
310+
}
311+
291312
/**
292313
* Perform each retry after a fixed amount of time.
293314
* @param interval fixed interval in milliseconds
@@ -584,6 +605,12 @@ public RetryTemplate build() {
584605
finalPolicy.setPolicies(new RetryPolicy[] { this.baseRetryPolicy, exceptionRetryPolicy });
585606
retryTemplate.setRetryPolicy(finalPolicy);
586607

608+
// Logger
609+
610+
if (this.logger != null) {
611+
retryTemplate.setLogger(this.logger);
612+
}
613+
587614
// Backoff policy
588615

589616
if (this.backOffPolicy == null) {

src/test/java/org/springframework/retry/support/RetryTemplateBuilderTests.java

+17
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.List;
2525
import java.util.function.Predicate;
2626

27+
import org.apache.commons.logging.Log;
2728
import org.junit.jupiter.api.Test;
2829
import org.springframework.classify.BinaryExceptionClassifier;
2930
import org.springframework.retry.RetryListener;
@@ -58,6 +59,7 @@
5859
* @author Gary Russell
5960
* @author Andreas Ahlenstorf
6061
* @author Morulai Planinski
62+
* @author Tobias Soloschenko
6163
*/
6264
public class RetryTemplateBuilderTests {
6365

@@ -346,6 +348,21 @@ public void testValidateZeroInitInterval() {
346348
.isThrownBy(() -> RetryTemplate.builder().exponentialBackoff(0, 2, 200).build());
347349
}
348350

351+
@Test
352+
public void testBuilderWithLogger() {
353+
Log logMock = mock(Log.class);
354+
RetryTemplate retryTemplate = RetryTemplate.builder().withLogger(logMock).build();
355+
Log logger = getPropertyValue(retryTemplate, "logger", Log.class);
356+
assertThat(logger).isEqualTo(logMock);
357+
}
358+
359+
@Test
360+
public void testBuilderWithDefaultLogger() {
361+
RetryTemplate retryTemplate = RetryTemplate.builder().build();
362+
Log logger = getPropertyValue(retryTemplate, "logger", Log.class);
363+
assertThat(logger).isNotNull();
364+
}
365+
349366
/* ---------------- Utils -------------- */
350367

351368
private static class PolicyTuple {

src/test/java/org/springframework/retry/support/RetryTemplateTests.java

+17-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
import java.util.concurrent.atomic.AtomicBoolean;
2121
import java.util.concurrent.atomic.AtomicInteger;
2222

23+
import org.apache.commons.logging.Log;
2324
import org.junit.jupiter.api.Test;
2425

26+
import org.mockito.ArgumentCaptor;
2527
import org.springframework.classify.BinaryExceptionClassifier;
2628
import org.springframework.retry.RetryCallback;
2729
import org.springframework.retry.RetryContext;
@@ -45,6 +47,7 @@
4547
import static org.mockito.BDDMockito.given;
4648
import static org.mockito.Mockito.mock;
4749
import static org.mockito.Mockito.verify;
50+
import static org.mockito.Mockito.when;
4851

4952
/**
5053
* @author Rob Harrop
@@ -53,6 +56,7 @@
5356
* @author Henning Pöttker
5457
* @author Emanuele Ivaldi
5558
* @author Morulai Planinski
59+
* @author Tobias Soloschenko
5660
*/
5761
public class RetryTemplateTests {
5862

@@ -286,7 +290,6 @@ public void testRethrowError() {
286290
}
287291
}
288292

289-
@SuppressWarnings("serial")
290293
@Test
291294
public void testFailedPolicy() {
292295
RetryTemplate retryTemplate = new RetryTemplate();
@@ -325,7 +328,6 @@ public void testNoBackOffForRethrownException() {
325328
tested.setRetryPolicy(new SimpleRetryPolicy(1));
326329

327330
BackOffPolicy bop = mock(BackOffPolicy.class);
328-
@SuppressWarnings("serial")
329331
BackOffContext backOffContext = new BackOffContext() {
330332
};
331333
tested.setBackOffPolicy(bop);
@@ -439,4 +441,17 @@ public void backOff(BackOffContext backOffContext) throws BackOffInterruptedExce
439441

440442
}
441443

444+
@Test
445+
public void testLoggingAppliedCorrectly() throws Exception {
446+
ArgumentCaptor<String> logOutputCaptor = ArgumentCaptor.forClass(String.class);
447+
RetryTemplate retryTemplate = new RetryTemplate();
448+
Log logMock = mock(Log.class);
449+
when(logMock.isTraceEnabled()).thenReturn(false);
450+
when(logMock.isDebugEnabled()).thenReturn(true);
451+
retryTemplate.setLogger(logMock);
452+
retryTemplate.execute(new MockRetryCallback());
453+
verify(logMock).debug(logOutputCaptor.capture());
454+
assertThat(logOutputCaptor.getValue()).contains("Retry: count=0");
455+
}
456+
442457
}

0 commit comments

Comments
 (0)