-
Notifications
You must be signed in to change notification settings - Fork 848
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
BatchSpanProcessor that uses provided ScheduledExecutorService #3036
Changes from 1 commit
f8eb30a
6b6060a
f974774
50143a3
53d49f0
2ffa3ba
61eeec1
036c03f
16a1e35
02a951e
25d58ee
fdcc455
e46a194
2a9fa7e
3bdd671
34d32c6
92c63fa
3850782
40a217f
39a4aff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ | |
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.sdk.extension.trace.export; | ||
package io.opentelemetry.sdk.extension.incubator.trace; | ||
|
||
import io.opentelemetry.context.Context; | ||
import io.opentelemetry.sdk.common.CompletableResultCode; | ||
|
@@ -12,14 +12,16 @@ | |
import io.opentelemetry.sdk.trace.SpanProcessor; | ||
import io.opentelemetry.sdk.trace.data.SpanData; | ||
import io.opentelemetry.sdk.trace.export.SpanExporter; | ||
import io.opentelemetry.sdk.trace.export.Worker; | ||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.List; | ||
import java.util.concurrent.ArrayBlockingQueue; | ||
import java.util.concurrent.BlockingQueue; | ||
import java.util.concurrent.ScheduledExecutorService; | ||
import java.util.concurrent.ScheduledFuture; | ||
import java.util.concurrent.TimeUnit; | ||
import java.util.concurrent.atomic.AtomicBoolean; | ||
import java.util.concurrent.atomic.AtomicLong; | ||
|
||
public class ExecutorServiceSpanProcessor implements SpanProcessor { | ||
|
||
|
@@ -114,4 +116,72 @@ public CompletableResultCode forceFlush() { | |
List<SpanData> getBatch() { | ||
return new ArrayList<>(worker.getBatch()); | ||
} | ||
|
||
private static class Worker extends WorkerBase { | ||
|
||
private final AtomicLong nextExportTime = new AtomicLong(); | ||
|
||
private final ArrayBlockingQueue<SpanData> batch; | ||
|
||
private Worker( | ||
SpanExporter spanExporter, | ||
long scheduleDelayNanos, | ||
int maxExportBatchSize, | ||
long exporterTimeoutNanos, | ||
BlockingQueue<ReadableSpan> queue, | ||
String spanProcessorTypeLabel, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a good reason to have these part of the constructor? Aren't they always the same? I'd rather just have them be constants, probably in the enclosing class. |
||
String spanProcessorTypeValue) { | ||
super( | ||
spanExporter, | ||
scheduleDelayNanos, | ||
maxExportBatchSize, | ||
exporterTimeoutNanos, | ||
queue, | ||
spanProcessorTypeLabel, | ||
spanProcessorTypeValue); | ||
|
||
this.batch = new ArrayBlockingQueue<>(maxExportBatchSize); | ||
updateNextExportTime(); | ||
} | ||
|
||
private void updateNextExportTime() { | ||
nextExportTime.set(System.nanoTime() + scheduleDelayNanos); | ||
} | ||
|
||
@Override | ||
public void run() { | ||
// nextExportTime is set for the first time in the constructor | ||
|
||
continueWork.set(true); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this need to be an atomic field? It seems that a local boolean variable would work just as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Oberon00 I don't know what would happen if the next run of the worker There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But it looks like the boolean is never used outside this method, except in shutdown, and there it seems to change nothing as you already check isShutdown too. But I may have misread the logic. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The question is: If There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Oberon00 you are correct. I've converted |
||
while (continueWork.get()) { | ||
if (flushRequested.get() != null) { | ||
flush(); | ||
} | ||
|
||
try { | ||
ReadableSpan lastElement = queue.peek(); | ||
if (lastElement != null) { | ||
batch.add(lastElement.toSpanData()); | ||
// drain queue | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this comment doesn't seem accurate. You're not draining the queue, you're just removing the element you just There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll try to plug in jctools queue. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. all tests pass 👍 |
||
queue.take(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rather than There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't want the thread to be blocked when the queue is empty. With |
||
} else { | ||
continueWork.set(false); | ||
} | ||
} catch (InterruptedException e) { | ||
Thread.currentThread().interrupt(); | ||
return; | ||
} | ||
|
||
if (batch.size() >= maxExportBatchSize || System.nanoTime() >= nextExportTime.get()) { | ||
exportCurrentBatch(); | ||
updateNextExportTime(); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public Collection<SpanData> getBatch() { | ||
return batch; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we want to leave
metrics
as an implementation detail for now, like we have in the core sdk trace module.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍