diff --git a/google-cloud-clients/google-cloud-logging/src/main/java/com/google/cloud/logging/Logging.java b/google-cloud-clients/google-cloud-logging/src/main/java/com/google/cloud/logging/Logging.java index e8b39e3e06ec..c262fdedae26 100644 --- a/google-cloud-clients/google-cloud-logging/src/main/java/com/google/cloud/logging/Logging.java +++ b/google-cloud-clients/google-cloud-logging/src/main/java/com/google/cloud/logging/Logging.java @@ -186,8 +186,15 @@ public static EntryListOption filter(String filter) { Synchronicity getWriteSynchronicity(); /** - * Sets flush severity for asynchronous logging writes. Default is ERROR. Logs will be immediately - * written out for entries at or higher than flush severity. + * Sets flush severity for asynchronous logging writes. It is disabled by default, enabled when + * this method is called with not null value. Logs will be immediately written out for entries at + * or higher than flush severity. + * + *

Enabling this can cause the leaking and hanging threads, see BUG(2796) BUG(3880). However + * you can explicitly call {@link #flush}. + * + *

TODO: Enable this by default once functionality to trigger rpc is available in generated + * code. */ void setFlushSeverity(Severity flushSeverity); @@ -664,8 +671,8 @@ ApiFuture> listMonitoredResourceDescripto /** * Flushes any pending asynchronous logging writes. Logs are automatically flushed based on time * and message count that be configured via {@link com.google.api.gax.batching.BatchingSettings}, - * Logs are also flushed if at or above flush severity, see {@link #setFlushSeverity}. Logging - * frameworks require support for an explicit flush. See usage in the java.util.logging + * Logs are also flushed if enabled, at or above flush severity, see {@link #setFlushSeverity}. + * Logging frameworks require support for an explicit flush. See usage in the java.util.logging * handler{@link LoggingHandler}. */ void flush(); diff --git a/google-cloud-clients/google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingImpl.java b/google-cloud-clients/google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingImpl.java index 07bb2cd70e69..7c572af069b5 100644 --- a/google-cloud-clients/google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingImpl.java +++ b/google-cloud-clients/google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingImpl.java @@ -75,16 +75,19 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; class LoggingImpl extends BaseService implements Logging { + private static final int FLUSH_WAIT_TIMEOUT_SECONDS = 6; private final LoggingRpc rpc; private final Object writeLock = new Object(); private final Set> pendingWrites = Collections.newSetFromMap(new IdentityHashMap, Boolean>()); private volatile Synchronicity writeSynchronicity = Synchronicity.ASYNC; - private volatile Severity flushSeverity = Severity.ERROR; + private volatile Severity flushSeverity = null; private boolean closed; private static final Function EMPTY_TO_BOOLEAN_FUNCTION = @@ -553,11 +556,13 @@ public void write(Iterable logEntries, WriteOption... options) { try { writeLogEntries(logEntries, options); - for (LogEntry logEntry : logEntries) { - // flush pending writes if log severity at or above flush severity - if (logEntry.getSeverity().compareTo(flushSeverity) >= 0) { - flush(); - break; + if (flushSeverity != null) { + for (LogEntry logEntry : logEntries) { + // flush pending writes if log severity at or above flush severity + if (logEntry.getSeverity().compareTo(flushSeverity) >= 0) { + flush(); + break; + } } } } finally { @@ -574,8 +579,8 @@ public void flush() { } try { - ApiFutures.allAsList(writesToFlush).get(); - } catch (InterruptedException | ExecutionException e) { + ApiFutures.allAsList(writesToFlush).get(FLUSH_WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS); + } catch (InterruptedException | ExecutionException | TimeoutException e) { throw new RuntimeException(e); } } diff --git a/google-cloud-clients/google-cloud-logging/src/test/java/com/google/cloud/logging/BaseSystemTest.java b/google-cloud-clients/google-cloud-logging/src/test/java/com/google/cloud/logging/BaseSystemTest.java index 4360d6724ab5..d3f53cdd3bdf 100644 --- a/google-cloud-clients/google-cloud-logging/src/test/java/com/google/cloud/logging/BaseSystemTest.java +++ b/google-cloud-clients/google-cloud-logging/src/test/java/com/google/cloud/logging/BaseSystemTest.java @@ -229,6 +229,7 @@ public void testWriteAndListLogEntries() throws InterruptedException { .build(); logging().write(ImmutableList.of(firstEntry)); logging().write(ImmutableList.of(secondEntry)); + logging().flush(); String filter = createEqualityFilter("logName", logName); EntryListOption[] options = {EntryListOption.filter(filter), EntryListOption.pageSize(1)}; Page page = logging().listLogEntries(options); diff --git a/google-cloud-clients/google-cloud-logging/src/test/java/com/google/cloud/logging/LoggingImplTest.java b/google-cloud-clients/google-cloud-logging/src/test/java/com/google/cloud/logging/LoggingImplTest.java index fd1335486226..7c711cd44a78 100644 --- a/google-cloud-clients/google-cloud-logging/src/test/java/com/google/cloud/logging/LoggingImplTest.java +++ b/google-cloud-clients/google-cloud-logging/src/test/java/com/google/cloud/logging/LoggingImplTest.java @@ -1188,6 +1188,41 @@ public void testWriteLogEntries() { logging.write(ImmutableList.of(LOG_ENTRY1, LOG_ENTRY2)); } + @Test + public void testWriteLogEntriesDoesnotEnableFlushByDefault() { + WriteLogEntriesRequest request = + WriteLogEntriesRequest.newBuilder() + .addAllEntries( + Iterables.transform( + ImmutableList.of( + LOG_ENTRY1, LOG_ENTRY2.toBuilder().setSeverity(Severity.EMERGENCY).build()), + LogEntry.toPbFunction(PROJECT))) + .build(); + ApiFuture apiFuture = SettableApiFuture.create(); + EasyMock.expect(loggingRpcMock.write(request)).andReturn(apiFuture); + EasyMock.replay(rpcFactoryMock, loggingRpcMock); + logging = options.getService(); + logging.write( + ImmutableList.of( + LOG_ENTRY1, LOG_ENTRY2.toBuilder().setSeverity(Severity.EMERGENCY).build())); + } + + @Test + public void testWriteLogEntriesWithSeverityFlushEnabled() { + WriteLogEntriesRequest request = + WriteLogEntriesRequest.newBuilder() + .addAllEntries( + Iterables.transform( + ImmutableList.of(LOG_ENTRY1, LOG_ENTRY2), LogEntry.toPbFunction(PROJECT))) + .build(); + WriteLogEntriesResponse response = WriteLogEntriesResponse.newBuilder().build(); + EasyMock.expect(loggingRpcMock.write(request)).andReturn(ApiFutures.immediateFuture(response)); + EasyMock.replay(rpcFactoryMock, loggingRpcMock); + logging = options.getService(); + logging.setFlushSeverity(Severity.DEFAULT); + logging.write(ImmutableList.of(LOG_ENTRY1, LOG_ENTRY2)); + } + @Test public void testWriteLogEntriesWithOptions() { Map labels = ImmutableMap.of("key", "value");