Skip to content

Commit 8115888

Browse files
feat: Add a sample snippet for use of the tailLogEntries API
Add sample in Java for use of tailLogEntries API * 🦉 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>
1 parent 5a7845a commit 8115888

File tree

9 files changed

+132
-16
lines changed

9 files changed

+132
-16
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ If you are using Maven without BOM, add this to your dependencies:
4242
<dependency>
4343
<groupId>com.google.cloud</groupId>
4444
<artifactId>google-cloud-logging</artifactId>
45-
<version>3.1.1</version>
45+
<version>3.1.2</version>
4646
</dependency>
4747

4848
```
@@ -235,6 +235,7 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-logging/tree/
235235
| List Logs | [source code](https://github.com/googleapis/java-logging/blob/master/samples/snippets/src/main/java/com/example/logging/ListLogs.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/ListLogs.java) |
236236
| 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) |
237237
| 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) |
238+
| 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) |
238239
| 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) |
239240
| 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) |
240241

google-cloud-logging/src/main/java/com/google/cloud/logging/JavaTimeConversions.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.google.cloud.logging;
1818

19+
import static com.google.common.base.Preconditions.checkNotNull;
1920
import static com.google.common.math.LongMath.checkedAdd;
2021
import static com.google.common.math.LongMath.checkedSubtract;
2122

@@ -33,8 +34,8 @@
3334
* The class complements convertion methods that are currently not supported in the published
3435
* protobuf-java-util. After migrating protobuf-java-util to Java 8 this class can be removed.
3536
*
36-
* @see <a
37-
* href="https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java-util">protobuf-java-util</a>
37+
* @see <a href=
38+
* "https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java-util">protobuf-java-util</a>
3839
*/
3940
class JavaTimeConversions {
4041
static final long NANOS_PER_SECOND = 1000000000;
@@ -48,6 +49,7 @@ private JavaTimeConversions() {}
4849
* Timestamps#isValid}.
4950
*/
5051
public static Instant toJavaInstant(Timestamp timestamp) {
52+
checkNotNull(timestamp);
5153
timestamp = normalizedTimestamp(timestamp.getSeconds(), timestamp.getNanos());
5254
return Instant.ofEpochSecond(timestamp.getSeconds(), timestamp.getNanos());
5355
}
@@ -59,6 +61,7 @@ public static Instant toJavaInstant(Timestamp timestamp) {
5961
* a {@link Timestamp}. See {@link Timestamps#isValid}.
6062
*/
6163
public static Timestamp toProtoTimestamp(Instant instant) {
64+
checkNotNull(instant);
6265
return normalizedTimestamp(instant.getEpochSecond(), instant.getNano());
6366
}
6467

google-cloud-logging/src/main/java/com/google/cloud/logging/LogEntryIterator.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,14 @@
2121
import java.util.Iterator;
2222
import java.util.LinkedList;
2323

24+
/**
25+
* The class implements {@see Iterator} interface over {@see LogEntry} by iterating through {@see
26+
* TailLogEntriesResponse} streamed by {@code BidiStream}. This class is instantiated by {@see
27+
* LogEntryServerStream} and is not intended to be used explicitly.
28+
*/
2429
public class LogEntryIterator implements Iterator<LogEntry> {
30+
// TODO: consider converting this to use generics instead of
31+
// fixed TailLogEntriesResponse
2532
private final Iterator<TailLogEntriesResponse> streamIterator;
2633
private final LinkedList<LogEntry> buffer = new LinkedList<>();
2734

google-cloud-logging/src/main/java/com/google/cloud/logging/LogEntryServerStream.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,26 @@
2222
import com.google.logging.v2.TailLogEntriesResponse;
2323
import java.util.Iterator;
2424

25+
/**
26+
* The class implements {@Iterable} interface over {@see LogEntry}. It wraps around {@BidiStream}
27+
* bi-directional gRPC stream to support iterating through ingested responses. The class uses {@see
28+
* LogEntryIterator} to iterate through the processed responses. The stream should be explicitly
29+
* canceled by calling {@see LogEntryServerStream#cancel()} method. The class does not provide
30+
* recovery or resuming functionality over the stream.
31+
*
32+
* <p>To iterate run:
33+
*
34+
* <pre>{@code
35+
* LogEntryServerStream stream;
36+
* // code to initialize stream
37+
* for (LogEntry log : stream) {
38+
* // do something with logs
39+
* }
40+
* stream.cancel();
41+
* }</pre>
42+
*
43+
* <p>The iteration can be blocked on waiting for another response sent in the stream.
44+
*/
2545
public class LogEntryServerStream implements Iterable<LogEntry> {
2646
private final BidiStream<TailLogEntriesRequest, TailLogEntriesResponse> serverStream;
2747

google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -924,7 +924,7 @@ public ApiFuture<AsyncPage<LogEntry>> listLogEntriesAsync(EntryListOption... opt
924924
return listLogEntriesAsync(getOptions(), optionMap(options));
925925
}
926926

927-
static TailLogEntriesRequest tailLogEntriesRequest(
927+
static TailLogEntriesRequest buildTailLogEntriesRequest(
928928
Map<Option.OptionType, ?> options, String defaultProjectId) {
929929
TailLogEntriesRequest.Builder builder = TailLogEntriesRequest.newBuilder();
930930

@@ -967,7 +967,7 @@ public LogEntryServerStream tailLogEntries(TailOption... options) {
967967
BidiStream<TailLogEntriesRequest, TailLogEntriesResponse> bidiStream =
968968
serviceOptions.getLoggingRpcV2().getTailLogEntriesStream();
969969
final TailLogEntriesRequest request =
970-
tailLogEntriesRequest(optionMap(options), serviceOptions.getProjectId());
970+
buildTailLogEntriesRequest(optionMap(options), serviceOptions.getProjectId());
971971
bidiStream.send(request);
972972
return new LogEntryServerStream(bidiStream);
973973
}

google-cloud-logging/src/test/java/com/google/cloud/logging/TailLogEntriesTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public class TailLogEntriesTest {
4343
@Test
4444
public void testTailOptions() {
4545
TailLogEntriesRequest request =
46-
LoggingImpl.tailLogEntriesRequest(
46+
LoggingImpl.buildTailLogEntriesRequest(
4747
LoggingImpl.optionMap(
4848
TailOption.filter(FILTER),
4949
TailOption.bufferWindow(WINDOW),
@@ -66,7 +66,7 @@ public void testTailOptions() {
6666
@Test
6767
public void testEmptyTailOptions() {
6868
TailLogEntriesRequest request =
69-
LoggingImpl.tailLogEntriesRequest(LoggingImpl.optionMap(), DEFAULT_PROJECT_ID);
69+
LoggingImpl.buildTailLogEntriesRequest(LoggingImpl.optionMap(), DEFAULT_PROJECT_ID);
7070
assertThat(request.getFilter()).isEqualTo("");
7171
assertThat(request.getBufferWindow()).isEqualTo(Duration.newBuilder().build());
7272
assertThat(request.getResourceNamesList()).containsExactly("projects/" + DEFAULT_PROJECT_ID);

google-cloud-logging/src/test/java/com/google/cloud/logging/it/ITTailLogsTest.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,6 @@ public class ITTailLogsTest extends BaseSystemTest {
3434
private static final MonitoredResource GLOBAL_RESOURCE =
3535
MonitoredResource.newBuilder("global").build();
3636

37-
// @BeforeClass
38-
// public static void configureWriteLogs() {
39-
// }
40-
4137
@AfterClass
4238
public static void cleanUpLogs() throws InterruptedException {
4339
assertTrue(cleanupLog(LOG_ID));
@@ -83,7 +79,9 @@ public void testTailLogEntries() throws InterruptedException {
8379
assertEquals(testLogEntry.getLogName(), resultEntry.getLogName());
8480
assertEquals(
8581
testLogEntry.getHttpRequest().getStatus(), resultEntry.getHttpRequest().getStatus());
82+
// assert equals for Payload objects
8683
assertTrue(testLogEntry.getPayload().equals(resultEntry.getPayload()));
84+
// assert equals for Map<String,String> objects
8785
assertTrue(testLogEntry.getLabels().equals(resultEntry.getLabels()));
8886
}
8987
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2021 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.logging;
18+
19+
// [START logging_write_log_entry]
20+
import com.google.cloud.logging.LogEntry;
21+
import com.google.cloud.logging.LogEntryServerStream;
22+
import com.google.cloud.logging.Logging;
23+
import com.google.cloud.logging.Logging.TailOption;
24+
import com.google.cloud.logging.LoggingOptions;
25+
26+
public class TailLogEntries {
27+
28+
public static void main(String[] args) throws Exception {
29+
// TODO(developer): Optionally provide the logname as an argument.
30+
String logName = args.length > 0 ? args[0] : "";
31+
32+
LoggingOptions options = LoggingOptions.getDefaultInstance();
33+
try (Logging logging = options.getService()) {
34+
35+
// Optionally compose a filter to tail log entries only from specific log
36+
LogEntryServerStream stream;
37+
38+
if (logName != "") {
39+
stream =
40+
logging.tailLogEntries(
41+
TailOption.filter(
42+
"logName=projects/" + options.getProjectId() + "/logs/" + logName));
43+
} else {
44+
stream = logging.tailLogEntries();
45+
}
46+
System.out.println("start streaming..");
47+
for (LogEntry log : stream) {
48+
System.out.println(log);
49+
// cancel infinite streaming after receiving first entry
50+
stream.cancel();
51+
}
52+
}
53+
}
54+
}
55+
// [END logging_write_log_entry]

samples/snippets/src/test/java/com/example/logging/LoggingIT.java

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,19 +64,18 @@ public void setUp() {
6464
public void tearDown() {
6565
// Clean up created logs
6666
deleteLog(TEST_LOG);
67-
6867
System.setOut(null);
6968
}
7069

7170
@Test
72-
public void testQuickstart() throws Exception {
71+
public void testQuickstartSample() throws Exception {
7372
QuickstartSample.main(TEST_LOG);
7473
String got = bout.toString();
7574
assertThat(got).contains(String.format("Logged: %s", STRING_PAYLOAD));
7675
}
7776

7877
@Test(timeout = 60000)
79-
public void testListLogEntries() throws Exception {
78+
public void testListLogEntriesSample() throws Exception {
8079
// write a log entry
8180
LogEntry entry =
8281
LogEntry.newBuilder(StringPayload.of(STRING_PAYLOAD2))
@@ -99,7 +98,7 @@ public void testListLogEntries() throws Exception {
9998
}
10099

101100
@Test(timeout = 60000)
102-
public void testWriteLogHttpRequest() throws Exception {
101+
public void testWriteLogHttpRequestSample() throws Exception {
103102
HttpRequest request =
104103
HttpRequest.newBuilder()
105104
.setRequestUrl("www.example.com")
@@ -126,7 +125,7 @@ public void testWriteLogHttpRequest() throws Exception {
126125
}
127126

128127
@Test(timeout = 60000)
129-
public void testListLogNames_shouldPass() throws Exception {
128+
public void testListLogNamesSample() throws Exception {
130129
ListLogs.main();
131130
// Check for mocked STDOUT having data
132131
while (bout.toString().isEmpty()) {
@@ -135,4 +134,37 @@ public void testListLogNames_shouldPass() throws Exception {
135134

136135
assertThat(bout.toString().contains(GOOGLEAPIS_AUDIT_LOGNAME)).isTrue();
137136
}
137+
138+
@Test(timeout = 60000)
139+
public void testTailLogEntriesSample() throws Exception {
140+
Runnable task =
141+
() -> {
142+
// wait 10 seconds to allow establishing tail stream in the sample
143+
try {
144+
Thread.sleep(10_000);
145+
try (Logging logging = LoggingOptions.getDefaultInstance().getService()) {
146+
// create an instance of LogEntry with HTTP request
147+
LogEntry logEntry =
148+
LogEntry.newBuilder(StringPayload.of(STRING_PAYLOAD))
149+
.setLogName(TEST_LOG)
150+
.setResource(MonitoredResource.newBuilder("global").build())
151+
.build();
152+
// Writes the log entry asynchronously
153+
logging.write(Collections.singleton(logEntry));
154+
}
155+
} catch (Exception t) {
156+
System.out.println("Failed to write log entry:\n" + t)
157+
}
158+
};
159+
Thread thread = new Thread(task);
160+
thread.start();
161+
162+
TailLogEntries.main(new String[] {TEST_LOG});
163+
164+
// Check for mocked STDOUT having data
165+
while (bout.toString().isEmpty()) {
166+
Thread.sleep(1000);
167+
}
168+
assertThat(bout.toString().contains(STRING_PAYLOAD)).isTrue();
169+
}
138170
}

0 commit comments

Comments
 (0)