diff --git a/google-cloud-logging/clirr-ignored-differences.xml b/google-cloud-logging/clirr-ignored-differences.xml new file mode 100644 index 000000000..cdd6886af --- /dev/null +++ b/google-cloud-logging/clirr-ignored-differences.xml @@ -0,0 +1,17 @@ + + + + + + + 7012 + com/google/cloud/logging/Logging + * listLogs*(com.google.cloud.logging.Logging$ListOption[]) + + + + 7012 + com/google/cloud/logging/spi/v2/LoggingRpc + * listLogs(com.google.logging.v2.ListLogsRequest) + + \ No newline at end of file diff --git a/google-cloud-logging/src/main/java/com/google/cloud/logging/Logging.java b/google-cloud-logging/src/main/java/com/google/cloud/logging/Logging.java index b4b89001f..ce7334255 100644 --- a/google-cloud-logging/src/main/java/com/google/cloud/logging/Logging.java +++ b/google-cloud-logging/src/main/java/com/google/cloud/logging/Logging.java @@ -414,6 +414,53 @@ public static EntryListOption folder(String folder) { */ ApiFuture deleteSinkAsync(String sink); + /** + * Lists the log names. This method returns a {@link Page} object that can be used to consume + * paginated results. Use {@link ListOption} to specify the page size or the page token from which + * to start listing logs. + * + *

Example of listing log names, specifying the page size. + * + *

{@code
+   * Page logNames = logging.listLogs(ListOption.pageSize(100));
+   * Iterator logIterator = logNames.iterateAll().iterator();
+   * while (logIterator.hasNext()) {
+   *   String logName = logIterator.next();
+   *   // do something with the log name
+   * }
+   * }
+ * + * @throws LoggingException upon failure + */ + default Page listLogs(ListOption... options) { + throw new UnsupportedOperationException( + "method listLogs() does not have default implementation"); + } + + /** + * Sends a request for listing log names. This method returns a {@code ApiFuture} object to + * consume the result. {@link ApiFuture#get()} returns an {@link AsyncPage} object that can be + * used to asynchronously handle paginated results. Use {@link ListOption} to specify the page + * size or the page token from which to start listing log names. + * + *

Example of asynchronously listing log names, specifying the page size. + * + *

{@code
+   * ApiFuture> future = logging.listLogsAsync(ListOption.pageSize(100));
+   * // ...
+   * AsyncPage logNames = future.get();
+   * Iterator logIterator = logNames.iterateAll().iterator();
+   * while (logIterator.hasNext()) {
+   *   String logName = logIterator.next();
+   *   // do something with the log name
+   * }
+   * }
+ */ + default ApiFuture> listLogsAsync(ListOption... options) { + throw new UnsupportedOperationException( + "method listLogsAsync() does not have default implementation"); + } + /** * Deletes a log and all its log entries. The log will reappear if new entries are written to it. * diff --git a/google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingImpl.java b/google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingImpl.java index bffc794b4..76c2195ce 100644 --- a/google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingImpl.java +++ b/google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingImpl.java @@ -65,6 +65,8 @@ import com.google.logging.v2.ListLogEntriesResponse; import com.google.logging.v2.ListLogMetricsRequest; import com.google.logging.v2.ListLogMetricsResponse; +import com.google.logging.v2.ListLogsRequest; +import com.google.logging.v2.ListLogsResponse; import com.google.logging.v2.ListMonitoredResourceDescriptorsRequest; import com.google.logging.v2.ListMonitoredResourceDescriptorsResponse; import com.google.logging.v2.ListSinksRequest; @@ -195,6 +197,19 @@ public ApiFuture> getNextPage() { } } + private static class LogNamePageFetcher extends BasePageFetcher { + + LogNamePageFetcher( + LoggingOptions serviceOptions, String cursor, Map requestOptions) { + super(serviceOptions, cursor, requestOptions); + } + + @Override + public ApiFuture> getNextPage() { + return listLogsAsync(serviceOptions(), requestOptions()); + } + } + private static class MonitoredResourceDescriptorPageFetcher extends BasePageFetcher { @@ -366,6 +381,63 @@ public ApiFuture deleteSinkAsync(String sink) { return transform(rpc.delete(request), EMPTY_TO_BOOLEAN_FUNCTION); } + /** + * Creates a new {@code ListLogsRequest} object. + * + *

Builds an instance of {@code ListLogsRequest} using page size, page token and project id + * from the {@code LoggingOptions}. The project id is used as the request's parent parameter. + * + * @see com.google.logging.v2.ListLogEntriesRequest + * @return the created {@code ListLogsRequest} object + */ + private static ListLogsRequest listLogsRequest( + LoggingOptions serviceOptions, Map options) { + ListLogsRequest.Builder builder = ListLogsRequest.newBuilder(); + builder.setParent(ProjectName.of(serviceOptions.getProjectId()).toString()); + Integer pageSize = PAGE_SIZE.get(options); + String pageToken = PAGE_TOKEN.get(options); + if (pageSize != null) { + builder.setPageSize(pageSize); + } + if (pageToken != null) { + builder.setPageToken(pageToken); + } + return builder.build(); + } + + private static ApiFuture> listLogsAsync( + final LoggingOptions serviceOptions, final Map options) { + final ListLogsRequest request = listLogsRequest(serviceOptions, options); + ApiFuture list = serviceOptions.getLoggingRpcV2().listLogs(request); + return transform( + list, + new Function>() { + @Override + public AsyncPage apply(ListLogsResponse listLogsResponse) { + List logNames = + listLogsResponse.getLogNamesList() == null + ? ImmutableList.of() + : listLogsResponse.getLogNamesList(); + String cursor = + listLogsResponse.getNextPageToken().equals("") + ? null + : listLogsResponse.getNextPageToken(); + return new AsyncPageImpl<>( + new LogNamePageFetcher(serviceOptions, cursor, options), cursor, logNames); + } + }); + } + + @Override + public Page listLogs(ListOption... options) { + return get(listLogsAsync(options)); + } + + @Override + public ApiFuture> listLogsAsync(ListOption... options) { + return listLogsAsync(getOptions(), optionMap(options)); + } + public boolean deleteLog(String log) { return get(deleteLogAsync(log)); } diff --git a/google-cloud-logging/src/main/java/com/google/cloud/logging/spi/v2/GrpcLoggingRpc.java b/google-cloud-logging/src/main/java/com/google/cloud/logging/spi/v2/GrpcLoggingRpc.java index 6b9730c66..9217bd4ea 100644 --- a/google-cloud-logging/src/main/java/com/google/cloud/logging/spi/v2/GrpcLoggingRpc.java +++ b/google-cloud-logging/src/main/java/com/google/cloud/logging/spi/v2/GrpcLoggingRpc.java @@ -61,6 +61,8 @@ import com.google.logging.v2.ListLogEntriesResponse; import com.google.logging.v2.ListLogMetricsRequest; import com.google.logging.v2.ListLogMetricsResponse; +import com.google.logging.v2.ListLogsRequest; +import com.google.logging.v2.ListLogsResponse; import com.google.logging.v2.ListMonitoredResourceDescriptorsRequest; import com.google.logging.v2.ListMonitoredResourceDescriptorsResponse; import com.google.logging.v2.ListSinksRequest; @@ -260,6 +262,11 @@ public ApiFuture delete(DeleteExclusionRequest request) { StatusCode.Code.NOT_FOUND); } + @Override + public ApiFuture listLogs(ListLogsRequest request) { + return translate(loggingClient.listLogsCallable().futureCall(request), true); + } + @Override public ApiFuture delete(DeleteLogRequest request) { return translate( diff --git a/google-cloud-logging/src/main/java/com/google/cloud/logging/spi/v2/LoggingRpc.java b/google-cloud-logging/src/main/java/com/google/cloud/logging/spi/v2/LoggingRpc.java index 06e4c068b..a41b35d24 100644 --- a/google-cloud-logging/src/main/java/com/google/cloud/logging/spi/v2/LoggingRpc.java +++ b/google-cloud-logging/src/main/java/com/google/cloud/logging/spi/v2/LoggingRpc.java @@ -34,6 +34,8 @@ import com.google.logging.v2.ListLogEntriesResponse; import com.google.logging.v2.ListLogMetricsRequest; import com.google.logging.v2.ListLogMetricsResponse; +import com.google.logging.v2.ListLogsRequest; +import com.google.logging.v2.ListLogsResponse; import com.google.logging.v2.ListMonitoredResourceDescriptorsRequest; import com.google.logging.v2.ListMonitoredResourceDescriptorsResponse; import com.google.logging.v2.ListSinksRequest; @@ -93,6 +95,18 @@ public interface LoggingRpc extends AutoCloseable, ServiceRpc { */ ApiFuture delete(DeleteSinkRequest request); + /** + * Sends a request to list the log names in a project. This method returns a {@code ApiFuture} + * object to consume the result. {@link ApiFuture#get()} returns a response object containing the + * listing result. + * + * @param request the request object containing all of the parameters for the API call + */ + default ApiFuture listLogs(ListLogsRequest request) { + throw new UnsupportedOperationException( + "method list(ListLogsRequest request) does not have default implementation"); + } + /** * Sends a request to deletes a log. This method returns a {@code ApiFuture} object to consume the * result. {@link ApiFuture#get()} returns {@link Empty#getDefaultInstance()} or {@code null} if diff --git a/google-cloud-logging/src/test/java/com/google/cloud/logging/LoggingImplTest.java b/google-cloud-logging/src/test/java/com/google/cloud/logging/LoggingImplTest.java index fe34719d8..d1cd5946e 100644 --- a/google-cloud-logging/src/test/java/com/google/cloud/logging/LoggingImplTest.java +++ b/google-cloud-logging/src/test/java/com/google/cloud/logging/LoggingImplTest.java @@ -63,6 +63,8 @@ import com.google.logging.v2.ListLogEntriesResponse; import com.google.logging.v2.ListLogMetricsRequest; import com.google.logging.v2.ListLogMetricsResponse; +import com.google.logging.v2.ListLogsRequest; +import com.google.logging.v2.ListLogsResponse; import com.google.logging.v2.ListMonitoredResourceDescriptorsRequest; import com.google.logging.v2.ListMonitoredResourceDescriptorsResponse; import com.google.logging.v2.ListSinksRequest; @@ -106,6 +108,9 @@ public class LoggingImplTest { com.google.api.MonitoredResourceDescriptor.getDefaultInstance(); private static final MonitoredResourceDescriptor DESCRIPTOR = MonitoredResourceDescriptor.fromPb(DESCRIPTOR_PB); + private static final String LOG_NAME1 = "test-list-log-name-1"; + private static final String LOG_NAME2 = "test-list-log-name-2"; + private static final String LOG_NAMES_CURSOR = "cursor"; private static final String LOG_NAME = "log"; private static final String LOG_NAME_PB = "projects/" + PROJECT + "/logs/" + LOG_NAME; private static final MonitoredResource MONITORED_RESOURCE = @@ -173,6 +178,40 @@ public com.google.api.MonitoredResourceDescriptor apply( private LoggingRpc loggingRpcMock; private Logging logging; + private void configureListLogsTests(List returnedList, String cursor) { + ListLogsRequest request = ListLogsRequest.newBuilder().setParent(PROJECT_PB).build(); + ListLogsResponse response = + ListLogsResponse.newBuilder().setNextPageToken(cursor).addAllLogNames(returnedList).build(); + ApiFuture futureResponse = ApiFutures.immediateFuture(response); + EasyMock.expect(loggingRpcMock.listLogs(request)).andReturn(futureResponse); + EasyMock.replay(loggingRpcMock); + } + + private void configureListLogsTests( + List page1ReturnedList, + List page2ReturnedList, + String page1Cursor, + String page2Cursor) { + ListLogsRequest request1 = ListLogsRequest.newBuilder().setParent(PROJECT_PB).build(); + ListLogsRequest request2 = + ListLogsRequest.newBuilder().setParent(PROJECT_PB).setPageToken(page1Cursor).build(); + ListLogsResponse response1 = + ListLogsResponse.newBuilder() + .setNextPageToken(page1Cursor) + .addAllLogNames(page1ReturnedList) + .build(); + ListLogsResponse response2 = + ListLogsResponse.newBuilder() + .setNextPageToken(page2Cursor) + .addAllLogNames(page2ReturnedList) + .build(); + ApiFuture futureResponse1 = ApiFutures.immediateFuture(response1); + ApiFuture futureResponse2 = ApiFutures.immediateFuture(response2); + EasyMock.expect(loggingRpcMock.listLogs(request1)).andReturn(futureResponse1); + EasyMock.expect(loggingRpcMock.listLogs(request2)).andReturn(futureResponse2); + EasyMock.replay(loggingRpcMock); + } + @Before public void setUp() { rpcFactoryMock = EasyMock.createStrictMock(LoggingRpcFactory.class); @@ -187,8 +226,10 @@ public void setUp() { .build(); // By default when calling ListLogEntries, we append a filter of last 24 hours. - // However when testing, the time when it was called by the test and by the method - // implementation might differ by microseconds so we use the same time filter implementation + // However when testing, the time when it was called by the test and by the + // method + // implementation might differ by microseconds so we use the same time filter + // implementation // for test and in "real" method LoggingImpl.defaultTimestampFilterCreator = new ITimestampDefaultFilter() { @@ -1576,6 +1617,89 @@ public void testListResourceDescriptorAsyncWithOptions() Iterables.toArray(page.getValues(), MonitoredResourceDescriptor.class)); } + @Test + public void testListLogsWithLogNames() { + EasyMock.replay(rpcFactoryMock); + logging = options.getService(); + List logNames = ImmutableList.of(LOG_NAME1, LOG_NAME2); + configureListLogsTests(logNames, LOG_NAMES_CURSOR); + + Page page = logging.listLogs(); + assertEquals(LOG_NAMES_CURSOR, page.getNextPageToken()); + assertArrayEquals(logNames.toArray(), Iterables.toArray(page.getValues(), String.class)); + } + + @Test + public void testListLogsWithEmptySet() { + EasyMock.replay(rpcFactoryMock); + logging = options.getService(); + List emptyList = ImmutableList.of(); + configureListLogsTests(emptyList, LOG_NAMES_CURSOR); + + Page page = logging.listLogs(); + assertEquals(LOG_NAMES_CURSOR, page.getNextPageToken()); + assertArrayEquals(emptyList.toArray(), Iterables.toArray(page.getValues(), String.class)); + } + + @Test + public void testListLogsNextPageWithLogNames() throws ExecutionException, InterruptedException { + EasyMock.replay(rpcFactoryMock); + logging = options.getService(); + List logNames1 = ImmutableList.of(LOG_NAME1, LOG_NAME2); + List logNames2 = ImmutableList.of(LOG_NAME1); + String nextPageCursor = "nextCursor"; + configureListLogsTests(logNames1, logNames2, LOG_NAMES_CURSOR, nextPageCursor); + + Page page = logging.listLogs(); + assertEquals(LOG_NAMES_CURSOR, page.getNextPageToken()); + assertArrayEquals(logNames1.toArray(), Iterables.toArray(page.getValues(), String.class)); + page = page.getNextPage(); + assertEquals(nextPageCursor, page.getNextPageToken()); + assertArrayEquals(logNames2.toArray(), Iterables.toArray(page.getValues(), String.class)); + } + + @Test + public void testListLogsAsyncWithLogNames() throws ExecutionException, InterruptedException { + EasyMock.replay(rpcFactoryMock); + logging = options.getService(); + List logNames = ImmutableList.of(LOG_NAME1, LOG_NAME2); + configureListLogsTests(logNames, LOG_NAMES_CURSOR); + + AsyncPage page = logging.listLogsAsync().get(); + assertEquals(LOG_NAMES_CURSOR, page.getNextPageToken()); + assertArrayEquals(logNames.toArray(), Iterables.toArray(page.getValues(), String.class)); + } + + @Test + public void testListLogsAsyncWithEmptySet() throws ExecutionException, InterruptedException { + EasyMock.replay(rpcFactoryMock); + logging = options.getService(); + List emptyList = ImmutableList.of(); + configureListLogsTests(emptyList, LOG_NAMES_CURSOR); + + AsyncPage page = logging.listLogsAsync().get(); + assertEquals(LOG_NAMES_CURSOR, page.getNextPageToken()); + assertArrayEquals(emptyList.toArray(), Iterables.toArray(page.getValues(), String.class)); + } + + @Test + public void testListLogsAsyncNextPageWithLogNames() + throws ExecutionException, InterruptedException { + EasyMock.replay(rpcFactoryMock); + logging = options.getService(); + List logNames1 = ImmutableList.of(LOG_NAME1, LOG_NAME2); + List logNames2 = ImmutableList.of(LOG_NAME1); + String nextPageCursor = "nextCursor"; + configureListLogsTests(logNames1, logNames2, LOG_NAMES_CURSOR, nextPageCursor); + + AsyncPage page = logging.listLogsAsync().get(); + assertEquals(LOG_NAMES_CURSOR, page.getNextPageToken()); + assertArrayEquals(logNames1.toArray(), Iterables.toArray(page.getValues(), String.class)); + page = page.getNextPageAsync().get(); + assertEquals(nextPageCursor, page.getNextPageToken()); + assertArrayEquals(logNames2.toArray(), Iterables.toArray(page.getValues(), String.class)); + } + @Test public void testDeleteLog() { DeleteLogRequest request = DeleteLogRequest.newBuilder().setLogName(LOG_NAME_PB).build(); @@ -2034,7 +2158,8 @@ public void testFlushStress() throws InterruptedException { EasyMock.expect(loggingRpcMock.write(request)).andReturn(mockRpcResponse).times(threads.length); EasyMock.replay(loggingRpcMock); - // log and flush concurrently in many threads to trigger a ConcurrentModificationException + // log and flush concurrently in many threads to trigger a + // ConcurrentModificationException final AtomicInteger exceptions = new AtomicInteger(0); for (int i = 0; i < threads.length; i++) { threads[i] = diff --git a/samples/snippets/src/main/java/com/example/logging/ListLogEntries.java b/samples/snippets/src/main/java/com/example/logging/ListLogEntries.java new file mode 100644 index 000000000..8c5131f41 --- /dev/null +++ b/samples/snippets/src/main/java/com/example/logging/ListLogEntries.java @@ -0,0 +1,60 @@ +/* + * Copyright 2021 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.logging; + +// [START logging_list_log_entries] +import com.google.api.gax.paging.Page; +import com.google.cloud.logging.LogEntry; +import com.google.cloud.logging.Logging; +import com.google.cloud.logging.Logging.EntryListOption; +import com.google.cloud.logging.LoggingOptions; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Calendar; + + +public class ListLogEntries { + + public static void main(String[] args) throws Exception { + // TODO(developer): Replace the variable value with valid log name before running the sample + // or provide it as an argument. + String logName = args.length > 0 ? args[0] : "test-log"; + + LoggingOptions options = LoggingOptions.getDefaultInstance(); + Logging logging = options.getService(); + + // When composing a filter, using indexed fields, such as timestamp, resource.type, logName and + // others can help accelerate the results + // Full list of indexed fields here: https://cloud.google.com/logging/docs/view/advanced-queries#finding-quickly + // This sample restrict the results to only last hour to minimize number of API calls + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.HOUR, -1); + DateFormat rfc3339 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); + String logFilter = "logName=projects/" + options.getProjectId() + "/logs/" + logName + + " AND timestamp>=\"" + rfc3339.format(calendar.getTime()) + "\""; + + // List all log entries + Page entries = logging.listLogEntries(EntryListOption.filter(logFilter)); + while (entries != null) { + for (LogEntry logEntry : entries.iterateAll()) { + System.out.println(logEntry); + } + entries = entries.getNextPage(); + } + } +} +// [END logging_list_log_entries] diff --git a/samples/snippets/src/main/java/com/example/logging/ListLogs.java b/samples/snippets/src/main/java/com/example/logging/ListLogs.java index 349c2788d..666077ebd 100644 --- a/samples/snippets/src/main/java/com/example/logging/ListLogs.java +++ b/samples/snippets/src/main/java/com/example/logging/ListLogs.java @@ -16,47 +16,34 @@ package com.example.logging; +// [START logging_list_logs] import com.google.api.gax.paging.Page; -import com.google.cloud.logging.LogEntry; import com.google.cloud.logging.Logging; -import com.google.cloud.logging.Logging.EntryListOption; import com.google.cloud.logging.LoggingOptions; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Calendar; -/** List logs programmatically using the Cloud Logging API. */ public class ListLogs { - /** Expects an existing Cloud Logging log name as an argument. */ public static void main(String... args) throws Exception { - // [START logging_list_log_entries] - // Instantiates a client - LoggingOptions options = LoggingOptions.getDefaultInstance(); - String logName = args[0]; - - try (Logging logging = options.getService()) { - - // When composing a filter, using indexed fields, such as - // timestamp, resource.type, logName and others can help accelerate the results - // Full list of indexed fields here: https://cloud.google.com/logging/docs/view/advanced-queries#finding-quickly - // Below we are restricting the results to only last hour to speedup getting the results back - Calendar calendar = Calendar.getInstance(); - calendar.add(Calendar.HOUR, -1); - DateFormat rfc3339 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); - String logFilter = "logName=projects/" + options.getProjectId() + "/logs/" + logName - + " AND timestamp>=\"" + rfc3339.format(calendar.getTime()) + "\""; - - // List all log entries - Page entries = logging.listLogEntries(EntryListOption.filter(logFilter)); - do { - for (LogEntry logEntry : entries.iterateAll()) { - System.out.println(logEntry); - } - entries = entries.getNextPage(); - } while (entries != null); + LoggingOptions options = LoggingOptions.getDefaultInstance(); + Logging logging = options.getService(); + + // List all log names + Page logNames = logging.listLogs(); + while (logNames != null) { + for (String logName : logNames.iterateAll()) { + System.out.println(logName); + } + logNames = logNames.getNextPage(); } - // [END logging_list_log_entries] } } +// [END logging_list_logs] + +// the following is a temporary location due to exclusive requirement +// from snippet layout vs. snippet-bot + +// [START logging_list_log_entries] + + +// [END logging_list_log_entries] diff --git a/samples/snippets/src/main/java/com/example/logging/LogEntryWriteHttpRequest.java b/samples/snippets/src/main/java/com/example/logging/LogEntryWriteHttpRequest.java index d17907d45..05e29a517 100644 --- a/samples/snippets/src/main/java/com/example/logging/LogEntryWriteHttpRequest.java +++ b/samples/snippets/src/main/java/com/example/logging/LogEntryWriteHttpRequest.java @@ -57,7 +57,7 @@ public static void createLogEntryRequest(String logName, String payLoad, HttpReq // Writes the log entry asynchronously logging.write(Collections.singleton(logEntry)); - System.out.printf("Logged: %s%n", payLoad); + System.out.printf("Logged: %s", payLoad); } } } diff --git a/samples/snippets/src/main/java/com/example/logging/QuickstartSample.java b/samples/snippets/src/main/java/com/example/logging/QuickstartSample.java index 7ed408ed7..754c0bf41 100644 --- a/samples/snippets/src/main/java/com/example/logging/QuickstartSample.java +++ b/samples/snippets/src/main/java/com/example/logging/QuickstartSample.java @@ -26,8 +26,8 @@ import java.util.Collections; /** - * This sample demonstrates writing logs using the Cloud Logging API. The library also offers - * a java.util.logging Handler `com.google.cloud.logging.LoggingHandler` Logback integration is also + * This sample demonstrates writing logs using the Cloud Logging API. The library also offers a + * java.util.logging Handler `com.google.cloud.logging.LoggingHandler` Logback integration is also * available : * https://github.com/googleapis/google-cloud-java/tree/master/google-cloud-clients/google-cloud-contrib/google-cloud-logging-logback * Using the java.util.logging handler / Logback appender should be preferred to using the API diff --git a/samples/snippets/src/test/java/com/example/logging/LoggingIT.java b/samples/snippets/src/test/java/com/example/logging/LoggingIT.java index 791f8c3b0..5bfc1e9b1 100644 --- a/samples/snippets/src/test/java/com/example/logging/LoggingIT.java +++ b/samples/snippets/src/test/java/com/example/logging/LoggingIT.java @@ -38,9 +38,10 @@ @SuppressWarnings("checkstyle:abbreviationaswordinname") public class LoggingIT { - private static final String QUICKSTART_LOG = "my-log"; - private static final String TEST_WRITE_LOG = "test-log"; - private static final String STRING_PAYLOAD = "Hello world!"; + private static final String TEST_LOG = "test-log"; + private static final String GOOGLEAPIS_AUDIT_LOGNAME = "cloudaudit.googleapis.com%2Factivity"; + private static final String STRING_PAYLOAD = "Hello, world!"; + private static final String STRING_PAYLOAD2 = "Hello world again"; private ByteArrayOutputStream bout; private PrintStream out; @@ -60,37 +61,38 @@ public void setUp() { @After public void tearDown() { // Clean up created logs - deleteLog(QUICKSTART_LOG); - deleteLog(TEST_WRITE_LOG); + deleteLog(TEST_LOG); System.setOut(null); } @Test public void testQuickstart() throws Exception { - QuickstartSample.main(QUICKSTART_LOG); + QuickstartSample.main(TEST_LOG); String got = bout.toString(); - assertThat(got).contains("Logged: Hello, world!"); + assertThat(got).contains(String.format("Logged: %s", STRING_PAYLOAD)); } @Test(timeout = 60000) public void testWriteAndListLogs() throws Exception { // write a log entry LogEntry entry = - LogEntry.newBuilder(StringPayload.of("Hello world again")) - .setLogName(TEST_WRITE_LOG) + LogEntry.newBuilder(StringPayload.of(STRING_PAYLOAD2)) + .setLogName(TEST_LOG) .setResource(MonitoredResource.newBuilder("global").build()) .build(); logging.write(Collections.singleton(entry)); // flush out log immediately logging.flush(); bout.reset(); - // Check if the log is listed yet + + // Check for mocked STDOUT having data + String[] args = new String[] {TEST_LOG}; while (bout.toString().isEmpty()) { - ListLogs.main(TEST_WRITE_LOG); + ListLogEntries.main(args); Thread.sleep(5000); } - assertThat(bout.toString().contains("Hello world again")).isTrue(); + assertThat(bout.toString().contains(STRING_PAYLOAD2)).isTrue(); } @Test(timeout = 60000) @@ -101,15 +103,17 @@ public void testWriteLogHttpRequest() throws Exception { .setRequestMethod(HttpRequest.RequestMethod.GET) .setStatus(200) .build(); - LogEntryWriteHttpRequest.createLogEntryRequest(TEST_WRITE_LOG, STRING_PAYLOAD, request); + LogEntryWriteHttpRequest.createLogEntryRequest(TEST_LOG, STRING_PAYLOAD, request); String got = bout.toString(); // Check weather log entry is logged or not assertThat(got).contains(String.format("Logged: %s", STRING_PAYLOAD)); bout.reset(); - // Check if the log is listed yet + + // Check for mocked STDOUT having data + String[] args = new String[] {TEST_LOG}; while (bout.toString().isEmpty()) { - ListLogs.main(TEST_WRITE_LOG); + ListLogEntries.main(args); Thread.sleep(5000); } @@ -117,4 +121,15 @@ public void testWriteLogHttpRequest() throws Exception { assertThat(bout.toString().contains(STRING_PAYLOAD)).isTrue(); assertThat(bout.toString().contains(request.toString())).isTrue(); } + + @Test(timeout = 60000) + public void testListLogNames_shouldPass() throws Exception { + ListLogs.main(); + // Check for mocked STDOUT having data + while (bout.toString().isEmpty()) { + Thread.sleep(5000); + } + + assertThat(bout.toString().contains(GOOGLEAPIS_AUDIT_LOGNAME)).isTrue(); + } }