Skip to content

Commit

Permalink
fix: fix samples region tags and test flakiness (#680)
Browse files Browse the repository at this point in the history
* chore: fix list logs snippet

define timestamp filter in UTC time.
change filter to last minute entries.
enforce closing logging client at the end of the snippet.
apply formatting.

* chore: enforce closing logging client in samples

force closing logging client at the end of the snippet

* fix: fix region tag for LogEntryWriteHttpRequest

change logging_write_request_entry to logging_write_log_entry_advanced

* fix: add snippet for missing logging_write_log_entry

* chore: move testListLogNamesSample to separate test

* fix: fix samples testing

add closing logging client at the end of the test unit
add multiple attempts to clean log after each test
print debug info in a case cleaning fails

* fix: add test for WriteLogEntry

remove unused textPayload from the snippet

* 🦉 Updates from OwlBot

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
  • Loading branch information
minherz and gcf-owl-bot[bot] committed Sep 23, 2021
1 parent 9db233f commit 53481bd
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 68 deletions.
22 changes: 22 additions & 0 deletions README.md
Expand Up @@ -166,6 +166,27 @@ LogEntry firstEntry = LogEntry.newBuilder(StringPayload.of("message"))
logging.write(Collections.singleton(firstEntry));
```

The library supports writing log entries synchronously and asynchronously.
In the synchronous mode each call to `write()` method results in a consequent call to Logging API to write a log entry.
In the asynchronous mode the call(s) to Logging API takes place asynchronously and few calls to `write()` method may be batched together to compose a single call to Logging API.
The default mode of writing is asynchronous.
It can be configured in the `java.util.logging` handler [configuration file](https://cloud.google.com/logging/docs/setup/java#javautillogging_configuration):

```
com.google.cloud.logging.LoggingHandler.synchronicity=SYNC
```

or in the code after initiating an instance of `Logging` by calling:

```java
logging.setWriteSynchronicity(Synchronicity.SYNC);
```

NOTE:
> Writing log entries asynchronously in some Google Cloud managed environments (e.g. Cloud Functions)
> may lead to unexpected results such as absense of expected log entries or abnormal program execution.
> To avoid these unexpected results, it is recommended to use synchronous mode.
#### Listing log entries

With Logging you can also list log entries that have been previously written. Add the following
Expand Down Expand Up @@ -236,6 +257,7 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-logging/tree/
| Log Entry Write Http Request | [source code](https://github.com/googleapis/java-logging/blob/master/samples/snippets/src/main/java/com/example/logging/LogEntryWriteHttpRequest.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-logging&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/logging/LogEntryWriteHttpRequest.java) |
| Quickstart Sample | [source code](https://github.com/googleapis/java-logging/blob/master/samples/snippets/src/main/java/com/example/logging/QuickstartSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-logging&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/logging/QuickstartSample.java) |
| Tail Log Entries | [source code](https://github.com/googleapis/java-logging/blob/master/samples/snippets/src/main/java/com/example/logging/TailLogEntries.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-logging&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/logging/TailLogEntries.java) |
| Write Log Entry | [source code](https://github.com/googleapis/java-logging/blob/master/samples/snippets/src/main/java/com/example/logging/WriteLogEntry.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-logging&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/logging/WriteLogEntry.java) |
| Quickstart | [source code](https://github.com/googleapis/java-logging/blob/master/samples/snippets/src/main/java/com/example/logging/jul/Quickstart.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-logging&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/logging/jul/Quickstart.java) |
| Example Enhancer | [source code](https://github.com/googleapis/java-logging/blob/master/samples/snippets/src/main/java/com/example/logging/jul/enhancers/ExampleEnhancer.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-logging&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/logging/jul/enhancers/ExampleEnhancer.java) |

Expand Down
Expand Up @@ -25,6 +25,7 @@
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;

public class ListLogEntries {

Expand All @@ -33,33 +34,34 @@ public static void main(String[] args) throws Exception {
// or provide it as an argument.
String logName = args.length > 0 ? args[0] : "test-log";

LoggingOptions options = LoggingOptions.getDefaultInstance();
Logging logging = options.getService();
try (Logging logging = LoggingOptions.getDefaultInstance().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())
+ "\"";
// 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 minute to minimize number of API calls
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
calendar.add(Calendar.MINUTE, -1);
DateFormat rfc3339 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
String logFilter =
"logName=projects/"
+ logging.getOptions().getProjectId()
+ "/logs/"
+ logName
+ " AND timestamp>=\""
+ rfc3339.format(calendar.getTime())
+ "\"";

// List all log entries
Page<LogEntry> entries = logging.listLogEntries(EntryListOption.filter(logFilter));
while (entries != null) {
for (LogEntry logEntry : entries.iterateAll()) {
System.out.println(logEntry);
// List all log entries
Page<LogEntry> entries = logging.listLogEntries(EntryListOption.filter(logFilter));
while (entries != null) {
for (LogEntry logEntry : entries.iterateAll()) {
System.out.println(logEntry);
}
entries = entries.getNextPage();
}
entries = entries.getNextPage();
}
}
}
Expand Down
16 changes: 8 additions & 8 deletions samples/snippets/src/main/java/com/example/logging/ListLogs.java
Expand Up @@ -25,16 +25,16 @@ public class ListLogs {

public static void main(String... args) throws Exception {

LoggingOptions options = LoggingOptions.getDefaultInstance();
Logging logging = options.getService();
try (Logging logging = LoggingOptions.getDefaultInstance().getService()) {

// List all log names
Page<String> logNames = logging.listLogs();
while (logNames != null) {
for (String logName : logNames.iterateAll()) {
System.out.println(logName);
// List all log names
Page<String> logNames = logging.listLogs();
while (logNames != null) {
for (String logName : logNames.iterateAll()) {
System.out.println(logName);
}
logNames = logNames.getNextPage();
}
logNames = logNames.getNextPage();
}
}
}
Expand Down
Expand Up @@ -16,7 +16,7 @@

package com.example.logging;

// [START logging_write_request_entry]
// [START logging_write_log_entry_advanced]
import com.google.cloud.MonitoredResource;
import com.google.cloud.logging.HttpRequest;
import com.google.cloud.logging.LogEntry;
Expand Down Expand Up @@ -61,4 +61,4 @@ public static void createLogEntryRequest(String logName, String payLoad, HttpReq
}
}
}
// [END logging_write_request_entry]
// [END logging_write_log_entry_advanced]
Expand Up @@ -37,27 +37,24 @@ public class QuickstartSample {

/** Expects a new or existing Cloud log name as the first argument. */
public static void main(String... args) throws Exception {

// Instantiates a client
Logging logging = LoggingOptions.getDefaultInstance().getService();

// The name of the log to write to
String logName = args[0]; // "my-log";
String textPayload = "Hello, world!";

// The data to write to the log
String text = "Hello, world!";

LogEntry entry =
LogEntry.newBuilder(StringPayload.of(text))
.setSeverity(Severity.ERROR)
.setLogName(logName)
.setResource(MonitoredResource.newBuilder("global").build())
.build();

// Writes the log entry asynchronously
logging.write(Collections.singleton(entry));

System.out.printf("Logged: %s%n", text);
// Instantiates a client
try (Logging logging = LoggingOptions.getDefaultInstance().getService()) {

LogEntry entry =
LogEntry.newBuilder(StringPayload.of(textPayload))
.setSeverity(Severity.ERROR)
.setLogName(logName)
.setResource(MonitoredResource.newBuilder("global").build())
.build();

// Writes the log entry asynchronously
logging.write(Collections.singleton(entry));
}
System.out.printf("Logged: %s%n", textPayload);
}
}
// [END logging_quickstart]
@@ -0,0 +1,53 @@
/*
* 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_write_log_entry]
import com.google.cloud.MonitoredResource;
import com.google.cloud.logging.LogEntry;
import com.google.cloud.logging.Logging;
import com.google.cloud.logging.LoggingOptions;
import com.google.cloud.logging.Payload.JsonPayload;
import com.google.cloud.logging.Severity;
import com.google.common.collect.ImmutableMap;
import java.util.Collections;
import java.util.Map;

public class WriteLogEntry {

public static void main(String[] args) throws Exception {
// TODO(developer): Optionally provide the logname as an argument
String logName = args.length > 0 ? args[0] : "test-log";

// Instantiates a client
try (Logging logging = LoggingOptions.getDefaultInstance().getService()) {
Map<String, String> payload =
ImmutableMap.of(
"name", "King Arthur", "quest", "Find the Holy Grail", "favorite_color", "Blue");
LogEntry entry =
LogEntry.newBuilder(JsonPayload.of(payload))
.setSeverity(Severity.INFO)
.setLogName(logName)
.setResource(MonitoredResource.newBuilder("global").build())
.build();

logging.write(Collections.singleton(entry));
}
System.out.printf("Wrote to %s\n", logName);
}
}
// [END logging_write_log_entry]
52 changes: 36 additions & 16 deletions samples/snippets/src/test/java/com/example/logging/LoggingIT.java
Expand Up @@ -30,7 +30,9 @@
import java.io.PrintStream;
import java.util.Collections;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
Expand All @@ -41,16 +43,38 @@
public class LoggingIT {

private static final String TEST_LOG = formatForTest("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;
private Logging logging = LoggingOptions.getDefaultInstance().getService();
private static Logging logging;

private void deleteLog(String logName) throws InterruptedException {
int deleteAttempts = 0;
int allowedDeleteAttempts = 5;
boolean deleted = false;
while (!deleted && deleteAttempts < allowedDeleteAttempts) {
deleted = logging.deleteLog(logName);
deleteAttempts++;
if (!deleted) {
Thread.sleep(1000);
}
}
if (!deleted) {
System.err.println(
"Failed to clean up log entries after 5 attempts. Following tests may be flaky...");
}
}

private void deleteLog(String logName) {
logging.deleteLog(logName);
@BeforeClass
public static void startup() {
logging = LoggingOptions.getDefaultInstance().getService();
}

@AfterClass
public static void shutDown() throws Exception {
logging.close();
}

@Before
Expand All @@ -61,13 +85,13 @@ public void setUp() {
}

@After
public void tearDown() {
public void tearDown() throws Exception {
// Clean up created logs
deleteLog(TEST_LOG);
System.setOut(null);
}

@Test
@Test(timeout = 60000)
public void testQuickstartSample() throws Exception {
QuickstartSample.main(TEST_LOG);
String got = bout.toString();
Expand Down Expand Up @@ -116,7 +140,7 @@ public void testWriteLogHttpRequestSample() throws Exception {
String[] args = new String[] {TEST_LOG};
while (bout.toString().isEmpty()) {
ListLogEntries.main(args);
Thread.sleep(5000);
Thread.sleep(1000);
}

// check log entry contain request data
Expand All @@ -125,14 +149,10 @@ public void testWriteLogHttpRequestSample() throws Exception {
}

@Test(timeout = 60000)
public void testListLogNamesSample() 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();
public void testWriteLogEntrySample() throws Exception {
WriteLogEntry.main(new String[] {TEST_LOG});
String got = bout.toString();
assertThat(got).contains(String.format("Wrote to %s", TEST_LOG));
}

@Test(timeout = 60000)
Expand All @@ -153,7 +173,7 @@ public void testTailLogEntriesSample() throws Exception {
logging.write(Collections.singleton(logEntry));
}
} catch (Exception t) {
System.out.println("Failed to write log entry:\n" + t);
System.err.println("Failed to write log entry:\n" + t);
}
};
Thread thread = new Thread(task);
Expand Down

0 comments on commit 53481bd

Please sign in to comment.