|
18 | 18 |
|
19 | 19 | import static com.google.common.base.MoreObjects.firstNonNull; |
20 | 20 |
|
| 21 | +import com.google.api.gax.core.ApiFuture; |
| 22 | +import com.google.api.gax.core.ApiFutureCallback; |
| 23 | +import com.google.api.gax.core.ApiFutures; |
21 | 24 | import com.google.cloud.MonitoredResource; |
22 | 25 | import com.google.cloud.logging.Logging.WriteOption; |
23 | | -import com.google.api.gax.core.ApiFutures; |
24 | | -import com.google.api.gax.core.ApiFutureCallback; |
25 | 26 | import com.google.common.collect.ImmutableList; |
26 | 27 | import com.google.common.collect.ImmutableMap; |
| 28 | +import com.google.common.util.concurrent.Uninterruptibles; |
27 | 29 | import java.util.ArrayList; |
28 | 30 | import java.util.Collections; |
29 | | -import java.util.LinkedList; |
| 31 | +import java.util.IdentityHashMap; |
30 | 32 | import java.util.List; |
| 33 | +import java.util.Set; |
31 | 34 | import java.util.logging.ErrorManager; |
32 | 35 | import java.util.logging.Filter; |
33 | 36 | import java.util.logging.Formatter; |
@@ -120,6 +123,10 @@ public class LoggingHandler extends Handler { |
120 | 123 | // https://github.com/GoogleCloudPlatform/google-cloud-java/issues/1740 . |
121 | 124 | private final Level baseLevel; |
122 | 125 |
|
| 126 | + private final Object writeLock = new Object(); |
| 127 | + private final Set<ApiFuture<Void>> pendingWrites = |
| 128 | + Collections.newSetFromMap(new IdentityHashMap<ApiFuture<Void>, Boolean>()); |
| 129 | + |
123 | 130 | /** |
124 | 131 | * Creates an handler that publishes messages to Stackdriver Logging. |
125 | 132 | */ |
@@ -376,6 +383,9 @@ public void publish(LogRecord record) { |
376 | 383 | if (entry != null) { |
377 | 384 | write(entry, writeOptions); |
378 | 385 | } |
| 386 | + if (record.getLevel().intValue() >= flushLevel.intValue()) { |
| 387 | + flush(); |
| 388 | + } |
379 | 389 | } finally { |
380 | 390 | inPublishCall.remove(); |
381 | 391 | } |
@@ -457,28 +467,60 @@ void write(LogEntry entry, WriteOption... options) { |
457 | 467 | reportError(null, ex, ErrorManager.FLUSH_FAILURE); |
458 | 468 | } |
459 | 469 | break; |
| 470 | + |
460 | 471 | case ASYNC: |
461 | 472 | default: |
462 | | - ApiFutures.addCallback(getLogging().writeAsync(entryList, options), new ApiFutureCallback<Void>() { |
463 | | - @Override |
464 | | - public void onSuccess(Void v) {} |
465 | | - |
466 | | - @Override |
467 | | - public void onFailure(Throwable t) { |
468 | | - if (t instanceof Exception) { |
469 | | - reportError(null, (Exception) t, ErrorManager.FLUSH_FAILURE); |
470 | | - } else { |
471 | | - reportError(null, new Exception(t), ErrorManager.FLUSH_FAILURE); |
472 | | - } |
473 | | - } |
474 | | - }); |
| 473 | + final ApiFuture<Void> writeFuture = getLogging().writeAsync(entryList, options); |
| 474 | + synchronized(writeLock) { |
| 475 | + pendingWrites.add(writeFuture); |
| 476 | + } |
| 477 | + ApiFutures.addCallback( |
| 478 | + writeFuture, |
| 479 | + new ApiFutureCallback<Void>() { |
| 480 | + private void removeFromPending() { |
| 481 | + synchronized(writeLock) { |
| 482 | + pendingWrites.remove(writeFuture); |
| 483 | + } |
| 484 | + } |
| 485 | + |
| 486 | + @Override |
| 487 | + public void onSuccess(Void v) { |
| 488 | + removeFromPending(); |
| 489 | + } |
| 490 | + |
| 491 | + @Override |
| 492 | + public void onFailure(Throwable t) { |
| 493 | + try { |
| 494 | + if (t instanceof Exception) { |
| 495 | + reportError(null, (Exception) t, ErrorManager.FLUSH_FAILURE); |
| 496 | + } else { |
| 497 | + reportError(null, new Exception(t), ErrorManager.FLUSH_FAILURE); |
| 498 | + } |
| 499 | + } finally { |
| 500 | + removeFromPending(); |
| 501 | + } |
| 502 | + } |
| 503 | + }); |
475 | 504 | break; |
476 | 505 | } |
477 | 506 | } |
478 | 507 |
|
479 | 508 | @Override |
480 | 509 | public void flush() { |
481 | | - // BUG(1795): flush is broken, need support from batching implementation. |
| 510 | + // BUG(1795): We should force batcher to issue RPC call for buffered messages, |
| 511 | + // so the code below doesn't wait uselessly. |
| 512 | + |
| 513 | + ArrayList<ApiFuture<Void>> writesToFlush = new ArrayList<>(); |
| 514 | + synchronized(writeLock) { |
| 515 | + writesToFlush.addAll(pendingWrites); |
| 516 | + } |
| 517 | + for (ApiFuture<Void> write : writesToFlush) { |
| 518 | + try { |
| 519 | + Uninterruptibles.getUninterruptibly(write); |
| 520 | + } catch (Exception e) { |
| 521 | + // Ignore exceptions, they are propagated to the error manager. |
| 522 | + } |
| 523 | + } |
482 | 524 | } |
483 | 525 |
|
484 | 526 | /** |
|
0 commit comments