Skip to content

Commit b01760b

Browse files
committed
leverage the usage of io.opentelemetry.sdk.common.export.RetryPolicy
instead of using individual values Signed-off-by: Hilmar Falkenberg <[email protected]>
1 parent 0f3bc18 commit b01760b

File tree

3 files changed

+55
-107
lines changed

3 files changed

+55
-107
lines changed

sdk/logs/src/main/java/io/opentelemetry/sdk/logs/export/AuditLogRecordProcessor.java

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import io.opentelemetry.context.Context;
99
import io.opentelemetry.sdk.common.CompletableResultCode;
10+
import io.opentelemetry.sdk.common.export.RetryPolicy;
1011
import io.opentelemetry.sdk.logs.LogRecordProcessor;
1112
import io.opentelemetry.sdk.logs.ReadWriteLogRecord;
1213
import io.opentelemetry.sdk.logs.data.LogRecordData;
@@ -77,17 +78,8 @@ public static AuditLogRecordProcessorBuilder builder(
7778
/** The timeout for exporting logs in nanoseconds. */
7879
private final long timeout;
7980

80-
/** Maximum number of retry attempts for failed exports. */
81-
private final int maxRetryAttempts;
82-
83-
/** Initial retry delay in milliseconds. */
84-
private final long initialRetryDelayMillis;
85-
86-
/** Maximum retry delay in milliseconds to cap exponential backoff. */
87-
private final long maxRetryDelayMillis;
88-
89-
/** Retry multiplier for exponential backoff. */
90-
private final double retryMultiplier;
81+
/** The retry policy for handling failed exports. */
82+
private final RetryPolicy retryPolicy;
9183

9284
/** Current retry attempt counter. */
9385
private final AtomicInteger currentRetryAttempt = new AtomicInteger(0);
@@ -107,10 +99,7 @@ public static AuditLogRecordProcessorBuilder builder(
10799
* @param scheduleDelayNanos the delay in nanoseconds between periodic exports.
108100
* @param maxExportBatchSize the maximum number of logs to export in a single batch.
109101
* @param exporterTimeoutNanos the timeout for exporting logs in nanoseconds.
110-
* @param maxRetryAttempts the maximum number of retry attempts for failed exports.
111-
* @param initialRetryDelayMillis the initial retry delay in milliseconds.
112-
* @param maxRetryDelayMillis the maximum retry delay in milliseconds.
113-
* @param retryMultiplier the retry multiplier for exponential backoff.
102+
* @param retryPolicy the retry policy for handling failed exports.
114103
* @param waitOnExport whether to wait for the export to complete.
115104
*/
116105
AuditLogRecordProcessor(
@@ -120,19 +109,13 @@ public static AuditLogRecordProcessorBuilder builder(
120109
long scheduleDelayNanos,
121110
int maxExportBatchSize,
122111
long exporterTimeoutNanos,
123-
int maxRetryAttempts,
124-
long initialRetryDelayMillis,
125-
long maxRetryDelayMillis,
126-
double retryMultiplier,
112+
RetryPolicy retryPolicy,
127113
boolean waitOnExport) {
128114
exporter = logRecordExporter;
129115
size = maxExportBatchSize;
130116
timeout = exporterTimeoutNanos;
131117
handler = exceptionHandler;
132-
this.maxRetryAttempts = maxRetryAttempts;
133-
this.initialRetryDelayMillis = initialRetryDelayMillis;
134-
this.maxRetryDelayMillis = maxRetryDelayMillis;
135-
this.retryMultiplier = retryMultiplier;
118+
this.retryPolicy = retryPolicy;
136119
this.waitOnExport = waitOnExport;
137120
queue =
138121
new PriorityBlockingQueue<>(
@@ -228,7 +211,7 @@ void exportLogs() {
228211
if (all.isDone() && !all.isSuccess()) {
229212
if (waitOnExport) {
230213
// Export failed, prepare for retry if attempts remain
231-
if (currentRetryAttempt.getAndAdd(1) < maxRetryAttempts) {
214+
if (currentRetryAttempt.getAndAdd(1) < retryPolicy.getMaxAttempts()) {
232215
lastRetryTimestamp.set(System.currentTimeMillis());
233216
queue.addAll(allFailedLogs);
234217
try {
@@ -274,10 +257,13 @@ private CompletableResultCode tryExport(Collection<LogRecordData> logs) {
274257
* @return delay in milliseconds
275258
*/
276259
private long calculateRetryDelay(int attemptNumber) {
277-
long delay = (long) (initialRetryDelayMillis * Math.pow(retryMultiplier, attemptNumber - 1));
260+
long delay =
261+
(long)
262+
(retryPolicy.getInitialBackoff().toMillis()
263+
* Math.pow(retryPolicy.getBackoffMultiplier(), attemptNumber - 1));
278264

279265
// Cap the delay to maximum
280-
delay = Math.min(delay, maxRetryDelayMillis);
266+
delay = Math.min(delay, retryPolicy.getMaxBackoff().toMillis());
281267

282268
// Add jitter to prevent thundering herd (±25% random variation)
283269
double jitter = 0.25 * delay * (Math.random() - 0.5);
@@ -298,7 +284,7 @@ private void handleExportFailure(
298284
handler.handle(new AuditException("Export failed", cause, failedLogs));
299285
return;
300286
}
301-
if (currentRetryAttempt.get() < maxRetryAttempts) {
287+
if (currentRetryAttempt.get() < retryPolicy.getMaxAttempts()) {
302288
// If retries haven't been exhausted, the retry logic will handle the next attempt
303289
return;
304290
}
@@ -311,7 +297,7 @@ private void handleExportFailure(
311297
String.format(
312298
Locale.ENGLISH,
313299
"Export failed after %d retry attempts. Last error: %s",
314-
maxRetryAttempts,
300+
retryPolicy.getMaxAttempts(),
315301
cause != null ? cause.getMessage() : "Unknown error");
316302

317303
if (handler != null) {
@@ -425,6 +411,8 @@ public String toString() {
425411
builder.append(size);
426412
builder.append(", timeout=");
427413
builder.append(timeout);
414+
builder.append(", retryPolicy=");
415+
builder.append(retryPolicy);
428416
builder.append(", persistency=");
429417
builder.append(persistency);
430418
builder.append("]");

sdk/logs/src/main/java/io/opentelemetry/sdk/logs/export/AuditLogRecordProcessorBuilder.java

Lines changed: 14 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@
88
import static io.opentelemetry.api.internal.Utils.checkArgument;
99
import static java.util.Objects.requireNonNull;
1010

11+
import io.opentelemetry.sdk.common.export.RetryPolicy;
1112
import java.util.concurrent.TimeUnit;
1213
import javax.annotation.Nonnull;
1314
import javax.annotation.Nullable;
1415

1516
/**
16-
* Builder class for {@link BatchLogRecordProcessor}.
17+
* Builder class for {@link AuditLogRecordProcessor}.
1718
*
1819
* @since 1.27.0
1920
*/
@@ -22,35 +23,21 @@ public final class AuditLogRecordProcessorBuilder {
2223
// Visible for testing
2324
public static final int DEFAULT_EXPORT_TIMEOUT_MILLIS = 30_000;
2425
// Visible for testing
25-
public static final long DEFAULT_INITIAL_RETRY_DELAY_MILLIS = 1000;
26-
// Visible for testing
2726
public static final int DEFAULT_MAX_EXPORT_BATCH_SIZE = 512;
2827
// Visible for testing
29-
public static final int DEFAULT_MAX_RETRY_ATTEMPTS = 3;
30-
// Visible for testing
31-
public static final long DEFAULT_MAX_RETRY_DELAY_MILLIS = 30_000;
32-
// Visible for testing
33-
public static final double DEFAULT_RETRY_MULTIPLIER = 2.0;
34-
// Visible for testing
3528
public static final long DEFAULT_SCHEDULE_DELAY_MILLIS = 1000;
3629

3730
@Nullable private AuditExceptionHandler exceptionHandler;
3831

3932
private long exporterTimeoutNanos = TimeUnit.MILLISECONDS.toNanos(DEFAULT_EXPORT_TIMEOUT_MILLIS);
4033

41-
private long initialRetryDelayMillis = DEFAULT_INITIAL_RETRY_DELAY_MILLIS;
42-
4334
@Nonnull private final LogRecordExporter logRecordExporter;
4435

4536
@Nonnull private final AuditLogStore logStore;
4637

4738
private int maxExportBatchSize = DEFAULT_MAX_EXPORT_BATCH_SIZE;
4839

49-
private int maxRetryAttempts = DEFAULT_MAX_RETRY_ATTEMPTS;
50-
51-
private long maxRetryDelayMillis = DEFAULT_MAX_RETRY_DELAY_MILLIS;
52-
53-
private double retryMultiplier = DEFAULT_RETRY_MULTIPLIER;
40+
private RetryPolicy retryPolicy = RetryPolicy.getDefault();
5441

5542
private long scheduleDelayNanos = TimeUnit.MILLISECONDS.toNanos(DEFAULT_SCHEDULE_DELAY_MILLIS);
5643

@@ -76,10 +63,7 @@ public AuditLogRecordProcessor build() {
7663
scheduleDelayNanos,
7764
maxExportBatchSize,
7865
exporterTimeoutNanos,
79-
maxRetryAttempts,
80-
initialRetryDelayMillis,
81-
maxRetryDelayMillis,
82-
retryMultiplier,
66+
retryPolicy,
8367
waitOnExport);
8468
}
8569

@@ -93,11 +77,6 @@ long getExporterTimeoutNanos() {
9377
return exporterTimeoutNanos;
9478
}
9579

96-
// Visible for testing
97-
long getInitialRetryDelayMillis() {
98-
return initialRetryDelayMillis;
99-
}
100-
10180
AuditLogStore getLogStore() {
10281
return logStore;
10382
}
@@ -108,18 +87,8 @@ int getMaxExportBatchSize() {
10887
}
10988

11089
// Visible for testing
111-
int getMaxRetryAttempts() {
112-
return maxRetryAttempts;
113-
}
114-
115-
// Visible for testing
116-
long getMaxRetryDelayMillis() {
117-
return maxRetryDelayMillis;
118-
}
119-
120-
// Visible for testing
121-
double getRetryMultiplier() {
122-
return retryMultiplier;
90+
RetryPolicy getRetryPolicy() {
91+
return retryPolicy;
12392
}
12493

12594
// Visible for testing
@@ -149,18 +118,6 @@ public AuditLogRecordProcessorBuilder setExporterTimeout(long timeout, @Nonnull
149118
return this;
150119
}
151120

152-
/**
153-
* Sets the initial delay in milliseconds before the first retry attempt. If unset, defaults to
154-
* {@value DEFAULT_INITIAL_RETRY_DELAY_MILLIS}ms.
155-
*/
156-
public AuditLogRecordProcessorBuilder setInitialRetryDelay(
157-
long initialRetryDelay, TimeUnit unit) {
158-
requireNonNull(unit, "unit");
159-
checkArgument(initialRetryDelay >= 0, "initialRetryDelay must be non-negative");
160-
this.initialRetryDelayMillis = unit.toMillis(initialRetryDelay);
161-
return this;
162-
}
163-
164121
/**
165122
* Sets the maximum batch size for every export. This must be smaller or equal to {@code
166123
* maxQueueSize}.
@@ -178,33 +135,15 @@ public AuditLogRecordProcessorBuilder setMaxExportBatchSize(int maxExportBatchSi
178135
}
179136

180137
/**
181-
* Sets the maximum number of retry attempts for failed exports. If unset, defaults to {@value
182-
* DEFAULT_MAX_RETRY_ATTEMPTS}.
183-
*/
184-
public AuditLogRecordProcessorBuilder setMaxRetryAttempts(int maxRetryAttempts) {
185-
checkArgument(maxRetryAttempts >= 0, "maxRetryAttempts must be non-negative.");
186-
this.maxRetryAttempts = maxRetryAttempts;
187-
return this;
188-
}
189-
190-
/**
191-
* Sets the maximum delay in milliseconds between retry attempts. If unset, defaults to {@value
192-
* DEFAULT_MAX_RETRY_DELAY_MILLIS}ms.
193-
*/
194-
public AuditLogRecordProcessorBuilder setMaxRetryDelay(long maxRetryDelay, TimeUnit unit) {
195-
requireNonNull(unit, "unit");
196-
checkArgument(maxRetryDelay >= 0, "maxRetryDelay must be non-negative");
197-
this.maxRetryDelayMillis = unit.toMillis(maxRetryDelay);
198-
return this;
199-
}
200-
201-
/**
202-
* Sets the multiplier for increasing the retry delay after each failed attempt. If unset,
203-
* defaults to {@value DEFAULT_RETRY_MULTIPLIER}.
138+
* Sets the retry policy for failed exports. If unset, defaults to {@link
139+
* RetryPolicy#getDefault()}.
140+
*
141+
* @param retryPolicy the retry policy to use for failed exports
142+
* @return this
204143
*/
205-
public AuditLogRecordProcessorBuilder setRetryMultiplier(double retryMultiplier) {
206-
checkArgument(retryMultiplier > 1.0, "retryMultiplier must be greater than 1.0");
207-
this.retryMultiplier = retryMultiplier;
144+
public AuditLogRecordProcessorBuilder setRetryPolicy(@Nonnull RetryPolicy retryPolicy) {
145+
requireNonNull(retryPolicy, "retryPolicy");
146+
this.retryPolicy = retryPolicy;
208147
return this;
209148
}
210149

sdk/logs/src/test/java/io/opentelemetry/sdk/logs/export/AuditLogRecordProcessorTest.java

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919

2020
import io.opentelemetry.internal.testing.slf4j.SuppressLogger;
2121
import io.opentelemetry.sdk.common.CompletableResultCode;
22+
import io.opentelemetry.sdk.common.export.RetryPolicy;
2223
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
2324
import io.opentelemetry.sdk.logs.data.LogRecordData;
2425
import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessorTest.CompletableLogRecordExporter;
2526
import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessorTest.WaitingLogRecordExporter;
2627
import java.io.IOException;
28+
import java.time.Duration;
2729
import java.util.ArrayList;
2830
import java.util.Arrays;
2931
import java.util.Collection;
@@ -87,6 +89,7 @@ void builderDefaults() {
8789
.isEqualTo(
8890
TimeUnit.MILLISECONDS.toNanos(
8991
AuditLogRecordProcessorBuilder.DEFAULT_EXPORT_TIMEOUT_MILLIS));
92+
assertThat(builder.getRetryPolicy()).isEqualTo(RetryPolicy.getDefault());
9093
}
9194

9295
@Test
@@ -121,6 +124,12 @@ void builderInvalidConfig() {
121124
.setMaxExportBatchSize(0))
122125
.isInstanceOf(IllegalArgumentException.class)
123126
.hasMessage("maxExportBatchSize must be positive.");
127+
assertThatThrownBy(
128+
() ->
129+
AuditLogRecordProcessor.builder(mockLogRecordExporter, mockLogStore)
130+
.setRetryPolicy(null))
131+
.isInstanceOf(NullPointerException.class)
132+
.hasMessage("retryPolicy");
124133
}
125134

126135
private void emitLog(SdkLoggerProvider sdkLoggerProvider, String message) {
@@ -335,14 +344,20 @@ void testRetry() throws Exception {
335344
assertThat(exception.logRecords).isNotEmpty();
336345
};
337346

347+
RetryPolicy retryPolicy =
348+
RetryPolicy.builder()
349+
.setMaxAttempts(3)
350+
.setInitialBackoff(Duration.ofMillis(1))
351+
.setMaxBackoff(Duration.ofMillis(1))
352+
.build();
353+
338354
AuditLogRecordProcessor processor =
339355
AuditLogRecordProcessor.builder(mockLogRecordExporter, logStore)
340356
.setScheduleDelay(MAX_SCHEDULE_DELAY_MILLIS, TimeUnit.MILLISECONDS)
341357
.setExceptionHandler(exceptionHandler)
342358
.setWaitOnExport(true) // enable waiting on export to ensure retries are attempted
343359
.setMaxExportBatchSize(1) // ensure each log is exported individually
344-
.setMaxRetryAttempts(3) // set max retry attempts
345-
.setMaxRetryDelay(1, TimeUnit.MILLISECONDS) // set retry delay
360+
.setRetryPolicy(retryPolicy)
346361
.build();
347362
SdkLoggerProvider sdkLoggerProvider =
348363
SdkLoggerProvider.builder().addLogRecordProcessor(processor).build();
@@ -372,14 +387,20 @@ void testRetryFails() throws Exception {
372387
assertThat(exception.logRecords).isNotEmpty();
373388
};
374389

390+
RetryPolicy retryPolicy =
391+
RetryPolicy.builder()
392+
.setMaxAttempts(2) // Only 1 retry attempt (2 total attempts)
393+
.setInitialBackoff(Duration.ofMillis(1))
394+
.setMaxBackoff(Duration.ofMillis(1))
395+
.build();
396+
375397
AuditLogRecordProcessor processor =
376398
AuditLogRecordProcessor.builder(mockLogRecordExporter, logStore)
377399
.setScheduleDelay(MAX_SCHEDULE_DELAY_MILLIS, TimeUnit.MILLISECONDS)
378400
.setExceptionHandler(exceptionHandler)
379401
.setWaitOnExport(true) // enable waiting on export to ensure retries are attempted
380402
.setMaxExportBatchSize(1) // ensure each log is exported individually
381-
.setMaxRetryAttempts(1) // set max retry attempts
382-
.setMaxRetryDelay(1, TimeUnit.MILLISECONDS)
403+
.setRetryPolicy(retryPolicy)
383404
.build();
384405
SdkLoggerProvider sdkLoggerProvider =
385406
SdkLoggerProvider.builder().addLogRecordProcessor(processor).build();

0 commit comments

Comments
 (0)