Skip to content

Commit e90c772

Browse files
committed
Implement LogEntry methods and tests (#1110)
1 parent a5c98b2 commit e90c772

3 files changed

Lines changed: 576 additions & 0 deletions

File tree

gcloud-java-logging/src/main/java/com/google/cloud/logging/Logging.java

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717
package com.google.cloud.logging;
1818

1919
import com.google.cloud.AsyncPage;
20+
import com.google.cloud.MonitoredResource;
2021
import com.google.cloud.MonitoredResourceDescriptor;
2122
import com.google.cloud.Page;
2223
import com.google.cloud.Service;
24+
import com.google.common.collect.ImmutableMap;
2325

2426
import java.util.Map;
2527
import java.util.concurrent.Future;
@@ -62,6 +64,134 @@ public static ListOption pageToken(String pageToken) {
6264
}
6365
}
6466

67+
/**
68+
* Class for specifying options for writing log entries.
69+
*/
70+
final class WriteOption extends Option {
71+
72+
private static final long serialVersionUID = 715900132268584612L;
73+
74+
enum OptionType implements Option.OptionType {
75+
LOG_NAME, RESOURCE, LABELS;
76+
77+
@SuppressWarnings("unchecked")
78+
<T> T get(Map<Option.OptionType, ?> options) {
79+
return (T) options.get(this);
80+
}
81+
}
82+
83+
private WriteOption(OptionType option, Object value) {
84+
super(option, value);
85+
}
86+
87+
/**
88+
* Returns an option to specify a default log name (see {@link LogEntry#logName()}) for those
89+
* log entries that do not specify their own log name. Example: {@code syslog}.
90+
*/
91+
public static WriteOption logName(String logName) {
92+
return new WriteOption(OptionType.LOG_NAME, logName);
93+
}
94+
95+
/**
96+
* Returns an option to specify a default monitored resource (see {@link LogEntry#resource()})
97+
* for those log entries that do not specify their own resource.
98+
*/
99+
public static WriteOption resource(MonitoredResource resource) {
100+
return new WriteOption(OptionType.RESOURCE, resource);
101+
}
102+
103+
/**
104+
* Sets an option to specify (key, value) pairs that are added to the {@link LogEntry#labels()}
105+
* of each log entry written, except when a log entry already has a value associated to the
106+
* same key.
107+
*/
108+
public static WriteOption labels(Map<String, String> labels) {
109+
return new WriteOption(OptionType.LABELS, ImmutableMap.copyOf(labels));
110+
}
111+
}
112+
113+
/**
114+
* Fields according to which log entries can be sorted.
115+
*/
116+
enum SortingField {
117+
TIMESTAMP;
118+
119+
String selector() {
120+
return name().toLowerCase();
121+
}
122+
}
123+
124+
/**
125+
* Sorting orders available when listing log entries.
126+
*/
127+
enum SortingOrder {
128+
DESCENDING("desc"),
129+
ASCENDING("asc");
130+
131+
private final String selector;
132+
133+
SortingOrder(String selector) {
134+
this.selector = selector;
135+
}
136+
137+
String selector() {
138+
return selector;
139+
}
140+
}
141+
142+
/**
143+
* Class for specifying options for listing log entries.
144+
*/
145+
final class EntryListOption extends Option {
146+
147+
private static final long serialVersionUID = -1561159676386917050L;
148+
149+
enum OptionType implements Option.OptionType {
150+
PAGE_SIZE, PAGE_TOKEN, ORDER_BY, FILTER;
151+
152+
@SuppressWarnings("unchecked")
153+
<T> T get(Map<Option.OptionType, ?> options) {
154+
return (T) options.get(this);
155+
}
156+
}
157+
158+
private EntryListOption(OptionType option, Object value) {
159+
super(option, value);
160+
}
161+
162+
/**
163+
* Returns an option to specify the maximum number of log entries returned per page.
164+
*/
165+
public static EntryListOption pageSize(int pageSize) {
166+
return new EntryListOption(OptionType.PAGE_SIZE, pageSize);
167+
}
168+
169+
/**
170+
* Returns an option to specify the page token from which to start listing log entries.
171+
*/
172+
public static EntryListOption pageToken(String pageToken) {
173+
return new EntryListOption(OptionType.PAGE_TOKEN, pageToken);
174+
}
175+
176+
/**
177+
* Returns an option to sort log entries. If not specified, log entries are sorted in ascending
178+
* (most-recent last) order with respect to the {@link LogEntry#timestamp()} value.
179+
*/
180+
public static EntryListOption sortOrder(SortingField field, SortingOrder order) {
181+
return new EntryListOption(OptionType.ORDER_BY, field.selector() + ' ' + order.selector());
182+
}
183+
184+
/**
185+
* Returns an option to specify a filter to the log entries to be listed.
186+
*
187+
* @see <a href="https://cloud.google.com/logging/docs/view/advanced_filters">Advanced Logs
188+
* Filters</a>
189+
*/
190+
public static EntryListOption filter(String filter) {
191+
return new EntryListOption(OptionType.FILTER, filter);
192+
}
193+
}
194+
65195
/**
66196
* Creates a new sink.
67197
*
@@ -244,4 +374,49 @@ Future<AsyncPage<MonitoredResourceDescriptor>> listMonitoredResourceDescriptorsA
244374
* if it was not found.
245375
*/
246376
Future<Boolean> deleteMetricAsync(String metric);
377+
378+
/**
379+
* Writes log entries to Cloud Logging. Use {@link WriteOption#logName(String)} to provide a log
380+
* name for those entries that do not specify one. Use
381+
* {@link WriteOption#resource(MonitoredResource)} to provide a monitored resource for those
382+
* entries that do not specify one. Use {@link WriteOption#labels(Map)} to provide some labels
383+
* to be added to every entry in {@code logEntries}.
384+
*/
385+
void write(Iterable<LogEntry> logEntries, WriteOption... options);
386+
387+
/**
388+
* Sends a request to log entries to Cloud Logging. Use {@link WriteOption#logName(String)} to
389+
* provide a log name for those entries that do not specify one. Use
390+
* {@link WriteOption#resource(MonitoredResource)} to provide a monitored resource for those
391+
* entries that do not specify one. Use {@link WriteOption#labels(Map)} to provide some labels
392+
* to be added to every entry in {@code logEntries}. The method returns a {@code Future} object
393+
* that can be used to wait for the write operation to be completed.
394+
*/
395+
Future<Void> writeAsync(Iterable<LogEntry> logEntries, WriteOption... options);
396+
397+
/**
398+
* Lists log entries. This method returns a {@link Page} object that can be used to consume
399+
* paginated results. Use {@link EntryListOption#pageSize(int)} to specify the page size. Use
400+
* {@link EntryListOption#pageToken(String)} to specify the page token from which to start listing
401+
* entries. Use {@link EntryListOption#sortOrder(SortingField, SortingOrder)} to sort log entries
402+
* according to your preferred order (default is most-recent last). Use
403+
* {@link EntryListOption#filter(String)} to filter listed log entries.
404+
*
405+
* @throws LoggingException upon failure
406+
*/
407+
Page<LogEntry> listLogEntries(EntryListOption... options);
408+
409+
/**
410+
* Sends a request for listing log entries. This method returns a {@code Future} object to consume
411+
* the result. {@link Future#get()} returns an {@link AsyncPage} object that can be used to
412+
* asynchronously handle paginated results. Use {@link EntryListOption#pageSize(int)} to specify
413+
* the page size. Use {@link EntryListOption#pageToken(String)} to specify the page token from
414+
* which to start listing entries. Use
415+
* {@link EntryListOption#sortOrder(SortingField, SortingOrder)} to sort log entries according to
416+
* your preferred order (default is most-recent last). Use {@link EntryListOption#filter(String)}
417+
* to filter listed log entries.
418+
*
419+
* @throws LoggingException upon failure
420+
*/
421+
Future<AsyncPage<LogEntry>> listLogEntriesAsync(EntryListOption... options);
247422
}

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

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,19 @@
1717
package com.google.cloud.logging;
1818

1919
import static com.google.api.client.util.Preconditions.checkArgument;
20+
import static com.google.cloud.logging.Logging.EntryListOption.OptionType.FILTER;
21+
import static com.google.cloud.logging.Logging.EntryListOption.OptionType.ORDER_BY;
2022
import static com.google.cloud.logging.Logging.ListOption.OptionType.PAGE_SIZE;
2123
import static com.google.cloud.logging.Logging.ListOption.OptionType.PAGE_TOKEN;
24+
import static com.google.cloud.logging.Logging.WriteOption.OptionType.LABELS;
25+
import static com.google.cloud.logging.Logging.WriteOption.OptionType.LOG_NAME;
26+
import static com.google.cloud.logging.Logging.WriteOption.OptionType.RESOURCE;
2227
import static com.google.common.util.concurrent.Futures.lazyTransform;
2328

2429
import com.google.cloud.AsyncPage;
2530
import com.google.cloud.AsyncPageImpl;
2631
import com.google.cloud.BaseService;
32+
import com.google.cloud.MonitoredResource;
2733
import com.google.cloud.MonitoredResourceDescriptor;
2834
import com.google.cloud.Page;
2935
import com.google.cloud.PageImpl;
@@ -34,6 +40,7 @@
3440
import com.google.common.base.Function;
3541
import com.google.common.base.Throwables;
3642
import com.google.common.collect.ImmutableList;
43+
import com.google.common.collect.Iterables;
3744
import com.google.common.collect.Lists;
3845
import com.google.common.collect.Maps;
3946
import com.google.common.util.concurrent.Uninterruptibles;
@@ -44,6 +51,8 @@
4451
import com.google.logging.v2.DeleteSinkRequest;
4552
import com.google.logging.v2.GetLogMetricRequest;
4653
import com.google.logging.v2.GetSinkRequest;
54+
import com.google.logging.v2.ListLogEntriesRequest;
55+
import com.google.logging.v2.ListLogEntriesResponse;
4756
import com.google.logging.v2.ListLogMetricsRequest;
4857
import com.google.logging.v2.ListLogMetricsResponse;
4958
import com.google.logging.v2.ListMonitoredResourceDescriptorsRequest;
@@ -52,6 +61,8 @@
5261
import com.google.logging.v2.ListSinksResponse;
5362
import com.google.logging.v2.UpdateLogMetricRequest;
5463
import com.google.logging.v2.UpdateSinkRequest;
64+
import com.google.logging.v2.WriteLogEntriesRequest;
65+
import com.google.logging.v2.WriteLogEntriesResponse;
5566
import com.google.protobuf.Empty;
5667

5768
import java.util.List;
@@ -71,6 +82,13 @@ public Boolean apply(Empty input) {
7182
return input != null;
7283
}
7384
};
85+
private static final Function<WriteLogEntriesResponse, Void> WRITE_RESPONSE_TO_VOID_FUNCTION =
86+
new Function<WriteLogEntriesResponse, Void>() {
87+
@Override
88+
public Void apply(WriteLogEntriesResponse input) {
89+
return null;
90+
}
91+
};
7492

7593
LoggingImpl(LoggingOptions options) {
7694
super(options);
@@ -154,6 +172,21 @@ public Future<AsyncPage<Metric>> nextPage() {
154172
}
155173
}
156174

175+
private static class LogEntryPageFetcher extends BasePageFetcher<LogEntry> {
176+
177+
private static final long serialVersionUID = 4001239712280747734L;
178+
179+
LogEntryPageFetcher(LoggingOptions serviceOptions, String cursor,
180+
Map<Option.OptionType, ?> requestOptions) {
181+
super(serviceOptions, cursor, requestOptions);
182+
}
183+
184+
@Override
185+
public Future<AsyncPage<LogEntry>> nextPage() {
186+
return listLogEntriesAsync(serviceOptions(), requestOptions());
187+
}
188+
}
189+
157190
@Override
158191
public Sink create(SinkInfo sink) {
159192
return get(createAsync(sink));
@@ -408,6 +441,87 @@ public Future<Boolean> deleteMetricAsync(String metric) {
408441
return lazyTransform(rpc.delete(request), EMPTY_TO_BOOLEAN_FUNCTION);
409442
}
410443

444+
private static WriteLogEntriesRequest writeLogEntriesRequest(LoggingOptions serviceOptions,
445+
Iterable<LogEntry> logEntries, Map<Option.OptionType, ?> options) {
446+
String projectId = serviceOptions.projectId();
447+
WriteLogEntriesRequest.Builder builder = WriteLogEntriesRequest.newBuilder();
448+
String logName = LOG_NAME.get(options);
449+
if (logName != null) {
450+
builder.setLogName(LoggingServiceV2Api.formatLogName(projectId, logName));
451+
}
452+
MonitoredResource resource = RESOURCE.get(options);
453+
if (resource != null) {
454+
builder.setResource(resource.toPb());
455+
}
456+
Map<String, String> labels = LABELS.get(options);
457+
if (labels != null) {
458+
builder.putAllLabels(labels);
459+
}
460+
builder.addAllEntries(Iterables.transform(logEntries, LogEntry.toPbFunction(projectId)));
461+
return builder.build();
462+
}
463+
464+
public void write(Iterable<LogEntry> logEntries, WriteOption... options) {
465+
get(writeAsync(logEntries, options));
466+
}
467+
468+
public Future<Void> writeAsync(Iterable<LogEntry> logEntries, WriteOption... options) {
469+
return lazyTransform(
470+
rpc.write(writeLogEntriesRequest(options(), logEntries, optionMap(options))),
471+
WRITE_RESPONSE_TO_VOID_FUNCTION);
472+
}
473+
474+
private static ListLogEntriesRequest listLogEntriesRequest(LoggingOptions serviceOptions,
475+
Map<Option.OptionType, ?> options) {
476+
ListLogEntriesRequest.Builder builder = ListLogEntriesRequest.newBuilder();
477+
builder.addProjectIds(serviceOptions.projectId());
478+
Integer pageSize = PAGE_SIZE.get(options);
479+
if (pageSize != null) {
480+
builder.setPageSize(pageSize);
481+
}
482+
String pageToken = PAGE_TOKEN.get(options);
483+
if (pageToken != null) {
484+
builder.setPageToken(pageToken);
485+
}
486+
String orderBy = ORDER_BY.get(options);
487+
if (orderBy != null) {
488+
builder.setOrderBy(orderBy);
489+
}
490+
String filter = FILTER.get(options);
491+
if (filter != null) {
492+
builder.setFilter(filter);
493+
}
494+
return builder.build();
495+
}
496+
497+
private static Future<AsyncPage<LogEntry>> listLogEntriesAsync(
498+
final LoggingOptions serviceOptions, final Map<Option.OptionType, ?> options) {
499+
final ListLogEntriesRequest request = listLogEntriesRequest(serviceOptions, options);
500+
Future<ListLogEntriesResponse> list = serviceOptions.rpc().list(request);
501+
return lazyTransform(list, new Function<ListLogEntriesResponse, AsyncPage<LogEntry>>() {
502+
@Override
503+
public AsyncPage<LogEntry> apply(ListLogEntriesResponse listLogEntrysResponse) {
504+
List<LogEntry> entries = listLogEntrysResponse.getEntriesList() == null
505+
? ImmutableList.<LogEntry>of() : Lists.transform(listLogEntrysResponse.getEntriesList(),
506+
LogEntry.FROM_PB_FUNCTION);
507+
String cursor = listLogEntrysResponse.getNextPageToken().equals("") ? null
508+
: listLogEntrysResponse.getNextPageToken();
509+
return new AsyncPageImpl<>(new LogEntryPageFetcher(serviceOptions, cursor, options), cursor,
510+
entries);
511+
}
512+
});
513+
}
514+
515+
@Override
516+
public Page<LogEntry> listLogEntries(EntryListOption... options) {
517+
return get(listLogEntriesAsync(options));
518+
}
519+
520+
@Override
521+
public Future<AsyncPage<LogEntry>> listLogEntriesAsync(EntryListOption... options) {
522+
return listLogEntriesAsync(options(), optionMap(options));
523+
}
524+
411525
@Override
412526
public void close() throws Exception {
413527
if (closed) {

0 commit comments

Comments
 (0)