2020import java .util .Queue ;
2121import java .util .concurrent .ArrayBlockingQueue ;
2222import java .util .concurrent .BlockingQueue ;
23- import java .util .concurrent .TimeUnit ;
23+ import java .util .concurrent .Semaphore ; import java . util . concurrent . TimeUnit ;
2424import java .util .concurrent .atomic .AtomicBoolean ;
2525import java .util .concurrent .atomic .AtomicInteger ;
2626import java .util .concurrent .atomic .AtomicReference ;
@@ -68,6 +68,7 @@ public static BatchLogRecordProcessorBuilder builder(LogRecordExporter logRecord
6868 long scheduleDelayNanos ,
6969 int maxQueueSize ,
7070 int maxExportBatchSize ,
71+ int maxConcurrentExports ,
7172 long exporterTimeoutNanos ) {
7273 this .worker =
7374 new Worker (
@@ -76,6 +77,7 @@ public static BatchLogRecordProcessorBuilder builder(LogRecordExporter logRecord
7677 telemetryVersion ,
7778 scheduleDelayNanos ,
7879 maxExportBatchSize ,
80+ maxConcurrentExports ,
7981 exporterTimeoutNanos ,
8082 new ArrayBlockingQueue <>(maxQueueSize ),
8183 maxQueueSize ); // TODO: use JcTools.newFixedSizeQueue(..)
@@ -161,13 +163,15 @@ private static final class Worker implements Runnable {
161163 private volatile boolean continueWork = true ;
162164 private final ArrayList <LogRecordData > batch ;
163165 private final long maxQueueSize ;
166+ private final Semaphore concurrencyLimiter ;
164167
165168 private Worker (
166169 LogRecordExporter logRecordExporter ,
167170 Supplier <MeterProvider > meterProvider ,
168171 InternalTelemetryVersion telemetryVersion ,
169172 long scheduleDelayNanos ,
170173 int maxExportBatchSize ,
174+ int maxConcurrentExports ,
171175 long exporterTimeoutNanos ,
172176 Queue <ReadWriteLogRecord > queue ,
173177 long maxQueueSize ) {
@@ -180,6 +184,7 @@ private Worker(
180184 logProcessorInstrumentation =
181185 LogRecordProcessorInstrumentation .get (telemetryVersion , COMPONENT_ID , meterProvider );
182186 this .maxQueueSize = maxQueueSize ;
187+ this .concurrencyLimiter = new Semaphore (maxConcurrentExports - 1 , true );
183188
184189 this .batch = new ArrayList <>(this .maxExportBatchSize );
185190 }
@@ -234,10 +239,10 @@ private void flush() {
234239 batch .add (logRecord .toLogRecordData ());
235240 logsToFlush --;
236241 if (batch .size () >= maxExportBatchSize ) {
237- exportCurrentBatch ();
242+ exportCurrentBatchSync ();
238243 }
239244 }
240- exportCurrentBatch ();
245+ exportCurrentBatchSync ();
241246 CompletableResultCode flushResult = flushRequested .get ();
242247 if (flushResult != null ) {
243248 flushResult .succeed ();
@@ -284,6 +289,15 @@ private CompletableResultCode forceFlush() {
284289 }
285290
286291 private void exportCurrentBatch () {
292+ if (!concurrencyLimiter .tryAcquire ()) {
293+ exportCurrentBatchSync ();
294+ return ;
295+ }
296+
297+ exportCurrentBatchAsync ();
298+ }
299+
300+ private void exportCurrentBatchSync () {
287301 if (batch .isEmpty ()) {
288302 return ;
289303 }
@@ -309,5 +323,29 @@ private void exportCurrentBatch() {
309323 batch .clear ();
310324 }
311325 }
326+
327+ private void exportCurrentBatchAsync () {
328+ if (batch .isEmpty ()) {
329+ return ;
330+ }
331+
332+ List <LogRecordData > batchCopy = new ArrayList <>(batch );
333+ batch .clear ();
334+
335+ CompletableResultCode result = logRecordExporter .export (Collections .unmodifiableList (batchCopy ));
336+ result .whenComplete (() -> {
337+ String error = null ;
338+ if (!result .isSuccess ()) {
339+ logger .log (Level .FINE , "Exporter failed" );
340+ if (result .getFailureThrowable () != null ) {
341+ error = result .getFailureThrowable ().getClass ().getName ();
342+ } else {
343+ error = "export_failed" ;
344+ }
345+ }
346+ logProcessorInstrumentation .finishLogs (batchCopy .size (), error );
347+ concurrencyLimiter .release ();
348+ });
349+ }
312350 }
313351}
0 commit comments